Merge lp:~bruno-chareyre/yade/collide into lp:~yade-dev/yade/trunk
- collide
- Merge into trunk
Proposed by
Bruno Chareyre
Status: | Merged |
---|---|
Merged at revision: | 2922 |
Proposed branch: | lp:~bruno-chareyre/yade/collide |
Merge into: | lp:~yade-dev/yade/trunk |
Diff against target: |
552 lines (+194/-71) 9 files modified
core/Bound.hpp (+7/-0) core/InteractionContainer.hpp (+3/-0) pkg/common/Dispatching.cpp (+32/-2) pkg/common/Dispatching.hpp (+6/-0) pkg/common/InsertionSortCollider.cpp (+88/-43) pkg/common/InsertionSortCollider.hpp (+22/-3) pkg/common/InteractionLoop.cpp (+7/-3) pkg/dem/NewtonIntegrator.cpp (+22/-20) pkg/dem/NewtonIntegrator.hpp (+7/-0) |
To merge this branch: | bzr merge lp:~bruno-chareyre/yade/collide |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Yade developers | Pending | ||
Review via email: mp+59029@code.launchpad.net |
Commit message
Description of the change
Improved colliding (only implemented for non-periodic BCs at the moment).
- Some useless operations are removed (see diff).
- The behaviour with nBins=0 tracks displacements (while nBins>0 tracks max velocity) to update bounds
- Experimental features: targetInterval (adjust bound sizes so that they will be updated each N iterations), updatingDispFactor (only update bounds where the body's motion is at least boundSize/factor, hence saving sorting time).
Overall CPU time reduced by a factor 0.6 (average).
To post a comment you must log in.
lp:~bruno-chareyre/yade/collide
updated
- 2823. By Bruno Chareyre
-
- default params + a smarter inversion handling for not-overlapping bounds
- 2824. By Bruno Chareyre
-
-no change
- 2825. By Bruno Chareyre
-
-merge
- 2826. By Bruno Chareyre
-
- fix commit mistake + documentation
- 2827. By Bruno Chareyre
-
- missing bracket
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'core/Bound.hpp' |
2 | --- core/Bound.hpp 2010-11-30 13:51:41 +0000 |
3 | +++ core/Bound.hpp 2011-04-26 10:44:50 +0000 |
4 | @@ -22,6 +22,13 @@ |
5 | class Bound: public Serializable, public Indexable{ |
6 | public: |
7 | YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(Bound,Serializable,"Object bounding part of space taken by associated body; might be larger, used to optimalize collision detection", |
8 | + #define ORI_VERLET |
9 | + #ifdef ORI_VERLET |
10 | + ((int,lastUpdateIter,0,Attr::readonly,"record iteration of last reference position update |yupdate|")) |
11 | + ((Vector3r,refPos,Vector3r(NaN,NaN,NaN),Attr::readonly,"Reference position, updated at current body position each time the bound dispatcher update bounds - only used if oriVerlet striding is active |yupdate|")) |
12 | + ((bool,isBounding,false,Attr::readonly,"A flag used to tell when the body moves out of bounds - only used if oriVerlet striding is active :yref:`BoundDispatcher::updatingDispFactor`>0 |yupdate|")) |
13 | + ((Real,sweepLength,0, Attr::readonly,"The length used to increase the bounding boxe size, can be adjusted on the basis of previous displacement if :yref:`BoundDispatcher::targetInterv`>0. Only used if oriVerlet striding is active (:yref:`InsertionSortCollider::oriVerlet`=true) |yupdate|")) |
14 | + #endif |
15 | ((Vector3r,color,Vector3r(1,1,1),,"Color for rendering this object")) |
16 | ((Vector3r,min,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Lower corner of box containing this bound (and the :yref:`Body` as well)")) |
17 | ((Vector3r,max,Vector3r(NaN,NaN,NaN),(Attr::noSave | Attr::readonly),"Lower corner of box containing this bound (and the :yref:`Body` as well)")) |
18 | |
19 | === modified file 'core/InteractionContainer.hpp' |
20 | --- core/InteractionContainer.hpp 2011-02-27 13:54:43 +0000 |
21 | +++ core/InteractionContainer.hpp 2011-04-26 10:44:50 +0000 |
22 | @@ -82,6 +82,9 @@ |
23 | bool insert(const shared_ptr<Interaction>& i); |
24 | bool erase(Body::id_t id1,Body::id_t id2); |
25 | const shared_ptr<Interaction>& find(Body::id_t id1,Body::id_t id2); |
26 | +// bool found(Body::id_t id1,Body::id_t id2); |
27 | + inline bool found(const Body::id_t& id1,const Body::id_t& id2){ |
28 | + assert(bodies); return (id1>id2)?(*bodies)[id2]->intrs.count(id1):(*bodies)[id1]->intrs.count(id2);} |
29 | // index access |
30 | shared_ptr<Interaction>& operator[](size_t id){return linIntrs[id];} |
31 | const shared_ptr<Interaction>& operator[](size_t id) const { return linIntrs[id];} |
32 | |
33 | === modified file 'pkg/common/Dispatching.cpp' |
34 | --- pkg/common/Dispatching.cpp 2011-02-20 10:28:40 +0000 |
35 | +++ pkg/common/Dispatching.cpp 2011-04-26 10:44:50 +0000 |
36 | @@ -21,12 +21,33 @@ |
37 | const long numBodies=(long)bodies->size(); |
38 | bool haveBins=(bool)velocityBins; |
39 | if(sweepDist!=0 && haveBins){ LOG_FATAL("Only one of sweepDist or velocityBins can used!"); abort(); } |
40 | - //#pragma omp parallel for |
41 | +// #pragma omp parallel for |
42 | for(int id=0; id<numBodies; id++){ |
43 | if(!bodies->exists(id)) continue; // don't delete this check - Janek |
44 | const shared_ptr<Body>& b=(*bodies)[id]; |
45 | shared_ptr<Shape>& shape=b->shape; |
46 | - if(!shape || !b->isBounded()) continue; |
47 | + if(!shape || !b->isBounded()) continue; |
48 | + #ifdef ORI_VERLET |
49 | + if(oriVerlet && b->bound) { |
50 | + //Do we need to update this bound (determined in Newton)? |
51 | + if(!b->bound->isBounding){ |
52 | + Real& sweepLength = b->bound->sweepLength; |
53 | + if (targetInterv>=0) { |
54 | + Vector3r disp = b->state->pos-b->bound->refPos; |
55 | + Real dist = max(abs(disp[0]),max(abs(disp[1]),abs(disp[2]))); |
56 | + assert(b->bound->lastUpdateIter<scene->iter); |
57 | +// Real sweepMult = dist*targetInterv/((scene->iter-b->bound->lastUpdateIter)*sweepLength); |
58 | + Real newLength = dist*targetInterv/(scene->iter-b->bound->lastUpdateIter); |
59 | + newLength = max(0.9*sweepLength,newLength);//don't decrease size too fast to prevent time consuming oscillations |
60 | + sweepLength=max(minSweepDistFactor*sweepDist,min(newLength,sweepDist)); |
61 | + } else { |
62 | + sweepLength=sweepDist; |
63 | + } |
64 | + } |
65 | + else continue; |
66 | + } |
67 | + #endif |
68 | + |
69 | #ifdef BV_FUNCTOR_CACHE |
70 | if(!shape->boundFunctor){ shape->boundFunctor=this->getFunctor1D(shape); if(!shape->boundFunctor) continue; } |
71 | // LOG_DEBUG("shape->boundFunctor.get()=="<<shape->boundFunctor.get()<<" for "<<b->shape->getClassName()<<", #"<<id); |
72 | @@ -37,9 +58,18 @@ |
73 | #endif |
74 | if(!b->bound) continue; // the functor did not create new bound |
75 | if(sweepDist>0){ |
76 | + #ifdef ORI_VERLET |
77 | + b->bound->refPos=b->state->pos; |
78 | + b->bound->lastUpdateIter=scene->iter; |
79 | + const Real& sweepLength = b->bound->sweepLength; |
80 | + Aabb* aabb=YADE_CAST<Aabb*>(b->bound.get()); |
81 | + aabb->min-=Vector3r(sweepLength,sweepLength,sweepLength); |
82 | + aabb->max+=Vector3r(sweepLength,sweepLength,sweepLength); |
83 | + #else |
84 | Aabb* aabb=YADE_CAST<Aabb*>(b->bound.get()); |
85 | aabb->min-=Vector3r(sweepDist,sweepDist,sweepDist); |
86 | aabb->max+=Vector3r(sweepDist,sweepDist,sweepDist); |
87 | + #endif |
88 | } |
89 | if(haveBins){ |
90 | Aabb* aabb=YADE_CAST<Aabb*>(b->bound.get()); |
91 | |
92 | === modified file 'pkg/common/Dispatching.hpp' |
93 | --- pkg/common/Dispatching.hpp 2011-01-29 22:47:18 +0000 |
94 | +++ pkg/common/Dispatching.hpp 2011-04-26 10:44:50 +0000 |
95 | @@ -89,6 +89,12 @@ |
96 | /*additional attrs*/ |
97 | ((bool,activated,true,,"Whether the engine is activated (only should be changed by the collider)")) |
98 | ((Real,sweepDist,0,,"Distance by which enlarge all bounding boxes, to prevent collider from being run at every step (only should be changed by the collider).")) |
99 | + #ifdef ORI_VERLET |
100 | + ((Real,minSweepDistFactor,0.05,,"Minimal distance by which enlarge all bounding boxes; superseeds computed value of sweepDist when lower that minSweepDist.")) |
101 | + ((Real,updatingDispFactor,-1,,"see :yref:`InsertionSortCollider::updatingDispFactor` |yupdate|")) |
102 | + ((Real,targetInterv,-1,,"see :yref:`InsertionSortCollider::targetInterv` |yupdate|")) |
103 | + ((bool,oriVerlet,false,,"Compare Verlet distance with displacement instead of velocity (only should be changed by the collider)")) |
104 | + #endif |
105 | ,/*ctor*/,/*py*/ |
106 | ); |
107 | }; |
108 | |
109 | === modified file 'pkg/common/InsertionSortCollider.cpp' |
110 | --- pkg/common/InsertionSortCollider.cpp 2011-02-27 13:54:43 +0000 |
111 | +++ pkg/common/InsertionSortCollider.cpp 2011-04-26 10:44:50 +0000 |
112 | @@ -18,44 +18,39 @@ |
113 | YADE_PLUGIN((InsertionSortCollider)) |
114 | CREATE_LOGGER(InsertionSortCollider); |
115 | |
116 | -// return true if bodies bb overlap in all 3 dimensions |
117 | -bool InsertionSortCollider::spatialOverlap(Body::id_t id1, Body::id_t id2) const { |
118 | - assert(!periodic); |
119 | - return |
120 | - (minima[3*id1+0]<=maxima[3*id2+0]) && (maxima[3*id1+0]>=minima[3*id2+0]) && |
121 | - (minima[3*id1+1]<=maxima[3*id2+1]) && (maxima[3*id1+1]>=minima[3*id2+1]) && |
122 | - (minima[3*id1+2]<=maxima[3*id2+2]) && (maxima[3*id1+2]>=minima[3*id2+2]); |
123 | -} |
124 | |
125 | // called by the insertion sort if 2 bodies swapped their bounds |
126 | void InsertionSortCollider::handleBoundInversion(Body::id_t id1, Body::id_t id2, InteractionContainer* interactions, Scene*){ |
127 | assert(!periodic); |
128 | assert(id1!=id2); |
129 | - // do bboxes overlap in all 3 dimensions? |
130 | - bool overlap=spatialOverlap(id1,id2); |
131 | - // existing interaction? |
132 | + //existing interaction? |
133 | + if (interactions->found(id1,id2)) { |
134 | + //if existing interaction is virtual and bounds don't overlap, remove it |
135 | + if (!interactions->find(id1,id2)->isReal() && !spatialOverlap(id1,id2)){ interactions->erase(id1,id2); return;}} |
136 | + //if it doesn't exist and bounds overlap, create a virtual interaction |
137 | + else if (spatialOverlap(id1,id2) && Collider::mayCollide(Body::byId(id1,scene).get(),Body::byId(id2,scene).get())) |
138 | + interactions->insert(shared_ptr<Interaction>(new Interaction(id1,id2))); |
139 | +} |
140 | + |
141 | +// called by the insertion sort if 2 bodies swapped their bounds |
142 | +void InsertionSortCollider::handleBoundSplit(Body::id_t id1, Body::id_t id2, InteractionContainer* interactions, Scene*){ |
143 | + assert(!periodic); |
144 | + assert(id1!=id2); |
145 | const shared_ptr<Interaction>& I=interactions->find(id1,id2); |
146 | - bool hasInter=(bool)I; |
147 | - // interaction doesn't exist and shouldn't, or it exists and should |
148 | - if(likely(!overlap && !hasInter)) return; |
149 | - if(overlap && hasInter){ return; } |
150 | - // create interaction if not yet existing |
151 | - if(overlap && !hasInter){ // second condition only for readability |
152 | - if(!Collider::mayCollide(Body::byId(id1,scene).get(),Body::byId(id2,scene).get())) return; |
153 | - // LOG_TRACE("Creating new interaction #"<<id1<<"+#"<<id2); |
154 | - shared_ptr<Interaction> newI=shared_ptr<Interaction>(new Interaction(id1,id2)); |
155 | - interactions->insert(newI); |
156 | - return; |
157 | - } |
158 | - if(!overlap && hasInter){ if(!I->isReal()) interactions->erase(id1,id2); return; } |
159 | - assert(false); // unreachable |
160 | + if ((bool)I && !I->isReal()) interactions->erase(id1,id2); |
161 | } |
162 | |
163 | void InsertionSortCollider::insertionSort(VecBounds& v, InteractionContainer* interactions, Scene*, bool doCollide){ |
164 | assert(!periodic); |
165 | assert(v.size==(long)v.vec.size()); |
166 | - for(long i=0; i<v.size; i++){ |
167 | + for(long i=1; i<v.size; i++){ |
168 | + #ifdef ORI_VERLET |
169 | + assert (v[i].flags.hasBB && v[i-1].flags.hasBB); |
170 | + if (updatingDispFactor>0 && v[i].isBounding && v[i-1].isBounding) continue; |
171 | + #endif |
172 | const Bounds viInit=v[i]; long j=i-1; /* cache hasBB; otherwise 1% overall performance hit */ const bool viInitBB=viInit.flags.hasBB; |
173 | + const bool isMin=viInit.flags.isMin; |
174 | + |
175 | while(j>=0 && v[j]>viInit){ |
176 | v[j+1]=v[j]; |
177 | #ifdef PISC_DEBUG |
178 | @@ -65,7 +60,11 @@ |
179 | // no collisions without bounding boxes |
180 | // also, do not collide body with itself; it sometimes happens for facets aligned perpendicular to an axis, for reasons that are not very clear |
181 | // see https://bugs.launchpad.net/yade/+bug/669095 |
182 | - if(likely(doCollide && viInitBB && v[j].flags.hasBB && (viInit.id!=v[j].id))) handleBoundInversion(viInit.id,v[j].id,interactions,scene); |
183 | + // skip bounds with same isMin flags, since inversion doesn't imply anything in that case |
184 | + if(isMin!=v[j].flags.isMin && likely(doCollide && viInitBB && v[j].flags.hasBB && (viInit.id!=v[j].id))) { |
185 | + if (isMin) handleBoundInversion(viInit.id,v[j].id,interactions,scene); |
186 | + else handleBoundSplit(viInit.id,v[j].id,interactions,scene); |
187 | + } |
188 | j--; |
189 | } |
190 | v[j+1]=viInit; |
191 | @@ -94,6 +93,7 @@ |
192 | } |
193 | |
194 | // STRIDE |
195 | + |
196 | bool InsertionSortCollider::isActivated(){ |
197 | // activated if number of bodies changes (hence need to refresh collision information) |
198 | // or the time of scheduled run already came, or we were never scheduled yet |
199 | @@ -102,8 +102,18 @@ |
200 | if(nBins>=1 && newton->velocityBins->checkSize_incrementDists_shouldCollide(scene)) return true; |
201 | if(nBins<=0){ |
202 | if(fastestBodyMaxDist<0){fastestBodyMaxDist=0; return true;} |
203 | + #ifdef ORI_VERLET |
204 | + if (!oriVerlet){ |
205 | + fastestBodyMaxDist+=sqrt(newton->maxVelocitySq)*scene->dt; |
206 | + if(fastestBodyMaxDist>=verletDist) return true; |
207 | + } else { |
208 | + fastestBodyMaxDist=newton->maxVelocitySq; |
209 | + if(fastestBodyMaxDist>=1 || fastestBodyMaxDist==0) return true;} |
210 | + #else |
211 | fastestBodyMaxDist+=sqrt(newton->maxVelocitySq)*scene->dt; |
212 | if(fastestBodyMaxDist>=verletDist) return true; |
213 | + #endif |
214 | + |
215 | } |
216 | if((size_t)BB[0].size!=2*scene->bodies->size()) return true; |
217 | if(scene->interactions->dirty) return true; |
218 | @@ -159,16 +169,6 @@ |
219 | // compatibility block, can be removed later |
220 | findBoundDispatcherInEnginesIfNoFunctorsAndWarn(); |
221 | |
222 | - // update bounds via boundDispatcher |
223 | - boundDispatcher->scene=scene; |
224 | - boundDispatcher->action(); |
225 | - |
226 | - // if interactions are dirty, force reinitialization |
227 | - if(scene->interactions->dirty){ |
228 | - doInitSort=true; |
229 | - scene->interactions->dirty=false; |
230 | - } |
231 | - |
232 | if(verletDist<0){ |
233 | Real minR=std::numeric_limits<Real>::infinity(); |
234 | FOREACH(const shared_ptr<Body>& b, *scene->bodies){ |
235 | @@ -181,15 +181,33 @@ |
236 | verletDist=isinf(minR) ? 0 : abs(verletDist)*minR; |
237 | } |
238 | |
239 | + // update bounds via boundDispatcher |
240 | + boundDispatcher->scene=scene; |
241 | + #ifdef ORI_VERLET |
242 | + if (oriVerlet) { |
243 | + nBins=0; |
244 | + if(boundDispatcher->velocityBins) boundDispatcher->velocityBins=shared_ptr<VelocityBins>();//avoid FATAL in boundDispatcher->action() when switching from nBin>0 to oriVerlet=true |
245 | + boundDispatcher->oriVerlet=true; |
246 | + boundDispatcher->sweepDist=verletDist; |
247 | + boundDispatcher->targetInterv=targetInterv; |
248 | + boundDispatcher->updatingDispFactor=updatingDispFactor;} |
249 | + #endif |
250 | + boundDispatcher->action(); |
251 | |
252 | + // if interactions are dirty, force reinitialization |
253 | + if(scene->interactions->dirty){ |
254 | + doInitSort=true; |
255 | + scene->interactions->dirty=false; |
256 | + } |
257 | + |
258 | // STRIDE |
259 | - if(verletDist>0){ |
260 | - // get NewtonIntegrator, to ask for the maximum velocity value |
261 | - if(!newton){ |
262 | - FOREACH(shared_ptr<Engine>& e, scene->engines){ newton=dynamic_pointer_cast<NewtonIntegrator>(e); if(newton) break; } |
263 | - if(!newton){ throw runtime_error("InsertionSortCollider.verletDist>0, but unable to locate NewtonIntegrator within O.engines."); } |
264 | - } |
265 | + if(verletDist>0){ |
266 | + // get NewtonIntegrator, to ask for the maximum velocity value |
267 | + if(!newton){ |
268 | + FOREACH(shared_ptr<Engine>& e, scene->engines){ newton=dynamic_pointer_cast<NewtonIntegrator>(e); if(newton) break; } |
269 | + if(!newton){ throw runtime_error("InsertionSortCollider.verletDist>0, but unable to locate NewtonIntegrator within O.engines."); } |
270 | } |
271 | + } |
272 | ISC_CHECKPOINT("init"); |
273 | |
274 | // STRIDE |
275 | @@ -203,6 +221,20 @@ |
276 | // reset bins, in case they were active but are not anymore |
277 | if(newton->velocityBins) newton->velocityBins=shared_ptr<VelocityBins>(); if(boundDispatcher->velocityBins) boundDispatcher->velocityBins=shared_ptr<VelocityBins>(); |
278 | assert(strideActive); assert(newton->maxVelocitySq>=0); assert(sweepFactor>1.); |
279 | + #ifdef ORI_VERLET |
280 | + newton->oriVerlet=oriVerlet; |
281 | + newton->updatingDispFactor=updatingDispFactor; |
282 | + |
283 | + if (!oriVerlet){ |
284 | + Real sweepVelocity=sqrt(newton->maxVelocitySq)*sweepFactor; int stride=-1; |
285 | + if(sweepVelocity>0) { |
286 | + stride=max(1,int((verletDist/sweepVelocity)/scene->dt)); |
287 | + boundDispatcher->sweepDist=scene->dt*(stride-1)*sweepVelocity; |
288 | + } else { // no motion |
289 | + boundDispatcher->sweepDist=0; // nothing moves, no need to make bboxes larger |
290 | + } |
291 | + } |
292 | + #else |
293 | Real sweepVelocity=sqrt(newton->maxVelocitySq)*sweepFactor; int stride=-1; |
294 | if(sweepVelocity>0) { |
295 | stride=max(1,int((verletDist/sweepVelocity)/scene->dt)); |
296 | @@ -212,6 +244,9 @@ |
297 | } |
298 | LOG_DEBUG(scene->time<<"s: stride ≈"<<stride<<"; maxVelocity="<<sqrt(newton->maxVelocitySq)<<", sweepDist="<<boundDispatcher->sweepDist); |
299 | fastestBodyMaxDist=0; // reset |
300 | + #endif |
301 | + |
302 | + |
303 | } else { // nBins>=1 |
304 | if(!newton->velocityBins){ newton->velocityBins=shared_ptr<VelocityBins>(new VelocityBins(nBins,newton->maxVelocitySq,binCoeff,binOverlap)); } |
305 | if(!boundDispatcher->velocityBins) boundDispatcher->velocityBins=newton->velocityBins; |
306 | @@ -235,9 +270,16 @@ |
307 | const shared_ptr<Body>& b=Body::byId(id,scene); |
308 | if(likely(b)){ |
309 | const shared_ptr<Bound>& bv=b->bound; |
310 | + #ifdef ORI_VERLET |
311 | + if (oriVerlet){ |
312 | + if (bv && bv->isBounding) {BBj[i].isBounding=true; continue;} |
313 | + else BBj[i].isBounding=false;} |
314 | + #endif |
315 | // coordinate is min/max if has bounding volume, otherwise both are the position. Add periodic shift so that we are inside the cell |
316 | // watch out for the parentheses around ?: within ?: (there was unwanted conversion of the Reals to bools!) |
317 | + |
318 | BBj[i].coord=((BBj[i].flags.hasBB=((bool)bv)) ? (BBj[i].flags.isMin ? bv->min[j] : bv->max[j]) : (b->state->pos[j])) - (periodic ? BBj.cellDim*BBj[i].period : 0.); |
319 | + |
320 | } else { BBj[i].flags.hasBB=false; /* for vanished body, keep the coordinate as-is, to minimize inversions. */ } |
321 | // if initializing periodic, shift coords & record the period into BBj[i].period |
322 | if(doInitSort && periodic) { |
323 | @@ -251,6 +293,9 @@ |
324 | const shared_ptr<Body>& b=Body::byId(id,scene); |
325 | if(likely(b)){ |
326 | const shared_ptr<Bound>& bv=b->bound; |
327 | + #ifdef ORI_VERLET |
328 | + if (oriVerlet && bv && bv->isBounding) continue; |
329 | + #endif |
330 | if(likely(bv)) { memcpy(&minima[3*id],&bv->min,3*sizeof(Real)); memcpy(&maxima[3*id],&bv->max,3*sizeof(Real)); } // ⇐ faster than 6 assignments |
331 | else{ const Vector3r& pos=b->state->pos; memcpy(&minima[3*id],&pos,3*sizeof(Real)); memcpy(&maxima[3*id],&pos,3*sizeof(Real)); } |
332 | } else { memset(&minima[3*id],0,3*sizeof(Real)); memset(&maxima[3*id],0,3*sizeof(Real)); } |
333 | |
334 | === modified file 'pkg/common/InsertionSortCollider.hpp' |
335 | --- pkg/common/InsertionSortCollider.hpp 2011-01-09 16:34:50 +0000 |
336 | +++ pkg/common/InsertionSortCollider.hpp 2011-04-26 10:44:50 +0000 |
337 | @@ -68,7 +68,7 @@ |
338 | |
339 | |
340 | // #define this macro to enable timing within this engine |
341 | -//#define ISC_TIMING |
342 | +// #define ISC_TIMING |
343 | |
344 | // #define to turn on some tracing information for the periodic part |
345 | // all code under this can be probably removed at some point, when the collider will have been tested thoroughly |
346 | @@ -90,6 +90,9 @@ |
347 | Real coord; |
348 | //! id of the body this bound belongs to |
349 | Body::id_t id; |
350 | + #ifdef ORI_VERLET |
351 | + bool isBounding; |
352 | + #endif |
353 | //! periodic cell coordinate |
354 | int period; |
355 | //! is it the minimum (true) or maximum (false) bound? |
356 | @@ -152,12 +155,21 @@ |
357 | */ |
358 | void insertionSort(VecBounds& v,InteractionContainer*,Scene*,bool doCollide=true); |
359 | void handleBoundInversion(Body::id_t,Body::id_t,InteractionContainer*,Scene*); |
360 | - bool spatialOverlap(Body::id_t,Body::id_t) const; |
361 | +// bool spatialOverlap(Body::id_t,Body::id_t) const; |
362 | |
363 | // periodic variants |
364 | void insertionSortPeri(VecBounds& v,InteractionContainer*,Scene*,bool doCollide=true); |
365 | void handleBoundInversionPeri(Body::id_t,Body::id_t,InteractionContainer*,Scene*); |
366 | + void handleBoundSplit(Body::id_t,Body::id_t,InteractionContainer*,Scene*); |
367 | + |
368 | bool spatialOverlapPeri(Body::id_t,Body::id_t,Scene*,Vector3i&) const; |
369 | + inline bool spatialOverlap(const Body::id_t& id1, const Body::id_t& id2) const { |
370 | + assert(!periodic); |
371 | + return (minima[3*id1+0]<=maxima[3*id2+0]) && (maxima[3*id1+0]>=minima[3*id2+0]) && |
372 | + (minima[3*id1+1]<=maxima[3*id2+1]) && (maxima[3*id1+1]>=minima[3*id2+1]) && |
373 | + (minima[3*id1+2]<=maxima[3*id2+2]) && (maxima[3*id1+2]>=minima[3*id2+2]); |
374 | + } |
375 | + |
376 | static Real cellWrap(const Real, const Real, const Real, int&); |
377 | static Real cellWrapRel(const Real, const Real, const Real); |
378 | |
379 | @@ -199,7 +211,14 @@ |
380 | ", |
381 | ((int,sortAxis,0,,"Axis for the initial contact detection.")) |
382 | ((bool,sortThenCollide,false,,"Separate sorting and colliding phase; it is MUCH slower, but all interactions are processed at every step; this effectively makes the collider non-persistent, not remembering last state. (The default behavior relies on the fact that inversions during insertion sort are overlaps of bounding boxes that just started/ceased to exist, and only processes those; this makes the collider much more efficient.)")) |
383 | - ((Real,verletDist,((void)"Automatically initialized",-.05),,"Length by which to enlarge particle bounds, to avoid running collider at every step. Stride disabled if zero. Negative value will trigger automatic computation, so that the real value will be |verletDist| × minimum spherical particle radius; if there are no spherical particles, it will be disabled.")) |
384 | + #ifdef ORI_VERLET |
385 | + ((bool,oriVerlet,true,,"Compare Verlet distance with displacement instead of velocity (only used if nBins<=0)")) |
386 | + ((int,targetInterv,30,,"(experimental) Target number of iterations between bound update, used to define a smaller sweep distance for slower grains if >0, else always use 1*verletDist. Usefull in simulations with strong velocity contrasts between slow bodies and fast bodies. Only used if oriVerlet=true.")) |
387 | + ((Real,updatingDispFactor,-1,,"(experimental) Displacement factor used to trigger bound update when oriVerlet=true: the bound is updated only if updatingDispFactor*disp>sweepDist when >0, else all bounds are updated.")) |
388 | + ((Real,verletDist,((void)"Automatically initialized",-.9),,"Length by which to enlarge particle bounds, to avoid running collider at every step. Stride disabled if zero. Negative value will trigger automatic computation, so that the real value will be |verletDist| × minimum spherical particle radius; if there are no spherical particles, it will be disabled.")) |
389 | + #else |
390 | + ((Real,verletDist,((void)"Automatically initialized",-.15),,"Length by which to enlarge particle bounds, to avoid running collider at every step. Stride disabled if zero. Negative value will trigger automatic computation, so that the real value will be |verletDist| × minimum spherical particle radius; if there are no spherical particles, it will be disabled.")) |
391 | + #endif |
392 | ((Real,sweepFactor,1.05,,"Overestimation factor for the sweep velocity; must be >=1.0. Has no influence on verletDist, only on the computed stride. [DEPRECATED, is used only when bins are not used].")) |
393 | ((Real,fastestBodyMaxDist,-1,,"Maximum displacement of the fastest body since last run; if >= verletDist, we could get out of bboxes and will trigger full run. DEPRECATED, was only used without bins. |yupdate|")) |
394 | ((int,nBins,5,,"Number of velocity bins for striding. If <=0, bin-less strigin is used (this is however DEPRECATED).")) |
395 | |
396 | === modified file 'pkg/common/InteractionLoop.cpp' |
397 | --- pkg/common/InteractionLoop.cpp 2011-02-27 14:26:15 +0000 |
398 | +++ pkg/common/InteractionLoop.cpp 2011-04-26 10:44:50 +0000 |
399 | @@ -103,7 +103,11 @@ |
400 | |
401 | bool swap=false; |
402 | // IGeomDispatcher |
403 | + #ifdef ORI_VERLET |
404 | + if(unlikely(!I->functorCache.geom)){ |
405 | + #else |
406 | if(unlikely(!I->functorCache.geom || !I->functorCache.phys)){ |
407 | + #endif |
408 | I->functorCache.geom=geomDispatcher->getFunctor2D(b1_->shape,b2_->shape,swap); |
409 | // returns NULL ptr if no functor exists; remember that and shortcut |
410 | if(!I->functorCache.geom) {I->functorCache.geomExists=false; continue; } |
411 | @@ -112,10 +116,10 @@ |
412 | // arguments for the geom functor are in the reverse order (dispatcher would normally call goReverse). |
413 | // we don't remember the fact that is reverse, so we swap bodies within the interaction |
414 | // and can call go in all cases |
415 | - if(unlikely(swap)){I->swapOrder(); } |
416 | + if(unlikely(swap)){I->swapOrder();} |
417 | // body pointers must be updated, in case we swapped |
418 | - const shared_ptr<Body>& b1=Body::byId(I->getId1(),scene); |
419 | - const shared_ptr<Body>& b2=Body::byId(I->getId2(),scene); |
420 | + const shared_ptr<Body>& b1=swap?b2_:b1_; |
421 | + const shared_ptr<Body>& b2=swap?b1_:b2_; |
422 | |
423 | assert(I->functorCache.geom); |
424 | bool wasReal=I->isReal(); |
425 | |
426 | === modified file 'pkg/dem/NewtonIntegrator.cpp' |
427 | --- pkg/dem/NewtonIntegrator.cpp 2011-04-22 09:01:59 +0000 |
428 | +++ pkg/dem/NewtonIntegrator.cpp 2011-04-26 10:44:50 +0000 |
429 | @@ -9,7 +9,6 @@ |
430 | #include<yade/pkg/dem/NewtonIntegrator.hpp> |
431 | #include<yade/core/Scene.hpp> |
432 | #include<yade/pkg/dem/Clump.hpp> |
433 | -#include<yade/pkg/common/VelocityBins.hpp> |
434 | #include<yade/lib/base/Math.hpp> |
435 | |
436 | YADE_PLUGIN((NewtonIntegrator)); |
437 | @@ -66,7 +65,21 @@ |
438 | maxVelocitySq=max(maxVelocitySq,state->vel.squaredNorm()); |
439 | #endif |
440 | } |
441 | - |
442 | +#ifdef ORI_VERLET |
443 | +void NewtonIntegrator::saveMaximaDisplacement(const shared_ptr<Body>& b){ |
444 | + Vector3r disp=b->state->pos-b->bound->refPos; |
445 | + Real maxDisp=max(abs(disp[0]),max(abs(disp[1]),abs(disp[2]))); |
446 | + if (!maxDisp || maxDisp<=b->bound->sweepLength) {b->bound->isBounding = (updatingDispFactor>0 && (updatingDispFactor*maxDisp)<b->bound->sweepLength); |
447 | + maxDisp=0.5;//not 0, else it will be seen as "not updated" by the collider |
448 | + } |
449 | + else {b->bound->isBounding = false; maxDisp=2;} |
450 | + #ifdef YADE_OPENMP |
451 | + Real& thrMaxVSq=threadMaxVelocitySq[omp_get_thread_num()]; thrMaxVSq=max(thrMaxVSq,maxDisp); |
452 | + #else |
453 | + maxVelocitySq=max(maxVelocitySq,maxDisp); |
454 | + #endif |
455 | +} |
456 | +#endif |
457 | void NewtonIntegrator::action() |
458 | { |
459 | scene->forces.sync(); |
460 | @@ -108,21 +121,7 @@ |
461 | if(unlikely(!b || b->isClumpMember())) continue; |
462 | |
463 | State* state=b->state.get(); const Body::id_t& id=b->getId(); |
464 | - Vector3r f=Vector3r::Zero(), m=Vector3r::Zero(); |
465 | - // clumps forces |
466 | - if(b->isClump()) { |
467 | - b->shape->cast<Clump>().addForceTorqueFromMembers(state,scene,f,m); |
468 | - #ifdef YADE_OPENMP |
469 | - //it is safe here, since onky one thread will read/write |
470 | - scene->forces.getTorqueUnsynced(id)+=m; |
471 | - scene->forces.getForceUnsynced(id)+=f; |
472 | - #else |
473 | - scene->forces.addTorque(id,m); |
474 | - scene->forces.addForce(id, f); |
475 | - #endif |
476 | - } |
477 | - //in most cases, the initial force on clumps will zero and next line is not changing f and m, but make sure we don't miss something (e.g. user defined forces on clumps) |
478 | - f=scene->forces.getForce(id); m=scene->forces.getTorque(id); |
479 | + Vector3r f=scene->forces.getForce(id), m=scene->forces.getTorque(id); |
480 | #ifdef YADE_DEBUG |
481 | if(isnan(f[0])||isnan(f[1])||isnan(f[2])) throw runtime_error(("NewtonIntegrator: NaN force acting on #"+lexical_cast<string>(id)+".").c_str()); |
482 | if(isnan(m[0])||isnan(m[1])||isnan(m[2])) throw runtime_error(("NewtonIntegrator: NaN torque acting on #"+lexical_cast<string>(id)+".").c_str()); |
483 | @@ -134,8 +133,6 @@ |
484 | // in aperiodic boundaries, it is equal to absolute velocity |
485 | Vector3r fluctVel=isPeriodic?scene->cell->bodyFluctuationVel(b->state->pos,b->state->vel):state->vel; |
486 | |
487 | - |
488 | - |
489 | // numerical damping & kinetic energy |
490 | if(unlikely(trackEnergy)) updateEnergy(b,state,fluctVel,f,m); |
491 | |
492 | @@ -144,6 +141,8 @@ |
493 | |
494 | // for particles not totally blocked, compute accelerations; otherwise, the computations would be useless |
495 | if (state->blockedDOFs!=State::DOF_ALL) { |
496 | + // forces |
497 | + if(b->isClump()) b->shape->cast<Clump>().addForceTorqueFromMembers(state,scene,f,m); |
498 | // linear acceleration |
499 | Vector3r linAccel=computeAccel(f,state->mass,state->blockedDOFs); |
500 | cundallDamp2nd(dt,f,fluctVel,linAccel); |
501 | @@ -163,7 +162,10 @@ |
502 | leapfrogTranslate(state,id,dt); |
503 | if(!useAspherical) leapfrogSphericalRotate(state,id,dt); |
504 | else leapfrogAsphericalRotate(state,id,dt,m); |
505 | - |
506 | + #ifdef ORI_VERLET |
507 | + if (oriVerlet) saveMaximaDisplacement(b); |
508 | + else |
509 | + #endif |
510 | saveMaximaVelocity(id,state); |
511 | // move individual members of the clump, save maxima velocity (for collider stride) |
512 | if(b->isClump()) Clump::moveMembers(b,scene,this); |
513 | |
514 | === modified file 'pkg/dem/NewtonIntegrator.hpp' |
515 | --- pkg/dem/NewtonIntegrator.hpp 2011-04-22 09:01:59 +0000 |
516 | +++ pkg/dem/NewtonIntegrator.hpp 2011-04-26 10:44:50 +0000 |
517 | @@ -11,6 +11,7 @@ |
518 | #include<yade/core/Interaction.hpp> |
519 | #include<yade/lib/base/Math.hpp> |
520 | #include<yade/pkg/common/Callbacks.hpp> |
521 | +#include<yade/pkg/common/VelocityBins.hpp> |
522 | #ifdef YADE_OPENMP |
523 | #include<omp.h> |
524 | #endif |
525 | @@ -38,14 +39,19 @@ |
526 | |
527 | // whether the cell has changed from the previous step |
528 | bool cellChanged; |
529 | + |
530 | // wether a body has been selected in Qt view |
531 | bool bodySelected; |
532 | int homoDeform; // updated from scene at every call; -1 for aperiodic simulations, otherwise equal to scene->cell->homoDeform |
533 | Matrix3r dVelGrad; // dtto |
534 | |
535 | public: |
536 | + Real updatingDispFactor;//(experimental) Displacement factor used to trigger bound update when oriVerlet=true: the bound is updated only if updatingDispFactor*disp>sweepDist when >0, else all bounds are updated. |
537 | // function to save maximum velocity, for the verlet-distance optimization |
538 | void saveMaximaVelocity(const Body::id_t& id, State* state); |
539 | + #ifdef ORI_VERLET |
540 | + void saveMaximaDisplacement(const shared_ptr<Body>& b); |
541 | + #endif |
542 | #ifdef YADE_OPENMP |
543 | vector<Real> threadMaxVelocitySq; |
544 | #endif |
545 | @@ -56,6 +62,7 @@ |
546 | ((Real,damping,0.2,,"damping coefficient for Cundall's non viscous damping (see [Chareyre2005]_) [-]")) |
547 | ((Real,maxVelocitySq,NaN,,"store square of max. velocity, for informative purposes; computed again at every step. |yupdate|")) |
548 | ((bool,exactAsphericalRot,true,,"Enable more exact body rotation integrator for :yref:`aspherical bodies<Body.aspherical>` *only*, using formulation from [Allen1989]_, pg. 89.")) |
549 | + ((bool,oriVerlet,false,,"Compare Verlet distance with displacement instead of velocity (updated by the collider)")) |
550 | ((Matrix3r,prevVelGrad,Matrix3r::Zero(),,"Store previous velocity gradient (:yref:`Cell::velGrad`) to track acceleration. |yupdate|")) |
551 | #ifdef YADE_BODY_CALLBACK |
552 | ((vector<shared_ptr<BodyCallback> >,callbacks,,,"List (std::vector in c++) of :yref:`BodyCallbacks<BodyCallback>` which will be called for each body as it is being processed.")) |