void pySelfTest(){ selfTest_maybe(/*force*/true); }
void Scene::doOneStep(){ #ifdef WOO_LOOP_MUTEX_HELP // add some daly to help the other thread locking the mutex; will be removed once if(engineLoopMutexWaiting){ boost::this_thread::sleep(boost::posix_time::milliseconds(100)); } #endif boost::timed_mutex::scoped_lock lock(engineLoopMutex); if(runInternalConsistencyChecks){ runInternalConsistencyChecks=false; // checkStateTypes(); } // check and automatically set timestep if(isnan(dt)||isinf(dt)||dt<0){ #if 0 throw std::runtime_error("Scene::dt is NaN, Inf or negative"); #else dt=Inf; for(const auto& e: engines){ e->scene=this; if(!e->field && e->needsField()) throw std::runtime_error(e->pyStr()+" has no field to run on, but requires one."); if(e->dead) continue; // skip completely dead engines, but not those who are not isActivated() Real crDt=e->critDt(); LOG_INFO("Critical dt from "+e->pyStr()+": "<<crDt); dt=min(dt,crDt); } for(const auto& f: fields){ f->scene=this; Real crDt=f->critDt(); LOG_INFO("Critical dt from "+f->pyStr()+": "<<crDt); dt=min(dt,crDt); } if(isinf(dt)) throw std::runtime_error("Failed to obtain meaningful dt from engines and fields automatically."); dt=dtSafety*dt; #endif } // substepping or not, update engines from _nextEngines, if defined, at the beginning of step // subStep can be 0, which happens if simulations is saved in the middle of step (without substepping) // this assumes that prologue will not set _nextEngines, which is safe hopefully if(!_nextEngines.empty() && (subStep<0 || (subStep<=0 && !subStepping))){ engines=_nextEngines; _nextEngines.clear(); postLoad(*this,NULL); // setup labels, check fields etc // hopefully this will not break in some margin cases (subStepping with setting _nextEngines and such) subStep=-1; } for(const shared_ptr<Field>& f: fields) if(f->scene!=this) f->scene=this; if(likely(!subStepping && subStep<0)){ /* set substep to 0 during the loop, so that engines/nextEngines handler know whether we are inside the loop currently */ subStep=0; // ** 1. ** prologue selfTest_maybe(); if(isPeriodic) cell->integrateAndUpdate(dt); if(trackEnergy) energy->resetResettables(); const bool TimingInfo_enabled=TimingInfo::enabled; // cache the value, so that when it is changed inside the step, the engine that was just running doesn't get bogus values TimingInfo::delta last=TimingInfo::getNow(); // actually does something only if TimingInfo::enabled, no need to put the condition here // ** 2. ** engines for(const shared_ptr<Engine>& e: engines){ e->scene=this; if(!e->field && e->needsField()) throw std::runtime_error(e->pyStr()+" has no field to run on, but requires one."); if(e->dead || !e->isActivated()) continue; e->run(); if(unlikely(TimingInfo_enabled)) {TimingInfo::delta now=TimingInfo::getNow(); e->timingInfo.nsec+=now-last; e->timingInfo.nExec+=1; last=now;} } // ** 3. ** epilogue if(isPeriodic) cell->setNextGradV(); step++; time+=dt; subStep=-1; if(!isnan(nextDt)){ dt=nextDt; nextDt=NaN; } } else { /* IMPORTANT: take care to copy EXACTLY the same sequence as is in the block above !! */ if(TimingInfo::enabled){ TimingInfo::enabled=false; LOG_INFO("Master.timingEnabled disabled, since Master.subStepping is used."); } if(subStep<-1 || subStep>(int)engines.size()){ LOG_ERROR("Invalid value of Scene::subStep ("<<subStep<<"), setting to -1 (prologue will be run)."); subStep=-1; } // if subStepping is disabled, it means we have not yet finished last step completely; in that case, do that here by running all remaining substeps at once // if subStepping is enabled, just run the step we need (the loop is traversed only once, with subs==subStep) int maxSubStep=subStep; if(!subStepping){ maxSubStep=engines.size(); LOG_INFO("Running remaining sub-steps ("<<subStep<<"…"<<maxSubStep<<") before disabling sub-stepping."); } for(int subs=subStep; subs<=maxSubStep; subs++){ assert(subs>=-1 && subs<=(int)engines.size()); // ** 1. ** prologue if(subs==-1){ selfTest_maybe(); if(isPeriodic) cell->integrateAndUpdate(dt); if(trackEnergy) energy->resetResettables(); } // ** 2. ** engines else if(subs>=0 && subs<(int)engines.size()){ const shared_ptr<Engine>& e(engines[subs]); e->scene=this; if(!e->field && e->needsField()) throw std::runtime_error((getClassName()+" has no field to run on, but requires one.").c_str()); if(!e->dead && e->isActivated()) e->run(); } // ** 3. ** epilogue else if(subs==(int)engines.size()){ if(isPeriodic) cell->setNextGradV(); step++; time+=dt; /* gives -1 along with the increment afterwards */ subStep=-2; if(!isnan(nextDt)){ dt=nextDt; nextDt=NaN; } } // (?!) else { /* never reached */ assert(false); } } subStep++; // if not substepping, this will make subStep=-2+1=-1, which is what we want } }