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