/** \file elbeem/intern/simulation_object.cpp * \ingroup elbeem */ /****************************************************************************** * * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method * Copyright 2003-2006 Nils Thuerey * * Basic interface for all simulation modules * *****************************************************************************/ #include "simulation_object.h" #include "solver_interface.h" #include "ntl_bsptree.h" #include "ntl_ray.h" #include "ntl_world.h" #include "solver_interface.h" #include "particletracer.h" #include "elbeem.h" #if PARALLEL==1 #include #endif #ifdef _WIN32 #else #include #endif //! lbm factory functions LbmSolverInterface* createSolver(); #if PARALLEL==1 static int omp_threadcache; #endif /****************************************************************************** * Constructor *****************************************************************************/ SimulationObject::SimulationObject() : ntlGeometryShader(), mGeoStart(-100.0), mGeoEnd(100.0), mpGiTree(NULL), mpGiObjects(NULL), mpGlob(NULL), mPanic( false ), mDebugType( 1 /* =FLUIDDISPNothing*/ ), mpLbm(NULL), mpParam( NULL ), mShowSurface(true), mShowParticles(false), mSelectedCid( NULL ), mpElbeemSettings( NULL ) { mpParam = new Parametrizer(); //for(int i=0; igetSimScene(); mpGiObjects = scene->getObjects(); if(mpGiTree != NULL) delete mpGiTree; char treeFlag = (1<<(mGeoInitId+4)); mpGiTree = new ntlTree( 20, 4, // warning - fixed values for depth & maxtriangles here... scene, treeFlag ); // unused!! overriden by solver interface } /*****************************************************************************/ /*! destroy tree etc. when geometry init done */ /*****************************************************************************/ void SimulationObject::freeGeoTree() { if(mpGiTree != NULL) delete mpGiTree; } // copy & remember settings for later use void SimulationObject::copyElbeemSettings(elbeemSimulationSettings *settings) { mpElbeemSettings = new elbeemSimulationSettings; *mpElbeemSettings = *settings; mGeoInitId = settings->domainId+1; debMsgStd("SimulationObject",DM_MSG,"mGeoInitId="<readString("solver", mSolverType, "SimulationObject","mSolverType", false ); mpLbm = createSolver(); /* check lbm pointer */ if(mpLbm == NULL) { errFatal("SimulationObject::initializeLbmSimulation","Unable to init LBM solver! ", SIMWORLD_INITERROR); return 2; } debMsgStd("SimulationObject::initialized",DM_MSG,"IdStr:"<getIdString() <<" LBM solver! ", 2); mpParts = new ParticleTracer(); // for non-param simulations mpLbm->setParametrizer( mpParam ); mpParam->setAttrList( getAttributeList() ); // not needed.. done in solver_init: mpParam->setSize ... in solver_interface mpParam->parseAttrList(); mpLbm->setAttrList( getAttributeList() ); mpLbm->setSwsAttrList( getSwsAttributeList() ); mpLbm->parseAttrList(); mpParts->parseAttrList( getAttributeList() ); if(! isSimworldOk() ) return 3; mpParts->setName( getName() + "_part" ); mpParts->initialize( glob ); if(! isSimworldOk() ) return 4; // init material settings string matMc("default"); matMc = mpAttrs->readString("material_surf", matMc, "SimulationObject","matMc", false ); mShowSurface = mpAttrs->readInt("showsurface", mShowSurface, "SimulationObject","mShowSurface", false ); mShowParticles = mpAttrs->readInt("showparticles", mShowParticles, "SimulationObject","mShowParticles", false ); checkBoundingBox( mGeoStart, mGeoEnd, "SimulationObject::initializeSimulation" ); mpLbm->setLbmInitId( mGeoInitId ); mpLbm->setGeoStart( mGeoStart ); mpLbm->setGeoEnd( mGeoEnd ); mpLbm->setRenderGlobals( mpGlob ); mpLbm->setName( getName() + "_lbm" ); mpLbm->setParticleTracer( mpParts ); if(mpElbeemSettings) { // set further settings from API struct init if(mpElbeemSettings->outputPath) this->mOutFilename = string(mpElbeemSettings->outputPath); mpLbm->initDomainTrafo( mpElbeemSettings->surfaceTrafo ); mpLbm->setSmoothing(1.0 * mpElbeemSettings->surfaceSmoothing, 1.0 * mpElbeemSettings->surfaceSmoothing); mpLbm->setIsoSubdivs(mpElbeemSettings->surfaceSubdivs); #if PARALLEL==1 omp_threadcache = omp_get_max_threads(); omp_set_num_threads(mpElbeemSettings->threads); printf("Setting omp_threads to usersetting %d \n", mpElbeemSettings->threads); #endif mpLbm->setSizeX(mpElbeemSettings->resolutionxyz); mpLbm->setSizeY(mpElbeemSettings->resolutionxyz); mpLbm->setSizeZ(mpElbeemSettings->resolutionxyz); mpLbm->setPreviewSize(mpElbeemSettings->previewresxyz); mpLbm->setRefinementDesired(mpElbeemSettings->maxRefine); mpLbm->setGenerateParticles(mpElbeemSettings->generateParticles); // set initial particles mpParts->setNumInitialParticles(mpElbeemSettings->numTracerParticles); // surface generation flag mpLbm->setSurfGenSettings(mpElbeemSettings->mFsSurfGenSetting); string dinitType = string("no"); if (mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_PARTSLIP) dinitType = string("part"); else if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_FREESLIP) dinitType = string("free"); else /*if(mpElbeemSettings->domainobsType==FLUIDSIM_OBSTACLE_NOSLIP)*/ dinitType = string("no"); mpLbm->setDomainBound(dinitType); mpLbm->setDomainPartSlip(mpElbeemSettings->domainobsPartslip); mpLbm->setDumpVelocities(mpElbeemSettings->generateVertexVectors); mpLbm->setFarFieldSize(mpElbeemSettings->farFieldSize); debMsgStd("SimulationObject::initialize",DM_MSG,"Added domain bound: "<generateVertexVectors<<","<getDumpVelocities(), 9 ); debMsgStd("SimulationObject::initialize",DM_MSG,"Set ElbeemSettings values "<getGenerateParticles(),10); } if(! mpLbm->initializeSolverMemory() ) { errMsg("SimulationObject::initialize","initializeSolverMemory failed"); mPanic=true; return 10; } if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverMemory status"); mPanic=true; return 11; } if(! mpLbm->initializeSolverGrids() ) { errMsg("SimulationObject::initialize","initializeSolverGrids failed"); mPanic=true; return 12; } if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverGrids status"); mPanic=true; return 13; } if(! mpLbm->initializeSolverPostinit() ) { errMsg("SimulationObject::initialize","initializeSolverPostin failed"); mPanic=true; return 14; } if(checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0)) { errMsg("SimulationObject::initialize","initializeSolverPostin status"); mPanic=true; return 15; } // print cell type stats bool printStats = true; if(glob_mpnum>0) printStats=false; // skip in this case if(printStats) { const int jmax = sizeof(CellFlagType)*8; int totalCells = 0; int flagCount[jmax]; for(int j=0; jgetFirstCell(); for(; mpLbm->noEndCell( cid ); mpLbm->advanceCell( cid ) ) { int flag = mpLbm->getCellFlag(cid,0); int flag2 = mpLbm->getCellFlag(cid,1); if(flag != flag2) { diffInits++; } for(int j=0; jdeleteCellIterator( &cid ); char charNl = '\n'; debugOutNnl("SimulationObject::initializeLbmSimulation celltype stats: " <0) { out<<"\t" << flagCount[j] <<" x "<< convertCellFlagType2String( (CellFlagType)(1< 0) { debMsgStd("SimulationObject::initializeLbmSimulation",DM_MSG,"celltype Warning: Diffinits="<setStart( mGeoStart );? mpParts->setEnd( mGeoEnd );? mpParts->setStart( mpLbm->getGeoStart() ); mpParts->setEnd( mpLbm->getGeoEnd() ); mpParts->setCastShadows( false ); mpParts->setReceiveShadows( false ); mpParts->searchMaterial( glob->getMaterials() ); // this has to be inited here - before, the values might be unknown IsoSurface *surf = mpLbm->getSurfaceGeoObj(); if(surf) { surf->setName( "final" ); // final surface mesh // warning - this might cause overwriting effects for multiple sims and geom dump... surf->setCastShadows( true ); surf->setReceiveShadows( false ); surf->searchMaterial( glob->getMaterials() ); if(mShowSurface) mObjects.push_back( surf ); } #ifdef ELBEEM_PLUGIN mShowParticles=1; // for e.g. dumping #endif // ELBEEM_PLUGIN if((mpLbm->getGenerateParticles()>0.0)||(mpParts->getNumInitialParticles()>0)) { mShowParticles=1; mpParts->setDumpParts(true); } //debMsgStd("SimulationObject::init",DM_NOTIFY,"Using envvar ELBEEM_DUMPPARTICLE to set mShowParticles, DEBUG!",1); //} // DEBUG ENABLE!!!!!!!!!! if(mShowParticles) { mObjects.push_back(mpParts); } // add objects to display for debugging (e.g. levelset particles) vector debugObjs = mpLbm->getDebugObjects(); for(size_t i=0;isetCastShadows( false ); debugObjs[i]->setReceiveShadows( false ); debugObjs[i]->searchMaterial( glob->getMaterials() ); mObjects.push_back( debugObjs[i] ); debMsgStd("SimulationObject::init",DM_NOTIFY,"Added debug obj "<getName(), 10 ); } return 0; } /*! set current frame */ void SimulationObject::setFrameNum(int num) { // advance parametrizer mpParam->setFrameNum(num); } /****************************************************************************** * simluation interface: advance simulation another step (whatever delta time that might be) *****************************************************************************/ void SimulationObject::step( void ) { if(mpParam->getCurrentAniFrameTime()>0.0) { // dont advance for stopped time mpLbm->step(); mTime += mpParam->getTimestep(); //if(mTime>0.001) { errMsg("DEBUG!!!!!!!!","quit mlsu..."); xit(1); } // PROFILE DEBUG TEST! } if(mpLbm->getPanic()) mPanic = true; checkCallerStatus(FLUIDSIM_CBSTATUS_STEP, 0); //if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { //int ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, FLUIDSIM_CBSTATUS_STEP, 0); //errMsg("runSimulationCallback cbtest1"," "<getName()<<" ret="<prepareVisualization(); } /******************************************************************************/ /* get current start simulation time */ double SimulationObject::getStartTime( void ) { //return mpParam->calculateAniStart(); return mpParam->getAniStart(); } /* get time for a single animation frame */ double SimulationObject::getFrameTime( int frame ) { return mpParam->getAniFrameTime(frame); } /* get time for a single time step */ double SimulationObject::getTimestep( void ) { return mpParam->getTimestep(); } /****************************************************************************** * return a pointer to the geometry object of this simulation *****************************************************************************/ //ntlGeometryObject *SimulationObject::getGeometry() { return mpMC; } vector::iterator SimulationObject::getObjectsBegin() { return mObjects.begin(); } vector::iterator SimulationObject::getObjectsEnd() { return mObjects.end(); } /****************************************************************************** * GUI - display debug info *****************************************************************************/ void SimulationObject::drawDebugDisplay() { #ifndef NOGUI if(!getVisible()) return; //if( mDebugType > (MAX_DEBDISPSET-1) ){ errFatal("SimulationObject::drawDebugDisplay","Invalid debug type!", SIMWORLD_GENERICERROR); return; } //mDebDispSet[ mDebugType ].on = true; //errorOut( mDebugType <<"//"<< mDebDispSet[mDebugType].type ); mpLbm->debugDisplay( mDebugType ); //::lbmMarkedCellDisplay<>( mpLbm ); mpLbm->lbmMarkedCellDisplay(); #endif } /* GUI - display interactive info */ void SimulationObject::drawInteractiveDisplay() { #ifndef NOGUI if(!getVisible()) return; if(mSelectedCid) { // in debugDisplayNode if dispset is on is ignored... mpLbm->debugDisplayNode( FLUIDDISPGrid, mSelectedCid ); } #endif } /*******************************************************************************/ // GUI - handle mouse movement for selection /*******************************************************************************/ void SimulationObject::setMousePos(int x,int y, ntlVec3Gfx org, ntlVec3Gfx dir) { normalize( dir ); // assume 2D sim is in XY plane... double zplane = (mGeoEnd[2]-mGeoStart[2])*0.5; double zt = (zplane-org[2]) / dir[2]; ntlVec3Gfx pos( org[0]+ dir[0] * zt, org[1]+ dir[1] * zt, 0.0); mSelectedCid = mpLbm->getCellAt( pos ); //errMsg("SMP ", mName<< x<<" "<( mpLbm, mSelectedCid, mpLbm->getNodeInfoString() ); mpLbm->debugPrintNodeInfo( mSelectedCid ); } } /*! notify object that dump is in progress (e.g. for field dump) */ void SimulationObject::notifyShaderOfDump(int dumptype, int frameNr,char *frameNrStr,string outfilename) { if(!mpLbm) return; mpLbm->notifySolverOfDump(dumptype, frameNr,frameNrStr,outfilename); checkCallerStatus(FLUIDSIM_CBSTATUS_NEWFRAME, frameNr); } /*! check status (e.g. stop/abort) from calling program, returns !=0 if sth. happened... */ int SimulationObject::checkCallerStatus(int status, int frame) { //return 0; // DEBUG int ret = 0; if((mpElbeemSettings)&&(mpElbeemSettings->runsimCallback)) { ret = (mpElbeemSettings->runsimCallback)(mpElbeemSettings->runsimUserData, status,frame); if(ret!=FLUIDSIM_CBRET_CONTINUE) { if(ret==FLUIDSIM_CBRET_STOP) { debMsgStd("SimulationObject::notifySolverOfDump",DM_NOTIFY,"Got stop signal from caller",1); setElbeemState( SIMWORLD_STOP ); } else if(ret==FLUIDSIM_CBRET_ABORT) { errFatal("SimulationObject::notifySolverOfDump","Got abort signal from caller, aborting...", SIMWORLD_GENERICERROR ); mPanic = 1; } else { errMsg("SimulationObject::notifySolverOfDump","Invalid callback return value: "<getName()<<" ret="<