Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/elbeem/intern/solver_interface.cpp')
-rw-r--r--intern/elbeem/intern/solver_interface.cpp809
1 files changed, 809 insertions, 0 deletions
diff --git a/intern/elbeem/intern/solver_interface.cpp b/intern/elbeem/intern/solver_interface.cpp
new file mode 100644
index 00000000000..3d77e4a4968
--- /dev/null
+++ b/intern/elbeem/intern/solver_interface.cpp
@@ -0,0 +1,809 @@
+/******************************************************************************
+ *
+ * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
+ * All code distributed as part of El'Beem is covered by the version 2 of the
+ * GNU General Public License. See the file COPYING for details.
+ * Copyright 2003-2005 Nils Thuerey
+ *
+ * Combined 2D/3D Lattice Boltzmann Interface Class
+ * contains stuff to be statically compiled
+ *
+ *****************************************************************************/
+
+/* LBM Files */
+#include "solver_interface.h"
+#include "ntl_scene.h"
+#include "ntl_ray.h"
+
+
+/*****************************************************************************/
+//! common variables
+
+/*****************************************************************************/
+/*! class for solver templating - 3D implementation D3Q19 */
+
+ //! how many dimensions?
+ const int LbmD3Q19::cDimension = 3;
+
+ // Wi factors for collide step
+ const LbmFloat LbmD3Q19::cCollenZero = (1.0/3.0);
+ const LbmFloat LbmD3Q19::cCollenOne = (1.0/18.0);
+ const LbmFloat LbmD3Q19::cCollenSqrtTwo = (1.0/36.0);
+
+ //! threshold value for filled/emptied cells
+ const LbmFloat LbmD3Q19::cMagicNr2 = 1.0005;
+ const LbmFloat LbmD3Q19::cMagicNr2Neg = -0.0005;
+ const LbmFloat LbmD3Q19::cMagicNr = 1.010001;
+ const LbmFloat LbmD3Q19::cMagicNrNeg = -0.010001;
+
+ //! size of a single set of distribution functions
+ const int LbmD3Q19::cDfNum = 19;
+ //! direction vector contain vecs for all spatial dirs, even if not used for LBM model
+ const int LbmD3Q19::cDirNum = 27;
+
+ //const string LbmD3Q19::dfString[ cDfNum ] = {
+ const char* LbmD3Q19::dfString[ cDfNum ] = {
+ " C", " N"," S"," E"," W"," T"," B",
+ "NE","NW","SE","SW",
+ "NT","NB","ST","SB",
+ "ET","EB","WT","WB"
+ };
+
+ const int LbmD3Q19::dfNorm[ cDfNum ] = {
+ cDirC, cDirN, cDirS, cDirE, cDirW, cDirT, cDirB,
+ cDirNE, cDirNW, cDirSE, cDirSW,
+ cDirNT, cDirNB, cDirST, cDirSB,
+ cDirET, cDirEB, cDirWT, cDirWB
+ };
+
+ const int LbmD3Q19::dfInv[ cDfNum ] = {
+ cDirC, cDirS, cDirN, cDirW, cDirE, cDirB, cDirT,
+ cDirSW, cDirSE, cDirNW, cDirNE,
+ cDirSB, cDirST, cDirNB, cDirNT,
+ cDirWB, cDirWT, cDirEB, cDirET
+ };
+
+ const int LbmD3Q19::dfRefX[ cDfNum ] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ cDirSE, cDirSW, cDirNE, cDirNW,
+ 0, 0, 0, 0,
+ cDirEB, cDirET, cDirWB, cDirWT
+ };
+
+ const int LbmD3Q19::dfRefY[ cDfNum ] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ cDirNW, cDirNE, cDirSW, cDirSE,
+ cDirNB, cDirNT, cDirSB, cDirST,
+ 0, 0, 0, 0
+ };
+
+ const int LbmD3Q19::dfRefZ[ cDfNum ] = {
+ 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ cDirST, cDirSB, cDirNT, cDirNB,
+ cDirWT, cDirWB, cDirET, cDirEB
+ };
+
+ // Vector Order 3D:
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
+ // 0, 0, 0, 1,-1, 0, 0, 1,-1, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1,-1, 1,-1, 1,-1, 1,-1
+ // 0, 1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1, 0, 0, 0, 0, 1, 1,-1,-1, 1, 1,-1,-1
+ // 0, 0, 0, 0, 0, 1,-1, 0, 0, 0, 0, 1,-1, 1,-1, 1,-1, 1,-1, 1, 1, 1, 1, -1,-1,-1,-1
+
+ const int LbmD3Q19::dfVecX[ cDirNum ] = {
+ 0, 0,0, 1,-1, 0,0,
+ 1,-1,1,-1,
+ 0,0,0,0,
+ 1,1,-1,-1,
+ 1,-1, 1,-1,
+ 1,-1, 1,-1,
+ };
+ const int LbmD3Q19::dfVecY[ cDirNum ] = {
+ 0, 1,-1, 0,0,0,0,
+ 1,1,-1,-1,
+ 1,1,-1,-1,
+ 0,0,0,0,
+ 1, 1,-1,-1,
+ 1, 1,-1,-1
+ };
+ const int LbmD3Q19::dfVecZ[ cDirNum ] = {
+ 0, 0,0,0,0,1,-1,
+ 0,0,0,0,
+ 1,-1,1,-1,
+ 1,-1,1,-1,
+ 1, 1, 1, 1,
+ -1,-1,-1,-1
+ };
+
+ const LbmFloat LbmD3Q19::dfDvecX[ cDirNum ] = {
+ 0, 0,0, 1,-1, 0,0,
+ 1,-1,1,-1,
+ 0,0,0,0,
+ 1,1,-1,-1,
+ 1,-1, 1,-1,
+ 1,-1, 1,-1
+ };
+ const LbmFloat LbmD3Q19::dfDvecY[ cDirNum ] = {
+ 0, 1,-1, 0,0,0,0,
+ 1,1,-1,-1,
+ 1,1,-1,-1,
+ 0,0,0,0,
+ 1, 1,-1,-1,
+ 1, 1,-1,-1
+ };
+ const LbmFloat LbmD3Q19::dfDvecZ[ cDirNum ] = {
+ 0, 0,0,0,0,1,-1,
+ 0,0,0,0,
+ 1,-1,1,-1,
+ 1,-1,1,-1,
+ 1, 1, 1, 1,
+ -1,-1,-1,-1
+ };
+
+ /* principal directions */
+ const int LbmD3Q19::princDirX[ 2*LbmD3Q19::cDimension ] = {
+ 1,-1, 0,0, 0,0
+ };
+ const int LbmD3Q19::princDirY[ 2*LbmD3Q19::cDimension ] = {
+ 0,0, 1,-1, 0,0
+ };
+ const int LbmD3Q19::princDirZ[ 2*LbmD3Q19::cDimension ] = {
+ 0,0, 0,0, 1,-1
+ };
+
+ /*! arrays for les model coefficients, inited in lbmsolver constructor */
+ LbmFloat LbmD3Q19::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
+ LbmFloat LbmD3Q19::lesCoeffOffdiag[ cDimension ][ cDirNum ];
+
+
+ const LbmFloat LbmD3Q19::dfLength[ cDfNum ]= {
+ cCollenZero,
+ cCollenOne, cCollenOne, cCollenOne,
+ cCollenOne, cCollenOne, cCollenOne,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
+ };
+
+ /* precalculated equilibrium dfs, inited in lbmsolver constructor */
+ LbmFloat LbmD3Q19::dfEquil[ cDfNum ];
+
+// D3Q19 end
+
+
+
+/*****************************************************************************/
+/*! class for solver templating - 2D implementation D2Q9 */
+
+ //! how many dimensions?
+ const int LbmD2Q9::cDimension = 2;
+
+ //! Wi factors for collide step
+ const LbmFloat LbmD2Q9::cCollenZero = (4.0/9.0);
+ const LbmFloat LbmD2Q9::cCollenOne = (1.0/9.0);
+ const LbmFloat LbmD2Q9::cCollenSqrtTwo = (1.0/36.0);
+
+ //! threshold value for filled/emptied cells
+ const LbmFloat LbmD2Q9::cMagicNr2 = 1.0005;
+ const LbmFloat LbmD2Q9::cMagicNr2Neg = -0.0005;
+ const LbmFloat LbmD2Q9::cMagicNr = 1.010001;
+ const LbmFloat LbmD2Q9::cMagicNrNeg = -0.010001;
+
+ //! size of a single set of distribution functions
+ const int LbmD2Q9::cDfNum = 9;
+ const int LbmD2Q9::cDirNum = 9;
+
+ //const string LbmD2Q9::dfString[ cDfNum ] = {
+ const char* LbmD2Q9::dfString[ cDfNum ] = {
+ " C",
+ " N", " S", " E", " W",
+ "NE", "NW", "SE","SW"
+ };
+
+ const int LbmD2Q9::dfNorm[ cDfNum ] = {
+ cDirC,
+ cDirN, cDirS, cDirE, cDirW,
+ cDirNE, cDirNW, cDirSE, cDirSW
+ };
+
+ const int LbmD2Q9::dfInv[ cDfNum ] = {
+ cDirC,
+ cDirS, cDirN, cDirW, cDirE,
+ cDirSW, cDirSE, cDirNW, cDirNE
+ };
+
+ const int LbmD2Q9::dfRefX[ cDfNum ] = {
+ 0,
+ 0, 0, 0, 0,
+ cDirSE, cDirSW, cDirNE, cDirNW
+ };
+
+ const int LbmD2Q9::dfRefY[ cDfNum ] = {
+ 0,
+ 0, 0, 0, 0,
+ cDirNW, cDirNE, cDirSW, cDirSE
+ };
+
+ const int LbmD2Q9::dfRefZ[ cDfNum ] = {
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0
+ };
+
+ // Vector Order 2D:
+ // 0 1 2 3 4 5 6 7 8
+ // 0, 0,0, 1,-1, 1,-1,1,-1
+ // 0, 1,-1, 0,0, 1,1,-1,-1
+
+ const int LbmD2Q9::dfVecX[ cDirNum ] = {
+ 0,
+ 0,0, 1,-1,
+ 1,-1,1,-1
+ };
+ const int LbmD2Q9::dfVecY[ cDirNum ] = {
+ 0,
+ 1,-1, 0,0,
+ 1,1,-1,-1
+ };
+ const int LbmD2Q9::dfVecZ[ cDirNum ] = {
+ 0, 0,0,0,0, 0,0,0,0
+ };
+
+ const LbmFloat LbmD2Q9::dfDvecX[ cDirNum ] = {
+ 0,
+ 0,0, 1,-1,
+ 1,-1,1,-1
+ };
+ const LbmFloat LbmD2Q9::dfDvecY[ cDirNum ] = {
+ 0,
+ 1,-1, 0,0,
+ 1,1,-1,-1
+ };
+ const LbmFloat LbmD2Q9::dfDvecZ[ cDirNum ] = {
+ 0, 0,0,0,0, 0,0,0,0
+ };
+
+ const int LbmD2Q9::princDirX[ 2*LbmD2Q9::cDimension ] = {
+ 1,-1, 0,0
+ };
+ const int LbmD2Q9::princDirY[ 2*LbmD2Q9::cDimension ] = {
+ 0,0, 1,-1
+ };
+ const int LbmD2Q9::princDirZ[ 2*LbmD2Q9::cDimension ] = {
+ 0,0, 0,0
+ };
+
+
+ /*! arrays for les model coefficients, inited in lbmsolver constructor */
+ LbmFloat LbmD2Q9::lesCoeffDiag[ (cDimension-1)*(cDimension-1) ][ cDirNum ];
+ LbmFloat LbmD2Q9::lesCoeffOffdiag[ cDimension ][ cDirNum ];
+
+
+ const LbmFloat LbmD2Q9::dfLength[ cDfNum ]= {
+ cCollenZero,
+ cCollenOne, cCollenOne, cCollenOne, cCollenOne,
+ cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo, cCollenSqrtTwo
+ };
+
+ /* precalculated equilibrium dfs, inited in lbmsolver constructor */
+ LbmFloat LbmD2Q9::dfEquil[ cDfNum ];
+
+// D2Q9 end
+
+
+
+/******************************************************************************
+ * Interface Constructor
+ *****************************************************************************/
+LbmSolverInterface::LbmSolverInterface() :
+ mPanic( false ),
+ mSizex(10), mSizey(10), mSizez(10),
+ mStepCnt( 0 ),
+ mFixMass( 0.0 ),
+ mOmega( 1.0 ),
+ mGravity(0.0),
+ mSurfaceTension( 0.0 ),
+ mBoundaryEast( (CellFlagType)(CFBnd) ),mBoundaryWest( (CellFlagType)(CFBnd) ),mBoundaryNorth( (CellFlagType)(CFBnd) ),
+ mBoundarySouth( (CellFlagType)(CFBnd) ),mBoundaryTop( (CellFlagType)(CFBnd) ),mBoundaryBottom( (CellFlagType)(CFBnd) ),
+ mInitDone( false ),
+ mInitDensityGradient( false ),
+ mpAttrs( NULL ), mpParam( NULL ),
+ mNumParticlesLost(0), mNumInvalidDfs(0), mNumFilledCells(0), mNumEmptiedCells(0), mNumUsedCells(0), mMLSUPS(0),
+ mDebugVelScale( 1.0 ), mNodeInfoString("+"),
+ mRandom( 5123 ),
+ mvGeoStart(-1.0), mvGeoEnd(1.0),
+ mPerformGeoInit( false ),
+ mAccurateGeoinit(0),
+ mName("lbm_default") ,
+ mpIso( NULL ), mIsoValue(0.49999),
+ mSilent(false) ,
+ mGeoInitId( 0 ),
+ mpGiTree( NULL ),
+ mpGiObjects( NULL ), mGiObjInside(), mpGlob( NULL ),
+ mMarkedCells(), mMarkedCellIndex(0)
+{
+#if ELBEEM_BLENDER==1
+ if(gDebugLevel<=1) mSilent = true;
+#endif
+}
+
+
+/*******************************************************************************/
+/*! parse a boundary flag string */
+CellFlagType LbmSolverInterface::readBoundaryFlagInt(string name, int defaultValue, string source,string target, bool needed) {
+ string val = mpAttrs->readString(name, "", source, target, needed);
+ if(!strcmp(val.c_str(),"")) {
+ // no value given...
+ return CFEmpty;
+ }
+ if(!strcmp(val.c_str(),"bnd_no")) {
+ return (CellFlagType)( CFBnd );
+ }
+ if(!strcmp(val.c_str(),"bnd_free")) {
+ return (CellFlagType)( CFBnd );
+ }
+ if(!strcmp(val.c_str(),"fluid")) {
+ /* might be used for some in/out flow cases */
+ return (CellFlagType)( CFFluid );
+ }
+ errMsg("LbmStdSolver::readBoundaryFlagInt","Invalid value '"<<val<<"' " );
+# if LBM_STRICT_DEBUG==1
+ errFatal("readBoundaryFlagInt","Strict abort..."<<val, SIMWORLD_INITERROR);
+# endif
+ return defaultValue;
+}
+
+/*******************************************************************************/
+/*! parse standard attributes */
+void LbmSolverInterface::parseStdAttrList() {
+ if(!mpAttrs) {
+ errFatal("LbmStdSolver::parseAttrList","mpAttrs pointer not initialized!",SIMWORLD_INITERROR);
+ return; }
+
+ // st currently unused
+ //mSurfaceTension = mpAttrs->readFloat("d_surfacetension", mSurfaceTension, "LbmStdSolver", "mSurfaceTension", false);
+ mBoundaryEast = readBoundaryFlagInt("boundary_east", mBoundaryEast, "LbmStdSolver", "mBoundaryEast", false);
+ mBoundaryWest = readBoundaryFlagInt("boundary_west", mBoundaryWest, "LbmStdSolver", "mBoundaryWest", false);
+ mBoundaryNorth = readBoundaryFlagInt("boundary_north", mBoundaryNorth,"LbmStdSolver", "mBoundaryNorth", false);
+ mBoundarySouth = readBoundaryFlagInt("boundary_south", mBoundarySouth,"LbmStdSolver", "mBoundarySouth", false);
+ mBoundaryTop = readBoundaryFlagInt("boundary_top", mBoundaryTop,"LbmStdSolver", "mBoundaryTop", false);
+ mBoundaryBottom= readBoundaryFlagInt("boundary_bottom", mBoundaryBottom,"LbmStdSolver", "mBoundaryBottom", false);
+
+ LbmVec sizeVec(mSizex,mSizey,mSizez);
+ sizeVec = vec2L( mpAttrs->readVec3d("size", vec2P(sizeVec), "LbmStdSolver", "sizeVec", false) );
+ mSizex = (int)sizeVec[0];
+ mSizey = (int)sizeVec[1];
+ mSizez = (int)sizeVec[2];
+ mpParam->setSize(mSizex, mSizey, mSizez ); // param needs size in any case
+
+ mInitDensityGradient = mpAttrs->readBool("initdensitygradient", mInitDensityGradient,"LbmStdSolver", "mInitDensityGradient", false);
+ mPerformGeoInit = mpAttrs->readBool("geoinit", mPerformGeoInit,"LbmStdSolver", "mPerformGeoInit", false);
+ mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmStdSolver", "mGeoInitId", false);
+ mIsoValue = mpAttrs->readFloat("isovalue", mIsoValue, "LbmOptSolver","mIsoValue", false );
+
+ mDebugVelScale = mpAttrs->readFloat("debugvelscale", mDebugVelScale,"LbmStdSolver", "mDebugVelScale", false);
+ mNodeInfoString = mpAttrs->readString("nodeinfo", mNodeInfoString, "SimulationLbm","mNodeInfoString", false );
+}
+
+
+/*******************************************************************************/
+/*! geometry initialization */
+/*******************************************************************************/
+
+/*****************************************************************************/
+/*! init tree for certain geometry init */
+void LbmSolverInterface::initGeoTree(int id) {
+ if(mpGlob == NULL) { errFatal("LbmSolverInterface::initGeoTree","Requires globals!",SIMWORLD_INITERROR); return; }
+ mGeoInitId = id;
+ ntlScene *scene = mpGlob->getScene();
+ mpGiObjects = scene->getObjects();
+ mGiObjInside.resize( mpGiObjects->size() );
+ mGiObjDistance.resize( mpGiObjects->size() );
+ mGiObjSecondDist.resize( mpGiObjects->size() );
+ for(size_t i=0; i<mpGiObjects->size(); i++) {
+ if((*mpGiObjects)[i]->getGeoInitIntersect()) mAccurateGeoinit=true;
+ }
+ debMsgStd("LbmSolverInterface::initGeoTree",DM_MSG,"Accurate geo init: "<<mAccurateGeoinit, 9)
+
+ if(mpGiTree != NULL) delete mpGiTree;
+ char treeFlag = (1<<(mGeoInitId+4));
+ mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
+ scene, treeFlag );
+}
+
+/*****************************************************************************/
+/*! destroy tree etc. when geometry init done */
+void LbmSolverInterface::freeGeoTree() {
+ if(mpGiTree != NULL) {
+ delete mpGiTree;
+ mpGiTree = NULL;
+ }
+}
+
+
+/*****************************************************************************/
+/*! check for a certain flag type at position org */
+bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, int flags, int &OId, gfxReal &distance) {
+ // shift ve ctors to avoid rounding errors
+ org += ntlVec3Gfx(0.0001);
+ ntlVec3Gfx dir = ntlVec3Gfx(1.0, 0.0, 0.0);
+ OId = -1;
+ ntlRay ray(org, dir, 0, 1.0, mpGlob);
+ //int insCnt = 0;
+ bool done = false;
+ bool inside = false;
+ for(size_t i=0; i<mGiObjInside.size(); i++) {
+ mGiObjInside[i] = 0;
+ mGiObjDistance[i] = -1.0;
+ mGiObjSecondDist[i] = -1.0;
+ }
+ // if not inside, return distance to first hit
+ gfxReal firstHit=-1.0;
+ int firstOId = -1;
+
+ if(mAccurateGeoinit) {
+ while(!done) {
+ // find first inside intersection
+ ntlTriangle *triIns = NULL;
+ distance = -1.0;
+ ntlVec3Gfx normal(0.0);
+ mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
+ if(triIns) {
+ ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
+ LbmFloat orientation = dot(normal, dir);
+ OId = triIns->getObjectId();
+ if(orientation<=0.0) {
+ // outside hit
+ normal *= -1.0;
+ mGiObjInside[OId]++;
+ //mGiObjDistance[OId] = -1.0;
+ //errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
+ } else {
+ // inside hit
+ mGiObjInside[OId]++;
+ if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
+ //errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
+ }
+ norg += normal * getVecEpsilon();
+ ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
+ // remember first hit distance, in case we're not
+ // inside anything
+ if(firstHit<0.0) {
+ firstHit = distance;
+ firstOId = OId;
+ }
+ } else {
+ // no more intersections... return false
+ done = true;
+ //if(insCnt%2) inside=true;
+ }
+ }
+
+ distance = -1.0;
+ for(size_t i=0; i<mGiObjInside.size(); i++) {
+ //errMsg("CHIII","i"<<i<<" ins="<<mGiObjInside[i]<<" t"<<mGiObjDistance[i]<<" d"<<distance);
+ if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
+ if( (distance<0.0) || // first intersection -> good
+ ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
+ ) {
+ distance = mGiObjDistance[i];
+ OId = i;
+ inside = true;
+ }
+ }
+ }
+ if(!inside) {
+ distance = firstHit;
+ OId = firstOId;
+ }
+ //errMsg("CHIII","i"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
+
+ return inside;
+ } else {
+
+ // find first inside intersection
+ ntlTriangle *triIns = NULL;
+ distance = -1.0;
+ ntlVec3Gfx normal(0.0);
+ mpGiTree->intersectX(ray,distance,normal, triIns, flags, true);
+ if(triIns) {
+ // check outside intersect
+ LbmFloat orientation = dot(normal, dir);
+ if(orientation<=0.0) return false;
+
+ OId = triIns->getObjectId();
+ return true;
+ }
+ return false;
+ }
+}
+bool LbmSolverInterface::geoInitCheckPointInside(ntlVec3Gfx org, ntlVec3Gfx dir, int flags, int &OId, gfxReal &distance, const gfxReal halfCellsize, bool &thinHit, bool recurse) {
+ // shift ve ctors to avoid rounding errors
+ org += ntlVec3Gfx(0.0001); //?
+ OId = -1;
+ ntlRay ray(org, dir, 0, 1.0, mpGlob);
+ //int insCnt = 0;
+ bool done = false;
+ bool inside = false;
+ for(size_t i=0; i<mGiObjInside.size(); i++) {
+ mGiObjInside[i] = 0;
+ mGiObjDistance[i] = -1.0;
+ mGiObjSecondDist[i] = -1.0;
+ }
+ // if not inside, return distance to first hit
+ gfxReal firstHit=-1.0;
+ int firstOId = -1;
+ thinHit = false;
+
+ if(mAccurateGeoinit) {
+ while(!done) {
+ // find first inside intersection
+ ntlTriangle *triIns = NULL;
+ distance = -1.0;
+ ntlVec3Gfx normal(0.0);
+ mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
+ if(triIns) {
+ ntlVec3Gfx norg = ray.getOrigin() + ray.getDirection()*distance;
+ LbmFloat orientation = dot(normal, dir);
+ OId = triIns->getObjectId();
+ if(orientation<=0.0) {
+ // outside hit
+ normal *= -1.0;
+ //mGiObjDistance[OId] = -1.0;
+ //errMsg("IIO"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
+ } else {
+ // inside hit
+ //if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
+ //errMsg("III"," oid:"<<OId<<" org"<<org<<" norg"<<norg);
+ if(mGiObjInside[OId]==1) {
+ // second inside hit
+ if(mGiObjSecondDist[OId]<0.0) mGiObjSecondDist[OId] = distance;
+ }
+ }
+ mGiObjInside[OId]++;
+ // always store first hit for thin obj init
+ if(mGiObjDistance[OId]<0.0) mGiObjDistance[OId] = distance;
+
+ norg += normal * getVecEpsilon();
+ ray = ntlRay(norg, dir, 0, 1.0, mpGlob);
+ // remember first hit distance, in case we're not
+ // inside anything
+ if(firstHit<0.0) {
+ firstHit = distance;
+ firstOId = OId;
+ }
+ } else {
+ // no more intersections... return false
+ done = true;
+ //if(insCnt%2) inside=true;
+ }
+ }
+
+ distance = -1.0;
+ // standard inside check
+ for(size_t i=0; i<mGiObjInside.size(); i++) {
+ if(((mGiObjInside[i]%2)==1)&&(mGiObjDistance[i]>0.0)) {
+ if( (distance<0.0) || // first intersection -> good
+ ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
+ ) {
+ distance = mGiObjDistance[i];
+ OId = i;
+ inside = true;
+ }
+ }
+ }
+ // now check for thin hits
+ if(!inside) {
+ distance = -1.0;
+ for(size_t i=0; i<mGiObjInside.size(); i++) {
+ if((mGiObjInside[i]>=2)&&(mGiObjDistance[i]>0.0)&&(mGiObjSecondDist[i]>0.0)&&
+ (mGiObjDistance[i]<1.0*halfCellsize)&&(mGiObjSecondDist[i]<2.0*halfCellsize) ) {
+ if( (distance<0.0) || // first intersection -> good
+ ((distance>0.0)&&(distance>mGiObjDistance[i])) // more than one intersection -> use closest one
+ ) {
+ distance = mGiObjDistance[i];
+ OId = i;
+ inside = true;
+ thinHit = true;
+ }
+ }
+ }
+ }
+ if(!inside) {
+ // check for hit in this cell, opposite to current dir (only recurse once)
+ if(recurse) {
+ gfxReal r_distance;
+ int r_OId;
+ bool ret = geoInitCheckPointInside(org, dir*-1.0, flags, r_OId, r_distance, halfCellsize, thinHit, false);
+ if((ret)&&(thinHit)) {
+ OId = r_OId;
+ distance = 0.0;
+ return true;
+ }
+ }
+ }
+ // really no hit...
+ if(!inside) {
+ distance = firstHit;
+ OId = firstOId;
+ /*if((mGiObjDistance[OId]>0.0)&&(mGiObjSecondDist[OId]>0.0)) {
+ const gfxReal thisdist = mGiObjSecondDist[OId]-mGiObjDistance[OId];
+ // dont walk over this cell...
+ if(thisdist<halfCellsize) distance-=2.0*halfCellsize;
+ } // ? */
+ }
+ //errMsg("CHIII","i"<<inside<<" fh"<<firstHit<<" fo"<<firstOId<<" - h"<<distance<<" o"<<OId);
+
+ return inside;
+ } else {
+
+ // find first inside intersection
+ ntlTriangle *triIns = NULL;
+ distance = -1.0;
+ ntlVec3Gfx normal(0.0);
+ mpGiTree->intersect(ray,distance,normal, triIns, flags, true);
+ if(triIns) {
+ // check outside intersect
+ LbmFloat orientation = dot(normal, dir);
+ if(orientation<=0.0) return false;
+
+ OId = triIns->getObjectId();
+ return true;
+ }
+ return false;
+ }
+}
+
+/*****************************************************************************/
+/*! get max. velocity of all objects to initialize as fluid regions */
+ntlVec3Gfx LbmSolverInterface::getGeoMaxInitialVelocity() {
+ ntlScene *scene = mpGlob->getScene();
+ mpGiObjects = scene->getObjects();
+ ntlVec3Gfx max(0.0);
+
+ for(int i=0; i< (int)mpGiObjects->size(); i++) {
+ if( (*mpGiObjects)[i]->getGeoInitType() & FGI_FLUID ){
+ ntlVec3Gfx ovel = (*mpGiObjects)[i]->getInitialVelocity();
+ if( normNoSqrt(ovel) > normNoSqrt(max) ) { max = ovel; }
+ //errMsg("IVT","i"<<i<<" "<< (*mpGiObjects)[i]->getInitialVelocity() ); // DEBUG
+ }
+ }
+ //errMsg("IVT","max "<<" "<< max ); // DEBUG
+ // unused !? mGiInsideCnt.resize( mpGiObjects->size() );
+
+ return max;
+}
+
+
+/*******************************************************************************/
+/*! "traditional" initialization */
+/*******************************************************************************/
+
+
+/*****************************************************************************/
+// handle generic test cases (currently only reset geo init)
+bool LbmSolverInterface::initGenericTestCases() {
+ bool initTypeFound = false;
+ LbmSolverInterface::CellIdentifier cid = getFirstCell();
+ // deprecated! - only check for invalid cells...
+
+ // this is the default init - check if the geometry flag init didnt
+ initTypeFound = true;
+
+ while(noEndCell(cid)) {
+ // check node
+ if( (getCellFlag(cid,0)==CFInvalid) || (getCellFlag(cid,1)==CFInvalid) ) {
+ warnMsg("LbmSolverInterface::initGenericTestCases","GeoInit produced invalid Flag at "<<cid->getAsString()<<"!" );
+ }
+ advanceCell( cid );
+ }
+
+ deleteCellIterator( &cid );
+ return initTypeFound;
+}
+
+
+/*******************************************************************************/
+/*! cell iteration functions */
+/*******************************************************************************/
+
+
+
+
+/*****************************************************************************/
+//! add cell to mMarkedCells list
+void
+LbmSolverInterface::addCellToMarkedList( CellIdentifierInterface *cid ) {
+ for(size_t i=0; i<mMarkedCells.size(); i++) {
+ // check if cids alreay in
+ if( mMarkedCells[i]->equal(cid) ) return;
+ //mMarkedCells[i]->setEnd(false);
+ }
+ mMarkedCells.push_back( cid );
+ //cid->setEnd(true);
+}
+
+/*****************************************************************************/
+//! marked cell iteration methods
+CellIdentifierInterface*
+LbmSolverInterface::markedGetFirstCell( ) {
+ if(mMarkedCells.size() > 0){ return mMarkedCells[0]; }
+ return NULL;
+}
+
+CellIdentifierInterface*
+LbmSolverInterface::markedAdvanceCell() {
+ mMarkedCellIndex++;
+ if(mMarkedCellIndex>=(int)mMarkedCells.size()) return NULL;
+ return mMarkedCells[mMarkedCellIndex];
+}
+
+void LbmSolverInterface::markedClearList() {
+ // FIXME free cids?
+ mMarkedCells.clear();
+}
+
+/*******************************************************************************/
+/*! string helper functions */
+/*******************************************************************************/
+
+
+
+// 32k
+string convertSingleFlag2String(CellFlagType cflag) {
+ CellFlagType flag = cflag;
+ if(flag == CFUnused ) return string("cCFUnused");
+ if(flag == CFEmpty ) return string("cCFEmpty");
+ if(flag == CFBnd ) return string("cCFBnd");
+ if(flag == CFNoInterpolSrc ) return string("cCFNoInterpolSrc");
+ if(flag == CFFluid ) return string("cCFFluid");
+ if(flag == CFInter ) return string("cCFInter");
+ if(flag == CFNoNbFluid ) return string("cCFNoNbFluid");
+ if(flag == CFNoNbEmpty ) return string("cCFNoNbEmpty");
+ if(flag == CFNoDelete ) return string("cCFNoDelete");
+ if(flag == CFNoBndFluid ) return string("cCFNoBndFluid");
+ if(flag == CFGrNorm ) return string("cCFGrNorm");
+ if(flag == CFGrFromFine ) return string("cCFGrFromFine");
+ if(flag == CFGrFromCoarse ) return string("cCFGrFromCoarse");
+ if(flag == CFGrCoarseInited ) return string("cCFGrCoarseInited");
+ if(flag == CFMbndInflow ) return string("cCFMbndInflow");
+ if(flag == CFMbndOutflow ) return string("cCFMbndOutflow");
+ if(flag == CFInvalid ) return string("cfINVALID");
+
+ std::ostringstream mult;
+ int val = 0;
+ if(flag != 0) {
+ while(! (flag&1) ) {
+ flag = flag>>1;
+ val++;
+ }
+ } else {
+ val = -1;
+ }
+ mult << "cfUNKNOWN_" << val <<"_TYPE";
+ return mult.str();
+}
+
+//! helper function to convert flag to string (for debuggin)
+string convertCellFlagType2String( CellFlagType cflag ) {
+ int flag = cflag;
+
+ const int jmax = sizeof(CellFlagType)*8;
+ bool somefound = false;
+ std::ostringstream mult;
+ mult << "[";
+ for(int j=0; j<jmax ; j++) {
+ if(flag& (1<<j)) {
+ if(somefound) mult << "|";
+ mult << j<<"<"<< convertSingleFlag2String( (CellFlagType)(1<<j) ); // this call should always be _non_-recursive
+ somefound = true;
+ }
+ };
+ mult << "]";
+
+ // return concatenated string
+ if(somefound) return mult.str();
+
+ // empty?
+ return string("[emptyCFT]");
+}
+