← Back to team overview

yade-dev team mailing list archive

[svn] r1853 - in trunk: pkg/common pkg/common/Engine/StandAloneEngine pkg/dem/Engine/DeusExMachina scripts/test

 

Author: eudoxos
Date: 2009-07-10 21:16:01 +0200 (Fri, 10 Jul 2009)
New Revision: 1853

Modified:
   trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp
   trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.hpp
   trunk/pkg/common/SConscript
   trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.cpp
   trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.hpp
   trunk/scripts/test/collider-stride-triax.py
Log:
1. Make NewtonsDampedLaw compute maxVlocitySq at every step anew.
2. Make InsertionSortCollider find NewtonsDampedLaw and get max speed from there. Together with InsertionSortColider::sweepLength, this makes stride adapted automatically to maxVelocitySq; this will described at http://yade.wikia.com/wiki/Insertion_Sort_Collider_Stride. 
3. Update test script for that.


Modified: trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp
===================================================================
--- trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp	2009-07-10 09:52:33 UTC (rev 1852)
+++ trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.cpp	2009-07-10 19:16:01 UTC (rev 1853)
@@ -5,6 +5,7 @@
 #include<yade/core/Interaction.hpp>
 #include<yade/core/InteractionContainer.hpp>
 #include<yade/pkg-common/BoundingVolumeMetaEngine.hpp>
+#include<yade/pkg-dem/NewtonsDampedLaw.hpp>
 
 #include<algorithm>
 #include<vector>
@@ -65,16 +66,31 @@
 		// activated if number of bodies changes (hence need to refresh collision information)
 		// or the time of scheduled run already came, or we were never scheduled yet
 		if(stride<=1) return true;
-		bool ret=XX.size()!=2*rb->bodies->size() || scheduledRun<0 || rb->simulationTime>=scheduledRun;
-		// we wouldn't run in this step; just delete pending interactions
-		// this could be done in ::action, but it would make the call counters not reflect the stride
+		if(sweepLength<=0) return true;
+		if(!newton) return true; // we wouldn't be able to find the max velocity
+		bool ret=rb->simulationTime>=scheduledRun ||
+			// if the max velocity is bigger than the one that we used for bb computation last time
+			// and the distance bodies would travel with this bigger velocity since last run (rb->simulationTime-lastRun)
+			// would be the same or greater than the one that would be traveled with the original velocity
+			// over the stride time (scheduledRun-lastRun)
+			(newton->maxVelocitySq<0) || // no valid data about max velocity, run always
+			(sweepVelocity==0 && newton->maxVelocitySq>0) || 
+			(sweepVelocity<sqrt(newton->maxVelocitySq) && rb->simulationTime-lastRun>=(sweepVelocity/sqrt(newton->maxVelocitySq)/* we know maxVelocitySq>0 from the first condition */)*(scheduledRun-lastRun)) ||
+			// number of bodies changed
+			XX.size()!=2*rb->bodies->size() ||
+			// we've never run yet (this should never happen as per if(!newton) above)
+			scheduledRun<0;
+		// we wouldn't run in this step; in that case, just delete pending interactions
+		// this is done in ::action normally, but it would make the call counters not reflect the stride
 		if(!ret) rb->interactions->erasePending(*this);
 		return ret;
 	}
 #endif
 
 void InsertionSortCollider::action(MetaBody* rb){
-	// timingDeltas->start();
+	#ifdef ISC_TIMING
+		timingDeltas->start();
+	#endif
 
 	size_t nBodies=rb->bodies->size();
 	InteractionContainer* interactions=rb->interactions.get();
@@ -107,28 +123,44 @@
 			// get the BoundingVolumeMetaEngine and turn it off; we will call it ourselves
 			if(!boundDispatcher){
 				FOREACH(shared_ptr<Engine>& e, rb->engines){ boundDispatcher=dynamic_pointer_cast<BoundingVolumeMetaEngine>(e); if(boundDispatcher) break; }
-				if(!boundDispatcher){ LOG_FATAL("Unable to locate BoundingVolumeMetaEngine within engines, aborting."); throw runtime_error("Explanation above"); }
+				if(!boundDispatcher){ LOG_FATAL("Unable to locate BoundingVolumeMetaEngine within engines, aborting."); abort(); }
 				boundDispatcher->activated=false; // deactive the engine, we will call it ourselves from now (just when needed)
 			}
+			if(sweepLength>0){
+				// get NewtonsDampedLaw, to ask for the maximum velocity value
+				if(!newton){
+					FOREACH(shared_ptr<Engine>& e, rb->engines){ newton=dynamic_pointer_cast<NewtonsDampedLaw>(e); if(newton) break; }
+					if(!newton){ LOG_FATAL("Unable to locate NewtonsDampedLaw within engines, aborting."); abort(); }
+				}
+			}
 		#endif
-	// timingDeltas->checkpoint("init");
+	ISC_CHECKPOINT("init");
 
 		#ifdef COLLIDE_STRIDED
-			// FIXME: should be able to adapt stride based on the potential_interaction_count_increase/stride_speedup tradeoff
-			// this depends on the packing density, for instance, maximum velocities/accels etc.
-			if(stride>1 && sweepTimeFactor<1 && sweepVelocity<=0){ LOG_WARN("Stride is "<<stride<<", but no sweeping effective!! Setting stride back to 1."); stride=1; }
-			if(stride>1){
-				//schedule next run
-				scheduledRun=rb->simulationTime+rb->dt*(stride-.5); // -.5 to avoid rounding issues
-				if(sweepTimeFactor>=1) boundDispatcher->sweepTime=rb->dt*stride*sweepTimeFactor;
-				if(sweepVelocity>0) boundDispatcher->sweepDist=rb->dt*stride*sweepVelocity;
+			if(sweepLength>0){
+				if(newton->maxVelocitySq>=0){ // non-negative, i.e. a really computed value
+					// compute new stride value
+					assert(sweepFactor>1.);
+					sweepVelocity=sqrt(newton->maxVelocitySq)*sweepFactor;
+					if(sweepVelocity>0) {
+						stride=max(1,int((sweepLength/sweepVelocity)/rb->dt));
+						boundDispatcher->sweepDist=rb->dt*(stride-1)*sweepVelocity;
+					} else { // no motion
+						stride=1000; // shouldn't this be some saner value? Infinity? How to decide?
+						boundDispatcher->sweepDist=0; // nothing moves, no need to make bboxes larger
+					}
+					scheduledRun=rb->simulationTime+rb->dt*(stride-.5); // -.5 to avoid rounding issues
+				} else { /* no valid data yet, run next time again */ boundDispatcher->sweepDist=0; stride=1; scheduledRun=rb->simulationTime+rb->dt; }
+				LOG_DEBUG(rb->simulationTime<<"s: stride adapted to "<<stride<<"; sweepVelocity="<<sweepVelocity<<", maxVelocity="<<sqrt(newton->maxVelocitySq)<<", sweepDist="<<boundDispatcher->sweepDist);
+				newton->maxVelocitySq=-1; // reset to invalid value again
 			} else { scheduledRun=-1; boundDispatcher->sweepTime=-1; boundDispatcher->sweepDist=0; }
 			boundDispatcher->action(rb);
 		#endif
-	// timingDeltas->checkpoint("bound");
 
+	ISC_CHECKPOINT("bound");
 
 
+
 	// copy bounds along given axis into our arrays
 		for(size_t i=0; i<2*nBodies; i++){
 			const body_id_t& idXX=XX[i].id; const body_id_t& idYY=YY[i].id; const body_id_t& idZZ=ZZ[i].id;
@@ -144,11 +176,11 @@
 				else{ const Vector3r& pos=Body::byId(idXX,rb)->physicalParameters->se3.position; memcpy(&minima[3*idXX],pos,3*sizeof(Real)); memcpy(&maxima[3*idXX],pos,3*sizeof(Real)); }
 			}
 		}
+	ISC_CHECKPOINT("copy");
 
-	// timingDeltas->checkpoint("copy");
-
 	// process interactions that the constitutive law asked to be erased
-	interactions->erasePending(*this);
+		interactions->erasePending(*this);
+	ISC_CHECKPOINT("erase");
 
 	// sort
 		if(!doInitSort && !sortThenCollide){
@@ -159,13 +191,9 @@
 			if(doInitSort){
 				// the initial sort is in independent in 3 dimensions, may be run in parallel
 				// it seems that there is no time gain running this in parallel, though
-				#pragma omp parallel sections
 				{
-					#pragma omp section
 						std::sort(XX.begin(),XX.end());
-					#pragma omp section	
 						std::sort(YY.begin(),YY.end());
-					#pragma omp section
 						std::sort(ZZ.begin(),ZZ.end());
 				}
 			} else { // sortThenCollide
@@ -205,5 +233,5 @@
 				}
 			}
 		}
-	// timingDeltas->checkpoint("sort&collide");
+	ISC_CHECKPOINT("sort&collide");
 }

Modified: trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.hpp
===================================================================
--- trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.hpp	2009-07-10 09:52:33 UTC (rev 1852)
+++ trunk/pkg/common/Engine/StandAloneEngine/InsertionSortCollider.hpp	2009-07-10 19:16:01 UTC (rev 1853)
@@ -15,7 +15,18 @@
 */
 
 #define COLLIDE_STRIDED
+
+// #define this macro to enable timing whichin this engine
+//#define ISC_TIMING
+
+#ifdef ISC_TIMING
+	#define ISC_CHECKPOINT(cpt) timingDeltas->checkPoint(cpt)
+#else
+	#define ISC_CHECKPOINT(cpt)
+#endif
+
 class BoundingVolumeMetaEngine;
+class NewtonsDampedLaw;
 
 class InsertionSortCollider: public Collider{
 	//! struct for storing bounds of bodies
@@ -33,16 +44,25 @@
 	#ifdef COLLIDE_STRIDED
 		// keep this dispatcher and call it ourselves as needed
 		shared_ptr<BoundingVolumeMetaEngine> boundDispatcher;
-		// interval at which we will run; if <=1, we run always (as usual). 0 by default.
+		// we need this to find out about current maxVelocitySq
+		shared_ptr<NewtonsDampedLaw> newton;
+		// interval at which we will run; if 0, we run always (as usual).
 		int stride;
-		// virtual time when we have to run the next time
-		Real scheduledRun;
-		//! If >1 and using stride, sweep time will be multiplied by this number; it should be >=1. to accomodate non-linearities in the system.
-		/// If deactivated (-1 by default), current-velocity-based sweeping will not be enabled.
-		Real sweepTimeFactor;
-		//! If >0 and using stride, all bodies will be swept as if having this velocity.
-		/// It should be the maximum (predicted or measured) velocity increased by some safety margin, otherwise bodies may get out of their AABB. Deactivated (-1) by default.
+		//! virtual time when we were run last time
+		Real lastRun;
+		//! virtual time when we have to run the next time
+		Real scheduledRun; 
+		/// Absolute length that will be added to bounding boxes at each side; it should be something like 1/5 of typical grain radius
+		/// this value is used to adapt stride; if too large, stride will be big, but the ratio of potential-only interactions will be very big, 
+		/// thus slowing down collider & interaction loops significantly (remember: O(addLength^3))
+		/// If non-positive, collider runs always, without stride adaptivity
+		Real sweepLength;
+		//! Current sweeping velocity; computed from maxVelocity*sweepVelocityFactor
 		Real sweepVelocity;
+		//! Overestimation factor for the sweep velocity; must be >=1.0.
+		/// Has no influence on sweepLength, only on the computed stride.
+		/// Default 1.05
+		Real sweepFactor;
 	#endif
 	//! storage for bounds
 	std::vector<Bound> XX,YY,ZZ;
@@ -72,14 +92,18 @@
 
 	InsertionSortCollider():
 	#ifdef COLLIDE_STRIDED
-		stride(0), scheduledRun(-1), sweepTimeFactor(-1), sweepVelocity(-1),
+		stride(0), lastRun(-1), scheduledRun(-1), sweepLength(-1), sweepVelocity(-1), sweepFactor(1.05),
 	#endif
-		 sortAxis(0), sortThenCollide(false){ /* timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas); */ }
+		sortAxis(0), sortThenCollide(false){
+			#ifdef ISC_TIMING
+				timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas);
+			#endif 
+		 }
 	virtual void action(MetaBody*);
 	REGISTER_CLASS_AND_BASE(InsertionSortCollider,Collider);
 	REGISTER_ATTRIBUTES(Collider,(sortAxis)(sortThenCollide)
 		#ifdef COLLIDE_STRIDED
-			(stride)(scheduledRun)(sweepTimeFactor)(sweepVelocity)
+			(stride)(lastRun)(scheduledRun)(sweepLength)(sweepFactor)(sweepVelocity)
 		#endif
 	);
 	DECLARE_LOGGER;

Modified: trunk/pkg/common/SConscript
===================================================================
--- trunk/pkg/common/SConscript	2009-07-10 09:52:33 UTC (rev 1852)
+++ trunk/pkg/common/SConscript	2009-07-10 19:16:01 UTC (rev 1853)
@@ -143,7 +143,7 @@
 	env.SharedLibrary('SpheresFactory',['Engine/StandAloneEngine/SpheresFactory.cpp'],
 		LIBS=env['LIBS']+['AABB','InteractingSphere','Facet','Sphere','BodyMacroParameters','InteractionGeometryMetaEngine']),
 	env.SharedLibrary('SpatialQuickSortCollider',['Engine/StandAloneEngine/SpatialQuickSortCollider.cpp']),
-	env.SharedLibrary('InsertionSortCollider',['Engine/StandAloneEngine/InsertionSortCollider.cpp'],LIBS=env['LIBS']+['BoundingVolumeMetaEngine']),
+	env.SharedLibrary('InsertionSortCollider',['Engine/StandAloneEngine/InsertionSortCollider.cpp'],LIBS=env['LIBS']+['BoundingVolumeMetaEngine','NewtonsDampedLaw']),
 	env.SharedLibrary('PersistentSAPCollider',['Engine/StandAloneEngine/PersistentSAPCollider.cpp']),
 	env.SharedLibrary('DistantPersistentSAPCollider',['Engine/StandAloneEngine/DistantPersistentSAPCollider.cpp']),
 	env.SharedLibrary('PhysicalActionContainerReseter',['Engine/StandAloneEngine/PhysicalActionContainerReseter.cpp']),

Modified: trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.cpp
===================================================================
--- trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.cpp	2009-07-10 09:52:33 UTC (rev 1852)
+++ trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.cpp	2009-07-10 19:16:01 UTC (rev 1853)
@@ -25,6 +25,7 @@
 {
 	ncb->bex.sync();
 	Real dt=Omega::instance().getTimeStep();
+	maxVelocitySq=-1;
 
 	FOREACH(const shared_ptr<Body>& b, *ncb->bodies){
 		// clump members are non-dynamic; they skip the rest of loop once their forces are properly taken into account, however

Modified: trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.hpp
===================================================================
--- trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.hpp	2009-07-10 09:52:33 UTC (rev 1852)
+++ trunk/pkg/dem/Engine/DeusExMachina/NewtonsDampedLaw.hpp	2009-07-10 19:16:01 UTC (rev 1853)
@@ -38,10 +38,10 @@
 	public:
 		///damping coefficient for Cundall's non viscous damping
 		Real damping;
-		/// store square of max. velocity, for informative purposes
+		/// store square of max. velocity, for informative purposes; computed again at every step
 		Real maxVelocitySq;
 		virtual void applyCondition(MetaBody *);		
-		NewtonsDampedLaw(): damping(0.2), maxVelocitySq(0){}
+		NewtonsDampedLaw(): damping(0.2), maxVelocitySq(-1){}
 	REGISTER_ATTRIBUTES(DeusExMachina,(damping)(maxVelocitySq));
 	REGISTER_CLASS_AND_BASE(NewtonsDampedLaw,DeusExMachina);
 };

Modified: trunk/scripts/test/collider-stride-triax.py
===================================================================
--- trunk/scripts/test/collider-stride-triax.py	2009-07-10 09:52:33 UTC (rev 1852)
+++ trunk/scripts/test/collider-stride-triax.py	2009-07-10 19:16:01 UTC (rev 1853)
@@ -4,30 +4,19 @@
 import os.path
 loadFrom='/tmp/triax.xml'
 if not os.path.exists(loadFrom):
-	TriaxialTest(numberOfGrains=8000,fast=fast,noFiles=True).generate(loadFrom)
+	TriaxialTest(numberOfGrains=8000,fast=True,noFiles=True).generate(loadFrom)
 O.load(loadFrom)
 log.setLevel('TriaxialCompressionEngine',log.WARN) # shut up
+log.setLevel('InsertionSortCollider',log.DEBUG) # shut up
 
 collider=utils.typedEngine('InsertionSortCollider')
 newton=utils.typedEngine('NewtonsDampedLaw')
 
 # use striding; say "if 0:" to disable striding and compare to regular runs
 if 1:
-	collider['stride']=4
-	collider['sweepVelocity']=16
-	# try to update maximum velocity dynamically:
-	if 1:
-		O.engines=O.engines+[PeriodicPythonRunner(command='adjustMaxVelocity()',iterPeriod=50)]
+	# length by which bboxes will be made larger
+	collider['sweepLength']=.05*O.bodies[100].shape['radius']
 
-def adjustMaxVelocity():
-	newMax=sqrt(newton['maxVelocitySq']); newton['maxVelocitySq']=0
-	collider['sweepVelocity']=newMax
-	# try to adjust stride here; the 4 and 16 are original (reference) values for stride and sweepVelocity
-	# if this were inverse-proportional (without sqrt), stride is getting too high
-	collider['stride']=4*int(sqrt(16/newMax))
-	print 'step %d; new max velocity %g, stride %d'%(O.iter,newMax,collider['stride'])
-
-
 O.step() # filter out initialization
 O.timingEnabled=True
 totalTime=0




Follow ups