1 /******************************************************************************
3 * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
4 * Copyright 2003-2006 Nils Thuerey
6 * Standard LBM Factory implementation
8 *****************************************************************************/
10 #include "solver_class.h"
11 #include "solver_relax.h"
12 #include "particletracer.h"
15 #include "ntl_world.h"
16 #include "simulation_object.h"
18 #include <stdlib.h> /* rand(3) */
25 /******************************************************************************
27 *****************************************************************************/
29 // try to enhance surface?
32 extern bool glob_mpactive
;
33 extern bool glob_mpnum
;
34 extern bool glob_mpindex
;
37 void LbmFsgrSolver::prepareVisualization( void ) {
39 int workSet
= mLevel
[lev
].setCurr
;
42 LbmFloat mainGravLen
= 0.;
44 LbmFloat thisGravLen
= dot(LbmVec(dfVecX
[l
],dfVecY
[l
],dfVecZ
[l
]), getNormalized(mLevel
[mMaxRefine
].gravity
) );
45 if(thisGravLen
>mainGravLen
) {
46 mainGravLen
= thisGravLen
;
52 // 2d, place in the middle of isofield slice (k=2)
54 // 2d z offset = 2, lbmGetData adds 1, so use one here
56 // reset all values...
57 for(int k
= 0; k
< 5; ++k
)
58 for(int j
=0;j
<mLevel
[lev
].lSizey
-0;j
++)
59 for(int i
=0;i
<mLevel
[lev
].lSizex
-0;i
++) {
60 *mpIso
->lbmGetData(i
,j
,ZKOFF
)=0.0;
63 // 3d, use normal bounds
66 // reset all values...
67 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(lev
); ++k
)
68 for(int j
=0;j
<mLevel
[lev
].lSizey
-0;j
++)
69 for(int i
=0;i
<mLevel
[lev
].lSizex
-0;i
++) {
70 *mpIso
->lbmGetData(i
,j
,ZKOFF
)=0.0;
75 if((glob_mpactive
) && (glob_mpnum
>1) && (glob_mpindex
==0)) {
80 LbmFloat minval
= mIsoValue
*1.05; // / mIsoWeight[13];
83 for(int k
= getForZMin1(); k
< getForZMax1(lev
); ++k
)
84 for(int j
=1;j
<mLevel
[lev
].lSizey
-1;j
++)
85 for(int i
=1;i
<mLevel
[lev
].lSizex
-1;i
++) {
86 const CellFlagType cflag
= RFLAG(lev
, i
,j
,k
,workSet
);
87 //if(cflag&(CFBnd|CFEmpty)) {
92 if( (cflag
&(CFFluid
|CFUnused
)) ) {
94 } else if( (cflag
&CFInter
) ) {
95 val
= (QCELL(lev
, i
,j
,k
,workSet
, dFfrac
));
100 #else // SURFACE_ENH!=1
102 // treated in second loop
104 } else if(cflag
&CFUnused
) {
106 } else if( (cflag
&CFFluid
) && (cflag
&CFNoBndFluid
)) {
109 } else if( (cflag
&(CFEmpty
|CFInter
|CFFluid
)) ) {
113 const CellFlagType nbflag
= RFLAG_NB(lev
, i
,j
,k
, workSet
,l
);
114 if(nbflag
&CFInter
){ intercnt
++; }
116 // check all directions otherwise we get bugs with splashes on obstacles
117 // if(l!=mainGravDir) continue; // only check bnd along main grav. dir
118 //if((nbflag&CFBnd)&&(nbflag&CFBndNoslip)){ noslipbnd=1; }
119 if((nbflag
&CFBnd
)){ noslipbnd
=1; }
123 // special empty treatment
124 if((noslipbnd
)&&(intercnt
>6)) {
125 *mpIso
->lbmGetData(i
,j
,ZKOFF
) += minval
;
126 } else if((noslipbnd
)&&(intercnt
>0)) {
128 *mpIso
->lbmGetData(i
,j
,ZKOFF
) += mIsoValue
*0.9;
134 } else if(cflag
&(CFNoNbEmpty
|CFFluid
)) {
135 // no empty nb interface cells are treated as full
138 val
= (QCELL(lev
, i
,j
,k
,workSet
, dFfrac
));
142 if(val
<minval
) val
= minval
;
143 *mpIso
->lbmGetData(i
,j
,ZKOFF
) += minval
-( val
* mIsoWeight
[13] );
145 } else { // all others, unused?
148 #endif // SURFACE_ENH>0
150 *mpIso
->lbmGetData( i
-1 , j
-1 ,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[0] );
151 *mpIso
->lbmGetData( i
, j
-1 ,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[1] );
152 *mpIso
->lbmGetData( i
+1 , j
-1 ,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[2] );
154 *mpIso
->lbmGetData( i
-1 , j
,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[3] );
155 *mpIso
->lbmGetData( i
, j
,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[4] );
156 *mpIso
->lbmGetData( i
+1 , j
,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[5] );
158 *mpIso
->lbmGetData( i
-1 , j
+1 ,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[6] );
159 *mpIso
->lbmGetData( i
, j
+1 ,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[7] );
160 *mpIso
->lbmGetData( i
+1 , j
+1 ,ZKOFF
-ZKD1
) += ( val
* mIsoWeight
[8] );
163 *mpIso
->lbmGetData( i
-1 , j
-1 ,ZKOFF
) += ( val
* mIsoWeight
[9] );
164 *mpIso
->lbmGetData( i
, j
-1 ,ZKOFF
) += ( val
* mIsoWeight
[10] );
165 *mpIso
->lbmGetData( i
+1 , j
-1 ,ZKOFF
) += ( val
* mIsoWeight
[11] );
167 *mpIso
->lbmGetData( i
-1 , j
,ZKOFF
) += ( val
* mIsoWeight
[12] );
168 *mpIso
->lbmGetData( i
, j
,ZKOFF
) += ( val
* mIsoWeight
[13] );
169 *mpIso
->lbmGetData( i
+1 , j
,ZKOFF
) += ( val
* mIsoWeight
[14] );
171 *mpIso
->lbmGetData( i
-1 , j
+1 ,ZKOFF
) += ( val
* mIsoWeight
[15] );
172 *mpIso
->lbmGetData( i
, j
+1 ,ZKOFF
) += ( val
* mIsoWeight
[16] );
173 *mpIso
->lbmGetData( i
+1 , j
+1 ,ZKOFF
) += ( val
* mIsoWeight
[17] );
176 *mpIso
->lbmGetData( i
-1 , j
-1 ,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[18] );
177 *mpIso
->lbmGetData( i
, j
-1 ,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[19] );
178 *mpIso
->lbmGetData( i
+1 , j
-1 ,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[20] );
180 *mpIso
->lbmGetData( i
-1 , j
,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[21] );
181 *mpIso
->lbmGetData( i
, j
,ZKOFF
+ZKD1
)+= ( val
* mIsoWeight
[22] );
182 *mpIso
->lbmGetData( i
+1 , j
,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[23] );
184 *mpIso
->lbmGetData( i
-1 , j
+1 ,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[24] );
185 *mpIso
->lbmGetData( i
, j
+1 ,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[25] );
186 *mpIso
->lbmGetData( i
+1 , j
+1 ,ZKOFF
+ZKD1
) += ( val
* mIsoWeight
[26] );
192 if(mFsSurfGenSetting
&fssgNoObs
) {
193 for(int k
= getForZMin1(); k
< getForZMax1(lev
); ++k
)
194 for(int j
=1;j
<mLevel
[lev
].lSizey
-1;j
++)
195 for(int i
=1;i
<mLevel
[lev
].lSizex
-1;i
++) {
196 const CellFlagType cflag
= RFLAG(lev
, i
,j
,k
,workSet
);
198 CellFlagType nbored
=0;
199 LbmFloat avgfill
=0.,avgfcnt
=0.;
201 const int ni
= i
+dfVecX
[l
];
202 const int nj
= j
+dfVecY
[l
];
203 const int nk
= ZKOFF
+dfVecZ
[l
];
205 const CellFlagType nbflag
= RFLAG(lev
, ni
,nj
,nk
, workSet
);
208 avgfill
+= QCELL(lev
, ni
,nj
,nk
, workSet
,dFfrac
); avgfcnt
+= 1.;
209 } else if(nbflag
&CFFluid
) {
210 avgfill
+= 1.; avgfcnt
+= 1.;
211 } else if(nbflag
&CFEmpty
) {
212 avgfill
+= 0.; avgfcnt
+= 1.;
215 //if( (ni<0) || (nj<0) || (nk<0)
216 //|| (ni>=mLevel[mMaxRefine].lSizex)
217 //|| (nj>=mLevel[mMaxRefine].lSizey)
218 //|| (nk>=mLevel[mMaxRefine].lSizez) ) continue;
222 if(avgfcnt
>0.) avgfill
/=avgfcnt
;
223 *mpIso
->lbmGetData(i
,j
,ZKOFF
) = avgfill
; continue;
225 else if(nbored
&CFFluid
) {
226 *mpIso
->lbmGetData(i
,j
,ZKOFF
) = 1.; continue;
232 // move surface towards inner "row" of obstacle
233 // cells if necessary (all obs cells without fluid/inter
234 // nbs (=iso==0) next to obstacles...)
235 for(int k
= getForZMin1(); k
< getForZMax1(lev
); ++k
)
236 for(int j
=1;j
<mLevel
[lev
].lSizey
-1;j
++)
237 for(int i
=1;i
<mLevel
[lev
].lSizex
-1;i
++) {
238 const CellFlagType cflag
= RFLAG(lev
, i
,j
,k
,workSet
);
239 if( (cflag
&(CFBnd
)) && (*mpIso
->lbmGetData(i
,j
,ZKOFF
)==0.)) {
242 const int ni
= i
+dfVecX
[l
];
243 const int nj
= j
+dfVecY
[l
];
244 const int nk
= ZKOFF
+dfVecZ
[l
];
245 const CellFlagType nbflag
= RFLAG(lev
, ni
,nj
,nk
, workSet
);
246 if(nbflag
&CFBnd
) bndnbcnt
++;
248 if(bndnbcnt
>0) *mpIso
->lbmGetData(i
,j
,ZKOFF
)=mIsoValue
*0.95;
254 if(mFsSurfGenSetting
&fssgNoNorth
)
255 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(lev
); ++k
)
256 for(int j
=0;j
<mLevel
[lev
].lSizey
-0;j
++) {
257 *mpIso
->lbmGetData(0, j
,ZKOFF
) = *mpIso
->lbmGetData(1, j
,ZKOFF
);
259 if(mFsSurfGenSetting
&fssgNoEast
)
260 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(lev
); ++k
)
261 for(int i
=0;i
<mLevel
[lev
].lSizex
-0;i
++) {
262 *mpIso
->lbmGetData(i
,0, ZKOFF
) = *mpIso
->lbmGetData(i
,1, ZKOFF
);
264 if(mFsSurfGenSetting
&fssgNoSouth
)
265 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(lev
); ++k
)
266 for(int j
=0;j
<mLevel
[lev
].lSizey
-0;j
++) {
267 *mpIso
->lbmGetData(mLevel
[lev
].lSizex
-1,j
,ZKOFF
) = *mpIso
->lbmGetData(mLevel
[lev
].lSizex
-2,j
,ZKOFF
);
269 if(mFsSurfGenSetting
&fssgNoWest
)
270 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(lev
); ++k
)
271 for(int i
=0;i
<mLevel
[lev
].lSizex
-0;i
++) {
272 *mpIso
->lbmGetData(i
,mLevel
[lev
].lSizey
-1,ZKOFF
) = *mpIso
->lbmGetData(i
,mLevel
[lev
].lSizey
-2,ZKOFF
);
275 if(mFsSurfGenSetting
&fssgNoBottom
)
276 for(int j
=0;j
<mLevel
[lev
].lSizey
-0;j
++)
277 for(int i
=0;i
<mLevel
[lev
].lSizex
-0;i
++) {
278 *mpIso
->lbmGetData(i
,j
,0 ) = *mpIso
->lbmGetData(i
,j
,1 );
280 if(mFsSurfGenSetting
&fssgNoTop
)
281 for(int j
=0;j
<mLevel
[lev
].lSizey
-0;j
++)
282 for(int i
=0;i
<mLevel
[lev
].lSizex
-0;i
++) {
283 *mpIso
->lbmGetData(i
,j
,mLevel
[lev
].lSizez
-1) = *mpIso
->lbmGetData(i
,j
,mLevel
[lev
].lSizez
-2);
286 #endif // SURFACE_ENH>=2
289 // update preview, remove 2d?
290 if((mOutputSurfacePreview
)&&(LBMDIM
==3)) {
291 int pvsx
= (int)(mPreviewFactor
*mSizex
);
292 int pvsy
= (int)(mPreviewFactor
*mSizey
);
293 int pvsz
= (int)(mPreviewFactor
*mSizez
);
294 //float scale = (float)mSizex / previewSize;
295 LbmFloat scalex
= (LbmFloat
)mSizex
/(LbmFloat
)pvsx
;
296 LbmFloat scaley
= (LbmFloat
)mSizey
/(LbmFloat
)pvsy
;
297 LbmFloat scalez
= (LbmFloat
)mSizez
/(LbmFloat
)pvsz
;
298 for(int k
= 0; k
< (pvsz
-1); ++k
)
299 for(int j
=0;j
< pvsy
;j
++)
300 for(int i
=0;i
< pvsx
;i
++) {
301 *mpPreviewSurface
->lbmGetData(i
,j
,k
) = *mpIso
->lbmGetData( (int)(i
*scalex
), (int)(j
*scaley
), (int)(k
*scalez
) );
303 // set borders again...
304 for(int k
= 0; k
< (pvsz
-1); ++k
) {
305 for(int j
=0;j
< pvsy
;j
++) {
306 *mpPreviewSurface
->lbmGetData(0,j
,k
) = *mpIso
->lbmGetData( 0, (int)(j
*scaley
), (int)(k
*scalez
) );
307 *mpPreviewSurface
->lbmGetData(pvsx
-1,j
,k
) = *mpIso
->lbmGetData( mSizex
-1, (int)(j
*scaley
), (int)(k
*scalez
) );
309 for(int i
=0;i
< pvsx
;i
++) {
310 *mpPreviewSurface
->lbmGetData(i
,0,k
) = *mpIso
->lbmGetData( (int)(i
*scalex
), 0, (int)(k
*scalez
) );
311 *mpPreviewSurface
->lbmGetData(i
,pvsy
-1,k
) = *mpIso
->lbmGetData( (int)(i
*scalex
), mSizey
-1, (int)(k
*scalez
) );
314 for(int j
=0;j
<pvsy
;j
++)
315 for(int i
=0;i
<pvsx
;i
++) {
316 *mpPreviewSurface
->lbmGetData(i
,j
,0) = *mpIso
->lbmGetData( (int)(i
*scalex
), (int)(j
*scaley
) , 0);
317 *mpPreviewSurface
->lbmGetData(i
,j
,pvsz
-1) = *mpIso
->lbmGetData( (int)(i
*scalex
), (int)(j
*scaley
) , mSizez
-1);
320 if(mFarFieldSize
>=1.2) {
321 // also remove preview border
322 for(int k
= 0; k
< (pvsz
-1); ++k
) {
323 for(int j
=0;j
< pvsy
;j
++) {
324 *mpPreviewSurface
->lbmGetData(0,j
,k
) =
325 *mpPreviewSurface
->lbmGetData(1,j
,k
) =
326 *mpPreviewSurface
->lbmGetData(2,j
,k
);
327 *mpPreviewSurface
->lbmGetData(pvsx
-1,j
,k
) =
328 *mpPreviewSurface
->lbmGetData(pvsx
-2,j
,k
) =
329 *mpPreviewSurface
->lbmGetData(pvsx
-3,j
,k
);
332 for(int i
=0;i
< pvsx
;i
++) {
333 *mpPreviewSurface
->lbmGetData(i
,0,k
) =
334 *mpPreviewSurface
->lbmGetData(i
,1,k
) =
335 *mpPreviewSurface
->lbmGetData(i
,2,k
);
336 *mpPreviewSurface
->lbmGetData(i
,pvsy
-1,k
) =
337 *mpPreviewSurface
->lbmGetData(i
,pvsy
-2,k
) =
338 *mpPreviewSurface
->lbmGetData(i
,pvsy
-3,k
);
342 for(int j
=0;j
<pvsy
;j
++)
343 for(int i
=0;i
<pvsx
;i
++) {
344 *mpPreviewSurface
->lbmGetData(i
,j
,0) =
345 *mpPreviewSurface
->lbmGetData(i
,j
,1) =
346 *mpPreviewSurface
->lbmGetData(i
,j
,2);
347 *mpPreviewSurface
->lbmGetData(i
,j
,pvsz
-1) =
348 *mpPreviewSurface
->lbmGetData(i
,j
,pvsz
-2) =
349 *mpPreviewSurface
->lbmGetData(i
,j
,pvsz
-3);
356 #if LBM_INCLUDE_TESTSOLVERS==1
358 #endif // LBM_INCLUDE_TESTSOLVERS==1
363 /*! calculate speeds of fluid objects (or inflow) */
364 void LbmFsgrSolver::recalculateObjectSpeeds() {
365 const bool debugRecalc
= false;
366 int numobjs
= (int)(this->mpGiObjects
->size());
367 // note - (numobjs + 1) is entry for domain settings
369 if(debugRecalc
) errMsg("recalculateObjectSpeeds","start, #obj:"<<numobjs
);
371 errFatal("LbmFsgrSolver::recalculateObjectSpeeds","More than 256 objects currently not supported...",SIMWORLD_INITERROR
);
374 mObjectSpeeds
.resize(numobjs
+1);
375 for(int i
=0; i
<(int)(numobjs
+0); i
++) {
376 mObjectSpeeds
[i
] = vec2L(this->mpParam
->calculateLattVelocityFromRw( vec2P( (*this->mpGiObjects
)[i
]->getInitialVelocity(mSimulationTime
) )));
377 if(debugRecalc
) errMsg("recalculateObjectSpeeds","id"<<i
<<" set to "<< mObjectSpeeds
[i
]<<", unscaled:"<< (*this->mpGiObjects
)[i
]->getInitialVelocity(mSimulationTime
) );
380 // also reinit part slip values here
381 mObjectPartslips
.resize(numobjs
+1);
382 for(int i
=0; i
<=(int)(numobjs
+0); i
++) {
384 mObjectPartslips
[i
] = (LbmFloat
)(*this->mpGiObjects
)[i
]->getGeoPartSlipValue();
387 mObjectPartslips
[i
] = this->mDomainPartSlipValue
;
389 LbmFloat set
= mObjectPartslips
[i
];
391 // as in setInfluenceVelocity
392 const LbmFloat dt
= mLevel
[mMaxRefine
].timestep
;
393 const LbmFloat dtInter
= 0.01;
394 //LbmFloat facFv = 1.-set;
395 // mLevel[mMaxRefine].timestep
396 LbmFloat facNv
= (LbmFloat
)( 1.-pow( (double)(set
), (double)(dt
/dtInter
)) );
397 errMsg("mObjectPartslips","id:"<<i
<<"/"<<numobjs
<<" ts:"<<dt
<< " its:"<<(dt
/dtInter
) <<" set"<<set
<<" nv"<<facNv
<<" test:"<<
398 pow( (double)(1.-facNv
),(double)(dtInter
/dt
)) );
399 mObjectPartslips
[i
] = facNv
;
401 if(debugRecalc
) errMsg("recalculateObjectSpeeds","id"<<i
<<" parts "<< mObjectPartslips
[i
] );
404 if(debugRecalc
) errMsg("recalculateObjectSpeeds","done, domain:"<<mObjectPartslips
[numobjs
]<<" n"<<numobjs
);
409 /*****************************************************************************/
410 /*! debug object display */
411 /*****************************************************************************/
412 vector
<ntlGeometryObject
*> LbmFsgrSolver::getDebugObjects() {
413 vector
<ntlGeometryObject
*> debo
;
414 if(this->mOutputSurfacePreview
) {
415 debo
.push_back( mpPreviewSurface
);
417 #if LBM_INCLUDE_TESTSOLVERS==1
419 vector
<ntlGeometryObject
*> tdebo
;
420 tdebo
= mpTest
->getDebugObjects();
421 for(size_t i
=0; i
<tdebo
.size(); i
++) debo
.push_back( tdebo
[i
] );
423 #endif // ELBEEM_PLUGIN
427 /******************************************************************************
429 *****************************************************************************/
431 /*! init particle positions */
432 int LbmFsgrSolver::initParticles() {
433 int workSet
= mLevel
[mMaxRefine
].setCurr
;
436 ParticleTracer
*partt
= mpParticles
;
438 partt
->setStart( this->mvGeoStart
+ ntlVec3Gfx(mLevel
[mMaxRefine
].nodeSize
*0.5) );
439 partt
->setEnd ( this->mvGeoEnd
+ ntlVec3Gfx(mLevel
[mMaxRefine
].nodeSize
*0.5) );
441 partt
->setSimStart( ntlVec3Gfx(0.0) );
442 partt
->setSimEnd ( ntlVec3Gfx(mSizex
, mSizey
, getForZMaxBnd(mMaxRefine
)) );
444 while( (num
<partt
->getNumInitialParticles()) && (tries
<100*partt
->getNumInitialParticles()) ) {
446 x
= 1.0+(( (LbmFloat
)(mSizex
-3.) ) * (rand()/(RAND_MAX
+1.0)) );
447 y
= 1.0+(( (LbmFloat
)(mSizey
-3.) ) * (rand()/(RAND_MAX
+1.0)) );
448 z
= 1.0+(( (LbmFloat
) getForZMax1(mMaxRefine
)-2. )* (rand()/(RAND_MAX
+1.0)) );
449 int i
= (int)(x
+0.5);
450 int j
= (int)(y
+0.5);
451 int k
= (int)(z
+0.5);
453 k
= 0; z
= 0.5; // place in the middle of domain
456 //if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFFluid) )
457 //&& ( RFLAG(mMaxRefine, i,j,k, workSet)& CFNoNbFluid )
458 //if( RFLAG(mMaxRefine, i,j,k, workSet) & (CFFluid|CFInter|CFMbndInflow) ) {
459 if( RFLAG(mMaxRefine
, i
,j
,k
, workSet
) & (CFNoBndFluid
|CFUnused
) ) {
461 //? FORDF1 { if(!(RFLAG_NB(mMaxRefine,i,j,k,workSet, l) & CFFluid)) cellOk = false; }
462 if(!cellOk
) continue;
464 partt
->addParticle(x
,y
,z
);
465 partt
->getLast()->setStatus(PART_IN
);
466 partt
->getLast()->setType(PART_TRACER
);
468 partt
->getLast()->setSize(1.);
470 partt
->getLast()->setSize(0.5 + (rand()/(RAND_MAX
+1.0)));
472 if( ( partt
->getInitStart()>0.)
473 && ( partt
->getInitEnd()>0.)
474 && ( partt
->getInitEnd()>partt
->getInitStart() )) {
475 t
= partt
->getInitStart()+ (partt
->getInitEnd()-partt
->getInitStart())*(rand()/(RAND_MAX
+1.0));
476 partt
->getLast()->setLifeTime( -t
);
483 /*FSGR_FORIJK1(mMaxRefine) {
484 if( (RFLAG(mMaxRefine,i,j,k, workSet) & (CFNoBndFluid)) ) {
485 LbmFloat rndn = (rand()/(RAND_MAX+1.0));
487 ntlVec3Gfx pos( (LbmFloat)(i)-0.5, (LbmFloat)(j)-0.5, (LbmFloat)(k)-0.5 );
488 if(LBMDIM==2) { pos[2]=0.5; }
489 partt->addParticle( pos[0],pos[1],pos[2] );
490 partt->getLast()->setStatus(PART_IN);
491 partt->getLast()->setType(PART_TRACER);
492 partt->getLast()->setSize(1.0);
499 #if LBM_INCLUDE_TESTSOLVERS==1
501 const bool partDebug
=false;
502 if(mpTest
->mPartTestcase
==0){ errMsg("LbmTestdata"," part init "<<mpTest
->mPartTestcase
); }
503 if(mpTest
->mPartTestcase
==-12){
504 const int lev
= mMaxRefine
;
505 for(int i
=5;i
<15;i
++) {
507 y
= 0.5+(LbmFloat
)(i
);
508 x
= mLevel
[lev
].lSizex
/20.0*10.0;
509 z
= mLevel
[lev
].lSizez
/20.0*2.0;
510 partt
->addParticle(x
,y
,z
);
511 partt
->getLast()->setStatus(PART_IN
);
512 partt
->getLast()->setType(PART_BUBBLE
);
513 partt
->getLast()->setSize( (-4.0+(LbmFloat
)i
)/1.0 );
514 if(partDebug
) errMsg("PARTTT","SET "<<PRINT_VEC(x
,y
,z
)<<" p"<<partt
->getLast()->getPos() <<" s"<<partt
->getLast()->getSize() );
517 if(mpTest
->mPartTestcase
==-11){
518 const int lev
= mMaxRefine
;
519 for(int i
=5;i
<15;i
++) {
521 y
= 10.5+(LbmFloat
)(i
);
522 x
= mLevel
[lev
].lSizex
/20.0*10.0;
523 z
= mLevel
[lev
].lSizez
/20.0*40.0;
524 partt
->addParticle(x
,y
,z
);
525 partt
->getLast()->setStatus(PART_IN
);
526 partt
->getLast()->setType(PART_DROP
);
527 partt
->getLast()->setSize( (-4.0+(LbmFloat
)i
)/1.0 );
528 if(partDebug
) errMsg("PARTTT","SET "<<PRINT_VEC(x
,y
,z
)<<" p"<<partt
->getLast()->getPos() <<" s"<<partt
->getLast()->getSize() );
531 // place floats on rectangular region FLOAT_JITTER_BND
532 if(mpTest
->mPartTestcase
==-10){
533 const int lev
= mMaxRefine
;
534 const int sx
= mLevel
[lev
].lSizex
;
535 const int sy
= mLevel
[lev
].lSizey
;
536 //for(int j=-(int)(sy*0.25);j<-(int)(sy*0.25)+2;++j) { for(int i=-(int)(sx*0.25);i<-(int)(sy*0.25)+2;++i) {
537 //for(int j=-(int)(sy*1.25);j<(int)(2.25*sy);++j) { for(int i=-(int)(sx*1.25);i<(int)(2.25*sx);++i) {
538 for(int j
=-(int)(sy
*0.3);j
<(int)(1.3*sy
);++j
) { for(int i
=-(int)(sx
*0.3);i
<(int)(1.3*sx
);++i
) {
539 //for(int j=-(int)(sy*0.2);j<(int)(0.2*sy);++j) { for(int i= (int)(sx*0.5);i<= (int)(0.51*sx);++i) {
541 x
= 0.0+(LbmFloat
)(i
);
542 y
= 0.0+(LbmFloat
)(j
);
543 //z = mLevel[lev].lSizez/10.0*2.5 - 1.0;
544 z
= mLevel
[lev
].lSizez
/20.0*9.5 - 1.0;
545 //z = mLevel[lev].lSizez/20.0*4.5 - 1.0;
546 partt
->addParticle(x
,y
,z
);
547 //if( (i>0)&&(i<sx) && (j>0)&&(j<sy) ) { partt->getLast()->setStatus(PART_IN); } else { partt->getLast()->setStatus(PART_OUT); }
548 partt
->getLast()->setStatus(PART_IN
);
549 partt
->getLast()->setType(PART_FLOAT
);
550 partt
->getLast()->setSize( 15.0 );
551 if(partDebug
) errMsg("PARTTT","SET "<<PRINT_VEC(x
,y
,z
)<<" p"<<partt
->getLast()->getPos() <<" s"<<partt
->getLast()->getSize() );
556 #endif // LBM_INCLUDE_TESTSOLVERS
559 debMsgStd("LbmFsgrSolver::initParticles",DM_MSG
,"Added "<<num
<<" particles, genProb:"<<this->mPartGenProb
<<", tries:"<<tries
, 10);
560 if(num
!= partt
->getNumParticles()) return 1;
565 // helper function for particle debugging
566 /*static string getParticleStatusString(int state) {
567 std::ostringstream out;
568 if(state&PART_DROP) out << "dropp ";
569 if(state&PART_TRACER) out << "tracr ";
570 if(state&PART_BUBBLE) out << "bubbl ";
571 if(state&PART_FLOAT) out << "float ";
572 if(state&PART_INTER) out << "inter ";
574 if(state&PART_IN) out << "inn ";
575 if(state&PART_OUT) out << "out ";
576 if(state&PART_INACTIVE) out << "INACT ";
577 if(state&PART_OUTFLUID) out << "outfluid ";
581 #define P_CHANGETYPE(p, newtype) \
582 p->setLifeTime(0.); \
583 /* errMsg("PIT","U pit"<<(p)->getId()<<" pos:"<< (p)->getPos()<<" status:"<<convertFlags2String((p)->getFlags())<<" to "<< (newtype) ); */ \
587 #define TRACE_JITTER 0.025
588 #define TRACE_RAND (rand()/(RAND_MAX+1.0))*TRACE_JITTER-(TRACE_JITTER*0.5)
589 #define FFGET_NORM(var,dl) \
590 if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFInter)){ (var) = QCELL_NB(lev,i,j,k,workSet,dl,dFfrac); } \
591 else if(RFLAG_NB(lev,i,j,k,workSet, dl) &(CFFluid|CFUnused)){ (var) = 1.; } else (var) = 0.0;
594 #define FLOAT_JITTER_BND (FLOAT_JITTER*2.0)
595 #define FLOAT_JITTBNDRAND(x) ((rand()/(RAND_MAX+1.0))*FLOAT_JITTER_BND*(1.-(x/(LbmFloat)maxdw))-(FLOAT_JITTER_BND*(1.-(x)/(LbmFloat)maxdw)*0.5))
598 /*errMsg("PIT","DEL AT "<< __LINE__<<" type:"<<p->getType()<<" "); */ \
599 p->setActive( false ); \
602 void LbmFsgrSolver::advanceParticles() {
603 const int level
= mMaxRefine
;
604 const int workSet
= mLevel
[level
].setCurr
;
605 LbmFloat vx
=0.0,vy
=0.0,vz
=0.0;
606 //int debugOutCounter=0; // debug output counter
608 myTime_t parttstart
= getTime();
609 const LbmFloat cellsize
= this->mpParam
->getCellSize();
610 const LbmFloat timestep
= this->mpParam
->getTimestep();
611 //const LbmFloat viscAir = 1.79 * 1e-5; // RW2L kin. viscosity, mu
612 //const LbmFloat viscWater = 1.0 * 1e-6; // RW2L kin. viscosity, mu
613 const LbmFloat rhoAir
= 1.2; // [kg m^-3] RW2L
614 const LbmFloat rhoWater
= 1000.0; // RW2L
615 const LbmFloat minDropSize
= 0.0005; // [m], = 2mm RW2L
616 const LbmVec
velAir(0.); // [m / s]
618 const LbmFloat r1
= 0.005; // r max
619 const LbmFloat r2
= 0.0005; // r min
620 const LbmFloat v1
= 9.0; // v max
621 const LbmFloat v2
= 2.0; // v min
622 const LbmVec rwgrav
= vec2L( this->mpParam
->getGravity(mSimulationTime
) );
623 const bool useff
= (mFarFieldSize
>1.2); // if(mpTest->mFarfMode>0){
625 // TODO scale bubble/part damping dep. on timestep, also drop bnd rev damping
626 const int cutval
= mCutoff
; // use full border!?
627 if(this->mStepCnt
%50==49) { mpParticles
->cleanup(); }
628 for(vector
<ParticleObject
>::iterator pit
= mpParticles
->getParticlesBegin();
629 pit
!= mpParticles
->getParticlesEnd(); pit
++) {
630 //if((*pit).getPos()[2]>10.) errMsg("PIT"," pit"<<(*pit).getId()<<" pos:"<< (*pit).getPos()<<" status:["<<getParticleStatusString((*pit).getFlags())<<"] vel:"<< (*pit).getVel() );
631 if( (*pit
).getActive()==false ) continue;
632 // skip until reached
633 ParticleObject
*p
= &(*pit
);
634 if(p
->getLifeTime()<0.){
635 if(p
->getLifeTime() < -mSimulationTime
) continue;
636 else p
->setLifeTime(-mLevel
[level
].timestep
); // zero for following update
639 p
->setLifeTime(p
->getLifeTime()+mLevel
[level
].timestep
);
641 // nearest neighbor, particle positions don't include empty bounds
642 ntlVec3Gfx pos
= p
->getPos();
643 i
= (int)pos
[0]; j
= (int)pos
[1]; k
= (int)pos
[2];// no offset necessary
644 if(LBMDIM
==2) { k
= 0; }
646 // only testdata handling, all for sws
647 #if LBM_INCLUDE_TESTSOLVERS==1
648 if(useff
&& (mpTest
->mFarfMode
>0)) {
649 p
->setStatus(PART_OUT
);
650 mpTest
->handleParticle(p
, i
,j
,k
); continue;
652 #endif // LBM_INCLUDE_TESTSOLVERS==1
655 if(p
->getStatus()&PART_IN
) { // IN
656 if( (i
<cutval
)||(i
>mSizex
-1-cutval
)||
657 (j
<cutval
)||(j
>mSizey
-1-cutval
)
658 //||(k<cutval)||(k>mSizez-1-cutval)
660 if(!useff
) { DEL_PART
;
662 p
->setStatus(PART_OUT
);
665 } else { // OUT rough check
667 if( (i
>=cutval
)&&(i
<=mSizex
-1-cutval
)&&
668 (j
>=cutval
)&&(j
<=mSizey
-1-cutval
)
670 p
->setStatus(PART_IN
);
674 if( (p
->getType()==PART_BUBBLE
) ||
675 (p
->getType()==PART_TRACER
) ) {
679 if(p
->getStatus()&PART_IN
) { // IN
681 if(k
>mSizez
-1-cutval
) DEL_PART
;
683 if( RFLAG(level
, i
,j
,k
, workSet
)&(CFFluid
|CFUnused
) ) {
686 int si
=i
, sj
=j
, sk
=k
;
687 while(partLev
>0 && RFLAG(partLev
, si
,sj
,sk
, workSet
)&(CFUnused
)) {
693 // get velocity from fluid cell
694 if( RFLAG(partLev
, si
,sj
,sk
, workSet
)&(CFFluid
) ) {
695 LbmFloat
*ccel
= RACPNT(partLev
, si
,sj
,sk
, workSet
);
697 LbmFloat cdf
= RAC(ccel
, l
);
699 vx
+= (this->dfDvecX
[l
]*cdf
);
700 vy
+= (this->dfDvecY
[l
]*cdf
);
701 vz
+= (this->dfDvecZ
[l
]*cdf
);
703 // remove gravity influence
704 const LbmFloat lesomega
= mLevel
[level
].omega
; // no les
705 vx
-= mLevel
[level
].gravity
[0] * lesomega
*0.5;
706 vy
-= mLevel
[level
].gravity
[1] * lesomega
*0.5;
707 vz
-= mLevel
[level
].gravity
[2] * lesomega
*0.5;
711 // out of bounds, deactivate...
712 // FIXME make fsgr treatment
713 if(p
->getType()==PART_BUBBLE
) { P_CHANGETYPE(p
, PART_FLOAT
); continue; }
716 // below 3d region, just rise
719 # if LBM_INCLUDE_TESTSOLVERS==1
720 if(useff
) { mpTest
->handleParticle(p
, i
,j
,k
); }
722 # else // LBM_INCLUDE_TESTSOLVERS==1
724 # endif // LBM_INCLUDE_TESTSOLVERS==1
725 // TODO use x,y vel...?
728 ntlVec3Gfx v
= p
->getVel(); // dampen...
729 if( (useff
)&& (p
->getType()==PART_BUBBLE
) ) {
732 if(mPartUsePhysModel
) {
733 LbmFloat radius
= p
->getSize() * minDropSize
;
734 LbmVec velPart
= vec2L(p
->getVel()) *cellsize
/timestep
; // L2RW, lattice velocity
735 LbmVec velWater
= LbmVec(vx
,vy
,vz
) *cellsize
/timestep
;// L2RW, fluid velocity
736 LbmVec velRel
= velWater
- velPart
;
737 //LbmFloat velRelNorm = norm(velRel);
738 LbmFloat pvolume
= rhoAir
* 4.0/3.0 * M_PI
* radius
*radius
*radius
; // volume: 4/3 pi r^3
740 LbmVec fb
= -rwgrav
* pvolume
*rhoWater
;
741 LbmVec fd
= velRel
*6.0*M_PI
*radius
* (1e-3); //viscWater;
742 LbmVec change
= (fb
+fd
) *10.0*timestep
*(timestep
/cellsize
);
743 /*if(debugOutCounter<0) {
744 errMsg("PIT","BTEST1 vol="<<pvolume<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel);
745 errMsg("PIT","BTEST2 cellsize="<<cellsize<<" timestep="<<timestep<<" viscW="<<viscWater<<" ss/mb="<<(timestep/(pvolume*rhoAir)));
746 errMsg("PIT","BTEST2 grav="<<rwgrav<<" " );
747 errMsg("PIT","BTEST2 change="<<(change)<<" fb="<<(fb)<<" fd="<<(fd)<<" ");
748 errMsg("PIT","BTEST2 change="<<norm(change)<<" fb="<<norm(fb)<<" fd="<<norm(fd)<<" ");
751 LbmVec fd2
= (LbmVec(vx
,vy
,vz
)-vec2L(p
->getVel())) * 6.0*M_PI
*radius
* (1e-3); //viscWater;
753 vz
= (1.0-w
)*vz
+ w
*(p
->getVel()[2]-0.5*(p
->getSize()/5.0)*mLevel
[level
].gravity
[2]);
754 v
= ntlVec3Gfx(vx
,vy
,vz
)+vec2G(fd2
);
757 // non phys, half old, half fluid, use slightly slower acc
758 v
= v
*0.5 + ntlVec3Gfx(vx
,vy
,vz
)* 0.5-vec2G(mLevel
[level
].gravity
)*0.5;
759 p
->setVel( v
* 0.99 );
763 } else if(p
->getType()==PART_TRACER
) {
764 v
= ntlVec3Gfx(vx
,vy
,vz
);
765 CellFlagType fflag
= RFLAG(level
, i
,j
,k
, workSet
);
767 if(fflag
&(CFFluid
|CFInter
) ) { p
->setInFluid(true);
768 } else { p
->setInFluid(false); }
770 if( (( fflag
&CFFluid
) && ( fflag
&CFNoBndFluid
)) ||
771 (( fflag
&CFInter
) && (!(fflag
&CFNoNbFluid
)) ) ) {
774 p
->advance( TRACE_RAND
,TRACE_RAND
,TRACE_RAND
);
776 p
->advance( TRACE_RAND
,TRACE_RAND
, 0.);
780 // move inwards along normal, make sure normal is valid first
781 // todo use class funcs!
782 const int lev
= level
;
783 LbmFloat nx
=0.,ny
=0.,nz
=0., nv1
,nv2
;
785 if(i
<=0) { nx
= -1.; nonorm
= true; }
786 if(i
>=mSizex
-1) { nx
= 1.; nonorm
= true; }
787 if(j
<=0) { ny
= -1.; nonorm
= true; }
788 if(j
>=mSizey
-1) { ny
= 1.; nonorm
= true; }
790 if(k
<=0) { nz
= -1.; nonorm
= true; }
791 if(k
>=mSizez
-1) { nz
= 1.; nonorm
= true; }
794 FFGET_NORM(nv1
,dE
); FFGET_NORM(nv2
,dW
);
796 FFGET_NORM(nv1
,dN
); FFGET_NORM(nv2
,dS
);
799 FFGET_NORM(nv1
,dT
); FFGET_NORM(nv2
,dB
);
805 v
= p
->getVel() + vec2G(mLevel
[level
].gravity
);
807 p
->advanceVec( (ntlVec3Gfx(nx
,ny
,nz
)) * -0.1 ); // + vec2G(mLevel[level].gravity);
816 else if(p
->getType()==PART_DROP
) {
817 ntlVec3Gfx v
= p
->getVel(); // dampen...
819 if(mPartUsePhysModel
) {
820 LbmFloat radius
= p
->getSize() * minDropSize
;
821 LbmVec velPart
= vec2L(p
->getVel()) *cellsize
/timestep
; // * cellsize / timestep; // L2RW, lattice velocity
822 LbmVec velRel
= velAir
- velPart
;
823 //LbmVec velRelLat = velRel /cellsize*timestep; // L2RW
824 LbmFloat velRelNorm
= norm(velRel
);
825 // TODO calculate values in lattice units, compute CD?!??!
826 LbmFloat mb
= rhoWater
* 4.0/3.0 * M_PI
* radius
*radius
*radius
; // mass: 4/3 pi r^3 rho
827 const LbmFloat rw
= (r1
-radius
)/(r1
-r2
);
828 const LbmFloat rmax
= (0.5 + 0.5*rw
);
829 const LbmFloat vmax
= (v2
+ (v1
-v2
)* (1.0-rw
) );
830 const LbmFloat cd
= (rmax
) * (velRelNorm
)/(vmax
);
832 LbmVec fg
= rwgrav
* mb
;// * (1.0-rhoAir/rhoWater);
833 LbmVec fd
= velRel
* velRelNorm
* cd
*M_PI
*rhoAir
*0.5 *radius
*radius
;
834 LbmVec change
= (fg
+ fd
) *timestep
/ mb
*(timestep
/cellsize
);
835 //if(k>0) { errMsg("\nPIT","NTEST1 mb="<<mb<<" radius="<<radius<<" vn="<<velRelNorm<<" velPart="<<velPart<<" velRel"<<velRel<<" pgetVel="<<p->getVel() ); }
842 int gravk
= (int)(p
->getPos()[2]+mLevel
[level
].gravity
[2]);
843 if(gravk
>=0 && gravk
<mSizez
&& RFLAG(level
, i
,j
,gravk
, workSet
)&CFBnd
) {
844 // dont add for "resting" parts
846 p
->setVel( v
*0.9 ); // restdamping
848 p
->addToVel( vec2G(mLevel
[level
].gravity
) );
853 if(p
->getStatus()&PART_IN
) { // IN
854 if(k
<cutval
) { DEL_PART
; continue; }
855 if(k
<=mSizez
-1-cutval
){
856 CellFlagType pflag
= RFLAG(level
, i
,j
,k
, workSet
);
857 //errMsg("PIT move"," at "<<PRINT_IJK<<" flag"<<convertCellFlagType2String(pflag) );
858 if(pflag
& (CFBnd
)) {
859 handleObstacleParticle(p
);
861 } else if(pflag
& (CFEmpty
)) {
863 } else if((pflag
& CFInter
)
864 //&&(!(RFLAG(level, i,j,k, workSet)& CFNoNbFluid))
866 // add to no nb fluid i.f.'s, so skip if interface with fluid nb
867 } else if(pflag
& (CFFluid
|CFUnused
|CFInter
) ){ // interface cells ignored here due to previous check!
868 // add dropmass again, (these are only interf. with nonbfl.)
869 int oi
= (int)(pos
[0]-1.25*v
[0]+0.5);
870 int oj
= (int)(pos
[1]-1.25*v
[1]+0.5);
871 int ok
= (int)(pos
[2]-1.25*v
[2]+0.5);
872 const LbmFloat size
= p
->getSize();
873 const LbmFloat dropmass
= ParticleObject::getMass(mPartDropMassSub
*size
);
874 bool orgcellok
= false;
875 if( (oi
<0)||(oi
>mSizex
-1)||
876 (oj
<0)||(oj
>mSizey
-1)||
877 (ok
<0)||(ok
>mSizez
-1) ) {
879 } else if( RFLAG(level
, oi
,oj
,ok
, workSet
) & (CFInter
) ){
882 // search upward for interface
884 for(int kk
=0; kk
<5 && ok
<=mSizez
-2; kk
++) {
885 ok
++; // check sizez-2 due to this increment!
886 if( RFLAG(level
, oi
,oj
,ok
, workSet
) & (CFInter
) ){
887 kk
= 5; orgcellok
= true;
892 //errMsg("PTIMPULSE"," new v"<<v<<" at "<<PRINT_VEC(oi,oj,ok)<<" , was "<<PRINT_VEC(i,j,k)<<" ok "<<orgcellok );
894 QCELL(level
, oi
,oj
,ok
, workSet
, dMass
) += dropmass
;
895 QCELL(level
, oi
,oj
,ok
, workSet
, dFfrac
) += dropmass
; // assume rho=1?
897 if(RFLAG(level
, oi
,oj
,ok
, workSet
) & CFNoBndFluid
){
898 // check speed, perhaps normalize
899 gfxReal vlensqr
= normNoSqrt(v
);
900 if(vlensqr
> 0.166*0.166) {
901 v
*= 1./sqrtf((float)vlensqr
)*0.166;
903 // compute cell velocity
904 LbmFloat
*tcel
= RACPNT(level
, oi
,oj
,ok
, workSet
);
905 LbmFloat velUx
=0., velUy
=0., velUz
=0.;
907 velUx
+= (this->dfDvecX
[l
]*RAC(tcel
,l
));
908 velUy
+= (this->dfDvecY
[l
]*RAC(tcel
,l
));
909 velUz
+= (this->dfDvecZ
[l
]*RAC(tcel
,l
));
913 LbmFloat cellVelSqr = velUx*velUx+ velUy*velUy+ velUz*velUz;
914 //errMsg("PTIMPULSE"," new v"<<v<<" cvs"<<cellVelSqr<<"="<<sqrt(cellVelSqr));
915 if(cellVelSqr< 0.166*0.166) {
917 const LbmFloat add = 3. * dropmass * this->dfLength[l]*(v[0]*this->dfDvecX[l]+v[1]*this->dfDvecY[l]+v[2]*this->dfDvecZ[l]);
920 } // only add impulse away from obstacles!
923 // FIXME make fsgr treatment
924 P_CHANGETYPE(p
, PART_FLOAT
); continue;
925 // jitter in cell to prevent stacking when hitting a steep surface
926 ntlVec3Gfx cpos
= p
->getPos();
927 cpos
[0] += (rand()/(RAND_MAX
+1.0))-0.5;
928 cpos
[1] += (rand()/(RAND_MAX
+1.0))-0.5;
929 cpos
[2] += (rand()/(RAND_MAX
+1.0))-0.5;
933 this->mNumParticlesLost
++;
937 # if LBM_INCLUDE_TESTSOLVERS==1
938 if(useff
) { mpTest
->handleParticle(p
, i
,j
,k
); }
940 # else // LBM_INCLUDE_TESTSOLVERS==1
942 # endif // LBM_INCLUDE_TESTSOLVERS==1
948 else if(p
->getType()==PART_INTER
) {
950 if(p
->getStatus()&PART_IN
) { // IN
951 if((k
<cutval
)||(k
>mSizez
-1-cutval
)) {
952 // undecided particle above or below... remove?
956 CellFlagType pflag
= RFLAG(level
, i
,j
,k
, workSet
);
957 if(pflag
& CFInter
) {
959 } else if(pflag
& (CFFluid
|CFUnused
) ) {
960 P_CHANGETYPE(p
, PART_FLOAT
); continue;
961 } else if(pflag
& CFEmpty
) {
962 P_CHANGETYPE(p
, PART_DROP
); continue;
963 } else if(pflag
& CFBnd
) {
964 P_CHANGETYPE(p
, PART_FLOAT
); continue;
967 // undecided particle outside... remove?
973 else if(p
->getType()==PART_FLOAT
) {
975 if(p
->getStatus()&PART_IN
) { // IN
976 if(k
<cutval
) DEL_PART
;
977 // not valid for mass...
980 // define from particletracer.h
982 const int DEPTH_AVG
=3; // only average interface vels
984 for(int kk
=0;kk
<DEPTH_AVG
;kk
+=1) {
985 if((k
-kk
)<1) continue;
986 if(RFLAG(level
, i
,j
,k
, workSet
)&(CFInter
)) {} else continue;
989 LbmFloat cdf
= QCELL(level
, i
,j
,k
-kk
, workSet
, l
);
990 vx
+= (this->dfDvecX
[l
]*cdf
);
991 vy
+= (this->dfDvecY
[l
]*cdf
);
992 vz
+= (this->dfDvecZ
[l
]*cdf
);
996 // use halved surface velocity (todo, use omega instead)
997 vx
/=(LbmFloat
)(ccnt
* 2.0); // half xy speed! value2
998 vy
/=(LbmFloat
)(ccnt
* 2.0);
999 vz
/=(LbmFloat
)(ccnt
); }
1000 #else // MOVE_FLOATS==1
1001 vx
=vy
=0.; //p->setVel(ntlVec3Gfx(0.) ); // static_float
1002 #endif // MOVE_FLOATS==1
1003 vx
+= (rand()/(RAND_MAX
+1.0))*(FLOAT_JITTER
*0.2)-(FLOAT_JITTER
*0.2*0.5);
1004 vy
+= (rand()/(RAND_MAX
+1.0))*(FLOAT_JITTER
*0.2)-(FLOAT_JITTER
*0.2*0.5);
1006 //bool delfloat = false;
1007 if( ( RFLAG(level
, i
,j
,k
, workSet
)& (CFFluid
|CFUnused
) ) ) {
1009 vz
= p
->getVel()[2]-1.0*mLevel
[level
].gravity
[2]; // simply rise...
1011 } else if( ( RFLAG(level
, i
,j
,k
, workSet
)& CFBnd
) ) {
1012 // force downwards movement, move below obstacle...
1013 //vz = p->getVel()[2]+1.0*mLevel[level].gravity[2]; // fall...
1016 } else if( ( RFLAG(level
, i
,j
,k
, workSet
)& CFInter
) ) {
1017 // keep in interface , one grid cell offset is added in part. gen
1018 } else { // all else...
1019 if( ( RFLAG(level
, i
,j
,k
-1, workSet
)& (CFFluid
|CFInter
) ) ) {
1020 vz
= p
->getVel()[2]+2.0*mLevel
[level
].gravity
[2]; // fall...
1025 p
->setVel( vec2G( ntlVec3Gfx(vx
,vy
,vz
) ) ); //?
1028 #if LBM_INCLUDE_TESTSOLVERS==1
1029 if(useff
) { mpTest
->handleParticle(p
, i
,j
,k
); }
1031 #else // LBM_INCLUDE_TESTSOLVERS==1
1033 #endif // LBM_INCLUDE_TESTSOLVERS==1
1036 // additional bnd jitter
1037 if((0) && (useff
) && (p
->getLifeTime()<3.*mLevel
[level
].timestep
)) {
1038 // use half butoff border 1/8
1039 int maxdw
= (int)(mLevel
[level
].lSizex
*0.125*0.5);
1040 if(maxdw
<3) maxdw
=3;
1041 if((j
>=0)&&(j
<=mSizey
-1)) {
1042 if(ABS(i
-( cutval
))<maxdw
) { p
->advance( FLOAT_JITTBNDRAND( ABS(i
-( cutval
))), 0.,0.); }
1043 if(ABS(i
-(mSizex
-1-cutval
))<maxdw
) { p
->advance( FLOAT_JITTBNDRAND( ABS(i
-(mSizex
-1-cutval
))), 0.,0.); }
1048 // unknown particle type
1050 errMsg("LbmFsgrSolver::advanceParticles","PIT pit invalid type!? "<<p
->getStatus() );
1053 myTime_t parttend
= getTime();
1054 debMsgStd("LbmFsgrSolver::advanceParticles",DM_MSG
,"Time for particle update:"<< getTimeString(parttend
-parttstart
)<<", #particles:"<<mpParticles
->getNumParticles() , 10 );
1057 void LbmFsgrSolver::notifySolverOfDump(int dumptype
, int frameNr
,char *frameNrStr
,string outfilename
) {
1058 int workSet
= mLevel
[mMaxRefine
].setCurr
;
1059 std::ostringstream name
;
1061 // debug - raw dump of ffrac values, as text!
1063 name
<< outfilename
<< frameNrStr
<<".dump";
1064 FILE *file
= fopen(name
.str().c_str(),"w");
1067 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(mMaxRefine
); ++k
) {
1068 for(int j
=0;j
<mLevel
[mMaxRefine
].lSizey
-0;j
++) {
1069 for(int i
=0;i
<mLevel
[mMaxRefine
].lSizex
-0;i
++) {
1071 if(RFLAG(mMaxRefine
, i
,j
,k
, workSet
) & CFInter
) {
1072 val
= QCELL(mMaxRefine
,i
,j
,k
, mLevel
[mMaxRefine
].setCurr
,dFfrac
);
1076 if(RFLAG(mMaxRefine
, i
,j
,k
, workSet
) & CFFluid
) val
= 1.;
1077 fprintf(file
, "%f ",val
); // text
1078 //errMsg("W", PRINT_IJK<<" val:"<<val);
1080 fprintf(file
, "\n"); // text
1082 fprintf(file
, "\n"); // text
1089 if(mDumpRawBinary
) {
1090 if(!mDumpRawBinaryZip
) {
1091 // unzipped, only fill
1092 name
<< outfilename
<< frameNrStr
<<".bdump";
1093 FILE *file
= fopen(name
.str().c_str(),"w");
1095 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(mMaxRefine
); ++k
) {
1096 for(int j
=0;j
<mLevel
[mMaxRefine
].lSizey
-0;j
++) {
1097 for(int i
=0;i
<mLevel
[mMaxRefine
].lSizex
-0;i
++) {
1099 if(RFLAG(mMaxRefine
, i
,j
,k
, workSet
) & CFInter
) {
1100 val
= QCELL(mMaxRefine
,i
,j
,k
, mLevel
[mMaxRefine
].setCurr
,dFfrac
);
1104 if(RFLAG(mMaxRefine
, i
,j
,k
, workSet
) & CFFluid
) val
= 1.;
1105 fwrite( &val
, sizeof(val
), 1, file
); // binary
1113 // zipped, use iso values
1114 prepareVisualization();
1115 name
<< outfilename
<< frameNrStr
<<".bdump.gz";
1116 gzFile gzf
= gzopen(name
.str().c_str(),"wb9");
1120 s
=mSizex
; gzwrite(gzf
, &s
, sizeof(s
));
1121 s
=mSizey
; gzwrite(gzf
, &s
, sizeof(s
));
1122 s
=mSizez
; gzwrite(gzf
, &s
, sizeof(s
));
1125 for(int k
= getForZMinBnd(); k
< getForZMaxBnd(mMaxRefine
); ++k
) {
1126 for(int j
=0;j
<mLevel
[mMaxRefine
].lSizey
;j
++) {
1127 for(int i
=0;i
<mLevel
[mMaxRefine
].lSizex
;i
++) {
1129 val
= *mpIso
->lbmGetData( i
,j
,k
);
1130 gzwrite(gzf
, &val
, sizeof(val
));
1139 dumptype
= 0; frameNr
= 0; // get rid of warning
1142 /*! move a particle at a boundary */
1143 void LbmFsgrSolver::handleObstacleParticle(ParticleObject
*p
) {
1144 //if(normNoSqrt(v)<=0.) continue; // skip stuck
1146 p->setVel( v * -1. ); // revert
1147 p->advanceVel(); // move back twice...
1148 if( RFLAG(mMaxRefine, i,j,k, workSet)& (CFBndNoslip)) {
1149 p->setVel( v * -0.5 ); // revert & dampen
1153 // TODO mark/remove stuck parts!?
1155 const int level
= mMaxRefine
;
1156 const int workSet
= mLevel
[level
].setCurr
;
1157 LbmVec v
= vec2L( p
->getVel() );
1158 if(normNoSqrt(v
)<=0.) {
1159 p
->setVel(vec2G(mLevel
[level
].gravity
));
1162 CellFlagType pflag
= CFBnd
;
1163 ntlVec3Gfx
posOrg(p
->getPos());
1164 ntlVec3Gfx
npos(0.);
1168 // try to undo movement
1169 p
->advanceVec( (p
->getVel()-vec2G(mLevel
[level
].gravity
)) * -2.);
1171 npos
= p
->getPos(); ni
= (int)npos
[0];
1172 nj
= (int)npos
[1]; nk
= (int)npos
[2];
1173 if(LBMDIM
==2) { nk
= 0; }
1174 //errMsg("BOUNDCPAR"," t"<<PRINT_VEC(ni,nj,nk)<<" v"<<v<<" p"<<npos);
1176 // delete out of domain
1177 if(!checkDomainBounds(level
,ni
,nj
,nk
)) {
1178 //errMsg("BOUNDCPAR"," DEL! ");
1179 p
->setActive( false );
1182 pflag
= RFLAG(level
, ni
,nj
,nk
, workSet
);
1184 // try to force particle out of boundary
1185 bool haveNorm
= false;
1188 npos
= posOrg
; ni
= (int)npos
[0];
1189 nj
= (int)npos
[1]; nk
= (int)npos
[2];
1190 if(LBMDIM
==2) { nk
= 0; }
1192 computeObstacleSurfaceNormalAcc(ni
,nj
,nk
, &bnormal
[0]);
1198 while(pflag
&CFBnd
&& tries
<=5) {
1199 // use increasing step sizes
1200 p
->advanceVec( vec2G( bnormal
*0.5 *(gfxReal
)tries
) );
1206 // delete out of domain
1207 if(!checkDomainBounds(level
,ni
,nj
,nk
)) {
1208 //errMsg("BOUNDCPAR"," DEL! ");
1209 p
->setActive( false );
1212 pflag
= RFLAG(level
, ni
,nj
,nk
, workSet
);
1216 // really stuck, delete...
1218 p
->setActive( false );
1223 // not in bound anymore!
1225 CellFlagType
*bflag
= &RFLAG(level
, ni
,nj
,nk
, workSet
);
1226 LbmFloat
*bcell
= RACPNT(level
, ni
,nj
,nk
, workSet
);
1227 computeObstacleSurfaceNormal(bcell
,bflag
, &bnormal
[0]);
1230 LbmVec normComp
= bnormal
* dot(vec2L(v
),bnormal
);
1231 //errMsg("BOUNDCPAR","bnormal"<<bnormal<<" normComp"<<normComp<<" newv"<<(v-normComp) );
1232 v
= (v
-normComp
)*0.9; // only move tangential
1233 v
*= 0.9; // restdamping , todo use timestep
1234 p
->setVel(vec2G(v
));
1238 /*****************************************************************************/
1239 /*! internal quick print function (for debugging) */
1240 /*****************************************************************************/
1242 LbmFsgrSolver::printLbmCell(int level
, int i
, int j
, int k
, int set
) {
1243 stdCellId
*newcid
= new stdCellId
;
1244 newcid
->level
= level
;
1249 // this function is not called upon clicking, then its from setMouseClick
1250 debugPrintNodeInfo( newcid
, set
);
1254 LbmFsgrSolver::debugMarkCellCall(int level
, int vi
,int vj
,int vk
) {
1255 stdCellId
*newcid
= new stdCellId
;
1256 newcid
->level
= level
;
1260 this->addCellToMarkedList( newcid
);
1264 /*****************************************************************************/
1265 // implement CellIterator<UniformFsgrCellIdentifier> interface
1266 /*****************************************************************************/
1270 // values from guiflkt.cpp
1271 extern double guiRoiSX
, guiRoiSY
, guiRoiSZ
, guiRoiEX
, guiRoiEY
, guiRoiEZ
;
1272 extern int guiRoiMaxLev
, guiRoiMinLev
;
1273 #define CID_SX (int)( (mLevel[cid->level].lSizex-1) * guiRoiSX )
1274 #define CID_SY (int)( (mLevel[cid->level].lSizey-1) * guiRoiSY )
1275 #define CID_SZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiSZ )
1277 #define CID_EX (int)( (mLevel[cid->level].lSizex-1) * guiRoiEX )
1278 #define CID_EY (int)( (mLevel[cid->level].lSizey-1) * guiRoiEY )
1279 #define CID_EZ (int)( (mLevel[cid->level].lSizez-1) * guiRoiEZ )
1281 CellIdentifierInterface
*
1282 LbmFsgrSolver::getFirstCell( ) {
1283 int level
= mMaxRefine
;
1286 if(mMaxRefine
>0) { level
= mMaxRefine
-1; } // NO1HIGHESTLEV DEBUG
1288 level
= guiRoiMaxLev
;
1289 if(level
>mMaxRefine
) level
= mMaxRefine
;
1291 //errMsg("LbmFsgrSolver::getFirstCell","Celliteration started...");
1292 stdCellId
*cid
= new stdCellId
;
1300 LbmFsgrSolver::stdCellId
*
1301 LbmFsgrSolver::convertBaseCidToStdCid( CellIdentifierInterface
* basecid
) {
1302 //stdCellId *cid = dynamic_cast<stdCellId*>( basecid );
1303 stdCellId
*cid
= (stdCellId
*)( basecid
);
1307 void LbmFsgrSolver::advanceCell( CellIdentifierInterface
* basecid
) {
1308 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1309 if(cid
->getEnd()) return;
1311 //debugOut(" ADb "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
1313 if(cid
->x
> CID_EX
){ cid
->x
= CID_SX
; cid
->y
++;
1314 if(cid
->y
> CID_EY
){ cid
->y
= CID_SY
; cid
->z
++;
1315 if(cid
->z
> CID_EZ
){
1320 if(cid
->level
< guiRoiMinLev
) {
1321 cid
->level
= guiRoiMaxLev
;
1322 cid
->setEnd( true );
1327 //debugOut(" ADa "<<cid->x<<","<<cid->y<<","<<cid->z<<" e"<<cid->getEnd(), 10);
1330 bool LbmFsgrSolver::noEndCell( CellIdentifierInterface
* basecid
) {
1331 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1332 return (!cid
->getEnd());
1335 void LbmFsgrSolver::deleteCellIterator( CellIdentifierInterface
** cid
) {
1340 CellIdentifierInterface
* LbmFsgrSolver::getCellAt( ntlVec3Gfx pos
) {
1341 //int cellok = false;
1342 pos
-= (this->mvGeoStart
);
1344 LbmFloat mmaxsize
= mLevel
[mMaxRefine
].nodeSize
;
1345 for(int level
=mMaxRefine
; level
>=0; level
--) { // finest first
1346 //for(int level=0; level<=mMaxRefine; level++) { // coarsest first
1347 LbmFloat nsize
= mLevel
[level
].nodeSize
;
1349 // CHECK +- maxsize?
1350 x
= (int)((pos
[0]+0.5*mmaxsize
) / nsize
);
1351 y
= (int)((pos
[1]+0.5*mmaxsize
) / nsize
);
1352 z
= (int)((pos
[2]+0.5*mmaxsize
) / nsize
);
1353 if(LBMDIM
==2) z
= 0;
1359 if(x
>=mLevel
[level
].lSizex
) continue;
1360 if(y
>=mLevel
[level
].lSizey
) continue;
1361 if(z
>=mLevel
[level
].lSizez
) continue;
1363 // return fluid/if/border cells
1364 if( ( (RFLAG(level
, x
,y
,z
, mLevel
[level
].setCurr
)&(CFUnused
)) ) ||
1365 ( (level
<mMaxRefine
) && (RFLAG(level
, x
,y
,z
, mLevel
[level
].setCurr
)&(CFUnused
|CFEmpty
)) ) ) {
1369 stdCellId
*newcid
= new stdCellId
;
1370 newcid
->level
= level
;
1374 //errMsg("cellAt",this->mName<<" "<<pos<<" l"<<level<<":"<<x<<","<<y<<","<<z<<" "<<convertCellFlagType2String(RFLAG(level, x,y,z, mLevel[level].setCurr)) );
1384 int LbmFsgrSolver::getCellSet ( CellIdentifierInterface
* basecid
) {
1385 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1386 return mLevel
[cid
->level
].setCurr
;
1387 //return mLevel[cid->level].setOther;
1390 int LbmFsgrSolver::getCellLevel ( CellIdentifierInterface
* basecid
) {
1391 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1395 ntlVec3Gfx
LbmFsgrSolver::getCellOrigin ( CellIdentifierInterface
* basecid
) {
1398 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1399 ntlVec3Gfx
cs( mLevel
[cid
->level
].nodeSize
);
1400 if(LBMDIM
==2) { cs
[2] = 0.0; }
1403 ret
=(this->mvGeoStart
+ ntlVec3Gfx( cid
->x
*cs
[0], cid
->y
*cs
[1], (this->mvGeoEnd
[2]-this->mvGeoStart
[2])*0.5 )
1404 + ntlVec3Gfx(0.0,0.0,cs
[1]*-0.25)*cid
->level
)
1405 +getCellSize(basecid
);
1407 ret
=(this->mvGeoStart
+ ntlVec3Gfx( cid
->x
*cs
[0], cid
->y
*cs
[1], cid
->z
*cs
[2] ))
1408 +getCellSize(basecid
);
1413 ntlVec3Gfx
LbmFsgrSolver::getCellSize ( CellIdentifierInterface
* basecid
) {
1415 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1416 ntlVec3Gfx
retvec( mLevel
[cid
->level
].nodeSize
* 0.5 );
1417 // 2d display as rectangles
1418 if(LBMDIM
==2) { retvec
[2] = 0.0; }
1422 LbmFloat
LbmFsgrSolver::getCellDensity ( CellIdentifierInterface
* basecid
,int set
) {
1423 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1425 // skip non-fluid cells
1426 if(RFLAG(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
)&(CFFluid
|CFInter
)) {
1433 FORDF0
{ rho
+= QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, l
); } // ORG
1434 return ((rho
-1.0) * mLevel
[cid
->level
].simCellSize
/ mLevel
[cid
->level
].timestep
) +1.0; // ORG
1435 /*if(RFLAG(cid->level, cid->x,cid->y,cid->z, set)&CFInter) { // test
1438 int lev = cid->level;
1439 LbmFloat df[27], feqOld[27];
1441 rho += QCELL(lev, cid->x,cid->y,cid->z, set, l);
1442 ux += this->dfDvecX[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
1443 uy += this->dfDvecY[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
1444 uz += this->dfDvecZ[l]* QCELL(lev, cid->x,cid->y,cid->z, set, l);
1445 df[l] = QCELL(lev, cid->x,cid->y,cid->z, set, l);
1448 feqOld[l] = getCollideEq(l, rho,ux,uy,uz);
1451 //const LbmFloat Qo = this->getLesNoneqTensorCoeff(df,feqOld);
1452 //const LbmFloat modOmega = this->getLesOmega(mLevel[lev].omega, mLevel[lev].lcsmago,Qo);
1453 //rho = (2.0-modOmega) *25.0;
1455 //if(cid->x==24){ errMsg("MODOMT"," at "<<PRINT_VEC(cid->x,cid->y,cid->z)<<" = "<<rho<<" "<<Qo); }
1458 return rho; // test */
1461 LbmVec
LbmFsgrSolver::getCellVelocity ( CellIdentifierInterface
* basecid
,int set
) {
1462 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1464 // skip non-fluid cells
1465 if(RFLAG(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
)&(CFFluid
|CFInter
)) {
1474 ux
+= this->dfDvecX
[l
]* QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, l
);
1475 uy
+= this->dfDvecY
[l
]* QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, l
);
1476 uz
+= this->dfDvecZ
[l
]* QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, l
);
1478 LbmVec
vel(ux
,uy
,uz
);
1480 return (vel
* mLevel
[cid
->level
].simCellSize
/ mLevel
[cid
->level
].timestep
* this->mDebugVelScale
); // normal
1483 LbmFloat
LbmFsgrSolver::getCellDf( CellIdentifierInterface
* basecid
,int set
, int dir
) {
1484 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1485 return QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, dir
);
1487 LbmFloat
LbmFsgrSolver::getCellMass( CellIdentifierInterface
* basecid
,int set
) {
1488 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1489 return QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, dMass
);
1491 LbmFloat
LbmFsgrSolver::getCellFill( CellIdentifierInterface
* basecid
,int set
) {
1492 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1493 if(RFLAG(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
)&CFInter
) return QCELL(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
, dFfrac
);
1494 if(RFLAG(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
)&CFFluid
) return 1.0;
1496 //return QCELL(cid->level, cid->x,cid->y,cid->z, set, dFfrac);
1498 CellFlagType
LbmFsgrSolver::getCellFlag( CellIdentifierInterface
* basecid
,int set
) {
1499 stdCellId
*cid
= convertBaseCidToStdCid(basecid
);
1500 return RFLAG(cid
->level
, cid
->x
,cid
->y
,cid
->z
, set
);
1503 LbmFloat
LbmFsgrSolver::getEquilDf( int l
) {
1504 return this->dfEquil
[l
];
1508 ntlVec3Gfx
LbmFsgrSolver::getVelocityAt (float xp
, float yp
, float zp
) {
1509 ntlVec3Gfx
avgvel(0.0);
1510 LbmFloat avgnum
= 0.;
1512 // taken from getCellAt!
1513 const int level
= mMaxRefine
;
1514 const int workSet
= mLevel
[level
].setCurr
;
1515 const LbmFloat nsize
= mLevel
[level
].nodeSize
;
1516 const int x
= (int)((-this->mvGeoStart
[0]+xp
-0.5*nsize
) / nsize
);
1517 const int y
= (int)((-this->mvGeoStart
[1]+yp
-0.5*nsize
) / nsize
);
1518 int z
= (int)((-this->mvGeoStart
[2]+zp
-0.5*nsize
) / nsize
);
1520 //errMsg("DUMPVEL","p"<<PRINT_VEC(xp,yp,zp)<<" at "<<PRINT_VEC(x,y,z)<<" max"<<PRINT_VEC(mLevel[level].lSizex,mLevel[level].lSizey,mLevel[level].lSizez) );
1522 // return fluid/if/border cells
1523 // search neighborhood, do smoothing
1525 const int i
= x
+this->dfVecX
[l
];
1526 const int j
= y
+this->dfVecY
[l
];
1527 const int k
= z
+this->dfVecZ
[l
];
1529 if( (i
<0) || (j
<0) || (k
<0)
1530 || (i
>=mLevel
[level
].lSizex
)
1531 || (j
>=mLevel
[level
].lSizey
)
1532 || (k
>=mLevel
[level
].lSizez
) ) continue;
1534 if( (RFLAG(level
, i
,j
,k
, mLevel
[level
].setCurr
)&(CFFluid
|CFInter
)) ) {
1535 ntlVec3Gfx
vel(0.0);
1536 LbmFloat
*ccel
= RACPNT(level
, i
,j
,k
,workSet
); // omp
1537 for(int n
=1; n
<this->cDfNum
; n
++) {
1538 vel
[0] += (this->dfDvecX
[n
]*RAC(ccel
,n
));
1539 vel
[1] += (this->dfDvecY
[n
]*RAC(ccel
,n
));
1540 vel
[2] += (this->dfDvecZ
[n
]*RAC(ccel
,n
));
1545 if(l
==0) { // center slightly more weight
1546 avgvel
+= vel
; avgnum
+= 1.0;
1552 ntlVec3Gfx retv
= avgvel
/ avgnum
;
1553 retv
*= nsize
/mLevel
[level
].timestep
;
1554 // scale for current animation settings (frame time)
1555 retv
*= mpParam
->getCurrentAniFrameTime();
1556 //errMsg("DUMPVEL","t"<<mSimulationTime<<" at "<<PRINT_VEC(xp,yp,zp)<<" ret:"<<retv<<", avgv:"<<avgvel<<" n"<<avgnum<<" nsize"<<nsize<<" ts"<<mLevel[level].timestep<<" fr"<<mpParam->getCurrentAniFrameTime() );
1559 // no cells here...?
1560 //errMsg("DUMPVEL"," at "<<PRINT_VEC(xp,yp,zp)<<" v"<<avgvel<<" n"<<avgnum<<" no vel !?");
1561 return ntlVec3Gfx(0.);
1565 //! show simulation info (implement SimulationObject pure virtual func)
1567 LbmFsgrSolver::debugDisplay(int set
){
1568 //lbmDebugDisplay< LbmFsgrSolver >( set, this );
1569 lbmDebugDisplay( set
);
1573 /*****************************************************************************/
1574 // strict debugging functions
1575 /*****************************************************************************/
1576 #if FSGR_STRICT_DEBUG==1
1577 #define STRICT_EXIT *((int *)0)=0;
1579 int LbmFsgrSolver::debLBMGI(int level
, int ii
,int ij
,int ik
, int is
) {
1580 if(level
< 0){ errMsg("LbmStrict::debLBMGI"," invLev- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1581 if(level
> mMaxRefine
){ errMsg("LbmStrict::debLBMGI"," invLev+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1583 if((ii
==-1)&&(ij
==0)) {
1584 // special case for main loop, ok
1586 if(ii
<0){ errMsg("LbmStrict"," invX- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1587 if(ij
<0){ errMsg("LbmStrict"," invY- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1588 if(ii
>mLevel
[level
].lSizex
-1){ errMsg("LbmStrict"," invX+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1589 if(ij
>mLevel
[level
].lSizey
-1){ errMsg("LbmStrict"," invY+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1591 if(ik
<0){ errMsg("LbmStrict"," invZ- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1592 if(ik
>mLevel
[level
].lSizez
-1){ errMsg("LbmStrict"," invZ+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1593 if(is
<0){ errMsg("LbmStrict"," invS- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1594 if(is
>1){ errMsg("LbmStrict"," invS+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1595 return _LBMGI(level
, ii
,ij
,ik
, is
);
1598 CellFlagType
& LbmFsgrSolver::debRFLAG(int level
, int xx
,int yy
,int zz
,int set
){
1599 return _RFLAG(level
, xx
,yy
,zz
,set
);
1602 CellFlagType
& LbmFsgrSolver::debRFLAG_NB(int level
, int xx
,int yy
,int zz
,int set
, int dir
) {
1603 if(dir
<0) { errMsg("LbmStrict"," invD- l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1604 // warning might access all spatial nbs
1605 if(dir
>this->cDirNum
){ errMsg("LbmStrict"," invD+ l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1606 return _RFLAG_NB(level
, xx
,yy
,zz
,set
, dir
);
1609 CellFlagType
& LbmFsgrSolver::debRFLAG_NBINV(int level
, int xx
,int yy
,int zz
,int set
, int dir
) {
1610 if(dir
<0) { errMsg("LbmStrict"," invD- l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1611 if(dir
>this->cDirNum
){ errMsg("LbmStrict"," invD+ l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1612 return _RFLAG_NBINV(level
, xx
,yy
,zz
,set
, dir
);
1615 int LbmFsgrSolver::debLBMQI(int level
, int ii
,int ij
,int ik
, int is
, int l
) {
1616 if(level
< 0){ errMsg("LbmStrict::debLBMQI"," invLev- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1617 if(level
> mMaxRefine
){ errMsg("LbmStrict::debLBMQI"," invLev+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1619 if((ii
==-1)&&(ij
==0)) {
1620 // special case for main loop, ok
1622 if(ii
<0){ errMsg("LbmStrict"," invX- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1623 if(ij
<0){ errMsg("LbmStrict"," invY- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1624 if(ii
>mLevel
[level
].lSizex
-1){ errMsg("LbmStrict"," invX+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1625 if(ij
>mLevel
[level
].lSizey
-1){ errMsg("LbmStrict"," invY+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1627 if(ik
<0){ errMsg("LbmStrict"," invZ- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1628 if(ik
>mLevel
[level
].lSizez
-1){ errMsg("LbmStrict"," invZ+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1629 if(is
<0){ errMsg("LbmStrict"," invS- l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1630 if(is
>1){ errMsg("LbmStrict"," invS+ l"<<level
<<"|"<<ii
<<","<<ij
<<","<<ik
<<" s"<<is
); STRICT_EXIT
; }
1631 if(l
<0) { errMsg("LbmStrict"," invD- "<<" l"<<l
); STRICT_EXIT
; }
1632 if(l
>this->cDfNum
){ // dFfrac is an exception
1633 if((l
!= dMass
) && (l
!= dFfrac
) && (l
!= dFlux
)){ errMsg("LbmStrict"," invD+ "<<" l"<<l
); STRICT_EXIT
; } }
1634 #if COMPRESSGRIDS==1
1635 //if((!this->mInitDone) && (is!=mLevel[level].setCurr)){ STRICT_EXIT; } // COMPRT debug
1636 #endif // COMPRESSGRIDS==1
1637 return _LBMQI(level
, ii
,ij
,ik
, is
, l
);
1640 LbmFloat
& LbmFsgrSolver::debQCELL(int level
, int xx
,int yy
,int zz
,int set
,int l
) {
1641 //errMsg("LbmStrict","debQCELL debug: l"<<level<<"|"<<xx<<","<<yy<<","<<zz<<" s"<<set<<" l"<<l<<" index"<<LBMGI(level, xx,yy,zz,set));
1642 return _QCELL(level
, xx
,yy
,zz
,set
,l
);
1645 LbmFloat
& LbmFsgrSolver::debQCELL_NB(int level
, int xx
,int yy
,int zz
,int set
, int dir
,int l
) {
1646 if(dir
<0) { errMsg("LbmStrict"," invD- l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1647 if(dir
>this->cDfNum
){ errMsg("LbmStrict"," invD+ l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1648 return _QCELL_NB(level
, xx
,yy
,zz
,set
, dir
,l
);
1651 LbmFloat
& LbmFsgrSolver::debQCELL_NBINV(int level
, int xx
,int yy
,int zz
,int set
, int dir
,int l
) {
1652 if(dir
<0) { errMsg("LbmStrict"," invD- l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1653 if(dir
>this->cDfNum
){ errMsg("LbmStrict"," invD+ l"<<level
<<"|"<<xx
<<","<<yy
<<","<<zz
<<" s"<<set
<<" d"<<dir
); STRICT_EXIT
; }
1654 return _QCELL_NBINV(level
, xx
,yy
,zz
,set
, dir
,l
);
1657 LbmFloat
* LbmFsgrSolver::debRACPNT(int level
, int ii
,int ij
,int ik
, int is
) {
1658 return _RACPNT(level
, ii
,ij
,ik
, is
);
1661 LbmFloat
& LbmFsgrSolver::debRAC(LbmFloat
* s
,int l
) {
1662 if(l
<0) { errMsg("LbmStrict"," invD- "<<" l"<<l
); STRICT_EXIT
; }
1663 if(l
>dTotalNum
){ errMsg("LbmStrict"," invD+ "<<" l"<<l
); STRICT_EXIT
; }
1664 //if(l>this->cDfNum){ // dFfrac is an exception
1665 //if((l != dMass) && (l != dFfrac) && (l != dFlux)){ errMsg("LbmStrict"," invD+ "<<" l"<<l); STRICT_EXIT; } }
1669 #endif // FSGR_STRICT_DEBUG==1
1672 /******************************************************************************
1673 * GUI&debugging functions
1674 *****************************************************************************/
1678 #define USE_GLUTILITIES
1679 #include "../gui/gui_utilities.h"
1681 //! display a single node
1682 void LbmFsgrSolver::debugDisplayNode(int dispset
, CellIdentifierInterface
* cell
) {
1683 //debugOut(" DD: "<<cell->getAsString() , 10);
1684 ntlVec3Gfx org
= this->getCellOrigin( cell
);
1685 ntlVec3Gfx halfsize
= this->getCellSize( cell
);
1686 int set
= this->getCellSet( cell
);
1687 //debugOut(" DD: "<<cell->getAsString()<<" "<< (dispset->type) , 10);
1689 bool showcell
= true;
1692 LbmFloat cscale
= 1.0; //dispset->scale;
1694 #define DRAWDISPCUBE(col,scale) \
1695 { glLineWidth( linewidth ); \
1696 glColor3f( (col)[0], (col)[1], (col)[2]); \
1697 ntlVec3Gfx s = org-(halfsize * (scale)); \
1698 ntlVec3Gfx e = org+(halfsize * (scale)); \
1699 drawCubeWire( s,e ); }
1701 CellFlagType flag
= this->getCellFlag(cell
, set
);
1702 // always check types
1703 if(flag
& CFInvalid
) { if(!guiShowInvalid
) return; }
1704 if(flag
& CFUnused
) { if(!guiShowInvalid
) return; }
1705 if(flag
& CFEmpty
) { if(!guiShowEmpty
) return; }
1706 if(flag
& CFInter
) { if(!guiShowInterface
) return; }
1707 if(flag
& CFNoDelete
) { if(!guiShowNoDelete
) return; }
1708 if(flag
& CFBnd
) { if(!guiShowBnd
) return; }
1710 // only dismiss one of these types
1711 if(flag
& CFGrFromCoarse
) { if(!guiShowCoarseInner
) return; } // inner not really interesting
1713 if(flag
& CFGrFromFine
) { if(!guiShowCoarseBorder
) return; }
1715 if(flag
& CFFluid
) { if(!guiShowFluid
) return; }
1718 case FLUIDDISPNothing
: {
1721 case FLUIDDISPCelltypes
: {
1724 if(flag
& CFNoDelete
) { // debug, mark nodel cells
1725 ntlColor
ccol(0.7,0.0,0.0);
1726 DRAWDISPCUBE(ccol
, 0.1);
1728 if(flag
& CFPersistMask
) { // mark persistent flags
1730 DRAWDISPCUBE(ccol
, 0.125);
1732 if(flag
& CFNoBndFluid
) { // mark persistent flags
1733 ntlColor
ccol(0,0,1);
1734 DRAWDISPCUBE(ccol
, 0.075);
1737 if(flag
& CFInvalid
) {
1739 col
= ntlColor(0.0,0,0.0);
1741 else if(flag
& CFBnd
) {
1743 col
= ntlColor(0.4);
1746 else if(flag
& CFInter
) {
1748 col
= ntlColor(0,1,1);
1750 } else if(flag
& CFGrFromCoarse
) {
1751 // draw as - with marker
1752 ntlColor
col2(0.0,1.0,0.3);
1753 DRAWDISPCUBE(col2
, 0.1);
1755 showcell
=false; // DEBUG
1757 else if(flag
& CFFluid
) {
1759 if(flag
& CFGrToFine
) {
1760 ntlColor
col2(0.5,0.0,0.5);
1761 DRAWDISPCUBE(col2
, 0.1);
1762 col
= ntlColor(0,0,1);
1764 if(flag
& CFGrFromFine
) {
1765 ntlColor
col2(1.0,1.0,0.0);
1766 DRAWDISPCUBE(col2
, 0.1);
1767 col
= ntlColor(0,0,1);
1768 } else if(flag
& CFGrFromCoarse
) {
1769 // draw as fluid with marker
1770 ntlColor
col2(0.0,1.0,0.3);
1771 DRAWDISPCUBE(col2
, 0.1);
1772 col
= ntlColor(0,0,1);
1774 col
= ntlColor(0,0,1);
1777 else if(flag
& CFEmpty
) {
1782 case FLUIDDISPVelocities
: {
1783 // dont use cube display
1784 LbmVec vel
= this->getCellVelocity( cell
, set
);
1786 glColor3f( 0.0,0.0,0.0 );
1787 glVertex3f( org
[0], org
[1], org
[2] );
1788 org
+= vec2G(vel
* 10.0 * cscale
);
1789 glColor3f( 1.0,1.0,1.0 );
1790 glVertex3f( org
[0], org
[1], org
[2] );
1794 case FLUIDDISPCellfills
: {
1798 col
= ntlColor(0,0,0.5);
1800 else if(flag
& CFInter
) {
1801 cscale
= 0.75 * this->getCellMass(cell
,set
);
1802 col
= ntlColor(0,1,1);
1808 if( ABS(this->getCellMass(cell
,set
)) < 10.0 ) {
1809 cscale
= 0.75 * this->getCellMass(cell
,set
);
1814 col
= ntlColor(0,1,1);
1816 col
= ntlColor(1,1,0);
1820 case FLUIDDISPDensity
: {
1821 LbmFloat rho
= this->getCellDensity(cell
,set
);
1822 cscale
= rho
*rho
* 0.25;
1823 col
= ntlColor( MIN(0.5+cscale
,1.0) , MIN(0.0+cscale
,1.0), MIN(0.0+cscale
,1.0) );
1826 case FLUIDDISPGrid
: {
1828 col
= ntlColor(1.0);
1832 col
= ntlColor(1.0,0.0,0.0);
1836 if(!showcell
) return;
1837 if(cscale
==0.0) return; // dont draw zero values
1838 DRAWDISPCUBE(col
, cscale
);
1841 //! debug display function
1842 // D has to implement the CellIterator interface
1843 void LbmFsgrSolver::lbmDebugDisplay(int dispset
) {
1844 // DEBUG always display testdata
1845 #if LBM_INCLUDE_TESTSOLVERS==1
1847 cpDebugDisplay(dispset
);
1848 mpTest
->testDebugDisplay(dispset
);
1850 #endif // LBM_INCLUDE_TESTSOLVERS==1
1851 if(dispset
<=FLUIDDISPNothing
) return;
1852 //if(!dispset->on) return;
1853 glDisable( GL_LIGHTING
); // dont light lines
1855 #if LBM_INCLUDE_TESTSOLVERS==1
1856 if((!mUseTestdata
)|| (mUseTestdata
)&&(mpTest
->mFarfMode
<=0)) {
1857 #endif // LBM_INCLUDE_TESTSOLVERS==1
1859 LbmFsgrSolver::CellIdentifier cid
= this->getFirstCell();
1860 for(; this->noEndCell( cid
);
1861 this->advanceCell( cid
) ) {
1862 this->debugDisplayNode(dispset
, cid
);
1866 #if LBM_INCLUDE_TESTSOLVERS==1
1868 #endif // LBM_INCLUDE_TESTSOLVERS==1
1870 glEnable( GL_LIGHTING
); // dont light lines
1873 //! debug display function
1874 // D has to implement the CellIterator interface
1875 void LbmFsgrSolver::lbmMarkedCellDisplay() {
1876 //fluidDispSettings dispset;
1877 // trick - display marked cells as grid displa -> white, big
1878 int dispset
= FLUIDDISPGrid
;
1879 glDisable( GL_LIGHTING
); // dont light lines
1881 LbmFsgrSolver::CellIdentifier cid
= this->markedGetFirstCell();
1883 this->debugDisplayNode(dispset
, cid
);
1884 cid
= this->markedAdvanceCell();
1888 glEnable( GL_LIGHTING
); // dont light lines
1891 #endif // LBM_USE_GUI==1
1893 //! display a single node
1894 void LbmFsgrSolver::debugPrintNodeInfo(CellIdentifierInterface
* cell
, int forceSet
) {
1896 // force printing of one set? default = -1 = off
1897 bool printDF
= false;
1898 bool printRho
= false;
1899 bool printVel
= false;
1900 bool printFlag
= false;
1901 bool printGeom
= false;
1902 bool printMass
=false;
1903 bool printBothSets
= false;
1904 string printInfo
= this->getNodeInfoString();
1906 for(size_t i
=0; i
<printInfo
.length()-0; i
++) {
1907 char what
= printInfo
[i
];
1910 printDF
= true; printRho
= true; printVel
= true; printFlag
= true; printGeom
= true; printMass
= true ;
1911 printBothSets
= true; break;
1912 case '-': // all off
1913 printDF
= false; printRho
= false; printVel
= false; printFlag
= false; printGeom
= false; printMass
= false;
1914 printBothSets
= false; break;
1915 case 'd': printDF
= true; break;
1916 case 'r': printRho
= true; break;
1917 case 'v': printVel
= true; break;
1918 case 'f': printFlag
= true; break;
1919 case 'g': printGeom
= true; break;
1920 case 'm': printMass
= true; break;
1921 case 's': printBothSets
= true; break;
1923 errFatal("debugPrintNodeInfo","Invalid node info id "<<what
,SIMWORLD_GENERICERROR
); return;
1927 ntlVec3Gfx org
= this->getCellOrigin( cell
);
1928 ntlVec3Gfx halfsize
= this->getCellSize( cell
);
1929 int set
= this->getCellSet( cell
);
1930 debMsgStd("debugPrintNodeInfo",DM_NOTIFY
, "Printing cell info '"<<printInfo
<<"' for node: "<<cell
->getAsString()<<" from "<<this->getName()<<" currSet:"<<set
, 1);
1931 if(printGeom
) debMsgStd(" ",DM_MSG
, "Org:"<<org
<<" Halfsize:"<<halfsize
<<" ", 1);
1934 if(!printBothSets
) setmax
= 1;
1935 if(forceSet
>=0) setmax
= 1;
1937 for(int s
=0; s
<setmax
; s
++) {
1939 if(s
==1){ workset
= (set
^1); }
1940 if(forceSet
>=0) workset
= forceSet
;
1941 debMsgStd(" ",DM_MSG
, "Printing set:"<<workset
<<" orgSet:"<<set
, 1);
1944 for(int l
=0; l
<LBM_DFNUM
; l
++) { // FIXME ??
1945 debMsgStd(" ",DM_MSG
, " Df"<<l
<<": "<<this->getCellDf(cell
,workset
,l
), 1);
1949 debMsgStd(" ",DM_MSG
, " Rho: "<<this->getCellDensity(cell
,workset
), 1);
1952 debMsgStd(" ",DM_MSG
, " Vel: "<<this->getCellVelocity(cell
,workset
), 1);
1955 CellFlagType flag
= this->getCellFlag(cell
,workset
);
1956 debMsgStd(" ",DM_MSG
, " Flg: "<< flag
<<" "<<convertFlags2String( flag
) <<" "<<convertCellFlagType2String( flag
), 1);
1959 debMsgStd(" ",DM_MSG
, " Mss: "<<this->getCellMass(cell
,workset
), 1);
1961 // dirty... TODO fixme
1962 debMsgStd(" ",DM_MSG
, " Flx: "<<this->getCellDf(cell
,workset
,dFlux
), 1);