Blender V2.61 - r43446

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