Blender V2.61 - r43446
|
00001 00004 /****************************************************************************** 00005 * 00006 * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method 00007 * Copyright 2003-2006 Nils Thuerey 00008 * 00009 * Standard LBM Factory implementation 00010 * 00011 *****************************************************************************/ 00012 00013 #include "solver_class.h" 00014 #include "solver_relax.h" 00015 #include "particletracer.h" 00016 #include "loop_tools.h" 00017 #include <stdlib.h> 00018 00019 /*****************************************************************************/ 00021 /*****************************************************************************/ 00022 00023 double globdfcnt; 00024 double globdfavg[19]; 00025 double globdfmax[19]; 00026 double globdfmin[19]; 00027 extern int glob_mpindex,glob_mpnum; 00028 extern bool globOutstrForce; 00029 00030 // simulation object interface 00031 void LbmFsgrSolver::step() { 00032 stepMain(); 00033 } 00034 00035 // lbm main step 00036 void messageOutputForce(string from); 00037 void LbmFsgrSolver::stepMain() { 00038 myTime_t timestart = getTime(); 00039 00040 initLevelOmegas(); 00041 markedClearList(); // DMC clearMarkedCellsList 00042 00043 // safety check, counter reset 00044 mNumUsedCells = 0; 00045 mNumInterdCells = 0; 00046 mNumInvIfCells = 0; 00047 00048 //debugOutNnl("LbmFsgrSolver::step : "<<mStepCnt, 10); 00049 if(!mSilent){ debMsgStd("LbmFsgrSolver::step", DM_MSG, mName<<" cnt:"<<mStepCnt<<" t:"<<mSimulationTime, 10); } 00050 //debMsgDirect( "LbmFsgrSolver::step : "<<mStepCnt<<" "); 00051 //myTime_t timestart = 0; 00052 //if(mStartSymm) { checkSymmetry("step1"); } // DEBUG 00053 00054 // time adapt 00055 mMaxVlen = mMxvz = mMxvy = mMxvx = 0.0; 00056 00057 // init moving bc's, can change mMaxVlen 00058 initMovingObstacles(false); 00059 00060 // handle fluid control 00061 handleCpdata(); 00062 00063 // important - keep for tadap 00064 LbmFloat lastMass = mCurrentMass; 00065 mCurrentMass = mFixMass; // reset here for next step 00066 mCurrentVolume = 0.0; 00067 00068 //change to single step advance! 00069 int levsteps = 0; 00070 int dsbits = mStepCnt ^ (mStepCnt-1); 00071 //errMsg("S"," step:"<<mStepCnt<<" s-1:"<<(mStepCnt-1)<<" xf:"<<convertCellFlagType2String(dsbits)); 00072 for(int lev=0; lev<=mMaxRefine; lev++) { 00073 //if(! (mStepCnt&(1<<lev)) ) { 00074 if( dsbits & (1<<(mMaxRefine-lev)) ) { 00075 //errMsg("S"," l"<<lev); 00076 00077 if(lev==mMaxRefine) { 00078 // always advance fine level... 00079 fineAdvance(); 00080 } else { 00081 adaptGrid(lev); 00082 coarseRestrictFromFine(lev); 00083 coarseAdvance(lev); 00084 } 00085 #if FSGR_OMEGA_DEBUG==1 00086 errMsg("LbmFsgrSolver::step","LES stats l="<<lev<<" omega="<<mLevel[lev].omega<<" avgOmega="<< (mLevel[lev].avgOmega/mLevel[lev].avgOmegaCnt) ); 00087 mLevel[lev].avgOmega = 0.0; mLevel[lev].avgOmegaCnt = 0.0; 00088 #endif // FSGR_OMEGA_DEBUG==1 00089 levsteps++; 00090 } 00091 mCurrentMass += mLevel[lev].lmass; 00092 mCurrentVolume += mLevel[lev].lvolume; 00093 } 00094 00095 // prepare next step 00096 mStepCnt++; 00097 00098 00099 // some dbugging output follows 00100 // calculate MLSUPS 00101 myTime_t timeend = getTime(); 00102 00103 mNumUsedCells += mNumInterdCells; // count both types for MLSUPS 00104 mAvgNumUsedCells += mNumUsedCells; 00105 mMLSUPS = ((double)mNumUsedCells / ((timeend-timestart)/(double)1000.0) ) / (1000000.0); 00106 if(mMLSUPS>10000){ mMLSUPS = -1; } 00107 //else { mAvgMLSUPS += mMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups 00108 00109 LbmFloat totMLSUPS = ( ((mLevel[mMaxRefine].lSizex-2)*(mLevel[mMaxRefine].lSizey-2)*(getForZMax1(mMaxRefine)-getForZMin1())) / ((timeend-timestart)/(double)1000.0) ) / (1000000); 00110 if(totMLSUPS>10000) totMLSUPS = -1; 00111 mNumInvIfTotal += mNumInvIfCells; // debug 00112 00113 // do some formatting 00114 if(!mSilent){ 00115 int avgcls = (int)(mAvgNumUsedCells/(LONGINT)mStepCnt); 00116 debMsgStd("LbmFsgrSolver::step", DM_MSG, mName<<" cnt:"<<mStepCnt<<" t:"<<mSimulationTime<< 00117 " cur-mlsups:"<<mMLSUPS<< //" avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), "<< 00118 " totcls:"<<mNumUsedCells<< " avgcls:"<< avgcls<< 00119 " intd:"<<mNumInterdCells<< " invif:"<<mNumInvIfCells<< 00120 " invift:"<<mNumInvIfTotal<< " fsgrcs:"<<mNumFsgrChanges<< 00121 " filled:"<<mNumFilledCells<<", emptied:"<<mNumEmptiedCells<< 00122 " mMxv:"<<PRINT_VEC(mMxvx,mMxvy,mMxvz)<<", tscnts:"<<mTimeSwitchCounts<< 00123 //" RWmxv:"<<ntlVec3Gfx(mMxvx,mMxvy,mMxvz)*(mLevel[mMaxRefine].simCellSize / mLevel[mMaxRefine].timestep)<<" "<< /* realworld vel output */ 00124 " probs:"<<mNumProblems<< " simt:"<<mSimulationTime<< 00125 " took:"<< getTimeString(timeend-timestart)<< 00126 " for '"<<mName<<"' " , 10); 00127 } else { debMsgDirect("."); } 00128 00129 if(mStepCnt==1) { 00130 mMinNoCells = mMaxNoCells = mNumUsedCells; 00131 } else { 00132 if(mNumUsedCells>mMaxNoCells) mMaxNoCells = mNumUsedCells; 00133 if(mNumUsedCells<mMinNoCells) mMinNoCells = mNumUsedCells; 00134 } 00135 00136 // mass scale test 00137 if((mMaxRefine>0)&&(mInitialMass>0.0)) { 00138 LbmFloat mscale = mInitialMass/mCurrentMass; 00139 00140 mscale = 1.0; 00141 const LbmFloat dchh = 0.001; 00142 if(mCurrentMass<mInitialMass) mscale = 1.0+dchh; 00143 if(mCurrentMass>mInitialMass) mscale = 1.0-dchh; 00144 00145 // use mass rescaling? 00146 // with float precision this seems to be nonsense... 00147 const bool MREnable = false; 00148 00149 const int MSInter = 2; 00150 static int mscount = 0; 00151 if( (MREnable) && ((mLevel[0].lsteps%MSInter)== (MSInter-1)) && ( ABS( (mInitialMass/mCurrentMass)-1.0 ) > 0.01) && ( dsbits & (1<<(mMaxRefine-0)) ) ){ 00152 // example: FORCE RESCALE MASS! ini:1843.5, cur:1817.6, f=1.01425 step:22153 levstep:5539 msc:37 00153 // mass rescale MASS RESCALE check 00154 errMsg("MDTDD","\n\n"); 00155 errMsg("MDTDD","FORCE RESCALE MASS! " 00156 <<"ini:"<<mInitialMass<<", cur:"<<mCurrentMass<<", f="<<ABS(mInitialMass/mCurrentMass) 00157 <<" step:"<<mStepCnt<<" levstep:"<<mLevel[0].lsteps<<" msc:"<<mscount<<" " 00158 ); 00159 errMsg("MDTDD","\n\n"); 00160 00161 mscount++; 00162 for(int lev=mMaxRefine; lev>=0 ; lev--) { 00163 //for(int workSet = 0; workSet<=1; workSet++) { 00164 int wss = 0; 00165 int wse = 1; 00166 #if COMPRESSGRIDS==1 00167 if(lev== mMaxRefine) wss = wse = mLevel[lev].setCurr; 00168 #endif // COMPRESSGRIDS==1 00169 for(int workSet = wss; workSet<=wse; workSet++) { // COMPRT 00170 00171 FSGR_FORIJK1(lev) { 00172 if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm)) 00173 ) { 00174 00175 FORDF0 { QCELL(lev, i,j,k,workSet, l) *= mscale; } 00176 QCELL(lev, i,j,k,workSet, dMass) *= mscale; 00177 QCELL(lev, i,j,k,workSet, dFfrac) *= mscale; 00178 00179 } else { 00180 continue; 00181 } 00182 } 00183 } 00184 mLevel[lev].lmass *= mscale; 00185 } 00186 } 00187 00188 mCurrentMass *= mscale; 00189 }// if mass scale test */ 00190 else { 00191 // use current mass after full step for initial setting 00192 if((mMaxRefine>0)&&(mInitialMass<=0.0) && (levsteps == (mMaxRefine+1))) { 00193 mInitialMass = mCurrentMass; 00194 debMsgStd("MDTDD",DM_NOTIFY,"Second Initial Mass Init: "<<mInitialMass, 2); 00195 } 00196 } 00197 00198 #if LBM_INCLUDE_TESTSOLVERS==1 00199 if((mUseTestdata)&&(mInitDone)) { handleTestdata(); } 00200 mrExchange(); 00201 #endif 00202 00203 // advance positions with current grid 00204 advanceParticles(); 00205 if(mpParticles) { 00206 mpParticles->checkDumpTextPositions(mSimulationTime); 00207 mpParticles->checkTrails(mSimulationTime); 00208 } 00209 00210 // one of the last things to do - adapt timestep 00211 // was in fineAdvance before... 00212 if(mTimeAdap) { 00213 adaptTimestep(); 00214 } // time adaptivity 00215 00216 00217 #ifndef WIN32 00218 // good indicator for instabilities 00219 if( (!finite(mMxvx)) || (!finite(mMxvy)) || (!finite(mMxvz)) ) { CAUSE_PANIC; } 00220 if( (!finite(mCurrentMass)) || (!finite(mCurrentVolume)) ) { CAUSE_PANIC; } 00221 #endif // WIN32 00222 00223 // output total step time 00224 myTime_t timeend2 = getTime(); 00225 double mdelta = (lastMass-mCurrentMass); 00226 if(ABS(mdelta)<1e-12) mdelta=0.; 00227 double effMLSUPS = ((double)mNumUsedCells / ((timeend2-timestart)/(double)1000.0) ) / (1000000.0); 00228 if(mInitDone) { 00229 if(effMLSUPS>10000){ effMLSUPS = -1; } 00230 else { mAvgMLSUPS += effMLSUPS; mAvgMLSUPSCnt += 1.0; } // track average mlsups 00231 } 00232 00233 debMsgStd("LbmFsgrSolver::stepMain", DM_MSG, "mmpid:"<<glob_mpindex<<" step:"<<mStepCnt 00234 <<" dccd="<< mCurrentMass 00235 //<<",d"<<mdelta 00236 //<<",ds"<<(mCurrentMass-mObjectMassMovnd[1]) 00237 //<<"/"<<mCurrentVolume<<"(fix="<<mFixMass<<",ini="<<mInitialMass<<"), " 00238 <<" effMLSUPS=("<< effMLSUPS 00239 <<",avg:"<<(mAvgMLSUPS/mAvgMLSUPSCnt)<<"), " 00240 <<" took totst:"<< getTimeString(timeend2-timestart), 3); 00241 // nicer output 00242 //debMsgDirect(std::endl); 00243 // */ 00244 00245 messageOutputForce(""); 00246 //#endif // ELBEEM_PLUGIN!=1 00247 } 00248 00249 #define NEWDEBCHECK(str) \ 00250 if(!this->mPanic){ FSGR_FORIJK_BOUNDS(mMaxRefine) { \ 00251 if(RFLAG(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr)&(CFFluid|CFInter)) { \ 00252 for(int l=0;l<dTotalNum;l++) { \ 00253 if(!finite(QCELL(mMaxRefine,i,j,k,mLevel[mMaxRefine].setCurr,l))) { errMsg("NNOFIN"," "<<str<<" at "<<PRINT_IJK<<" l"<<l<<" "); }\ 00254 }/*for*/ \ 00255 }/*if*/ \ 00256 } } 00257 00258 void LbmFsgrSolver::fineAdvance() 00259 { 00260 // do the real thing... 00261 //NEWDEBCHECK("t1"); 00262 mainLoop( mMaxRefine ); 00263 if(mUpdateFVHeight) { 00264 // warning assume -Y gravity... 00265 mFVHeight = mCurrentMass*mFVArea/((LbmFloat)(mLevel[mMaxRefine].lSizex*mLevel[mMaxRefine].lSizez)); 00266 if(mFVHeight<1.0) mFVHeight = 1.0; 00267 mpParam->setFluidVolumeHeight(mFVHeight); 00268 } 00269 00270 // advance time before timestep change 00271 mSimulationTime += mpParam->getTimestep(); 00272 // time adaptivity 00273 mpParam->setSimulationMaxSpeed( sqrt(mMaxVlen / 1.5) ); 00274 //if(mStartSymm) { checkSymmetry("step2"); } // DEBUG 00275 if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," stepped from "<<mLevel[mMaxRefine].setCurr<<" to "<<mLevel[mMaxRefine].setOther<<" step"<< (mLevel[mMaxRefine].lsteps), 3 ); } 00276 00277 // update other set 00278 mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr; 00279 mLevel[mMaxRefine].setCurr ^= 1; 00280 mLevel[mMaxRefine].lsteps++; 00281 00282 // flag init... (work on current set, to simplify flag checks) 00283 reinitFlags( mLevel[mMaxRefine].setCurr ); 00284 if(!mSilent){ debMsgStd("fineAdvance",DM_NOTIFY," flags reinit on set "<< mLevel[mMaxRefine].setCurr, 3 ); } 00285 00286 // DEBUG VEL CHECK 00287 if(0) { 00288 int lev = mMaxRefine; 00289 int workSet = mLevel[lev].setCurr; 00290 int mi=0,mj=0,mk=0; 00291 LbmFloat compRho=0.; 00292 LbmFloat compUx=0.; 00293 LbmFloat compUy=0.; 00294 LbmFloat compUz=0.; 00295 LbmFloat maxUlen=0.; 00296 LbmVec maxU(0.); 00297 LbmFloat maxRho=-100.; 00298 int ri=0,rj=0,rk=0; 00299 00300 FSGR_FORIJK1(lev) { 00301 if( (RFLAG(lev,i,j,k, workSet) & (CFFluid| CFInter| CFGrFromCoarse| CFGrFromFine| CFGrNorm)) ) { 00302 compRho=QCELL(lev, i,j,k,workSet, dC); 00303 compUx = compUy = compUz = 0.0; 00304 for(int l=1; l<this->cDfNum; l++) { 00305 LbmFloat df = QCELL(lev, i,j,k,workSet, l); 00306 compRho += df; 00307 compUx += (this->dfDvecX[l]*df); 00308 compUy += (this->dfDvecY[l]*df); 00309 compUz += (this->dfDvecZ[l]*df); 00310 } 00311 LbmVec u(compUx,compUy,compUz); 00312 LbmFloat nu = norm(u); 00313 if(nu>maxUlen) { 00314 maxU = u; 00315 maxUlen = nu; 00316 mi=i; mj=j; mk=k; 00317 } 00318 if(compRho>maxRho) { 00319 maxRho=compRho; 00320 ri=i; rj=j; rk=k; 00321 } 00322 } else { 00323 continue; 00324 } 00325 } 00326 00327 errMsg("MAXVELCHECK"," at "<<PRINT_VEC(mi,mj,mk)<<" norm:"<<maxUlen<<" u:"<<maxU); 00328 errMsg("MAXRHOCHECK"," at "<<PRINT_VEC(ri,rj,rk)<<" rho:"<<maxRho); 00329 printLbmCell(lev, 30,36,23, -1); 00330 } // DEBUG VEL CHECK 00331 00332 } 00333 00334 00335 00336 // fine step defines 00337 00338 // access to own dfs during step (may be changed to local array) 00339 #define MYDF(l) RAC(ccel, l) 00340 00341 // drop model definitions 00342 #define RWVEL_THRESH 1.5 00343 #define RWVEL_WINDTHRESH (RWVEL_THRESH*0.5) 00344 00345 #if LBMDIM==3 00346 // normal 00347 #define SLOWDOWNREGION (mSizez/4) 00348 #else // LBMDIM==2 00349 // off 00350 #define SLOWDOWNREGION 10 00351 #endif // LBMDIM==2 00352 #define P_LCSMQO 0.01 00353 00354 /*****************************************************************************/ 00356 /*****************************************************************************/ 00357 void 00358 LbmFsgrSolver::mainLoop(int lev) 00359 { 00360 // loops over _only inner_ cells ----------------------------------------------------------------------------------- 00361 00362 // slow surf regions smooth (if below) 00363 const LbmFloat smoothStrength = 0.0; //0.01; 00364 const LbmFloat sssUsqrLimit = 1.5 * 0.03*0.03; 00365 const LbmFloat sssUsqrLimitInv = 1.0/sssUsqrLimit; 00366 00367 const int cutMin = 1; 00368 const int cutConst = mCutoff+2; 00369 00370 00371 # if LBM_INCLUDE_TESTSOLVERS==1 00372 // 3d region off... quit 00373 if((mUseTestdata)&&(mpTest->mFarfMode>0)) { return; } 00374 # endif // ELBEEM_PLUGIN!=1 00375 00376 // main loop region 00377 const bool doReduce = true; 00378 const int gridLoopBound=1; 00379 GRID_REGION_INIT(); 00380 #if PARALLEL==1 00381 #pragma omp parallel default(shared) \ 00382 reduction(+: \ 00383 calcCurrentMass,calcCurrentVolume, \ 00384 calcCellsFilled,calcCellsEmptied, \ 00385 calcNumUsedCells ) 00386 GRID_REGION_START(); 00387 #else // PARALLEL==1 00388 GRID_REGION_START(); 00389 #endif // PARALLEL==1 00390 00391 // local to main 00392 CellFlagType nbflag[LBM_DFNUM]; 00393 int oldFlag, newFlag, nbored; 00394 LbmFloat m[LBM_DFNUM]; 00395 LbmFloat rho, ux, uy, uz, tmp, usqr; 00396 00397 // smago vars 00398 LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega; 00399 00400 // ifempty cell conversion flags 00401 bool iffilled, ifemptied; 00402 LbmFloat nbfracs[LBM_DFNUM]; // ffracs of neighbors 00403 int recons[LBM_DFNUM]; // reconstruct this DF? 00404 int numRecons; // how many are reconstructed? 00405 00406 LbmFloat mass=0., change=0., lcsmqo=0.; 00407 rho= ux= uy= uz= usqr= tmp= 0.; 00408 lcsmqadd = lcsmomega = 0.; 00409 FORDF0{ lcsmeq[l] = 0.; } 00410 00411 // --- 00412 // now stream etc. 00413 // use //template functions for 2D/3D 00414 00415 GRID_LOOP_START(); 00416 // loop start 00417 // stream from current set to other, then collide and store 00418 //errMsg("l2"," at "<<PRINT_IJK<<" id"<<id); 00419 00420 # if FSGR_STRICT_DEBUG==1 00421 // safety pointer check 00422 rho = ux = uy = uz = tmp = usqr = -100.0; // DEBUG 00423 if( (&RFLAG(lev, i,j,k,mLevel[lev].setCurr) != pFlagSrc) || 00424 (&RFLAG(lev, i,j,k,mLevel[lev].setOther) != pFlagDst) ) { 00425 errMsg("LbmFsgrSolver::mainLoop","Err flagp "<<PRINT_IJK<<"="<< 00426 RFLAG(lev, i,j,k,mLevel[lev].setCurr)<<","<<RFLAG(lev, i,j,k,mLevel[lev].setOther)<<" but is "<< 00427 (*pFlagSrc)<<","<<(*pFlagDst) <<", pointers "<< 00428 (long)(&RFLAG(lev, i,j,k,mLevel[lev].setCurr))<<","<<(long)(&RFLAG(lev, i,j,k,mLevel[lev].setOther))<<" but is "<< 00429 (long)(pFlagSrc)<<","<<(long)(pFlagDst)<<" " 00430 ); 00431 CAUSE_PANIC; 00432 } 00433 if( (&QCELL(lev, i,j,k,mLevel[lev].setCurr,0) != ccel) || 00434 (&QCELL(lev, i,j,k,mLevel[lev].setOther,0) != tcel) ) { 00435 errMsg("LbmFsgrSolver::mainLoop","Err cellp "<<PRINT_IJK<<"="<< 00436 (long)(&QCELL(lev, i,j,k,mLevel[lev].setCurr,0))<<","<<(long)(&QCELL(lev, i,j,k,mLevel[lev].setOther,0))<<" but is "<< 00437 (long)(ccel)<<","<<(long)(tcel)<<" " 00438 ); 00439 CAUSE_PANIC; 00440 } 00441 # endif 00442 oldFlag = *pFlagSrc; 00443 00444 // old INTCFCOARSETEST==1 00445 if( (oldFlag & (CFGrFromCoarse)) ) { 00446 if(( mStepCnt & (1<<(mMaxRefine-lev)) ) ==1) { 00447 FORDF0 { RAC(tcel,l) = RAC(ccel,l); } 00448 } else { 00449 interpolateCellFromCoarse( lev, i,j,k, TSET(lev), 0.0, CFFluid|CFGrFromCoarse, false); 00450 calcNumUsedCells++; 00451 } 00452 continue; // interpolateFineFromCoarse test! 00453 } // interpolateFineFromCoarse test! 00454 00455 if(oldFlag & (CFMbndInflow)) { 00456 // fluid & if are ok, fill if later on 00457 int isValid = oldFlag & (CFFluid|CFInter); 00458 const LbmFloat iniRho = 1.0; 00459 const int OId = oldFlag>>24; 00460 if(!isValid) { 00461 // make new if cell 00462 const LbmVec vel(mObjectSpeeds[OId]); 00463 // TODO add OPT3D treatment 00464 FORDF0 { RAC(tcel, l) = this->getCollideEq(l, iniRho,vel[0],vel[1],vel[2]); } 00465 RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; 00466 RAC(tcel, dFlux) = FLUX_INIT; 00467 changeFlag(lev, i,j,k, TSET(lev), CFInter); 00468 calcCurrentMass += iniRho; 00469 calcCurrentVolume += 1.0; 00470 calcNumUsedCells++; 00471 mInitialMass += iniRho; 00472 // dont treat cell until next step 00473 continue; 00474 } 00475 } 00476 else // these are exclusive 00477 if(oldFlag & (CFMbndOutflow)) { 00478 int isnotValid = oldFlag & (CFFluid); 00479 if(isnotValid) { 00480 // remove fluid cells, shouldnt be here anyway 00481 LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; } 00482 mInitialMass -= fluidRho; 00483 const LbmFloat iniRho = 0.0; 00484 RAC(tcel, dMass) = RAC(tcel, dFfrac) = iniRho; 00485 RAC(tcel, dFlux) = FLUX_INIT; 00486 changeFlag(lev, i,j,k, TSET(lev), CFInter); 00487 00488 // same as ifemptied for if below 00489 LbmPoint oemptyp; oemptyp.flag = 0; 00490 oemptyp.x = i; oemptyp.y = j; oemptyp.z = k; 00491 LIST_EMPTY(oemptyp); 00492 calcCellsEmptied++; 00493 continue; 00494 } 00495 } 00496 00497 if(oldFlag & (CFBnd|CFEmpty|CFGrFromCoarse|CFUnused)) { 00498 *pFlagDst = oldFlag; 00499 continue; 00500 } 00501 /*if( oldFlag & CFNoBndFluid ) { // TEST ME FASTER? 00502 OPTIMIZED_STREAMCOLLIDE; PERFORM_USQRMAXCHECK; 00503 RAC(tcel,dFfrac) = 1.0; 00504 *pFlagDst = (CellFlagType)oldFlag; // newFlag; 00505 calcCurrentMass += rho; calcCurrentVolume += 1.0; 00506 calcNumUsedCells++; 00507 continue; 00508 }// TEST ME FASTER? */ 00509 00510 // only neighbor flags! not own flag 00511 nbored = 0; 00512 00513 #if OPT3D==0 00514 FORDF1 { 00515 nbflag[l] = RFLAG_NB(lev, i,j,k,SRCS(lev),l); 00516 nbored |= nbflag[l]; 00517 } 00518 #else 00519 nbflag[dSB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dSB]; 00520 nbflag[dWB] = *(pFlagSrc + (-mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWB]; 00521 nbflag[ dB] = *(pFlagSrc + (-mLevel[lev].lOffsy)); nbored |= nbflag[dB]; 00522 nbflag[dEB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dEB]; 00523 nbflag[dNB] = *(pFlagSrc + (-mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNB]; 00524 00525 nbflag[dSW] = *(pFlagSrc + (-mLevel[lev].lOffsx+-1)); nbored |= nbflag[dSW]; 00526 nbflag[ dS] = *(pFlagSrc + (-mLevel[lev].lOffsx)); nbored |= nbflag[dS]; 00527 nbflag[dSE] = *(pFlagSrc + (-mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dSE]; 00528 00529 nbflag[ dW] = *(pFlagSrc + (-1)); nbored |= nbflag[dW]; 00530 nbflag[ dE] = *(pFlagSrc + ( 1)); nbored |= nbflag[dE]; 00531 00532 nbflag[dNW] = *(pFlagSrc + ( mLevel[lev].lOffsx+-1)); nbored |= nbflag[dNW]; 00533 nbflag[ dN] = *(pFlagSrc + ( mLevel[lev].lOffsx)); nbored |= nbflag[dN]; 00534 nbflag[dNE] = *(pFlagSrc + ( mLevel[lev].lOffsx+ 1)); nbored |= nbflag[dNE]; 00535 00536 nbflag[dST] = *(pFlagSrc + ( mLevel[lev].lOffsy+-mLevel[lev].lOffsx)); nbored |= nbflag[dST]; 00537 nbflag[dWT] = *(pFlagSrc + ( mLevel[lev].lOffsy+-1)); nbored |= nbflag[dWT]; 00538 nbflag[ dT] = *(pFlagSrc + ( mLevel[lev].lOffsy)); nbored |= nbflag[dT]; 00539 nbflag[dET] = *(pFlagSrc + ( mLevel[lev].lOffsy+ 1)); nbored |= nbflag[dET]; 00540 nbflag[dNT] = *(pFlagSrc + ( mLevel[lev].lOffsy+ mLevel[lev].lOffsx)); nbored |= nbflag[dNT]; 00541 // */ 00542 #endif 00543 00544 // pointer to destination cell 00545 calcNumUsedCells++; 00546 00547 // FLUID cells 00548 if( oldFlag & CFFluid ) { 00549 // only standard fluid cells (with nothing except fluid as nbs 00550 00551 if(oldFlag&CFMbndInflow) { 00552 // force velocity for inflow, necessary to have constant direction of flow 00553 // FIXME , test also set interface cells? 00554 const int OId = oldFlag>>24; 00555 //? DEFAULT_STREAM; 00556 //const LbmFloat fluidRho = 1.0; 00557 // for submerged inflows, streaming would have to be performed... 00558 LbmFloat fluidRho = m[0]; FORDF1 { fluidRho += m[l]; } 00559 const LbmVec vel(mObjectSpeeds[OId]); 00560 ux=vel[0], uy=vel[1], uz=vel[2]; 00561 usqr = 1.5 * (ux*ux + uy*uy + uz*uz); 00562 FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } 00563 rho = fluidRho; 00564 //errMsg("INFLOW_DEBUG","std at "<<PRINT_IJK<<" v="<<vel<<" rho="<<rho); 00565 } else { 00566 if(nbored&CFBnd) { 00567 DEFAULT_STREAM; 00568 //ux = [0]; uy = mLevel[lev].gravity[1]; uz = mLevel[lev].gravity[2]; 00569 DEFAULT_COLLIDEG(mLevel[lev].gravity); 00570 oldFlag &= (~CFNoBndFluid); 00571 } else { 00572 // do standard stream/collide 00573 OPTIMIZED_STREAMCOLLIDE; 00574 oldFlag |= CFNoBndFluid; 00575 } 00576 } 00577 00578 PERFORM_USQRMAXCHECK; 00579 // "normal" fluid cells 00580 RAC(tcel,dFfrac) = 1.0; 00581 *pFlagDst = (CellFlagType)oldFlag; // newFlag; 00582 calcCurrentMass += rho; 00583 calcCurrentVolume += 1.0; 00584 continue; 00585 } 00586 00587 newFlag = oldFlag; 00588 // make sure here: always check which flags to really unset...! 00589 newFlag = newFlag & (~( 00590 CFNoNbFluid|CFNoNbEmpty| CFNoDelete 00591 | CFNoInterpolSrc 00592 | CFNoBndFluid 00593 )); 00594 if(!(nbored&CFBndNoslip)) { //NEWSURFT NEWSURFTNOS 00595 newFlag |= CFNoBndFluid; 00596 } 00597 /*if(!(nbored&CFBnd)) { //NEWSURFT NEWSURFTNOS 00598 // explicitly check for noslip neighbors 00599 bool hasnoslipnb = false; 00600 FORDF1 { if((nbflag[l]&CFBnd)&&(nbflag[l]&CFBndNoslip)) hasnoslipnb=true; } 00601 if(!hasnoslipnb) newFlag |= CFNoBndFluid; 00602 } // */ 00603 00604 // store own dfs and mass 00605 mass = RAC(ccel,dMass); 00606 00607 // WARNING - only interface cells arrive here! 00608 // read distribution funtions of adjacent cells = stream step 00609 DEFAULT_STREAM; 00610 00611 if((nbored & CFFluid)==0) { newFlag |= CFNoNbFluid; mNumInvIfCells++; } 00612 if((nbored & CFEmpty)==0) { newFlag |= CFNoNbEmpty; mNumInvIfCells++; } 00613 00614 // calculate mass exchange for interface cells 00615 LbmFloat myfrac = RAC(ccel,dFfrac); 00616 if(myfrac<0.) myfrac=0.; // NEWSURFT 00617 # define nbdf(l) m[ this->dfInv[(l)] ] 00618 00619 // update mass 00620 // only do boundaries for fluid cells, and interface cells without 00621 // any fluid neighbors (assume that interface cells _with_ fluid 00622 // neighbors are affected enough by these) 00623 // which Df's have to be reconstructed? 00624 // for fluid cells - just the f_i difference from streaming to empty cells ---- 00625 numRecons = 0; 00626 bool onlyBndnb = ((!(oldFlag&CFNoBndFluid))&&(oldFlag&CFNoNbFluid)&&(nbored&CFBndNoslip)); 00627 //onlyBndnb = false; // DEBUG test off 00628 00629 FORDF1 { // dfl loop 00630 recons[l] = 0; 00631 nbfracs[l] = 0.0; 00632 // finally, "normal" interface cells ---- 00633 if( nbflag[l]&(CFFluid|CFBnd) ) { // NEWTEST! FIXME check!!!!!!!!!!!!!!!!!! 00634 change = nbdf(l) - MYDF(l); 00635 } 00636 // interface cells - distuingish cells that shouldn't fill/empty 00637 else if( nbflag[l] & CFInter ) { 00638 00639 LbmFloat mynbfac,nbnbfac; 00640 // NEW TEST t1 00641 // t2 -> off 00642 if((oldFlag&CFNoBndFluid)&&(nbflag[l]&CFNoBndFluid)) { 00643 mynbfac = QCELL_NB(lev, i,j,k,SRCS(lev),l, dFlux) / QCELL(lev, i,j,k,SRCS(lev), dFlux); 00644 nbnbfac = 1.0/mynbfac; 00645 onlyBndnb = false; 00646 } else { 00647 mynbfac = nbnbfac = 1.0; // switch calc flux off 00648 goto changeDefault; // NEWSURFT 00649 //change = 0.; goto changeDone; // NEWSURFT 00650 } 00651 //mynbfac = nbnbfac = 1.0; // switch calc flux off t3 00652 00653 // perform interface case handling 00654 if ((oldFlag|nbflag[l])&(CFNoNbFluid|CFNoNbEmpty)) { 00655 switch (oldFlag&(CFNoNbFluid|CFNoNbEmpty)) { 00656 case 0: 00657 // we are a normal cell so... 00658 switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { 00659 case CFNoNbFluid: 00660 // just fill current cell = empty neighbor 00661 change = nbnbfac*nbdf(l) ; goto changeDone; 00662 case CFNoNbEmpty: 00663 // just empty current cell = fill neighbor 00664 change = - mynbfac*MYDF(l) ; goto changeDone; 00665 } 00666 break; 00667 00668 case CFNoNbFluid: 00669 // we dont have fluid nb's so... 00670 switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { 00671 case 0: 00672 case CFNoNbEmpty: 00673 // we have no fluid nb's -> just empty 00674 change = - mynbfac*MYDF(l) ; goto changeDone; 00675 } 00676 break; 00677 00678 case CFNoNbEmpty: 00679 // we dont have empty nb's so... 00680 switch (nbflag[l]&(CFNoNbFluid|CFNoNbEmpty)) { 00681 case 0: 00682 case CFNoNbFluid: 00683 // we have no empty nb's -> just fill 00684 change = nbnbfac*nbdf(l); goto changeDone; 00685 } 00686 break; 00687 }} // inter-inter exchange 00688 00689 changeDefault: ; 00690 // just do normal mass exchange... 00691 change = ( nbnbfac*nbdf(l) - mynbfac*MYDF(l) ) ; 00692 changeDone: ; 00693 nbfracs[l] = QCELL_NB(lev, i,j,k, SRCS(lev),l, dFfrac); 00694 if(nbfracs[l]<0.) nbfracs[l] = 0.; // NEWSURFT 00695 change *= (myfrac + nbfracs[l]) * 0.5; 00696 } // the other cell is interface 00697 00698 // last alternative - reconstruction in this direction 00699 else { 00700 // empty + bnd case 00701 recons[l] = 1; 00702 numRecons++; 00703 change = 0.0; 00704 } 00705 00706 // modify mass at SRCS 00707 mass += change; 00708 } // l 00709 // normal interface, no if empty/fluid 00710 00711 // computenormal 00712 LbmFloat surfaceNormal[3]; 00713 computeFluidSurfaceNormal(ccel,pFlagSrc, surfaceNormal); 00714 00715 if( (ABS(surfaceNormal[0])+ABS(surfaceNormal[1])+ABS(surfaceNormal[2])) > LBM_EPSILON) { 00716 // normal ok and usable... 00717 FORDF1 { 00718 if( (this->dfDvecX[l]*surfaceNormal[0] + this->dfDvecY[l]*surfaceNormal[1] + this->dfDvecZ[l]*surfaceNormal[2]) // dot Dvec,norml 00719 > LBM_EPSILON) { 00720 recons[l] = 2; 00721 numRecons++; 00722 } 00723 } 00724 } 00725 00726 // calculate macroscopic cell values 00727 LbmFloat oldUx, oldUy, oldUz; 00728 LbmFloat oldRho; // OLD rho = ccel->rho; 00729 # define REFERENCE_PRESSURE 1.0 // always atmosphere... 00730 # if OPT3D==0 00731 oldRho=RAC(ccel,0); 00732 oldUx = oldUy = oldUz = 0.0; 00733 for(int l=1; l<this->cDfNum; l++) { 00734 oldRho += RAC(ccel,l); 00735 oldUx += (this->dfDvecX[l]*RAC(ccel,l)); 00736 oldUy += (this->dfDvecY[l]*RAC(ccel,l)); 00737 oldUz += (this->dfDvecZ[l]*RAC(ccel,l)); 00738 } 00739 // reconstruct dist funcs from empty cells 00740 FORDF1 { 00741 if(recons[ l ]) { 00742 m[ this->dfInv[l] ] = 00743 this->getCollideEq(l, REFERENCE_PRESSURE, oldUx,oldUy,oldUz) + 00744 this->getCollideEq(this->dfInv[l], REFERENCE_PRESSURE, oldUx,oldUy,oldUz) 00745 - MYDF( l ); 00746 } 00747 } 00748 ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr 00749 usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on 00750 # else // OPT3D==0 00751 oldRho = + RAC(ccel,dC) + RAC(ccel,dN ) 00752 + RAC(ccel,dS ) + RAC(ccel,dE ) 00753 + RAC(ccel,dW ) + RAC(ccel,dT ) 00754 + RAC(ccel,dB ) + RAC(ccel,dNE) 00755 + RAC(ccel,dNW) + RAC(ccel,dSE) 00756 + RAC(ccel,dSW) + RAC(ccel,dNT) 00757 + RAC(ccel,dNB) + RAC(ccel,dST) 00758 + RAC(ccel,dSB) + RAC(ccel,dET) 00759 + RAC(ccel,dEB) + RAC(ccel,dWT) 00760 + RAC(ccel,dWB); 00761 00762 oldUx = + RAC(ccel,dE) - RAC(ccel,dW) 00763 + RAC(ccel,dNE) - RAC(ccel,dNW) 00764 + RAC(ccel,dSE) - RAC(ccel,dSW) 00765 + RAC(ccel,dET) + RAC(ccel,dEB) 00766 - RAC(ccel,dWT) - RAC(ccel,dWB); 00767 00768 oldUy = + RAC(ccel,dN) - RAC(ccel,dS) 00769 + RAC(ccel,dNE) + RAC(ccel,dNW) 00770 - RAC(ccel,dSE) - RAC(ccel,dSW) 00771 + RAC(ccel,dNT) + RAC(ccel,dNB) 00772 - RAC(ccel,dST) - RAC(ccel,dSB); 00773 00774 oldUz = + RAC(ccel,dT) - RAC(ccel,dB) 00775 + RAC(ccel,dNT) - RAC(ccel,dNB) 00776 + RAC(ccel,dST) - RAC(ccel,dSB) 00777 + RAC(ccel,dET) - RAC(ccel,dEB) 00778 + RAC(ccel,dWT) - RAC(ccel,dWB); 00779 00780 // now reconstruction 00781 ux=oldUx, uy=oldUy, uz=oldUz; // no local vars, only for usqr 00782 rho = REFERENCE_PRESSURE; 00783 usqr = 1.5 * (ux*ux + uy*uy + uz*uz); // needed later on 00784 if(recons[dN ]) { m[dS ] = EQN + EQS - MYDF(dN ); } 00785 if(recons[dS ]) { m[dN ] = EQS + EQN - MYDF(dS ); } 00786 if(recons[dE ]) { m[dW ] = EQE + EQW - MYDF(dE ); } 00787 if(recons[dW ]) { m[dE ] = EQW + EQE - MYDF(dW ); } 00788 if(recons[dT ]) { m[dB ] = EQT + EQB - MYDF(dT ); } 00789 if(recons[dB ]) { m[dT ] = EQB + EQT - MYDF(dB ); } 00790 if(recons[dNE]) { m[dSW] = EQNE + EQSW - MYDF(dNE); } 00791 if(recons[dNW]) { m[dSE] = EQNW + EQSE - MYDF(dNW); } 00792 if(recons[dSE]) { m[dNW] = EQSE + EQNW - MYDF(dSE); } 00793 if(recons[dSW]) { m[dNE] = EQSW + EQNE - MYDF(dSW); } 00794 if(recons[dNT]) { m[dSB] = EQNT + EQSB - MYDF(dNT); } 00795 if(recons[dNB]) { m[dST] = EQNB + EQST - MYDF(dNB); } 00796 if(recons[dST]) { m[dNB] = EQST + EQNB - MYDF(dST); } 00797 if(recons[dSB]) { m[dNT] = EQSB + EQNT - MYDF(dSB); } 00798 if(recons[dET]) { m[dWB] = EQET + EQWB - MYDF(dET); } 00799 if(recons[dEB]) { m[dWT] = EQEB + EQWT - MYDF(dEB); } 00800 if(recons[dWT]) { m[dEB] = EQWT + EQEB - MYDF(dWT); } 00801 if(recons[dWB]) { m[dET] = EQWB + EQET - MYDF(dWB); } 00802 # endif 00803 00804 00805 // inflow bc handling 00806 if(oldFlag & (CFMbndInflow)) { 00807 // fill if cells in inflow region 00808 if(myfrac<0.5) { 00809 mass += 0.25; 00810 mInitialMass += 0.25; 00811 } 00812 const int OId = oldFlag>>24; 00813 const LbmVec vel(mObjectSpeeds[OId]); 00814 ux=vel[0], uy=vel[1], uz=vel[2]; 00815 //? usqr = 1.5 * (ux*ux + uy*uy + uz*uz); 00816 //FORDF0 { RAC(tcel, l) = this->getCollideEq(l, fluidRho,ux,uy,uz); } rho = fluidRho; 00817 rho = REFERENCE_PRESSURE; 00818 FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); } 00819 //errMsg("INFLOW_DEBUG","if at "<<PRINT_IJK<<" v="<<vel<<" rho="<<rho); 00820 } else { 00821 // NEWSURFT, todo optimize! 00822 if(onlyBndnb) { //if(usqr<0.001*0.001) { 00823 rho = ux = uy = uz = 0.; 00824 FORDF0{ 00825 rho += m[l]; 00826 ux += (this->dfDvecX[l]*m[l]); 00827 uy += (this->dfDvecY[l]*m[l]); 00828 uz += (this->dfDvecZ[l]*m[l]); 00829 } 00830 FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,ux,uy,uz); } 00831 } else {// NEWSURFT */ 00832 if(usqr>0.3*0.3) { 00833 // force reset! , warning causes distortions... 00834 FORDF0 { RAC(tcel, l) = this->getCollideEq(l, rho,0.,0.,0.); } 00835 } else { 00836 // normal collide 00837 // mass streaming done... do normal collide 00838 LbmVec grav = mLevel[lev].gravity*mass; 00839 DEFAULT_COLLIDEG(grav); 00840 PERFORM_USQRMAXCHECK; } 00841 // rho init from default collide necessary for fill/empty check below 00842 } // test 00843 } 00844 00845 // testing..., particle generation 00846 // also check oldFlag for CFNoNbFluid, test 00847 // for inflow no pargen test // NOBUBBB! 00848 if((mInitDone) 00849 // dont allow new if cells, or submerged ones 00850 && (!((oldFlag|newFlag)& (CFNoDelete|CFNoNbEmpty) )) 00851 // dont try to subtract from empty cells 00852 && (mass>0.) && (mPartGenProb>0.0)) { 00853 bool doAdd = true; 00854 bool bndOk=true; 00855 if( (i<cutMin)||(i>mSizex-cutMin)|| 00856 (j<cutMin)||(j>mSizey-cutMin)|| 00857 (k<cutMin)||(k>mSizez-cutMin) ) { bndOk=false; } 00858 if(!bndOk) doAdd=false; 00859 00860 LbmFloat prob = (rand()/(RAND_MAX+1.0)); 00861 LbmFloat basethresh = mPartGenProb*lcsmqo*(LbmFloat)(mSizez+mSizey+mSizex)*0.5*0.333; 00862 00863 // physical drop model 00864 if(mPartUsePhysModel) { 00865 LbmFloat realWorldFac = (mLevel[lev].simCellSize / mLevel[lev].timestep); 00866 LbmFloat rux = (ux * realWorldFac); 00867 LbmFloat ruy = (uy * realWorldFac); 00868 LbmFloat ruz = (uz * realWorldFac); 00869 LbmFloat rl = norm(ntlVec3Gfx(rux,ruy,ruz)); 00870 basethresh *= rl; 00871 00872 // reduce probability in outer region? 00873 const int pibord = mLevel[mMaxRefine].lSizex/2-cutConst; 00874 const int pjbord = mLevel[mMaxRefine].lSizey/2-cutConst; 00875 LbmFloat pifac = 1.-(LbmFloat)(ABS(i-pibord)) / (LbmFloat)(pibord); 00876 LbmFloat pjfac = 1.-(LbmFloat)(ABS(j-pjbord)) / (LbmFloat)(pjbord); 00877 if(pifac<0.) pifac=0.; 00878 if(pjfac<0.) pjfac=0.; 00879 00880 //if( (prob< (basethresh*rl)) && (lcsmqo>0.0095) && (rl>RWVEL_THRESH) ) { 00881 if( (prob< (basethresh*rl*pifac*pjfac)) && (lcsmqo>0.0095) && (rl>RWVEL_THRESH) ) { 00882 // add 00883 } else { 00884 doAdd = false; // dont... 00885 } 00886 00887 // "wind" disturbance 00888 // use realworld relative velocity here instead? 00889 if( (doAdd && 00890 ((rl>RWVEL_WINDTHRESH) && (lcsmqo<P_LCSMQO)) )// normal checks 00891 ||(k>mSizez-SLOWDOWNREGION) ) { 00892 LbmFloat nuz = uz; 00893 if(k>mSizez-SLOWDOWNREGION) { 00894 // special case 00895 LbmFloat zfac = (LbmFloat)( k-(mSizez-SLOWDOWNREGION) ); 00896 zfac /= (LbmFloat)(SLOWDOWNREGION); 00897 nuz += (1.0) * zfac; // check max speed? OFF? 00898 //errMsg("TOPT"," at "<<PRINT_IJK<<" zfac"<<zfac); 00899 } else { 00900 // normal probability 00901 //? LbmFloat fac = P_LCSMQO-lcsmqo; 00902 //? jdf *= fac; 00903 } 00904 FORDF1 { 00905 const LbmFloat jdf = 0.05 * (rand()/(RAND_MAX+1.0)); 00906 // TODO use wind velocity? 00907 if(jdf>0.025) { 00908 const LbmFloat add = this->dfLength[l]*(-ux*this->dfDvecX[l]-uy*this->dfDvecY[l]-nuz*this->dfDvecZ[l])*jdf; 00909 RAC(tcel,l) += add; } 00910 } 00911 //errMsg("TOPDOWNCORR"," jdf:"<<jdf<<" rl"<<rl<<" vel "<<norm(LbmVec(ux,uy,nuz))<<" rwv"<<norm(LbmVec(rux,ruy,ruz)) ); 00912 } // wind disturbance 00913 } // mPartUsePhysModel 00914 else { 00915 // empirical model 00916 //if((prob<basethresh) && (lcsmqo>0.0095)) { // add 00917 if((prob<basethresh) && (lcsmqo>0.012)) { // add 00918 } else { doAdd = false; }// dont... 00919 } 00920 00921 00922 // remove noise 00923 if(usqr<0.0001) doAdd=false; // TODO check!? 00924 00925 // dont try to subtract from empty cells 00926 // ensure cell has enough mass for new drop 00927 LbmFloat newPartsize = 1.0; 00928 if(mPartUsePhysModel) { 00929 // 1-10 00930 newPartsize += 9.0* (rand()/(RAND_MAX+1.0)); 00931 } else { 00932 // 1-5, overall size has to be less than 00933 // .62 (ca. 0.5) to make drops significantly smaller 00934 // than a full cell! 00935 newPartsize += 4.0* (rand()/(RAND_MAX+1.0)); 00936 } 00937 LbmFloat dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); //PARTMASS(mPartDropMassSub*newPartsize); // mass: 4/3 pi r^3 rho 00938 while(dropmass>mass) { 00939 newPartsize -= 0.2; 00940 dropmass = ParticleObject::getMass(mPartDropMassSub*newPartsize); 00941 } 00942 if(newPartsize<=1.) doAdd=false; 00943 00944 if( (doAdd) ) { // init new particle 00945 for(int s=0; s<1; s++) { // one part! 00946 const LbmFloat posjitter = 0.05; 00947 const LbmFloat posjitteroffs = posjitter*-0.5; 00948 LbmFloat jpx = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); 00949 LbmFloat jpy = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); 00950 LbmFloat jpz = posjitteroffs+ posjitter* (rand()/(RAND_MAX+1.0)); 00951 00952 const LbmFloat jitterstr = 1.0; 00953 const LbmFloat jitteroffs = jitterstr*-0.5; 00954 LbmFloat jx = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); 00955 LbmFloat jy = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); 00956 LbmFloat jz = jitteroffs+ jitterstr* (rand()/(RAND_MAX+1.0)); 00957 00958 // average normal & velocity 00959 // -> mostly along velocity dir, many into surface 00960 // fluid velocity (not normalized!) 00961 LbmVec flvelVel = LbmVec(ux,uy,uz); 00962 LbmFloat flvelLen = norm(flvelVel); 00963 // surface normal 00964 LbmVec normVel = LbmVec(surfaceNormal[0],surfaceNormal[1],surfaceNormal[2]); 00965 normalize(normVel); 00966 LbmFloat normScale = (0.01+flvelLen); 00967 // jitter vector, 0.2 * flvel 00968 LbmVec jittVel = LbmVec(jx,jy,jz)*(0.05+flvelLen)*0.1; 00969 // weighten velocities 00970 const LbmFloat flvelWeight = 0.9; 00971 LbmVec newpartVel = normVel*normScale*(1.-flvelWeight) + flvelVel*(flvelWeight) + jittVel; 00972 00973 // offset towards surface (hide popping) 00974 jpx += -normVel[0]*0.4; 00975 jpy += -normVel[1]*0.4; 00976 jpz += -normVel[2]*0.4; 00977 00978 LbmFloat srci=i+0.5+jpx, srcj=j+0.5+jpy, srck=k+0.5+jpz; 00979 int type=0; 00980 type = PART_DROP; 00981 00982 # if LBMDIM==2 00983 newpartVel[2]=0.; srck=0.5; 00984 # endif // LBMDIM==2 00985 // subtract drop mass 00986 mass -= dropmass; 00987 // init new particle 00988 { 00989 ParticleObject np( ntlVec3Gfx(srci,srcj,srck) ); 00990 np.setVel(newpartVel[0],newpartVel[1],newpartVel[2]); 00991 np.setStatus(PART_IN); 00992 np.setType(type); 00993 //if((s%3)==2) np.setType(PART_FLOAT); 00994 np.setSize(newPartsize); 00995 //errMsg("NEWPART"," at "<<PRINT_IJK<<" u="<<norm(LbmVec(ux,uy,uz)) <<" add"<<doAdd<<" pvel="<<norm(newpartVel)<<" size="<<newPartsize ); 00996 //errMsg("NEWPT","u="<<newpartVel<<" norm="<<normVel<<" flvel="<<flvelVel<<" jitt="<<jittVel ); 00997 FSGR_ADDPART(np); 00998 } // new part 00999 //errMsg("PIT","NEW pit"<<np.getId()<<" pos:"<< np.getPos()<<" status:"<<convertFlags2String(np.getFlags())<<" vel:"<< np.getVel() ); 01000 } // multiple parts 01001 } // doAdd 01002 } // */ 01003 01004 01005 // interface cell filled or emptied? 01006 iffilled = ifemptied = 0; 01007 // interface cells empty/full?, WARNING: to mark these cells, better do it at the end of reinitCellFlags 01008 // interface cell if full? 01009 if( (mass) >= (rho * (1.0+FSGR_MAGICNR)) ) { iffilled = 1; } 01010 // interface cell if empty? 01011 if( (mass) <= (rho * ( -FSGR_MAGICNR)) ) { ifemptied = 1; } 01012 01013 if(oldFlag & (CFMbndOutflow)) { 01014 mInitialMass -= mass; 01015 mass = myfrac = 0.0; 01016 iffilled = 0; ifemptied = 1; 01017 } 01018 01019 // looks much nicer... LISTTRICK 01020 # if FSGR_LISTTRICK==1 01021 //if((oldFlag&CFNoNbEmpty)&&(newFlag&CFNoNbEmpty)) { TEST_IF_CHECK; } 01022 if(newFlag&CFNoBndFluid) { // test NEW TEST 01023 if(!iffilled) { 01024 // remove cells independent from amount of change... 01025 if( (oldFlag & CFNoNbEmpty)&&(newFlag & CFNoNbEmpty)&& 01026 ( (mass>(rho*FSGR_LISTTTHRESHFULL)) || ((nbored&CFInter)==0) )) { 01027 //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","filled "<<PRINT_IJK); }; 01028 iffilled = 1; 01029 } 01030 } 01031 if(!ifemptied) { 01032 if( (oldFlag & CFNoNbFluid)&&(newFlag & CFNoNbFluid)&& 01033 ( (mass<(rho*FSGR_LISTTTHRESHEMPTY)) || ((nbored&CFInter)==0) )) { 01034 //if((nbored&CFInter)==0){ errMsg("NBORED!CFINTER","emptied "<<PRINT_IJK); }; 01035 ifemptied = 1; 01036 } 01037 } 01038 } // nobndfluid only */ 01039 # endif 01040 //iffilled = ifemptied = 0; // DEBUG!!!!!!!!!!!!!!! 01041 01042 01043 // now that all dfs are known, handle last changes 01044 if(iffilled) { 01045 LbmPoint filledp; filledp.flag=0; 01046 if(!(newFlag&CFNoBndFluid)) filledp.flag |= 1; // NEWSURFT 01047 filledp.x = i; filledp.y = j; filledp.z = k; 01048 LIST_FULL(filledp); 01049 //mNumFilledCells++; // DEBUG 01050 calcCellsFilled++; 01051 } 01052 else if(ifemptied) { 01053 LbmPoint emptyp; emptyp.flag=0; 01054 if(!(newFlag&CFNoBndFluid)) emptyp.flag |= 1; // NEWSURFT 01055 emptyp.x = i; emptyp.y = j; emptyp.z = k; 01056 LIST_EMPTY(emptyp); 01057 //mNumEmptiedCells++; // DEBUG 01058 calcCellsEmptied++; 01059 } 01060 // dont cutoff values -> better cell conversions 01061 RAC(tcel,dFfrac) = (mass/rho); 01062 01063 // init new flux value 01064 float flux = FLUX_INIT; // dxqn on 01065 if(newFlag&CFNoBndFluid) { 01066 //flux = 50.0; // extreme on 01067 for(int nn=1; nn<this->cDfNum; nn++) { 01068 if(nbflag[nn] & (CFFluid|CFInter|CFBnd)) { flux += this->dfLength[nn]; } 01069 } 01070 // optical hack - smooth slow moving 01071 // surface regions 01072 if(usqr< sssUsqrLimit) { 01073 for(int nn=1; nn<this->cDfNum; nn++) { 01074 if(nbfracs[nn]!=0.0) { 01075 LbmFloat curSmooth = (sssUsqrLimit-usqr)*sssUsqrLimitInv; 01076 if(curSmooth>1.0) curSmooth=1.0; 01077 flux *= (1.0+ smoothStrength*curSmooth * (nbfracs[nn]-myfrac)) ; 01078 } 01079 } } 01080 // NEW TEST */ 01081 } 01082 // flux = FLUX_INIT; // calc flux off 01083 QCELL(lev, i,j,k,TSET(lev), dFlux) = flux; // */ 01084 01085 // perform mass exchange with streamed values 01086 QCELL(lev, i,j,k,TSET(lev), dMass) = mass; // MASST 01087 // set new flag 01088 *pFlagDst = (CellFlagType)newFlag; 01089 calcCurrentMass += mass; 01090 calcCurrentVolume += RAC(tcel,dFfrac); 01091 01092 // interface cell handling done... 01093 01094 #if PARALLEL!=1 01095 GRID_LOOPREG_END(); 01096 #else // PARALLEL==1 01097 #include "paraloopend.h" // = GRID_LOOPREG_END(); 01098 #endif // PARALLEL==1 01099 01100 // write vars from computations to class 01101 mLevel[lev].lmass = calcCurrentMass; 01102 mLevel[lev].lvolume = calcCurrentVolume; 01103 mNumFilledCells = calcCellsFilled; 01104 mNumEmptiedCells = calcCellsEmptied; 01105 mNumUsedCells = calcNumUsedCells; 01106 } 01107 01108 01109 01110 void 01111 LbmFsgrSolver::preinitGrids() 01112 { 01113 const int lev = mMaxRefine; 01114 const bool doReduce = false; 01115 const int gridLoopBound=0; 01116 01117 // preinit both grids 01118 for(int s=0; s<2; s++) { 01119 01120 GRID_REGION_INIT(); 01121 #if PARALLEL==1 01122 #pragma omp parallel default(shared) \ 01123 reduction(+: \ 01124 calcCurrentMass,calcCurrentVolume, \ 01125 calcCellsFilled,calcCellsEmptied, \ 01126 calcNumUsedCells ) 01127 #endif // PARALLEL==1 01128 GRID_REGION_START(); 01129 GRID_LOOP_START(); 01130 for(int l=0; l<dTotalNum; l++) { RAC(ccel,l) = 0.; } 01131 *pFlagSrc =0; 01132 *pFlagDst =0; 01133 //errMsg("l1"," at "<<PRINT_IJK<<" id"<<id); 01134 #if PARALLEL!=1 01135 GRID_LOOPREG_END(); 01136 #else // PARALLEL==1 01137 #include "paraloopend.h" // = GRID_LOOPREG_END(); 01138 #endif // PARALLEL==1 01139 01140 /* dummy, remove warnings */ 01141 calcCurrentMass = calcCurrentVolume = 0.; 01142 calcCellsFilled = calcCellsEmptied = calcNumUsedCells = 0; 01143 01144 // change grid 01145 mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr; 01146 mLevel[mMaxRefine].setCurr ^= 1; 01147 } 01148 } 01149 01150 void 01151 LbmFsgrSolver::standingFluidPreinit() 01152 { 01153 const int lev = mMaxRefine; 01154 const bool doReduce = false; 01155 const int gridLoopBound=1; 01156 01157 GRID_REGION_INIT(); 01158 #if PARALLEL==1 01159 #pragma omp parallel default(shared) \ 01160 reduction(+: \ 01161 calcCurrentMass,calcCurrentVolume, \ 01162 calcCellsFilled,calcCellsEmptied, \ 01163 calcNumUsedCells ) 01164 #endif // PARALLEL==1 01165 GRID_REGION_START(); 01166 01167 LbmFloat rho, ux,uy,uz, usqr; 01168 CellFlagType nbflag[LBM_DFNUM]; 01169 LbmFloat m[LBM_DFNUM]; 01170 LbmFloat lcsmqo; 01171 # if OPT3D==1 01172 LbmFloat lcsmqadd, lcsmeq[LBM_DFNUM], lcsmomega; 01173 CellFlagType nbored=0; 01174 # endif // OPT3D==true 01175 01176 GRID_LOOP_START(); 01177 //errMsg("l1"," at "<<PRINT_IJK<<" id"<<id); 01178 const CellFlagType currFlag = *pFlagSrc; //RFLAG(lev, i,j,k,workSet); 01179 if( (currFlag & (CFEmpty|CFBnd)) ) continue; 01180 01181 if( (currFlag & (CFInter)) ) { 01182 // copy all values 01183 for(int l=0; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); } 01184 continue; 01185 } 01186 01187 if( (currFlag & CFNoBndFluid)) { 01188 OPTIMIZED_STREAMCOLLIDE; 01189 } else { 01190 FORDF1 { 01191 nbflag[l] = RFLAG_NB(lev, i,j,k, SRCS(lev),l); 01192 } 01193 DEFAULT_STREAM; 01194 DEFAULT_COLLIDEG(mLevel[lev].gravity); 01195 } 01196 for(int l=LBM_DFNUM; l<dTotalNum;l++) { RAC(tcel,l) = RAC(ccel,l); } 01197 #if PARALLEL!=1 01198 GRID_LOOPREG_END(); 01199 #else // PARALLEL==1 01200 #include "paraloopend.h" // = GRID_LOOPREG_END(); 01201 #endif // PARALLEL==1 01202 01203 /* dummy remove warnings */ 01204 calcCurrentMass = calcCurrentVolume = 0.; 01205 calcCellsFilled = calcCellsEmptied = calcNumUsedCells = 0; 01206 01207 // change grid 01208 mLevel[mMaxRefine].setOther = mLevel[mMaxRefine].setCurr; 01209 mLevel[mMaxRefine].setCurr ^= 1; 01210 } 01211 01212 01213 /****************************************************************************** 01214 * work on lists from updateCellMass to reinit cell flags 01215 *****************************************************************************/ 01216 01217 LbmFloat LbmFsgrSolver::getMassdWeight(bool dirForw, int i,int j,int k,int workSet, int l) { 01218 //return 0.0; // test 01219 int level = mMaxRefine; 01220 LbmFloat *ccel = RACPNT(level, i,j,k, workSet); 01221 01222 // computenormal 01223 CellFlagType *cflag = &RFLAG(level, i,j,k, workSet); 01224 LbmFloat n[3]; 01225 computeFluidSurfaceNormal(ccel,cflag, n); 01226 LbmFloat scal = mDvecNrm[l][0]*n[0] + mDvecNrm[l][1]*n[1] + mDvecNrm[l][2]*n[2]; 01227 01228 LbmFloat ret = 1.0; 01229 // forward direction, add mass (for filling cells): 01230 if(dirForw) { 01231 if(scal<LBM_EPSILON) ret = 0.0; 01232 else ret = scal; 01233 } else { 01234 // backward for emptying 01235 if(scal>-LBM_EPSILON) ret = 0.0; 01236 else ret = scal * -1.0; 01237 } 01238 //errMsg("massd", PRINT_IJK<<" nv"<<nvel<<" : ret="<<ret ); //xit(1); //VECDEB 01239 return ret; 01240 } 01241 01242 // warning - normal compuations are without 01243 // boundary checks & 01244 // normalization 01245 void LbmFsgrSolver::computeFluidSurfaceNormal(LbmFloat *ccel, CellFlagType *cflagpnt,LbmFloat *snret) { 01246 const int level = mMaxRefine; 01247 LbmFloat nx,ny,nz, nv1,nv2; 01248 const CellFlagType flagE = *(cflagpnt+1); 01249 const CellFlagType flagW = *(cflagpnt-1); 01250 if(flagE &(CFFluid|CFInter)){ nv1 = RAC((ccel+QCELLSTEP ),dFfrac); } 01251 else if(flagE &(CFBnd)){ nv1 = 1.; } 01252 else nv1 = 0.0; 01253 if(flagW &(CFFluid|CFInter)){ nv2 = RAC((ccel-QCELLSTEP ),dFfrac); } 01254 else if(flagW &(CFBnd)){ nv2 = 1.; } 01255 else nv2 = 0.0; 01256 nx = 0.5* (nv2-nv1); 01257 01258 const CellFlagType flagN = *(cflagpnt+mLevel[level].lOffsx); 01259 const CellFlagType flagS = *(cflagpnt-mLevel[level].lOffsx); 01260 if(flagN &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); } 01261 else if(flagN &(CFBnd)){ nv1 = 1.; } 01262 else nv1 = 0.0; 01263 if(flagS &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsx*QCELLSTEP)),dFfrac); } 01264 else if(flagS &(CFBnd)){ nv2 = 1.; } 01265 else nv2 = 0.0; 01266 ny = 0.5* (nv2-nv1); 01267 01268 #if LBMDIM==3 01269 const CellFlagType flagT = *(cflagpnt+mLevel[level].lOffsy); 01270 const CellFlagType flagB = *(cflagpnt-mLevel[level].lOffsy); 01271 if(flagT &(CFFluid|CFInter)){ nv1 = RAC((ccel+(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); } 01272 else if(flagT &(CFBnd)){ nv1 = 1.; } 01273 else nv1 = 0.0; 01274 if(flagB &(CFFluid|CFInter)){ nv2 = RAC((ccel-(mLevel[level].lOffsy*QCELLSTEP)),dFfrac); } 01275 else if(flagB &(CFBnd)){ nv2 = 1.; } 01276 else nv2 = 0.0; 01277 nz = 0.5* (nv2-nv1); 01278 #else //LBMDIM==3 01279 nz = 0.0; 01280 #endif //LBMDIM==3 01281 01282 // return vals 01283 snret[0]=nx; snret[1]=ny; snret[2]=nz; 01284 } 01285 void LbmFsgrSolver::computeFluidSurfaceNormalAcc(LbmFloat *ccel, CellFlagType *cflagpnt, LbmFloat *snret) { 01286 LbmFloat nx=0.,ny=0.,nz=0.; 01287 ccel = NULL; cflagpnt=NULL; // remove warning 01288 snret[0]=nx; snret[1]=ny; snret[2]=nz; 01289 } 01290 void LbmFsgrSolver::computeObstacleSurfaceNormal(LbmFloat *ccel, CellFlagType *cflagpnt, LbmFloat *snret) { 01291 const int level = mMaxRefine; 01292 LbmFloat nx,ny,nz, nv1,nv2; 01293 ccel = NULL; // remove warning 01294 01295 const CellFlagType flagE = *(cflagpnt+1); 01296 const CellFlagType flagW = *(cflagpnt-1); 01297 if(flagE &(CFBnd)){ nv1 = 1.; } 01298 else nv1 = 0.0; 01299 if(flagW &(CFBnd)){ nv2 = 1.; } 01300 else nv2 = 0.0; 01301 nx = 0.5* (nv2-nv1); 01302 01303 const CellFlagType flagN = *(cflagpnt+mLevel[level].lOffsx); 01304 const CellFlagType flagS = *(cflagpnt-mLevel[level].lOffsx); 01305 if(flagN &(CFBnd)){ nv1 = 1.; } 01306 else nv1 = 0.0; 01307 if(flagS &(CFBnd)){ nv2 = 1.; } 01308 else nv2 = 0.0; 01309 ny = 0.5* (nv2-nv1); 01310 01311 #if LBMDIM==3 01312 const CellFlagType flagT = *(cflagpnt+mLevel[level].lOffsy); 01313 const CellFlagType flagB = *(cflagpnt-mLevel[level].lOffsy); 01314 if(flagT &(CFBnd)){ nv1 = 1.; } 01315 else nv1 = 0.0; 01316 if(flagB &(CFBnd)){ nv2 = 1.; } 01317 else nv2 = 0.0; 01318 nz = 0.5* (nv2-nv1); 01319 #else //LBMDIM==3 01320 nz = 0.0; 01321 #endif //LBMDIM==3 01322 01323 // return vals 01324 snret[0]=nx; snret[1]=ny; snret[2]=nz; 01325 } 01326 void LbmFsgrSolver::computeObstacleSurfaceNormalAcc(int i,int j,int k, LbmFloat *snret) { 01327 bool nonorm = false; 01328 LbmFloat nx=0.,ny=0.,nz=0.; 01329 if(i<=0) { nx = 1.; nonorm = true; } 01330 if(i>=mSizex-1) { nx = -1.; nonorm = true; } 01331 if(j<=0) { ny = 1.; nonorm = true; } 01332 if(j>=mSizey-1) { ny = -1.; nonorm = true; } 01333 # if LBMDIM==3 01334 if(k<=0) { nz = 1.; nonorm = true; } 01335 if(k>=mSizez-1) { nz = -1.; nonorm = true; } 01336 # endif // LBMDIM==3 01337 if(!nonorm) { 01338 // in domain, revert to helper, use setCurr&mMaxRefine 01339 LbmVec bnormal; 01340 CellFlagType *bflag = &RFLAG(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr); 01341 LbmFloat *bcell = RACPNT(mMaxRefine, i,j,k, mLevel[mMaxRefine].setCurr); 01342 computeObstacleSurfaceNormal(bcell,bflag, &bnormal[0]); 01343 // TODO check if there is a normal near here? 01344 // use wider range otherwise... 01345 snret[0]=bnormal[0]; snret[1]=bnormal[0]; snret[2]=bnormal[0]; 01346 return; 01347 } 01348 snret[0]=nx; snret[1]=ny; snret[2]=nz; 01349 } 01350 01351 void LbmFsgrSolver::addToNewInterList( int ni, int nj, int nk ) { 01352 #if FSGR_STRICT_DEBUG==10 01353 // dangerous, this can change the simulation... 01354 /*for( vector<LbmPoint>::iterator iter=mListNewInter.begin(); 01355 iter != mListNewInter.end(); iter++ ) { 01356 if(ni!=iter->x) continue; 01357 if(nj!=iter->y) continue; 01358 if(nk!=iter->z) continue; 01359 // all 3 values match... skip point 01360 return; 01361 } */ 01362 #endif // FSGR_STRICT_DEBUG==1 01363 // store point 01364 LbmPoint newinter; newinter.flag = 0; 01365 newinter.x = ni; newinter.y = nj; newinter.z = nk; 01366 mListNewInter.push_back(newinter); 01367 } 01368 01369 void LbmFsgrSolver::reinitFlags( int workSet ) { 01370 // reinitCellFlags OLD mods: 01371 // add all to intel list? 01372 // check ffrac for new cells 01373 // new if cell inits (last loop) 01374 // vweights handling 01375 01376 const int debugFlagreinit = 0; 01377 01378 // some things need to be read/modified on the other set 01379 int otherSet = (workSet^1); 01380 // fixed level on which to perform 01381 int workLev = mMaxRefine; 01382 01383 /* modify interface cells from lists */ 01384 /* mark filled interface cells as fluid, or emptied as empty */ 01385 /* count neighbors and distribute excess mass to interface neighbor cells 01386 * problems arise when there are no interface neighbors anymore 01387 * then just distribute to any fluid neighbors... 01388 */ 01389 01390 // for symmetry, first init all neighbor cells */ 01391 for( vector<LbmPoint>::iterator iter=mListFull.begin(); 01392 iter != mListFull.end(); iter++ ) { 01393 int i=iter->x, j=iter->y, k=iter->z; 01394 if(debugFlagreinit) errMsg("FULL", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM 01395 FORDF1 { 01396 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; 01397 //if((LBMDIM>2)&&( (ni<=0) || (nj<=0) || (nk<=0) || (ni>=mLevel[workLev].lSizex-1) || (nj>=mLevel[workLev].lSizey-1) || (nk>=mLevel[workLev].lSizez-1) )) { 01398 if( (ni<=0) || (nj<=0) || 01399 (ni>=mLevel[workLev].lSizex-1) || 01400 (nj>=mLevel[workLev].lSizey-1) 01401 # if LBMDIM==3 01402 || (nk<=0) || (nk>=mLevel[workLev].lSizez-1) 01403 # endif // LBMDIM==1 01404 ) { 01405 continue; } // new bc, dont treat cells on boundary NEWBC 01406 if( RFLAG(workLev, ni,nj,nk, workSet) & CFEmpty ){ 01407 01408 // preinit speed, get from average surrounding cells 01409 // interpolate from non-workset to workset, sets are handled in function 01410 01411 // new and empty interface cell, dont change old flag here! 01412 addToNewInterList(ni,nj,nk); 01413 01414 LbmFloat avgrho = 0.0; 01415 LbmFloat avgux = 0.0, avguy = 0.0, avguz = 0.0; 01416 interpolateCellValues(workLev,ni,nj,nk,workSet, avgrho,avgux,avguy,avguz); 01417 01418 // careful with l's... 01419 FORDF0M { 01420 QCELL(workLev,ni,nj,nk, workSet, m) = this->getCollideEq( m,avgrho, avgux, avguy, avguz ); 01421 //QCELL(workLev,ni,nj,nk, workSet, l) = avgnbdf[l]; // CHECK FIXME test? 01422 } 01423 //errMsg("FNEW", PRINT_VEC(ni,nj,nk)<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<<avgrho<<" vel"<<PRINT_VEC(avgux,avguy,avguz) ); // DEBUG SYMM 01424 QCELL(workLev,ni,nj,nk, workSet, dMass) = 0.0; //?? new 01425 QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 0.0; //?? new 01426 //RFLAG(workLev,ni,nj,nk,workSet) = (CellFlagType)(CFInter|CFNoInterpolSrc); 01427 changeFlag(workLev,ni,nj,nk,workSet, (CFInter|CFNoInterpolSrc)); 01428 if(debugFlagreinit) errMsg("NEWE", PRINT_IJK<<" newif "<<PRINT_VEC(ni,nj,nk)<<" rho"<<avgrho<<" vel("<<avgux<<","<<avguy<<","<<avguz<<") " ); 01429 } 01430 /* prevent surrounding interface cells from getting removed as empty cells 01431 * (also cells that are not newly inited) */ 01432 if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { 01433 //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete); 01434 changeFlag(workLev,ni,nj,nk, workSet, (RFLAG(workLev,ni,nj,nk, workSet) | CFNoDelete)); 01435 // also add to list... 01436 addToNewInterList(ni,nj,nk); 01437 } // NEW? 01438 } 01439 01440 // NEW? no extra loop... 01441 //RFLAG(workLev,i,j,k, workSet) = CFFluid; 01442 changeFlag(workLev,i,j,k, workSet,CFFluid); 01443 } 01444 01445 /* remove empty interface cells that are not allowed to be removed anyway 01446 * this is important, otherwise the dreaded cell-type-flickering can occur! */ 01447 for(int n=0; n<(int)mListEmpty.size(); n++) { 01448 int i=mListEmpty[n].x, j=mListEmpty[n].y, k=mListEmpty[n].z; 01449 if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)) { 01450 // treat as "new inter" 01451 addToNewInterList(i,j,k); 01452 // remove entry 01453 if(debugFlagreinit) errMsg("EMPT REMOVED!!!", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); // DEBUG SYMM 01454 if(n<(int)mListEmpty.size()-1) mListEmpty[n] = mListEmpty[mListEmpty.size()-1]; 01455 mListEmpty.pop_back(); 01456 n--; 01457 } 01458 } 01459 01460 01461 /* problems arise when adjacent cells empty&fill -> 01462 let fill cells+surrounding interface cells have the higher importance */ 01463 for( vector<LbmPoint>::iterator iter=mListEmpty.begin(); 01464 iter != mListEmpty.end(); iter++ ) { 01465 int i=iter->x, j=iter->y, k=iter->z; 01466 if((RFLAG(workLev,i,j,k, workSet)&(CFInter|CFNoDelete)) == (CFInter|CFNoDelete)){ errMsg("A"," ARGHARGRAG "); } // DEBUG 01467 if(debugFlagreinit) errMsg("EMPT", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" rho"<< QCELL(workLev, i,j,k, workSet, 0) ); 01468 01469 /* set surrounding fluid cells to interface cells */ 01470 FORDF1 { 01471 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; 01472 if( RFLAG(workLev,ni,nj,nk, workSet) & CFFluid){ 01473 // init fluid->interface 01474 //RFLAG(workLev,ni,nj,nk, workSet) = (CellFlagType)(CFInter); 01475 changeFlag(workLev,ni,nj,nk, workSet, CFInter); 01476 /* new mass = current density */ 01477 LbmFloat nbrho = QCELL(workLev,ni,nj,nk, workSet, dC); 01478 for(int rl=1; rl< this->cDfNum ; ++rl) { nbrho += QCELL(workLev,ni,nj,nk, workSet, rl); } 01479 QCELL(workLev,ni,nj,nk, workSet, dMass) = nbrho; 01480 QCELL(workLev,ni,nj,nk, workSet, dFfrac) = 1.0; 01481 01482 // store point 01483 addToNewInterList(ni,nj,nk); 01484 } 01485 if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter){ 01486 // test, also add to list... 01487 addToNewInterList(ni,nj,nk); 01488 } // NEW? 01489 } 01490 01491 /* for symmetry, set our flag right now */ 01492 changeFlag(workLev,i,j,k, workSet, CFEmpty); 01493 // mark cell not be changed mass... - not necessary, not in list anymore anyway! 01494 } // emptylist 01495 01496 01497 01498 // precompute weights to get rid of order dependancies 01499 vector<lbmFloatSet> vWeights; 01500 vWeights.resize( mListFull.size() + mListEmpty.size() ); 01501 int weightIndex = 0; 01502 int nbCount = 0; 01503 LbmFloat nbWeights[LBM_DFNUM]; 01504 LbmFloat nbTotWeights = 0.0; 01505 for( vector<LbmPoint>::iterator iter=mListFull.begin(); 01506 iter != mListFull.end(); iter++ ) { 01507 int i=iter->x, j=iter->y, k=iter->z; 01508 nbCount = 0; nbTotWeights = 0.0; 01509 FORDF1 { 01510 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; 01511 if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { 01512 nbCount++; 01513 if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT 01514 else nbWeights[l] = getMassdWeight(1,i,j,k,workSet,l); // NEWSURFT 01515 nbTotWeights += nbWeights[l]; 01516 } else { 01517 nbWeights[l] = -100.0; // DEBUG; 01518 } 01519 } 01520 if(nbCount>0) { 01521 //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights); 01522 vWeights[weightIndex].val[0] = nbTotWeights; 01523 FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; } 01524 vWeights[weightIndex].numNbs = (LbmFloat)nbCount; 01525 } else { 01526 vWeights[weightIndex].numNbs = 0.0; 01527 } 01528 weightIndex++; 01529 } 01530 for( vector<LbmPoint>::iterator iter=mListEmpty.begin(); 01531 iter != mListEmpty.end(); iter++ ) { 01532 int i=iter->x, j=iter->y, k=iter->z; 01533 nbCount = 0; nbTotWeights = 0.0; 01534 FORDF1 { 01535 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; 01536 if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { 01537 nbCount++; 01538 if(iter->flag&1) nbWeights[l] = 1.; // NEWSURFT 01539 else nbWeights[l] = getMassdWeight(0,i,j,k,workSet,l); // NEWSURFT 01540 nbTotWeights += nbWeights[l]; 01541 } else { 01542 nbWeights[l] = -100.0; // DEBUG; 01543 } 01544 } 01545 if(nbCount>0) { 01546 //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeights); 01547 vWeights[weightIndex].val[0] = nbTotWeights; 01548 FORDF1 { vWeights[weightIndex].val[l] = nbWeights[l]; } 01549 vWeights[weightIndex].numNbs = (LbmFloat)nbCount; 01550 } else { 01551 vWeights[weightIndex].numNbs = 0.0; 01552 } 01553 weightIndex++; 01554 } 01555 weightIndex = 0; 01556 01557 01558 /* process full list entries, filled cells are done after this loop */ 01559 for( vector<LbmPoint>::iterator iter=mListFull.begin(); 01560 iter != mListFull.end(); iter++ ) { 01561 int i=iter->x, j=iter->y, k=iter->z; 01562 01563 LbmFloat myrho = QCELL(workLev,i,j,k, workSet, dC); 01564 FORDF1 { myrho += QCELL(workLev,i,j,k, workSet, l); } // QCELL.rho 01565 01566 LbmFloat massChange = QCELL(workLev,i,j,k, workSet, dMass) - myrho; 01567 if(vWeights[weightIndex].numNbs>0.0) { 01568 const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0]; 01569 //errMsg("FF I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeightsp); 01570 FORDF1 { 01571 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; 01572 if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { 01573 LbmFloat change = -1.0; 01574 if(nbTotWeightsp>0.0) { 01575 //change = massChange * ( nbWeights[l]/nbTotWeightsp ); 01576 change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp ); 01577 } else { 01578 change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs); 01579 } 01580 QCELL(workLev,ni,nj,nk, workSet, dMass) += change; 01581 } 01582 } 01583 massChange = 0.0; 01584 } else { 01585 // Problem! no interface neighbors 01586 mFixMass += massChange; 01587 //TTT mNumProblems++; 01588 //errMsg(" FULL PROBLEM ", PRINT_IJK<<" "<<mFixMass); 01589 } 01590 weightIndex++; 01591 01592 // already done? RFLAG(workLev,i,j,k, workSet) = CFFluid; 01593 QCELL(workLev,i,j,k, workSet, dMass) = myrho; // should be rho... but unused? 01594 QCELL(workLev,i,j,k, workSet, dFfrac) = 1.0; // should be rho... but unused? 01595 } // fulllist 01596 01597 01598 /* now, finally handle the empty cells - order is important, has to be after 01599 * full cell handling */ 01600 for( vector<LbmPoint>::iterator iter=mListEmpty.begin(); 01601 iter != mListEmpty.end(); iter++ ) { 01602 int i=iter->x, j=iter->y, k=iter->z; 01603 01604 LbmFloat massChange = QCELL(workLev, i,j,k, workSet, dMass); 01605 if(vWeights[weightIndex].numNbs>0.0) { 01606 const LbmFloat nbTotWeightsp = vWeights[weightIndex].val[0]; 01607 //errMsg("EE I", PRINT_IJK<<" "<<weightIndex<<" "<<nbTotWeightsp); 01608 FORDF1 { 01609 int ni=i+this->dfVecX[l], nj=j+this->dfVecY[l], nk=k+this->dfVecZ[l]; 01610 if( RFLAG(workLev,ni,nj,nk, workSet) & CFInter) { 01611 LbmFloat change = -1.0; 01612 if(nbTotWeightsp>0.0) { 01613 change = massChange * ( vWeights[weightIndex].val[l]/nbTotWeightsp ); 01614 } else { 01615 change = (LbmFloat)(massChange/vWeights[weightIndex].numNbs); 01616 } 01617 QCELL(workLev, ni,nj,nk, workSet, dMass) += change; 01618 } 01619 } 01620 massChange = 0.0; 01621 } else { 01622 // Problem! no interface neighbors 01623 mFixMass += massChange; 01624 //TTT mNumProblems++; 01625 //errMsg(" EMPT PROBLEM ", PRINT_IJK<<" "<<mFixMass); 01626 } 01627 weightIndex++; 01628 01629 // finally... make it empty 01630 // already done? RFLAG(workLev,i,j,k, workSet) = CFEmpty; 01631 QCELL(workLev,i,j,k, workSet, dMass) = 0.0; 01632 QCELL(workLev,i,j,k, workSet, dFfrac) = 0.0; 01633 } 01634 for( vector<LbmPoint>::iterator iter=mListEmpty.begin(); 01635 iter != mListEmpty.end(); iter++ ) { 01636 int i=iter->x, j=iter->y, k=iter->z; 01637 changeFlag(workLev,i,j,k, otherSet, CFEmpty); 01638 } 01639 01640 01641 // check if some of the new interface cells can be removed again 01642 // never happens !!! not necessary 01643 // calculate ffrac for new IF cells NEW 01644 01645 // how many are really new interface cells? 01646 int numNewIf = 0; 01647 for( vector<LbmPoint>::iterator iter=mListNewInter.begin(); 01648 iter != mListNewInter.end(); iter++ ) { 01649 int i=iter->x, j=iter->y, k=iter->z; 01650 if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { 01651 continue; 01652 // FIXME remove from list? 01653 } 01654 numNewIf++; 01655 } 01656 01657 // redistribute mass, reinit flags 01658 if(debugFlagreinit) errMsg("NEWIF", "total:"<<mListNewInter.size()); 01659 float newIfFac = 1.0/(LbmFloat)numNewIf; 01660 for( vector<LbmPoint>::iterator iter=mListNewInter.begin(); 01661 iter != mListNewInter.end(); iter++ ) { 01662 int i=iter->x, j=iter->y, k=iter->z; 01663 if((i<=0) || (j<=0) || 01664 (i>=mLevel[workLev].lSizex-1) || 01665 (j>=mLevel[workLev].lSizey-1) || 01666 ((LBMDIM==3) && ((k<=0) || (k>=mLevel[workLev].lSizez-1) ) ) 01667 ) { 01668 continue; } // new bc, dont treat cells on boundary NEWBC 01669 if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { 01670 //errMsg("???"," "<<PRINT_IJK); 01671 continue; 01672 } // */ 01673 01674 QCELL(workLev,i,j,k, workSet, dMass) += (mFixMass * newIfFac); 01675 01676 int nbored = 0; 01677 FORDF1 { nbored |= RFLAG_NB(workLev, i,j,k, workSet,l); } 01678 if(!(nbored & CFBndNoslip)) { RFLAG(workLev,i,j,k, workSet) |= CFNoBndFluid; } 01679 if(!(nbored & CFFluid)) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbFluid; } 01680 if(!(nbored & CFEmpty)) { RFLAG(workLev,i,j,k, workSet) |= CFNoNbEmpty; } 01681 01682 if(!(RFLAG(workLev,i,j,k, otherSet)&CFInter)) { 01683 RFLAG(workLev,i,j,k, workSet) = (CellFlagType)(RFLAG(workLev,i,j,k, workSet) | CFNoDelete); 01684 } 01685 if(debugFlagreinit) errMsg("NEWIF", PRINT_IJK<<" mss"<<QCELL(workLev, i,j,k, workSet, dMass) <<" f"<< convertCellFlagType2String(RFLAG(workLev,i,j,k, workSet))<<" wl"<<workLev ); 01686 } 01687 01688 // reinit fill fraction 01689 for( vector<LbmPoint>::iterator iter=mListNewInter.begin(); 01690 iter != mListNewInter.end(); iter++ ) { 01691 int i=iter->x, j=iter->y, k=iter->z; 01692 if(!(RFLAG(workLev,i,j,k, workSet)&CFInter)) { continue; } 01693 01694 initInterfaceVars(workLev, i,j,k, workSet, false); //int level, int i,int j,int k,int workSet, bool initMass) { 01695 //LbmFloat nrho = 0.0; 01696 //FORDF0 { nrho += QCELL(workLev, i,j,k, workSet, l); } 01697 //QCELL(workLev,i,j,k, workSet, dFfrac) = QCELL(workLev,i,j,k, workSet, dMass)/nrho; 01698 //QCELL(workLev,i,j,k, workSet, dFlux) = FLUX_INIT; 01699 } 01700 01701 if(mListNewInter.size()>0){ 01702 //errMsg("FixMassDisted"," fm:"<<mFixMass<<" nif:"<<mListNewInter.size() ); 01703 mFixMass = 0.0; 01704 } 01705 01706 // empty lists for next step 01707 mListFull.clear(); 01708 mListEmpty.clear(); 01709 mListNewInter.clear(); 01710 } // reinitFlags 01711 01712 01713