Blender  V2.59
simulation_object.cpp
Go to the documentation of this file.
00001 
00004 /******************************************************************************
00005  *
00006  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
00007  * Copyright 2003-2006 Nils Thuerey
00008  *
00009  * Basic interface for all simulation modules
00010  *
00011  *****************************************************************************/
00012 
00013 #include "simulation_object.h"
00014 #include "solver_interface.h"
00015 #include "ntl_bsptree.h"
00016 #include "ntl_ray.h"
00017 #include "ntl_world.h"
00018 #include "solver_interface.h"
00019 #include "particletracer.h"
00020 #include "elbeem.h"
00021 
00022 #ifdef _WIN32
00023 #else
00024 #include <sys/time.h>
00025 #endif
00026 
00027 
00029 LbmSolverInterface* createSolver();
00030 
00031 
00032 /******************************************************************************
00033  * Constructor
00034  *****************************************************************************/
00035 SimulationObject::SimulationObject() :
00036         ntlGeometryShader(),
00037         mGeoStart(-100.0), mGeoEnd(100.0),
00038         mpGiTree(NULL), mpGiObjects(NULL),
00039         mpGlob(NULL),
00040         mPanic( false ),
00041         mDebugType( 1 /* =FLUIDDISPNothing*/ ),
00042         mpLbm(NULL), mpParam( NULL ),
00043         mShowSurface(true), mShowParticles(false),
00044         mSelectedCid( NULL ),
00045         mpElbeemSettings( NULL )
00046 
00047 {
00048         mpParam = new Parametrizer();
00049         //for(int i=0; i<MAX_DEBDISPSET; i++) { mDebDispSet[i].type  = (i); mDebDispSet[i].on    = false; mDebDispSet[i].scale = 1.0; }
00050 
00051         // reset time
00052         mTime                                           = 0.0;
00053 }
00054 
00055 
00056 /******************************************************************************
00057  * Destructor
00058  *****************************************************************************/
00059 SimulationObject::~SimulationObject()
00060 {
00061         if(mpGiTree)         delete mpGiTree;
00062         if(mpElbeemSettings) delete mpElbeemSettings;
00063         if(mpLbm)            delete mpLbm;
00064         if(mpParam)          delete mpParam;
00065         if(mpParts)          delete mpParts;
00066         debMsgStd("SimulationObject",DM_MSG,"El'Beem Done!\n",10);
00067 }
00068 
00069 
00070 
00071 /*****************************************************************************/
00073 /*****************************************************************************/
00074 void SimulationObject::initGeoTree() {
00075         // unused!! overriden by solver interface       
00076         if(mpGlob == NULL) { 
00077                 errFatal("SimulationObject::initGeoTree error","Requires globals!", SIMWORLD_INITERROR); 
00078                 return;
00079         }
00080         ntlScene *scene = mpGlob->getSimScene();
00081         mpGiObjects = scene->getObjects();
00082 
00083         if(mpGiTree != NULL) delete mpGiTree;
00084         char treeFlag = (1<<(mGeoInitId+4));
00085         mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here...
00086                                                                                                 scene, treeFlag );
00087         // unused!! overriden by solver interface       
00088 }
00089 
00090 /*****************************************************************************/
00092 /*****************************************************************************/
00093 void SimulationObject::freeGeoTree() {
00094         if(mpGiTree != NULL) delete mpGiTree;
00095 }
00096 
00097 
00098 
00099 // copy & remember settings for later use
00100 void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) {
00101         mpElbeemSettings = new elbeemSimulationSettings;
00102         *mpElbeemSettings = *settings;
00103 
00104         mGeoInitId = settings->domainId+1;
00105         debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<<mGeoInitId<<", domainId="<<settings->domainId, 8);
00106 }
00107 
00108 /******************************************************************************
00109  * simluation interface: initialize simulation using the given configuration file 
00110  *****************************************************************************/
00111 extern int glob_mpnum;
00112 int SimulationObject::initializeLbmSimulation(ntlRenderGlobals *glob)
00113 {
00114         if(! isSimworldOk() ) return 1;
00115         
00116         // already inited?
00117         if(mpLbm) return 0;
00118         
00119         mpGlob = glob;
00120         if(!getVisible()) {
00121                 mpAttrs->setAllUsed();
00122                 return 0;
00123         }
00124 
00125 
00126         mGeoInitId = mpAttrs->readInt("geoinitid", mGeoInitId,"LbmSolverInterface", "mGeoInitId", false);
00127         //mDimension, mSolverType are deprecated
00128         string mSolverType(""); 
00129         mSolverType = mpAttrs->readString("solver", mSolverType, "SimulationObject","mSolverType", false ); 
00130 
00131         mpLbm = createSolver(); 
00132   /* check lbm pointer */
00133         if(mpLbm == NULL) {
00134                 errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR);
00135                 return 2;
00136         }
00137         debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<<mpLbm->getIdString() <<" LBM solver! ", 2);
00138 
00139         mpParts = new ParticleTracer();
00140 
00141         // for non-param simulations
00142         mpLbm->setParametrizer( mpParam );
00143         mpParam->setAttrList( getAttributeList() );
00144         // not needed.. done in solver_init: mpParam->setSize ... in solver_interface
00145         mpParam->parseAttrList();
00146 
00147         mpLbm->setAttrList( getAttributeList() );
00148         mpLbm->setSwsAttrList( getSwsAttributeList() );
00149         mpLbm->parseAttrList();
00150         mpParts->parseAttrList( getAttributeList() );
00151 
00152         if(! isSimworldOk() ) return 3;
00153         mpParts->setName( getName() + "_part" );
00154         mpParts->initialize( glob );
00155         if(! isSimworldOk() ) return 4;
00156         
00157         // init material settings
00158         string matMc("default");
00159         matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false );
00160         mShowSurface   = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false ); 
00161         mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false ); 
00162 
00163         checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" );
00164         mpLbm->setLbmInitId( mGeoInitId );
00165         mpLbm->setGeoStart( mGeoStart );
00166         mpLbm->setGeoEnd( mGeoEnd );
00167         mpLbm->setRenderGlobals( mpGlob );
00168         mpLbm->setName( getName() + "_lbm" );
00169         mpLbm->setParticleTracer( mpParts );
00170         if(mpElbeemSettings) {
00171                 // set further settings from API struct init
00172                 if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath);
00173                 mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo );
00174                 mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing);
00175                 mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs);
00176                 mpLbm->setSizeX(mpElbeemSettings->resolutionxyz);
00177                 mpLbm->setSizeY(mpElbeemSettings->resolutionxyz);
00178                 mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz);
00179                 mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz);
00180                 mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine);
00181                 mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles);
00182                 // set initial particles
00183                 mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles);
00184                 
00185                 // surface generation flag
00186                 mpLbm->setSurfGenSettings(mpElbeemSettings->mFsSurfGenSetting);
00187 
00188                 string dinitType = string("no");
00189                 if     (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part"); 
00190                 else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free"); 
00191                 else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no"); 
00192                 mpLbm->setDomainBound(dinitType);
00193                 mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip);
00194                 mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors);
00195                 mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize);
00196                 debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<<dinitType<<" ps="<<mpElbeemSettings->domainobsPartslip<<" vv"<<mpElbeemSettings->generateVertexVectors<<","<<mpLbm->getDumpVelocities(), 9 );
00197 
00198                 debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<<mpLbm->getGenerateParticles(),10);
00199         }
00200 
00201         if(! mpLbm->initializeSolverMemory()   )         { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; }
00202         if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; } 
00203         if(! mpLbm->initializeSolverGrids()    )         { errMsg("SimulationObject::initialize","initializeSolverGrids  failed"); mPanic=true; return 12; }
00204         if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids  status"); mPanic=true; return 13; } 
00205         if(! mpLbm->initializeSolverPostinit() )         { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; }
00206         if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; } 
00207 
00208         // print cell type stats
00209         bool printStats = true;
00210         if(glob_mpnum>0) printStats=false; // skip in this case
00211         if(printStats) {
00212                 const int jmax = sizeof(CellFlagType)*8;
00213                 int totalCells = 0;
00214                 int flagCount[jmax];
00215                 for(int j=0; j<jmax ; j++) flagCount[j] = 0;
00216                 int diffInits = 0;
00217                 LbmSolverInterface::CellIdentifier cid = mpLbm->getFirstCell();
00218                 for(; mpLbm->noEndCell( cid );
00219                                         mpLbm->advanceCell( cid ) ) {
00220                         int flag = mpLbm->getCellFlag(cid,0);
00221                         int flag2 = mpLbm->getCellFlag(cid,1);
00222                         if(flag != flag2) {
00223                                 diffInits++;
00224                         }
00225                         for(int j=0; j<jmax ; j++) {
00226                                 if( flag&(1<<j) ) flagCount[j]++;
00227                         }
00228                         totalCells++;
00229                 }
00230                 mpLbm->deleteCellIterator( &cid );
00231 
00232                 char charNl = '\n';
00233                 debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <<charNl, 5);
00234                 debugOutNnl("no. of cells = "<<totalCells<<", "<<charNl ,5);
00235                 for(int j=0; j<jmax ; j++) {
00236                         std::ostringstream out;
00237                         if(flagCount[j]>0) {
00238                                 out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1<<j) ) <<", " << charNl;
00239                                 debugOutNnl(out.str(), 5);
00240                         }
00241                 }
00242                 // compute dist. of empty/bnd - fluid - if
00243                 // cfEmpty   = (1<<0), cfBnd  = (1<< 2), cfFluid   = (1<<10), cfInter   = (1<<11),
00244                 if(1){
00245                         std::ostringstream out;
00246                         out.precision(2); out.width(4);
00247                         int totNum = flagCount[1]+flagCount[2]+flagCount[7]+flagCount[8];
00248                         double ebFrac = (double)(flagCount[1]+flagCount[2]) / totNum;
00249                         double flFrac = (double)(flagCount[7]) / totNum;
00250                         double ifFrac = (double)(flagCount[8]) / totNum;
00251                         //???
00252                         out<<"\tFractions: [empty/bnd - fluid - interface - ext. if]  =  [" << ebFrac<<" - " << flFrac<<" - " << ifFrac<<"] "<< charNl;
00253 
00254                         if(diffInits > 0) {
00255                                 debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<<diffInits<<"!" , 5);
00256                         }
00257                         debugOutNnl(out.str(), 5);
00258                 }
00259         } // cellstats
00260 
00261         // might be modified by mpLbm
00262         //mpParts->setStart( mGeoStart );?  mpParts->setEnd( mGeoEnd );?
00263         mpParts->setStart( mpLbm->getGeoStart() );
00264         mpParts->setEnd(   mpLbm->getGeoEnd()   );
00265         mpParts->setCastShadows( false );
00266         mpParts->setReceiveShadows( false );
00267         mpParts->searchMaterial( glob->getMaterials() );
00268 
00269         // this has to be inited here - before, the values might be unknown
00270         IsoSurface *surf = mpLbm->getSurfaceGeoObj();
00271         if(surf) {
00272                 surf->setName( "final" ); // final surface mesh 
00273                 // warning - this might cause overwriting effects for multiple sims and geom dump...
00274                 surf->setCastShadows( true );
00275                 surf->setReceiveShadows( false );
00276                 surf->searchMaterial( glob->getMaterials() );
00277                 if(mShowSurface) mObjects.push_back( surf );
00278         }
00279         
00280 #ifdef ELBEEM_PLUGIN
00281         mShowParticles=1; // for e.g. dumping
00282 #endif // ELBEEM_PLUGIN
00283         if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) {
00284                 mShowParticles=1;
00285                 mpParts->setDumpParts(true);
00286         }
00287                 //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1);
00288         //}  // DEBUG ENABLE!!!!!!!!!!
00289         if(mShowParticles) {
00290                 mObjects.push_back(mpParts);
00291         }
00292 
00293         // add objects to display for debugging (e.g. levelset particles)
00294         vector<ntlGeometryObject *> debugObjs = mpLbm->getDebugObjects();
00295         for(size_t i=0;i<debugObjs.size(); i++) {
00296                 debugObjs[i]->setCastShadows( false );
00297                 debugObjs[i]->setReceiveShadows( false );
00298                 debugObjs[i]->searchMaterial( glob->getMaterials() );
00299                 mObjects.push_back( debugObjs[i] );
00300                 debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<<debugObjs[i]->getName(), 10 );
00301         }
00302         return 0;
00303 }
00304 
00306 void SimulationObject::setFrameNum(int num) {
00307         // advance parametrizer
00308         mpParam->setFrameNum(num);
00309 }
00310 
00311 /******************************************************************************
00312  * simluation interface: advance simulation another step (whatever delta time that might be) 
00313  *****************************************************************************/
00314 void SimulationObject::step( void )
00315 {
00316         if(mpParam->getCurrentAniFrameTime()>0.0) {
00317                 // dont advance for stopped time
00318                 mpLbm->step();
00319                 mTime += mpParam->getTimestep();
00320                 //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST!
00321         }
00322         if(mpLbm->getPanic()) mPanic = true;
00323 
00324         checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0);
00325         //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
00326                 //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0);
00327                 //errMsg("runSimulationCallback cbtest1"," "<<this->getName()<<" ret="<<ret);
00328         //}
00329   //debMsgStd("SimulationObject::step",DM_MSG," Sim '"<<mName<<"' stepped to "<<mTime<<" (stept="<<(mpParam->getTimestep())<<", framet="<<getFrameTime()<<") ", 10);
00330 }
00332 void SimulationObject::prepareVisualization( void ) {
00333         if(mPanic) return;
00334         mpLbm->prepareVisualization();
00335 }
00336 
00337 
00338 /******************************************************************************/
00339 /* get current start simulation time */
00340 double SimulationObject::getStartTime( void ) {
00341         //return mpParam->calculateAniStart();
00342         return mpParam->getAniStart();
00343 }
00344 /* get time for a single animation frame */
00345 double SimulationObject::getFrameTime( int frame ) {
00346         return mpParam->getAniFrameTime(frame);
00347 }
00348 /* get time for a single time step  */
00349 double SimulationObject::getTimestep( void ) {
00350         return mpParam->getTimestep();
00351 }
00352 
00353 
00354 /******************************************************************************
00355  * return a pointer to the geometry object of this simulation 
00356  *****************************************************************************/
00357 //ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; }
00358 vector<ntlGeometryObject *>::iterator 
00359 SimulationObject::getObjectsBegin()
00360 {
00361         return mObjects.begin();
00362 }
00363 vector<ntlGeometryObject *>::iterator 
00364 SimulationObject::getObjectsEnd()
00365 {
00366         return mObjects.end();
00367 }
00368 
00369 
00370 
00371 
00372 
00373 /******************************************************************************
00374  * GUI - display debug info 
00375  *****************************************************************************/
00376 
00377 void SimulationObject::drawDebugDisplay() {
00378 #ifndef NOGUI
00379         if(!getVisible()) return;
00380 
00381         //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; }
00382         //mDebDispSet[ mDebugType ].on = true;
00383         //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type );
00384         mpLbm->debugDisplay( mDebugType );
00385 
00386         //::lbmMarkedCellDisplay<>( mpLbm );
00387         mpLbm->lbmMarkedCellDisplay();
00388 #endif
00389 }
00390 
00391 /* GUI - display interactive info  */
00392 void SimulationObject::drawInteractiveDisplay()
00393 {
00394 #ifndef NOGUI
00395         if(!getVisible()) return;
00396         if(mSelectedCid) {
00397                 // in debugDisplayNode if dispset is on is ignored...
00398                 mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid );
00399         }
00400 #endif
00401 }
00402 
00403 
00404 /*******************************************************************************/
00405 // GUI - handle mouse movement for selection 
00406 /*******************************************************************************/
00407 void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir)
00408 {
00409         normalize( dir );
00410         // assume 2D sim is in XY plane...
00411         
00412         double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5;
00413         double zt = (zplane-org[2]) / dir[2];
00414         ntlVec3Gfx pos(
00415                         org[0]+ dir[0] * zt,
00416                         org[1]+ dir[1] * zt, 0.0);
00417 
00418         mSelectedCid = mpLbm->getCellAt( pos );
00419         //errMsg("SMP ", mName<< x<<" "<<y<<" - "<<dir );
00420         x = y = 0; // remove warning
00421 }
00422                         
00423 
00424 void SimulationObject::setMouseClick()
00425 {
00426         if(mSelectedCid) {
00427                 //::debugPrintNodeInfo<>( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() );
00428                 mpLbm->debugPrintNodeInfo( mSelectedCid );
00429         }
00430 }
00431 
00433 void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) {
00434         if(!mpLbm) return;
00435 
00436         mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename);
00437         checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr);
00438 }
00439 
00441 int SimulationObject::checkCallerStatus(int status, int frame) {
00442         //return 0; // DEBUG
00443         int ret = 0;
00444         if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) {
00445                 ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame);
00446                 if(ret!=FLUIDSIM_CBRET_CONTINUE) {
00447                         if(ret==FLUIDSIM_CBRET_STOP) {
00448                                 debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1);
00449                                 setElbeemState( SIMWORLD_STOP );
00450                         }
00451                         else if(ret==FLUIDSIM_CBRET_ABORT) {
00452                                 errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR );
00453                                 mPanic = 1;
00454                         }
00455                         else {
00456                                 errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<<ret<<", ignoring... ");
00457                         }
00458                 }
00459         }
00460 
00461         //debMsgStd("SimulationObject::checkCallerStatus",DM_MSG, "s="<<status<<",f="<<frame<<" "<<this->getName()<<" ret="<<ret);
00462         if(isSimworldOk()) return 0;
00463         return 1;
00464 }
00465