示例#1
0
文件: Scene.hpp 项目: CrazyHeex/woo
		void pySelfTest(){ selfTest_maybe(/*force*/true); }
示例#2
0
文件: Scene.cpp 项目: einoo/woodem
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
	}
}