Blender  V2.59
solver_interface.cpp
Go to the documentation of this file.
00001 
00004 /******************************************************************************
00005  *
00006  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
00007  * All code distributed as part of El'Beem is covered by the version 2 of the 
00008  * GNU General Public License. See the file COPYING for details.
00009  * Copyright 2003-2006 Nils Thuerey
00010  *
00011  * Combined 2D/3D Lattice Boltzmann Interface Class
00012  * contains stuff to be statically compiled
00013  * 
00014  *****************************************************************************/
00015 
00016 /* LBM Files */ 
00017 #include "ntl_matrices.h"
00018 #include "solver_interface.h" 
00019 #include "ntl_ray.h"
00020 #include "ntl_world.h"
00021 #include "elbeem.h"
00022 
00023 
00024 
00025 
00026 /******************************************************************************
00027  * Interface Constructor
00028  *****************************************************************************/
00029 LbmSolverInterface::LbmSolverInterface() :
00030         mPanic( false ),
00031   mSizex(10), mSizey(10), mSizez(10), 
00032   mAllfluid(false), mStepCnt( 0 ),
00033         mFixMass( 0.0 ),
00034   mOmega( 1.0 ),
00035   mGravity(0.0),
00036         mSurfaceTension( 0.0 ), 
00037         mBoundaryEast(  (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth(  (CellFlagType)(CFBnd) ),
00038         mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop(  (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ),
00039   mInitDone( false ),
00040   mInitDensityGradient( false ),
00041         mpSifAttrs( NULL ), mpSifSwsAttrs(NULL), mpParam( NULL ), mpParticles(NULL),
00042         mNumParticlesLost(0), 
00043         mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0),
00044         mDebugVelScale( 0.01 ), mNodeInfoString("+"),
00045         mvGeoStart(-1.0), mvGeoEnd(1.0), mpSimTrafo(NULL),
00046         mAccurateGeoinit(0),
00047         mName("lbm_default") ,
00048         mpIso( NULL ), mIsoValue(0.499),
00049         mSilent(false) , 
00050         mLbmInitId(1) ,
00051         mpGiTree( NULL ),
00052         mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL ),
00053         mRefinementDesired(0),
00054         mOutputSurfacePreview(0), mPreviewFactor(0.25),
00055         mSmoothSurface(1.0), mSmoothNormals(1.0),
00056         mIsoSubdivs(1), mPartGenProb(0.),
00057         mDumpVelocities(false),
00058         mMarkedCells(), mMarkedCellIndex(0),
00059         mDomainBound("noslip"), mDomainPartSlipValue(0.1),
00060         mFarFieldSize(0.), 
00061         mPartDropMassSub(0.1),  // good default
00062         mPartUsePhysModel(false),
00063         mTForceStrength(0.0), 
00064         mCppfStage(0),
00065         mDumpRawText(false),
00066         mDumpRawBinary(false),
00067         mDumpRawBinaryZip(true)
00068 {
00069 #if ELBEEM_PLUGIN==1
00070         if(gDebugLevel<=1) setSilent(true);
00071 #endif
00072         mpSimTrafo = new ntlMat4Gfx(0.0); 
00073         mpSimTrafo->initId();
00074 
00075         if(getenv("ELBEEM_RAWDEBUGDUMP")) { 
00076                 debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2);
00077                 mDumpRawText = true;
00078         }
00079 
00080         if(getenv("ELBEEM_BINDEBUGDUMP")) { 
00081                 debMsgStd("LbmSolverInterface",DM_MSG,"Using env var ELBEEM_RAWDEBUGDUMP, mDumpRawText on",2);
00082                 mDumpRawBinary = true;
00083         }
00084 }
00085 
00086 LbmSolverInterface::~LbmSolverInterface() 
00087 { 
00088         if(mpSimTrafo) delete mpSimTrafo;
00089 }
00090 
00091 
00092 /******************************************************************************
00093  * initialize correct grid sizes given a geometric bounding box
00094  * and desired grid resolutions, all params except maxrefine
00095  * will be modified
00096  *****************************************************************************/
00097 void initGridSizes(int &sizex, int &sizey, int &sizez,
00098                 ntlVec3Gfx &geoStart, ntlVec3Gfx &geoEnd, 
00099                 int mMaxRefine, bool parallel) 
00100 {
00101         // fix size inits to force cubic cells and mult4 level dimensions
00102         const int debugGridsizeInit = 1;
00103   if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Called - size X:"<<sizex<<" Y:"<<sizey<<" Z:"<<sizez<<" "<<geoStart<<","<<geoEnd ,10);
00104 
00105         int maxGridSize = sizex; // get max size
00106         if(sizey>maxGridSize) maxGridSize = sizey;
00107         if(sizez>maxGridSize) maxGridSize = sizez;
00108         LbmFloat maxGeoSize = (geoEnd[0]-geoStart[0]); // get max size
00109         if((geoEnd[1]-geoStart[1])>maxGeoSize) maxGeoSize = (geoEnd[1]-geoStart[1]);
00110         if((geoEnd[2]-geoStart[2])>maxGeoSize) maxGeoSize = (geoEnd[2]-geoStart[2]);
00111         // FIXME better divide max geo size by corresponding resolution rather than max? no prob for rx==ry==rz though
00112         LbmFloat cellSize = (maxGeoSize / (LbmFloat)maxGridSize);
00113   if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Start:"<<geoStart<<" End:"<<geoEnd<<" maxS:"<<maxGeoSize<<" maxG:"<<maxGridSize<<" cs:"<<cellSize, 10);
00114         // force grid sizes according to geom. size, rounded
00115         sizex = (int) ((geoEnd[0]-geoStart[0]) / cellSize +0.5);
00116         sizey = (int) ((geoEnd[1]-geoStart[1]) / cellSize +0.5);
00117         sizez = (int) ((geoEnd[2]-geoStart[2]) / cellSize +0.5);
00118         // match refinement sizes, round downwards to multiple of 4
00119         int sizeMask = 0;
00120         int maskBits = mMaxRefine;
00121         if(parallel==1) maskBits+=2;
00122         for(int i=0; i<maskBits; i++) { sizeMask |= (1<<i); }
00123 
00124         // at least size 4 on coarsest level
00125         int minSize = 4<<mMaxRefine; //(maskBits+2);
00126         if(sizex<minSize) sizex = minSize;
00127         if(sizey<minSize) sizey = minSize;
00128         if(sizez<minSize) sizez = minSize;
00129         
00130         sizeMask = ~sizeMask;
00131   if(debugGridsizeInit) debMsgStd("initGridSizes",DM_MSG,"Size X:"<<sizex<<" Y:"<<sizey<<" Z:"<<sizez<<" m"<<convertFlags2String(sizeMask)<<", maskBits:"<<maskBits<<",minSize:"<<minSize ,10);
00132         sizex &= sizeMask;
00133         sizey &= sizeMask;
00134         sizez &= sizeMask;
00135         // debug
00136         int nextinc = (~sizeMask)+1;
00137   debMsgStd("initGridSizes",DM_MSG,"MPTeffMLtest, curr size:"<<PRINT_VEC(sizex,sizey,sizez)<<", next size:"<<PRINT_VEC(sizex+nextinc,sizey+nextinc,sizez+nextinc) ,10);
00138 
00139         // force geom size to match rounded/modified grid sizes
00140         geoEnd[0] = geoStart[0] + cellSize*(LbmFloat)sizex;
00141         geoEnd[1] = geoStart[1] + cellSize*(LbmFloat)sizey;
00142         geoEnd[2] = geoStart[2] + cellSize*(LbmFloat)sizez;
00143 }
00144 
00145 void calculateMemreqEstimate( int resx,int resy,int resz, 
00146                 int refine, float farfield,
00147                 double *reqret, double *reqretFine, string *reqstr) {
00148         // debug estimation?
00149         const bool debugMemEst = true;
00150         // COMPRESSGRIDS define is not available here, make sure it matches
00151         const bool useGridComp = true;
00152         // make sure we can handle bid numbers here... all double
00153         double memCnt = 0.0;
00154         double ddTotalNum = (double)dTotalNum;
00155         if(reqretFine) *reqretFine = -1.;
00156 
00157         double currResx = (double)resx;
00158         double currResy = (double)resy;
00159         double currResz = (double)resz;
00160         double rcellSize = ((currResx*currResy*currResz) *ddTotalNum);
00161         memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0);
00162         if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"res:"<<PRINT_VEC(currResx,currResy,currResz)<<" rcellSize:"<<rcellSize<<" mc:"<<memCnt, 10);
00163   if(!useGridComp) {
00164                 memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
00165                 if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
00166                 if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," no-comp, mc:"<<memCnt, 10);
00167         } else {
00168                 double compressOffset = (double)(currResx*currResy*ddTotalNum*2.0);
00169                 memCnt += (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
00170                 if(reqretFine) *reqretFine = (double)(sizeof(LbmFloat) * (rcellSize+compressOffset +4.0));
00171                 if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG," w-comp, mc:"<<memCnt, 10);
00172         }
00173         for(int i=refine-1; i>=0; i--) {
00174                 currResx /= 2.0;
00175                 currResy /= 2.0;
00176                 currResz /= 2.0;
00177                 rcellSize = ((currResz*currResy*currResx) *ddTotalNum);
00178                 memCnt += (double)(sizeof(CellFlagType) * (rcellSize/ddTotalNum +4.0) *2.0);
00179                 memCnt += (double)(sizeof(LbmFloat) * (rcellSize +4.0) *2.0);
00180                 if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"refine "<<i<<", mc:"<<memCnt, 10);
00181         }
00182 
00183         // isosurface memory, use orig res values
00184         if(farfield>0.) {
00185                 memCnt += (double)( (3*sizeof(int)+sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) );
00186         } else {
00187                 // ignore 3 int slices...
00188                 memCnt += (double)( (              sizeof(float)) * ((resx+2)*(resy+2)*(resz+2)) );
00189         }
00190         if(debugMemEst) debMsgStd("calculateMemreqEstimate",DM_MSG,"iso, mc:"<<memCnt, 10);
00191 
00192         // cpdata init check missing...
00193 
00194         double memd = memCnt;
00195         const char *sizeStr = "";
00196         const double sfac = 1024.0;
00197         if(memd>sfac){ memd /= sfac; sizeStr="KB"; }
00198         if(memd>sfac){ memd /= sfac; sizeStr="MB"; }
00199         if(memd>sfac){ memd /= sfac; sizeStr="GB"; }
00200         if(memd>sfac){ memd /= sfac; sizeStr="TB"; }
00201 
00202         // return values
00203         std::ostringstream ret;
00204         if(memCnt< 1024.0*1024.0) {
00205                 // show full MBs
00206                 ret << (ceil(memd));
00207         } else {
00208                 // two digits for anything larger than MB
00209                 ret << (ceil(memd*100.0)/100.0);
00210         }
00211         ret     << " "<< sizeStr;
00212         *reqret = memCnt;
00213         *reqstr = ret.str();
00214         //debMsgStd("LbmFsgrSolver::initialize",DM_MSG,"Required Grid memory: "<< memd <<" "<< sizeStr<<" ",4);
00215 }
00216 
00217 void LbmSolverInterface::initDomainTrafo(float *mat) { 
00218         mpSimTrafo->initArrayCheck(mat); 
00219 }
00220 
00221 /*******************************************************************************/
00223 CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) {
00224         string val  = mpSifAttrs->readString(name, "", source, target, needed);
00225         if(!strcmp(val.c_str(),"")) {
00226                 // no value given...
00227                 return CFEmpty;
00228         }
00229         if(!strcmp(val.c_str(),"bnd_no")) {
00230                 return (CellFlagType)( CFBnd );
00231         }
00232         if(!strcmp(val.c_str(),"bnd_free")) {
00233                 return (CellFlagType)( CFBnd );
00234         }
00235         if(!strcmp(val.c_str(),"fluid")) {
00236                 /* might be used for some in/out flow cases */
00237                 return (CellFlagType)( CFFluid );
00238         }
00239         errMsg("LbmSolverInterface::readBoundaryFlagInt","Invalid value '"<<val<<"' " );
00240 # if FSGR_STRICT_DEBUG==1
00241         errFatal("readBoundaryFlagInt","Strict abort..."<<val, SIMWORLD_INITERROR);
00242 # endif
00243         return defaultValue;
00244 }
00245 
00246 /*******************************************************************************/
00248 void LbmSolverInterface::parseStdAttrList() {
00249         if(!mpSifAttrs) {
00250                 errFatal("LbmSolverInterface::parseAttrList","mpSifAttrs pointer not initialized!",SIMWORLD_INITERROR);
00251                 return; }
00252 
00253         // st currently unused
00254         mBoundaryEast  = readBoundaryFlagInt("boundary_east",  mBoundaryEast, "LbmSolverInterface", "mBoundaryEast", false);
00255         mBoundaryWest  = readBoundaryFlagInt("boundary_west",  mBoundaryWest, "LbmSolverInterface", "mBoundaryWest", false);
00256         mBoundaryNorth = readBoundaryFlagInt("boundary_north", mBoundaryNorth,"LbmSolverInterface", "mBoundaryNorth", false);
00257         mBoundarySouth = readBoundaryFlagInt("boundary_south", mBoundarySouth,"LbmSolverInterface", "mBoundarySouth", false);
00258         mBoundaryTop   = readBoundaryFlagInt("boundary_top",   mBoundaryTop,"LbmSolverInterface", "mBoundaryTop", false);
00259         mBoundaryBottom= readBoundaryFlagInt("boundary_bottom", mBoundaryBottom,"LbmSolverInterface", "mBoundaryBottom", false);
00260 
00261         mpSifAttrs->readMat4Gfx("domain_trafo" , (*mpSimTrafo), "ntlBlenderDumper","mpSimTrafo", false, mpSimTrafo ); 
00262 
00263         LbmVec sizeVec(mSizex,mSizey,mSizez);
00264         sizeVec = vec2L( mpSifAttrs->readVec3d("size",  vec2P(sizeVec), "LbmSolverInterface", "sizeVec", false) );
00265         mSizex = (int)sizeVec[0]; 
00266         mSizey = (int)sizeVec[1]; 
00267         mSizez = (int)sizeVec[2];
00268         // param needs size in any case
00269         // test solvers might not have mpPara, though
00270         if(mpParam) mpParam->setSize(mSizex, mSizey, mSizez ); 
00271 
00272         mInitDensityGradient = mpSifAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmSolverInterface", "mInitDensityGradient", false);
00273         mIsoValue = mpSifAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false );
00274 
00275         mDebugVelScale = mpSifAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmSolverInterface", "mDebugVelScale", false);
00276         mNodeInfoString = mpSifAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false );
00277 
00278         mDumpVelocities = mpSifAttrs->readBool("dump_velocities", mDumpVelocities, "SimulationLbm","mDumpVelocities", false );
00279         if(getenv("ELBEEM_DUMPVELOCITIES")) {
00280                 int get = atoi(getenv("ELBEEM_DUMPVELOCITIES"));
00281                 if((get==0)||(get==1)) {
00282                         mDumpVelocities = get;
00283                         debMsgStd("LbmSolverInterface::parseAttrList",DM_NOTIFY,"Using envvar ELBEEM_DUMPVELOCITIES to set mDumpVelocities to "<<get<<","<<mDumpVelocities,8);
00284                 }
00285         }
00286         
00287         // new test vars
00288         // mTForceStrength set from test solver 
00289         mFarFieldSize = mpSifAttrs->readFloat("farfieldsize", mFarFieldSize,"LbmSolverInterface", "mFarFieldSize", false);
00290         // old compat
00291         float sizeScale = mpSifAttrs->readFloat("test_scale", 0.,"LbmTestdata", "mSizeScale", false);
00292         if((mFarFieldSize<=0.)&&(sizeScale>0.)) { mFarFieldSize=sizeScale; errMsg("LbmTestdata","Warning - using mSizeScale..."); }
00293 
00294         mPartDropMassSub = mpSifAttrs->readFloat("part_dropmass", mPartDropMassSub,"LbmSolverInterface", "mPartDropMassSub", false);
00295 
00296         mCppfStage = mpSifAttrs->readInt("cppfstage", mCppfStage,"LbmSolverInterface", "mCppfStage", false);
00297         mPartGenProb = mpSifAttrs->readFloat("partgenprob", mPartGenProb,"LbmFsgrSolver", "mPartGenProb", false);
00298         mPartUsePhysModel = mpSifAttrs->readBool("partusephysmodel", mPartUsePhysModel,"LbmFsgrSolver", "mPartUsePhysModel", false);
00299         mIsoSubdivs = mpSifAttrs->readInt("isosubdivs", mIsoSubdivs,"LbmFsgrSolver", "mIsoSubdivs", false);
00300 }
00301 
00302 
00303 /*******************************************************************************/
00305 /*******************************************************************************/
00306 
00307 /*****************************************************************************/
00309 void LbmSolverInterface::initGeoTree() {
00310         if(mpGlob == NULL) { errFatal("LbmSolverInterface::initGeoTree","Requires globals!",SIMWORLD_INITERROR); return; }
00311         ntlScene *scene = mpGlob->getSimScene();
00312         mpGiObjects = scene->getObjects();
00313         mGiObjInside.resize( mpGiObjects->size() );
00314         mGiObjDistance.resize( mpGiObjects->size() );
00315         mGiObjSecondDist.resize( mpGiObjects->size() );
00316         for(size_t i=0; i<mpGiObjects->size(); i++) { 
00317                 if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true;
00318                 //debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"id:"<<mLbmInitId<<" obj:"<< (*mpGiObjects)[i]->getName() <<" gid:"<<(*mpGiObjects)[i]->getGeoInitId(), 9 );
00319         }
00320         debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<<mAccurateGeoinit, 9)
00321         debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Objects: "<<mpGiObjects->size() ,10);
00322 
00323         if(mpGiTree != NULL) delete mpGiTree;
00324         char treeFlag = (1<<(this->mLbmInitId+4));
00325         mpGiTree = new ntlTree( 
00326 # if FSGR_STRICT_DEBUG!=1
00327                         15, 8,  // TREEwarning - fixed values for depth & maxtriangles here...
00328 # else // FSGR_STRICT_DEBUG==1
00329                         10, 20,  // reduced/slower debugging values
00330 # endif // FSGR_STRICT_DEBUG==1
00331                         scene, treeFlag );
00332 }
00333 
00334 /*****************************************************************************/
00336 void LbmSolverInterface::freeGeoTree() {
00337         if(mpGiTree != NULL) {
00338                 delete mpGiTree;
00339                 mpGiTree = NULL;
00340         }
00341 }
00342 
00343 
00344 int globGeoInitDebug = 0;
00345 int globGICPIProblems = 0;
00346 /*****************************************************************************/
00348 bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance, int shootDir) {
00349         // shift ve ctors to avoid rounding errors
00350         org += ntlVec3Gfx(0.0001);
00351         OId = -1;
00352 
00353         // select shooting direction
00354         ntlVec3Gfx dir = ntlVec3Gfx(1., 0., 0.);
00355         if(shootDir==1) dir = ntlVec3Gfx(0., 1., 0.);
00356         else if(shootDir==2) dir = ntlVec3Gfx(0., 0., 1.);
00357         else if(shootDir==-2) dir = ntlVec3Gfx(0., 0., -1.);
00358         else if(shootDir==-1) dir = ntlVec3Gfx(0., -1., 0.);
00359         
00360         ntlRay ray(org, dir, 0, 1.0, mpGlob);
00361         bool done = false;
00362         bool inside = false;
00363 
00364         vector<int> giObjFirstHistSide;
00365         giObjFirstHistSide.resize( mpGiObjects->size() );
00366         for(size_t i=0; i<mGiObjInside.size(); i++) { 
00367                 mGiObjInside[i] = 0; 
00368                 mGiObjDistance[i] = -1.0; 
00369                 mGiObjSecondDist[i] = -1.0; 
00370                 giObjFirstHistSide[i] = 0; 
00371         }
00372         // if not inside, return distance to first hit
00373         gfxReal firstHit=-1.0;
00374         int     firstOId = -1;
00375         if(globGeoInitDebug) errMsg("IIIstart"," isect "<<org<<" f"<<flags<<" acc"<<mAccurateGeoinit);
00376         
00377         if(mAccurateGeoinit) {
00378                 while(!done) {
00379                         // find first inside intersection
00380                         ntlTriangle *triIns = NULL;
00381                         distance = -1.0;
00382                         ntlVec3Gfx normal(0.0);
00383                         if(shootDir==0) mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
00384                         else            mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
00385                         if(triIns) {
00386                                 ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
00387                                 LbmFloat orientation = dot(normal, dir);
00388                                 OId = triIns->getObjectId();
00389                                 if(orientation<=0.0) {
00390                                         // outside hit
00391                                         normal *= -1.0;
00392                                         mGiObjInside[OId]++;
00393                                         if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = 1;
00394                                         if(globGeoInitDebug) errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
00395                                 } else {
00396                                         // inside hit
00397                                         mGiObjInside[OId]++;
00398                                         if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
00399                                         if(globGeoInitDebug) errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg<<" orient:"<<orientation);
00400                                         if(giObjFirstHistSide[OId]==0) giObjFirstHistSide[OId] = -1;
00401                                 }
00402                                 norg += normal * getVecEpsilon();
00403                                 ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
00404                                 // remember first hit distance, in case we're not 
00405                                 // inside anything
00406                                 if(firstHit<0.0) {
00407                                         firstHit = distance;
00408                                         firstOId = OId;
00409                                 }
00410                         } else {
00411                                 // no more intersections... return false
00412                                 done = true;
00413                         }
00414                 }
00415 
00416                 distance = -1.0;
00417                 for(size_t i=0; i<mGiObjInside.size(); i++) {
00418                         if(mGiObjInside[i]>0) {
00419                                 bool mess = false;
00420                                 if((mGiObjInside[i]%2)==1) {
00421                                         if(giObjFirstHistSide[i] != -1) mess=true;
00422                                 } else {
00423                                         if(giObjFirstHistSide[i] !=  1) mess=true;
00424                                 }
00425                                 if(mess) {
00426                                         //errMsg("IIIproblem","At "<<org<<" obj "<<i<<" inside:"<<mGiObjInside[i]<<" firstside:"<<giObjFirstHistSide[i] );
00427                                         globGICPIProblems++;
00428                                         mGiObjInside[i]++; // believe first hit side...
00429                                 }
00430                         }
00431                 }
00432                 for(size_t i=0; i<mGiObjInside.size(); i++) {
00433                         if(globGeoInitDebug) errMsg("CHIII","i"<<i<<" ins="<<mGiObjInside[i]<<" t"<<mGiObjDistance[i]<<" d"<<distance);
00434                         if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
00435                                 if(  (distance<0.0)                             || // first intersection -> good
00436                                           ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
00437                                                 ) {                                             
00438                                         distance = mGiObjDistance[i];
00439                                         OId = i;
00440                                         inside = true;
00441                                 } 
00442                         }
00443                 }
00444                 if(!inside) {
00445                         distance = firstHit;
00446                         OId = firstOId;
00447                 }
00448                 if(globGeoInitDebug) errMsg("CHIII","i"<<inside<<"  fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
00449 
00450                 return inside;
00451         } else {
00452 
00453                 // find first inside intersection
00454                 ntlTriangle *triIns = NULL;
00455                 distance = -1.0;
00456                 ntlVec3Gfx normal(0.0);
00457                 if(shootDir==0) mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
00458                 else            mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
00459                 if(triIns) {
00460                         // check outside intersect
00461                         LbmFloat orientation = dot(normal, dir);
00462                         if(orientation<=0.0) return false;
00463 
00464                         OId = triIns->getObjectId();
00465                         return true;
00466                 }
00467                 return false;
00468         }
00469 }
00470 bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, const gfxReal halfCellsize, bool &thinHit, bool recurse) {
00471         // shift ve ctors to avoid rounding errors
00472         org += ntlVec3Gfx(0.0001); //?
00473         OId = -1;
00474         ntlRay ray(org, dir, 0, 1.0, mpGlob);
00475         //int insCnt = 0;
00476         bool done = false;
00477         bool inside = false;
00478         for(size_t i=0; i<mGiObjInside.size(); i++) { 
00479                 mGiObjInside[i] = 0; 
00480                 mGiObjDistance[i] = -1.0; 
00481                 mGiObjSecondDist[i] = -1.0; 
00482         }
00483         // if not inside, return distance to first hit
00484         gfxReal firstHit=-1.0;
00485         int     firstOId = -1;
00486         thinHit = false;
00487         
00488         if(mAccurateGeoinit) {
00489                 while(!done) {
00490                         // find first inside intersection
00491                         ntlTriangle *triIns = NULL;
00492                         distance = -1.0;
00493                         ntlVec3Gfx normal(0.0);
00494                         mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
00495                         if(triIns) {
00496                                 ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
00497                                 LbmFloat orientation = dot(normal, dir);
00498                                 OId = triIns->getObjectId();
00499                                 if(orientation<=0.0) {
00500                                         // outside hit
00501                                         normal *= -1.0;
00502                                         //mGiObjDistance[OId] = -1.0;
00503                                         //errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
00504                                 } else {
00505                                         // inside hit
00506                                         //if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
00507                                         //errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
00508                                         if(mGiObjInside[OId]==1) {
00509                                                 // second inside hit
00510                                                 if(mGiObjSecondDist[OId]<0.0) mGiObjSecondDist[OId] = distance;
00511                                         }
00512                                 }
00513                                 mGiObjInside[OId]++;
00514                                 // always store first hit for thin obj init
00515                                 if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
00516 
00517                                 norg += normal * getVecEpsilon();
00518                                 ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
00519                                 // remember first hit distance, in case we're not 
00520                                 // inside anything
00521                                 if(firstHit<0.0) {
00522                                         firstHit = distance;
00523                                         firstOId = OId;
00524                                 }
00525                         } else {
00526                                 // no more intersections... return false
00527                                 done = true;
00528                                 //if(insCnt%2) inside=true;
00529                         }
00530                 }
00531 
00532                 distance = -1.0;
00533                 // standard inside check
00534                 for(size_t i=0; i<mGiObjInside.size(); i++) {
00535                         if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
00536                                 if(  (distance<0.0)                             || // first intersection -> good
00537                                           ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
00538                                                 ) {                                             
00539                                         distance = mGiObjDistance[i];
00540                                         OId = i;
00541                                         inside = true;
00542                                 } 
00543                         }
00544                 }
00545                 // now check for thin hits
00546                 if(!inside) {
00547                         distance = -1.0;
00548                         for(size_t i=0; i<mGiObjInside.size(); i++) {
00549                                 if((mGiObjInside[i]>=2)&&(mGiObjDistance[i]>0.0)&&(mGiObjSecondDist[i]>0.0)&&
00550                                          (mGiObjDistance[i]<1.0*halfCellsize)&&(mGiObjSecondDist[i]<2.0*halfCellsize) ) {
00551                                         if(  (distance<0.0)                             || // first intersection -> good
00552                                                         ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
00553                                                         ) {                                             
00554                                                 distance = mGiObjDistance[i];
00555                                                 OId = i;
00556                                                 inside = true;
00557                                                 thinHit = true;
00558                                         } 
00559                                 }
00560                         }
00561                 }
00562                 if(!inside) {
00563                         // check for hit in this cell, opposite to current dir (only recurse once)
00564                         if(recurse) {
00565                                 gfxReal r_distance;
00566                                 int r_OId;
00567                                 bool ret = geoInitCheckPointInside(org, dir*-1.0, flags, r_OId, r_distance, halfCellsize, thinHit, false);
00568                                 if((ret)&&(thinHit)) {
00569                                         OId = r_OId;
00570                                         distance = 0.0; 
00571                                         return true;
00572                                 }
00573                         }
00574                 }
00575                 // really no hit...
00576                 if(!inside) {
00577                         distance = firstHit;
00578                         OId = firstOId;
00579                         /*if((mGiObjDistance[OId]>0.0)&&(mGiObjSecondDist[OId]>0.0)) {
00580                                 const gfxReal thisdist = mGiObjSecondDist[OId]-mGiObjDistance[OId];
00581                                 // dont walk over this cell...
00582                                 if(thisdist<halfCellsize) distance-=2.0*halfCellsize;
00583                         } // ? */
00584                 }
00585                 //errMsg("CHIII","i"<<inside<<"  fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
00586 
00587                 return inside;
00588         } else {
00589 
00590                 // find first inside intersection
00591                 ntlTriangle *triIns = NULL;
00592                 distance = -1.0;
00593                 ntlVec3Gfx normal(0.0);
00594                 mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
00595                 if(triIns) {
00596                         // check outside intersect
00597                         LbmFloat orientation = dot(normal, dir);
00598                         if(orientation<=0.0) return false;
00599 
00600                         OId = triIns->getObjectId();
00601                         return true;
00602                 }
00603                 return false;
00604         }
00605 }
00606 
00607 
00608 /*****************************************************************************/
00609 ntlVec3Gfx LbmSolverInterface::getGeoMaxMovementVelocity(LbmFloat simtime, LbmFloat stepsize) {
00610         ntlVec3Gfx max(0.0);
00611         if(mpGlob == NULL) return max;
00612         // mpGiObjects has to be inited here...
00613         
00614         for(int i=0; i< (int)mpGiObjects->size(); i++) {
00615                 //errMsg("LbmSolverInterface::getGeoMaxMovementVelocity","i="<<i<<" "<< (*mpGiObjects)[i]->getName() ); // DEBUG
00616                 if( (*mpGiObjects)[i]->getGeoInitType() & (FGI_FLUID|FGI_MBNDINFLOW) ){
00617                         //ntlVec3Gfx objMaxVel = obj->calculateMaxVel(sourceTime,targetTime);
00618                         ntlVec3Gfx orgvel = (*mpGiObjects)[i]->calculateMaxVel( simtime, simtime+stepsize );
00619                         if( normNoSqrt(orgvel) > normNoSqrt(max) ) { max = orgvel; } 
00620                         //errMsg("MVT","i"<<i<<" a"<< (*mpGiObjects)[i]->getInitialVelocity(simtime)<<" o"<<orgvel ); // DEBUG
00621                         // TODO check if inflow and simtime 
00622                         ntlVec3Gfx inivel = (*mpGiObjects)[i]->getInitialVelocity(simtime);
00623                         if( normNoSqrt(inivel) > normNoSqrt(max) ) { max = inivel; } 
00624                 }
00625         }
00626         errMsg("LbmSolverInterface::getGeoMaxMovementVelocity", "max="<< max ); // DEBUG
00627         return max;
00628 }
00629 
00630 
00631 
00632 
00633 /*******************************************************************************/
00635 /*******************************************************************************/
00636 
00637 
00638 
00639 
00640 /*****************************************************************************/
00642 void 
00643 LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) {
00644         for(size_t i=0; i<mMarkedCells.size(); i++) {
00645                 // check if cids alreay in
00646                 if( mMarkedCells[i]->equal(cid) ) return;
00647                 //mMarkedCells[i]->setEnd(false);
00648         }
00649         mMarkedCells.push_back( cid );
00650         //cid->setEnd(true);
00651 }
00652 
00653 /*****************************************************************************/
00655 CellIdentifierInterface* 
00656 LbmSolverInterface::markedGetFirstCell( ) {
00657         if(mMarkedCells.size() > 0){ return mMarkedCells[0]; }
00658         return NULL;
00659 }
00660 
00661 CellIdentifierInterface* 
00662 LbmSolverInterface::markedAdvanceCell() {
00663         mMarkedCellIndex++;
00664         if(mMarkedCellIndex>=(int)mMarkedCells.size()) return NULL;
00665         return mMarkedCells[mMarkedCellIndex];
00666 }
00667 
00668 void LbmSolverInterface::markedClearList() {
00669         // FIXME free cids?
00670         mMarkedCells.clear();
00671 }
00672 
00673 /*******************************************************************************/
00675 /*******************************************************************************/
00676 
00677 
00678 
00679 // 32k
00680 string convertSingleFlag2String(CellFlagType cflag) {
00681         CellFlagType flag = cflag;
00682         if(flag == CFUnused         ) return string("cCFUnused");
00683         if(flag == CFEmpty          ) return string("cCFEmpty");      
00684         if(flag == CFBnd            ) return string("cCFBnd");        
00685         if(flag == CFBndNoslip      ) return string("cCFBndNoSlip");        
00686         if(flag == CFBndFreeslip    ) return string("cCFBndFreeSlip");        
00687         if(flag == CFBndPartslip    ) return string("cCFBndPartSlip");        
00688         if(flag == CFNoInterpolSrc  ) return string("cCFNoInterpolSrc");
00689         if(flag == CFFluid          ) return string("cCFFluid");      
00690         if(flag == CFInter          ) return string("cCFInter");      
00691         if(flag == CFNoNbFluid      ) return string("cCFNoNbFluid");  
00692         if(flag == CFNoNbEmpty      ) return string("cCFNoNbEmpty");  
00693         if(flag == CFNoDelete       ) return string("cCFNoDelete");   
00694         if(flag == CFNoBndFluid     ) return string("cCFNoBndFluid"); 
00695         if(flag == CFGrNorm         ) return string("cCFGrNorm");     
00696         if(flag == CFGrFromFine     ) return string("cCFGrFromFine"); 
00697         if(flag == CFGrFromCoarse   ) return string("cCFGrFromCoarse");
00698         if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited");
00699         if(flag == CFMbndInflow )     return string("cCFMbndInflow");
00700         if(flag == CFMbndOutflow )    return string("cCFMbndOutflow");
00701         if(flag == CFInvalid        ) return string("cfINVALID");
00702 
00703         std::ostringstream mult;
00704         int val = 0;
00705         if(flag != 0) {
00706                 while(! (flag&1) ) {
00707                         flag = flag>>1;
00708                         val++;
00709                 }
00710         } else {
00711                 val = -1;
00712         }
00713         if(val>=24) {
00714                 mult << "cfOID_" << (flag>>24) <<"_TYPE";
00715         } else {
00716                 mult << "cfUNKNOWN_" << val <<"_TYPE";
00717         }
00718         return mult.str();
00719 }
00720         
00722 string convertCellFlagType2String( CellFlagType cflag ) {
00723         int flag = cflag;
00724 
00725         const int jmax = sizeof(CellFlagType)*8;
00726         bool somefound = false;
00727         std::ostringstream mult;
00728         mult << "[";
00729         for(int j=0; j<jmax ; j++) {
00730                 if(flag& (1<<j)) {
00731                         if(somefound) mult << "|";
00732                         mult << j<<"<"<< convertSingleFlag2String( (CellFlagType)(1<<j) ); // this call should always be _non_-recursive
00733                         somefound = true;
00734                 }
00735         };
00736         mult << "]";
00737 
00738         // return concatenated string
00739         if(somefound) return mult.str();
00740 
00741         // empty?
00742         return string("[emptyCFT]");
00743 }
00744