Fix various compiler warnings.
[blender-staging.git] / intern / elbeem / intern / simulation_object.cpp
1 /** \file elbeem/intern/simulation_object.cpp
2  *  \ingroup elbeem
3  */
4 /******************************************************************************
5  *
6  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
7  * Copyright 2003-2006 Nils Thuerey
8  *
9  * Basic interface for all simulation modules
10  *
11  *****************************************************************************/
12
13 #include "simulation_object.h"
14 #include "solver_interface.h"
15 #include "ntl_bsptree.h"
16 #include "ntl_ray.h"
17 #include "ntl_world.h"
18 #include "solver_interface.h"
19 #include "particletracer.h"
20 #include "elbeem.h"
21
22 #if PARALLEL==1
23 #include <omp.h>
24 #endif
25
26 #ifdef _WIN32
27 #else
28 #include <sys/time.h>
29 #endif
30
31
32 //! lbm factory functions
33 LbmSolverInterface* createSolver();
34
35 /******************************************************************************
36  * Constructor
37  *****************************************************************************/
38 SimulationObject::SimulationObject() :
39         ntlGeometryShader(),
40         mGeoStart(-100.0), mGeoEnd(100.0),
41         mpGiTree(NULL), mpGiObjects(NULL),
42         mpGlob(NULL),
43         mPanic( false ),
44         mDebugType( 1 /* =FLUIDDISPNothing*/ ),
45         mpLbm(NULL), mpParam( NULL ),
46         mShowSurface(true), mShowParticles(false),
47         mSelectedCid( NULL ),
48         mpElbeemSettings( NULL )
49
50 {
51         mpParam = new Parametrizer();
52         //for(int i=0; i<MAX_DEBDISPSET; i++) { mDebDispSet[i].type  = (i); mDebDispSet[i].on    = false; mDebDispSet[i].scale = 1.0; }
53
54         // reset time
55         mTime                                           = 0.0;
56 }
57
58
59 /******************************************************************************
60  * Destructor
61  *****************************************************************************/
62 SimulationObject::~SimulationObject()
63 {
64         if(mpGiTree)         delete mpGiTree;
65         if(mpElbeemSettings) delete mpElbeemSettings;
66         if(mpLbm)            delete mpLbm;
67         if(mpParam)          delete mpParam;
68         if(mpParts)          delete mpParts;
69         debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10);
70 }
71
72
73
74 /*****************************************************************************/
75 /*! init tree for certain geometry init */
76 /*****************************************************************************/
77 void SimulationObject::initGeoTree() {
78         // unused!! overriden by solver interface       
79         if(mpGlob == NULL) { 
80                 errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR); 
81                 return;
82         }
83         ntlScene *scene = mpGlob->getSimScene();
84         mpGiObjects = scene->getObjects();
85
86         if(mpGiTree != NULL) delete mpGiTree;
87         char treeFlag = (1<<(mGeoInitId+4));
88         mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
89                                                                                                 scene, treeFlag );
90         // unused!! overriden by solver interface       
91 }
92
93 /*****************************************************************************/
94 /*! destroy tree etc. when geometry init done */
95 /*****************************************************************************/
96 void SimulationObject::freeGeoTree() {
97         if(mpGiTree != NULL) delete mpGiTree;
98 }
99
100
101
102 // copy & remember settings for later use
103 void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) {
104         mpElbeemSettings = new elbeemSimulationSettings;
105         *mpElbeemSettings = *settings;
106
107         mGeoInitId = settings->domainId+1;
108         debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<<mGeoInitId<<", domainId="<<settings->domainId, 8);
109 }
110
111 /******************************************************************************
112  * simluation interface: initialize simulation using the given configuration file 
113  *****************************************************************************/
114 extern int glob_mpnum;
115 int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
116 {
117         if(! isSimworldOk() ) return 1;
118         
119         // already inited?
120         if(mpLbm) return 0;
121         
122         mpGlob = glob;
123         if(!getVisible()) {
124                 mpAttrs->setAllUsed();
125                 return 0;
126         }
127
128
129         mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmSolverInterface", "mGeoInitId", false);
130         //mDimension, mSolverType are deprecated
131         string mSolverType(""); 
132         mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false ); 
133
134         mpLbm = createSolver(); 
135   /* check lbm pointer */
136         if(mpLbm == NULL) {
137                 errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR);
138                 return 2;
139         }
140         debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<<mpLbm->getIdString() <<" LBM solver! ", 2);
141
142         mpParts = new ParticleTracer();
143
144         // for non-param simulations
145         mpLbm->setParametrizer( mpParam );
146         mpParam->setAttrList( getAttributeList() );
147         // not needed.. done in solver_init: mpParam->setSize ... in solver_interface
148         mpParam->parseAttrList();
149
150         mpLbm->setAttrList( getAttributeList() );
151         mpLbm->setSwsAttrList( getSwsAttributeList() );
152         mpLbm->parseAttrList();
153         mpParts->parseAttrList( getAttributeList() );
154
155         if(! isSimworldOk() ) return 3;
156         mpParts->setName( getName() + "_part" );
157         mpParts->initialize( glob );
158         if(! isSimworldOk() ) return 4;
159         
160         // init material settings
161         string matMc("default");
162         matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false );
163         mShowSurface   = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false ); 
164         mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false ); 
165
166         checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" );
167         mpLbm->setLbmInitId( mGeoInitId );
168         mpLbm->setGeoStart( mGeoStart );
169         mpLbm->setGeoEnd( mGeoEnd );
170         mpLbm->setRenderGlobals( mpGlob );
171         mpLbm->setName( getName() + "_lbm" );
172         mpLbm->setParticleTracer( mpParts );
173         if(mpElbeemSettings) {
174                 // set further settings from API struct init
175                 this->mOutFilename = string(mpElbeemSettings->outputPath);
176                 mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo );
177                 mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing);
178                 mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs);
179 #if PARALLEL==1
180                 mpLbm->setNumOMPThreads(mpElbeemSettings->threads);
181 #endif
182                 mpLbm->setSizeX(mpElbeemSettings->resolutionxyz);
183                 mpLbm->setSizeY(mpElbeemSettings->resolutionxyz);
184                 mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz);
185                 mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz);
186                 mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine);
187                 mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles);
188                 // set initial particles
189                 mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles);
190                 
191                 // surface generation flag
192                 mpLbm->setSurfGenSettings(mpElbeemSettings->mFsSurfGenSetting);
193
194                 string dinitType = string("no");
195                 if     (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part"); 
196                 else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free"); 
197                 else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no"); 
198                 mpLbm->setDomainBound(dinitType);
199                 mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip);
200                 mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors);
201                 mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize);
202                 debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<<dinitType<<" ps="<<mpElbeemSettings->domainobsPartslip<<" vv"<<mpElbeemSettings->generateVertexVectors<<","<<mpLbm->getDumpVelocities(), 9 );
203
204                 debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<<mpLbm->getGenerateParticles(),10);
205         }
206
207         if(! mpLbm->initializeSolverMemory()   )         { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; }
208         if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; } 
209         if(! mpLbm->initializeSolverGrids()    )         { errMsg("SimulationObject::initialize","initializeSolverGrids  failed"); mPanic=true; return 12; }
210         if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids  status"); mPanic=true; return 13; } 
211         if(! mpLbm->initializeSolverPostinit() )         { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; }
212         if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; } 
213
214         // print cell type stats
215         bool printStats = true;
216         if(glob_mpnum>0) printStats=false; // skip in this case
217         if(printStats) {
218                 const int jmax = sizeof(CellFlagType)*8;
219                 int totalCells = 0;
220                 int flagCount[jmax];
221                 for(int j=0; j<jmax ; j++) flagCount[j] = 0;
222                 int diffInits = 0;
223                 LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell();
224                 for(; mpLbm->noEndCell( cid );
225                                         mpLbm->advanceCell( cid ) ) {
226                         int flag = mpLbm->getCellFlag(cid,0);
227                         int flag2 = mpLbm->getCellFlag(cid,1);
228                         if(flag != flag2) {
229                                 diffInits++;
230                         }
231                         for(int j=0; j<jmax ; j++) {
232                                 if( flag&(1<<j) ) flagCount[j]++;
233                         }
234                         totalCells++;
235                 }
236                 mpLbm->deleteCellIterator( &cid );
237
238                 char charNl = '\n';
239                 debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5);
240                 debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5);
241                 for(int j=0; j<jmax ; j++) {
242                         std::ostringstream out;
243                         if(flagCount[j]>0) {
244                                 out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl;
245                                 debugOutNnl(out.str(), 5);
246                         }
247                 }
248                 // compute dist. of empty/bnd - fluid - if
249                 // cfEmpty   = (1<<0), cfBnd  = (1<< 2), cfFluid   = (1<<10), cfInter   = (1<<11),
250                 if(1){
251                         std::ostringstream out;
252                         out.precision(2); out.width(4);
253                         int totNum = flagCount[1]+flagCount[2]+flagCount[7]+flagCount[8];
254                         double ebFrac = (double)(flagCount[1]+flagCount[2]) / totNum;
255                         double flFrac = (double)(flagCount[7]) / totNum;
256                         double ifFrac = (double)(flagCount[8]) / totNum;
257                         //???
258                         out<<"\tFractions: [empty/bnd - fluid - interface - ext. if]  =  [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<"] "<< charNl;
259
260                         if(diffInits > 0) {
261                                 debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<<diffInits<<"!" , 5);
262                         }
263                         debugOutNnl(out.str(), 5);
264                 }
265         } // cellstats
266
267         // might be modified by mpLbm
268         //mpParts->setStart( mGeoStart );?  mpParts->setEnd( mGeoEnd );?
269         mpParts->setStart( mpLbm->getGeoStart() );
270         mpParts->setEnd(   mpLbm->getGeoEnd()   );
271         mpParts->setCastShadows( false );
272         mpParts->setReceiveShadows( false );
273         mpParts->searchMaterial( glob->getMaterials() );
274
275         // this has to be inited here - before, the values might be unknown
276         IsoSurface *surf = mpLbm->getSurfaceGeoObj();
277         if(surf) {
278                 surf->setName( "final" ); // final surface mesh 
279                 // warning - this might cause overwriting effects for multiple sims and geom dump...
280                 surf->setCastShadows( true );
281                 surf->setReceiveShadows( false );
282                 surf->searchMaterial( glob->getMaterials() );
283                 if(mShowSurface) mObjects.push_back( surf );
284         }
285         
286 #ifdef ELBEEM_PLUGIN
287         mShowParticles=1; // for e.g. dumping
288 #endif // ELBEEM_PLUGIN
289         if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) {
290                 mShowParticles=1;
291                 mpParts->setDumpParts(true);
292         }
293                 //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1);
294         //}  // DEBUG ENABLE!!!!!!!!!!
295         if(mShowParticles) {
296                 mObjects.push_back(mpParts);
297         }
298
299         // add objects to display for debugging (e.g. levelset particles)
300         vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects();
301         for(size_t i=0;i<debugObjs.size(); i++) {
302                 debugObjs[i]->setCastShadows( false );
303                 debugObjs[i]->setReceiveShadows( false );
304                 debugObjs[i]->searchMaterial( glob->getMaterials() );
305                 mObjects.push_back( debugObjs[i] );
306                 debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<<debugObjs[i]->getName(), 10 );
307         }
308         return 0;
309 }
310
311 /*! set current frame */
312 void SimulationObject::setFrameNum(int num) {
313         // advance parametrizer
314         mpParam->setFrameNum(num);
315 }
316
317 /******************************************************************************
318  * simluation interface: advance simulation another step (whatever delta time that might be) 
319  *****************************************************************************/
320 void SimulationObject::step( void )
321 {
322         if(mpParam->getCurrentAniFrameTime()>0.0) {
323                 // dont advance for stopped time
324                 mpLbm->step();
325                 mTime += mpParam->getTimestep();
326                 //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST!
327         }
328         if(mpLbm->getPanic()) mPanic = true;
329
330         checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
331         //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
332                 //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0);
333                 //errMsg("runSimulationCallback cbtest1"," "<<this->getName()<<" ret="<<ret);
334         //}
335   //debMsgStd("SimulationObject::step",DM_MSG," Sim '"<<mName<<"' stepped to "<<mTime<<" (stept="<<(mpParam->getTimestep())<<", framet="<<getFrameTime()<<") ", 10);
336 }
337 /*! prepare visualization of simulation for e.g. raytracing */
338 void SimulationObject::prepareVisualization( void ) {
339         if(mPanic) return;
340         mpLbm->prepareVisualization();
341 }
342
343
344 /******************************************************************************/
345 /* get current start simulation time */
346 double SimulationObject::getStartTime( void ) {
347         //return mpParam->calculateAniStart();
348         return mpParam->getAniStart();
349 }
350 /* get time for a single animation frame */
351 double SimulationObject::getFrameTime( int frame ) {
352         return mpParam->getAniFrameTime(frame);
353 }
354 /* get time for a single time step  */
355 double SimulationObject::getTimestep( void ) {
356         return mpParam->getTimestep();
357 }
358
359
360 /******************************************************************************
361  * return a pointer to the geometry object of this simulation 
362  *****************************************************************************/
363 //ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; }
364 vector<ntlGeometryObject *>::iterator 
365 SimulationObject::getObjectsBegin()
366 {
367         return mObjects.begin();
368 }
369 vector<ntlGeometryObject *>::iterator 
370 SimulationObject::getObjectsEnd()
371 {
372         return mObjects.end();
373 }
374
375
376
377
378
379 /******************************************************************************
380  * GUI - display debug info 
381  *****************************************************************************/
382
383 void SimulationObject::drawDebugDisplay() {
384 #ifndef NOGUI
385         if(!getVisible()) return;
386
387         //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; }
388         //mDebDispSet[ mDebugType ].on = true;
389         //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type );
390         mpLbm->debugDisplay( mDebugType );
391
392         //::lbmMarkedCellDisplay<>( mpLbm );
393         mpLbm->lbmMarkedCellDisplay();
394 #endif
395 }
396
397 /* GUI - display interactive info  */
398 void SimulationObject::drawInteractiveDisplay()
399 {
400 #ifndef NOGUI
401         if(!getVisible()) return;
402         if(mSelectedCid) {
403                 // in debugDisplayNode if dispset is on is ignored...
404                 mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid );
405         }
406 #endif
407 }
408
409
410 /*******************************************************************************/
411 // GUI - handle mouse movement for selection 
412 /*******************************************************************************/
413 void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir)
414 {
415         normalize( dir );
416         // assume 2D sim is in XY plane...
417         
418         double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5;
419         double zt = (zplane-org[2]) / dir[2];
420         ntlVec3Gfx pos(
421                         org[0]+ dir[0] * zt,
422                         org[1]+ dir[1] * zt, 0.0);
423
424         mSelectedCid = mpLbm->getCellAt( pos );
425         //errMsg("SMP ", mName<< x<<" "<<y<<" - "<<dir );
426         x = y = 0; // remove warning
427 }
428                         
429
430 void SimulationObject::setMouseClick()
431 {
432         if(mSelectedCid) {
433                 //::debugPrintNodeInfo<>( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() );
434                 mpLbm->debugPrintNodeInfo( mSelectedCid );
435         }
436 }
437
438 /*! notify object that dump is in progress (e.g. for field dump) */
439 void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
440         if(!mpLbm) return;
441
442         mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename);
443         checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr);
444 }
445
446 /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */
447 int SimulationObject::checkCallerStatus(int status, int frame) {
448         //return 0; // DEBUG
449         int ret = 0;
450         if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
451                 ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame);
452                 if(ret!=FLUIDSIM_CBRET_CONTINUE) {
453                         if(ret==FLUIDSIM_CBRET_STOP) {
454                                 debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1);
455                                 setElbeemState( SIMWORLD_STOP );
456                         }
457                         else if(ret==FLUIDSIM_CBRET_ABORT) {
458                                 errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR );
459                                 mPanic = 1;
460                         }
461                         else {
462                                 errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<<ret<<", ignoring... ");
463                         }
464                 }
465         }
466
467         //debMsgStd("SimulationObject::checkCallerStatus",DM_MSG, "s="<<status<<",f="<<frame<<" "<<this->getName()<<" ret="<<ret);
468         if(isSimworldOk()) return 0;
469         return 1;
470 }
471