1 /******************************************************************************
3 * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
4 * Copyright 2003-2006 Nils Thuerey
6 * Basic interface for all simulation modules
8 *****************************************************************************/
10 #include "simulation_object.h"
11 #include "solver_interface.h"
12 #include "ntl_bsptree.h"
14 #include "ntl_world.h"
15 #include "solver_interface.h"
16 #include "particletracer.h"
25 //! lbm factory functions
26 LbmSolverInterface* createSolver();
29 /******************************************************************************
31 *****************************************************************************/
32 SimulationObject::SimulationObject() :
34 mGeoStart(-100.0), mGeoEnd(100.0),
35 mpGiTree(NULL), mpGiObjects(NULL),
38 mDebugType( 1 /* =FLUIDDISPNothing*/ ),
39 mpLbm(NULL), mpParam( NULL ),
40 mShowSurface(true), mShowParticles(false),
42 mpElbeemSettings( NULL )
45 mpParam = new Parametrizer();
46 //for(int i=0; i<MAX_DEBDISPSET; i++) { mDebDispSet[i].type = (i); mDebDispSet[i].on = false; mDebDispSet[i].scale = 1.0; }
53 /******************************************************************************
55 *****************************************************************************/
56 SimulationObject::~SimulationObject()
58 if(mpGiTree) delete mpGiTree;
59 if(mpElbeemSettings) delete mpElbeemSettings;
60 if(mpLbm) delete mpLbm;
61 if(mpParam) delete mpParam;
62 if(mpParts) delete mpParts;
63 debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10);
68 /*****************************************************************************/
69 /*! init tree for certain geometry init */
70 /*****************************************************************************/
71 void SimulationObject::initGeoTree() {
72 // unused!! overriden by solver interface
74 errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR);
77 ntlScene *scene = mpGlob->getSimScene();
78 mpGiObjects = scene->getObjects();
80 if(mpGiTree != NULL) delete mpGiTree;
81 char treeFlag = (1<<(mGeoInitId+4));
82 mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
84 // unused!! overriden by solver interface
87 /*****************************************************************************/
88 /*! destroy tree etc. when geometry init done */
89 /*****************************************************************************/
90 void SimulationObject::freeGeoTree() {
91 if(mpGiTree != NULL) delete mpGiTree;
96 // copy & remember settings for later use
97 void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) {
98 mpElbeemSettings = new elbeemSimulationSettings;
99 *mpElbeemSettings = *settings;
101 mGeoInitId = settings->domainId+1;
102 debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<<mGeoInitId<<", domainId="<<settings->domainId, 8);
105 /******************************************************************************
106 * simluation interface: initialize simulation using the given configuration file
107 *****************************************************************************/
108 extern int glob_mpnum;
109 int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
111 if(! isSimworldOk() ) return 1;
118 mpAttrs->setAllUsed();
123 mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmSolverInterface", "mGeoInitId", false);
124 //mDimension, mSolverType are deprecated
125 string mSolverType("");
126 mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false );
128 mpLbm = createSolver();
129 /* check lbm pointer */
131 errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR);
134 debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<<mpLbm->getIdString() <<" LBM solver! ", 2);
136 mpParts = new ParticleTracer();
138 // for non-param simulations
139 mpLbm->setParametrizer( mpParam );
140 mpParam->setAttrList( getAttributeList() );
141 // not needed.. done in solver_init: mpParam->setSize ... in solver_interface
142 mpParam->parseAttrList();
144 mpLbm->setAttrList( getAttributeList() );
145 mpLbm->setSwsAttrList( getSwsAttributeList() );
146 mpLbm->parseAttrList();
147 mpParts->parseAttrList( getAttributeList() );
149 if(! isSimworldOk() ) return 3;
150 mpParts->setName( getName() + "_part" );
151 mpParts->initialize( glob );
152 if(! isSimworldOk() ) return 4;
154 // init material settings
155 string matMc("default");
156 matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false );
157 mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false );
158 mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false );
160 checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" );
161 mpLbm->setLbmInitId( mGeoInitId );
162 mpLbm->setGeoStart( mGeoStart );
163 mpLbm->setGeoEnd( mGeoEnd );
164 mpLbm->setRenderGlobals( mpGlob );
165 mpLbm->setName( getName() + "_lbm" );
166 mpLbm->setParticleTracer( mpParts );
167 if(mpElbeemSettings) {
168 // set further settings from API struct init
169 if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath);
170 mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo );
171 mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing);
172 mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs);
173 mpLbm->setSizeX(mpElbeemSettings->resolutionxyz);
174 mpLbm->setSizeY(mpElbeemSettings->resolutionxyz);
175 mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz);
176 mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz);
177 mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine);
178 mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles);
179 // set initial particles
180 mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles);
182 string dinitType = string("no");
183 if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part");
184 else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free");
185 else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no");
186 mpLbm->setDomainBound(dinitType);
187 mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip);
188 mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors);
189 mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize);
190 debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<<dinitType<<" ps="<<mpElbeemSettings->domainobsPartslip<<" vv"<<mpElbeemSettings->generateVertexVectors<<","<<mpLbm->getDumpVelocities(), 9 );
192 debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<<mpLbm->getGenerateParticles(),10);
195 if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; }
196 if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; }
197 if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; }
198 if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; }
199 if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; }
200 if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; }
202 // print cell type stats
203 bool printStats = true;
204 if(glob_mpnum>0) printStats=false; // skip in this case
206 const int jmax = sizeof(CellFlagType)*8;
209 for(int j=0; j<jmax ; j++) flagCount[j] = 0;
211 LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell();
212 for(; mpLbm->noEndCell( cid );
213 mpLbm->advanceCell( cid ) ) {
214 int flag = mpLbm->getCellFlag(cid,0);
215 int flag2 = mpLbm->getCellFlag(cid,1);
219 for(int j=0; j<jmax ; j++) {
220 if( flag&(1<<j) ) flagCount[j]++;
224 mpLbm->deleteCellIterator( &cid );
227 debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5);
228 debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5);
229 for(int j=0; j<jmax ; j++) {
230 std::ostringstream out;
232 out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl;
233 debugOutNnl(out.str(), 5);
236 // compute dist. of empty/bnd - fluid - if
237 // cfEmpty = (1<<0), cfBnd = (1<< 2), cfFluid = (1<<10), cfInter = (1<<11),
239 std::ostringstream out;
240 out.precision(2); out.width(4);
241 int totNum = flagCount[1]+flagCount[2]+flagCount[7]+flagCount[8];
242 double ebFrac = (double)(flagCount[1]+flagCount[2]) / totNum;
243 double flFrac = (double)(flagCount[7]) / totNum;
244 double ifFrac = (double)(flagCount[8]) / totNum;
246 out<<"\tFractions: [empty/bnd - fluid - interface - ext. if] = [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<"] "<< charNl;
249 debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<<diffInits<<"!" , 5);
251 debugOutNnl(out.str(), 5);
255 // might be modified by mpLbm
256 //mpParts->setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );?
257 mpParts->setStart( mpLbm->getGeoStart() );
258 mpParts->setEnd( mpLbm->getGeoEnd() );
259 mpParts->setCastShadows( false );
260 mpParts->setReceiveShadows( false );
261 mpParts->searchMaterial( glob->getMaterials() );
263 // this has to be inited here - before, the values might be unknown
264 IsoSurface *surf = mpLbm->getSurfaceGeoObj();
266 surf->setName( "final" ); // final surface mesh
267 // warning - this might cause overwriting effects for multiple sims and geom dump...
268 surf->setCastShadows( true );
269 surf->setReceiveShadows( false );
270 surf->searchMaterial( glob->getMaterials() );
271 if(mShowSurface) mObjects.push_back( surf );
275 mShowParticles=1; // for e.g. dumping
276 #endif // ELBEEM_PLUGIN
277 if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) {
279 mpParts->setDumpParts(true);
281 //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1);
282 //} // DEBUG ENABLE!!!!!!!!!!
284 mObjects.push_back(mpParts);
287 // add objects to display for debugging (e.g. levelset particles)
288 vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects();
289 for(size_t i=0;i<debugObjs.size(); i++) {
290 debugObjs[i]->setCastShadows( false );
291 debugObjs[i]->setReceiveShadows( false );
292 debugObjs[i]->searchMaterial( glob->getMaterials() );
293 mObjects.push_back( debugObjs[i] );
294 debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<<debugObjs[i]->getName(), 10 );
299 /*! set current frame */
300 void SimulationObject::setFrameNum(int num) {
301 // advance parametrizer
302 mpParam->setFrameNum(num);
305 /******************************************************************************
306 * simluation interface: advance simulation another step (whatever delta time that might be)
307 *****************************************************************************/
308 void SimulationObject::step( void )
310 if(mpParam->getCurrentAniFrameTime()>0.0) {
311 // dont advance for stopped time
313 mTime += mpParam->getTimestep();
314 //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST!
316 if(mpLbm->getPanic()) mPanic = true;
318 checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
319 //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
320 //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0);
321 //errMsg("runSimulationCallback cbtest1"," "<<this->getName()<<" ret="<<ret);
323 //debMsgStd("SimulationObject::step",DM_MSG," Sim '"<<mName<<"' stepped to "<<mTime<<" (stept="<<(mpParam->getTimestep())<<", framet="<<getFrameTime()<<") ", 10);
325 /*! prepare visualization of simulation for e.g. raytracing */
326 void SimulationObject::prepareVisualization( void ) {
328 mpLbm->prepareVisualization();
332 /******************************************************************************/
333 /* get current start simulation time */
334 double SimulationObject::getStartTime( void ) {
335 //return mpParam->calculateAniStart();
336 return mpParam->getAniStart();
338 /* get time for a single animation frame */
339 double SimulationObject::getFrameTime( int frame ) {
340 return mpParam->getAniFrameTime(frame);
342 /* get time for a single time step */
343 double SimulationObject::getTimestep( void ) {
344 return mpParam->getTimestep();
348 /******************************************************************************
349 * return a pointer to the geometry object of this simulation
350 *****************************************************************************/
351 //ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; }
352 vector<ntlGeometryObject *>::iterator
353 SimulationObject::getObjectsBegin()
355 return mObjects.begin();
357 vector<ntlGeometryObject *>::iterator
358 SimulationObject::getObjectsEnd()
360 return mObjects.end();
367 /******************************************************************************
368 * GUI - display debug info
369 *****************************************************************************/
371 void SimulationObject::drawDebugDisplay() {
373 if(!getVisible()) return;
375 //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; }
376 //mDebDispSet[ mDebugType ].on = true;
377 //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type );
378 mpLbm->debugDisplay( mDebugType );
380 //::lbmMarkedCellDisplay<>( mpLbm );
381 mpLbm->lbmMarkedCellDisplay();
385 /* GUI - display interactive info */
386 void SimulationObject::drawInteractiveDisplay()
389 if(!getVisible()) return;
391 // in debugDisplayNode if dispset is on is ignored...
392 mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid );
398 /*******************************************************************************/
399 // GUI - handle mouse movement for selection
400 /*******************************************************************************/
401 void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir)
404 // assume 2D sim is in XY plane...
406 double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5;
407 double zt = (zplane-org[2]) / dir[2];
410 org[1]+ dir[1] * zt, 0.0);
412 mSelectedCid = mpLbm->getCellAt( pos );
413 //errMsg("SMP ", mName<< x<<" "<<y<<" - "<<dir );
414 x = y = 0; // remove warning
418 void SimulationObject::setMouseClick()
421 //::debugPrintNodeInfo<>( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() );
422 mpLbm->debugPrintNodeInfo( mSelectedCid );
426 /*! notify object that dump is in progress (e.g. for field dump) */
427 void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
430 mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename);
431 checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr);
434 /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */
435 int SimulationObject::checkCallerStatus(int status, int frame) {
438 if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
439 ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame);
440 if(ret!=FLUIDSIM_CBRET_CONTINUE) {
441 if(ret==FLUIDSIM_CBRET_STOP) {
442 debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1);
443 setElbeemState( SIMWORLD_STOP );
445 else if(ret==FLUIDSIM_CBRET_ABORT) {
446 errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR );
450 errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<<ret<<", ignoring... ");
455 //debMsgStd("SimulationObject::checkCallerStatus",DM_MSG, "s="<<status<<",f="<<frame<<" "<<this->getName()<<" ret="<<ret);
456 if(isSimworldOk()) return 0;