yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #06144
[Branch ~yade-dev/yade/trunk] Rev 2542: 1. Allow O.engines to be modified inside the loop from python
------------------------------------------------------------
revno: 2542
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Fri 2010-11-12 10:48:58 +0100
message:
1. Allow O.engines to be modified inside the loop from python
2. Fix include dir creation (thanks, buildbot)
3. Fix Ip2_FrictMat_FrictMat_FrictPhys failure (inversed conditional)
4. Add tests for substepping, modification of O.engines and Engine.dead
5. Remove O.initializers
modified:
SConstruct
core/EnergyTracker.hpp
core/Scene.cpp
core/Scene.hpp
pkg/common/GravityEngines.cpp
pkg/common/GravityEngines.hpp
pkg/dem/CapillaryTriaxialTest.cpp
pkg/dem/Ip2_FrictMat_FrictMat_FrictPhys.cpp
pkg/dem/NewtonIntegrator.cpp
pkg/dem/NewtonIntegrator.hpp
pkg/dem/STLImporterTest.cpp
pkg/dem/Shop.cpp
pkg/dem/Shop.hpp
py/tests/omega.py
py/wrapper/yadeWrapper.cpp
scripts/test/energy.py
--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk
Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription
=== modified file 'SConstruct'
--- SConstruct 2010-11-12 08:03:16 +0000
+++ SConstruct 2010-11-12 09:48:58 +0000
@@ -465,7 +465,7 @@
if not env.GetOption('clean'):
# how to make that executed automatically??! For now, run always.
#env.AddPreAction(installAlias,installHeaders)
- from os.path import join,split,isabs,isdir,exists,lexists,islink,isfile,sep
+ from os.path import join,split,isabs,isdir,exists,lexists,islink,isfile,sep,dirname
#installHeaders() # install to buildDir always
#if 0: # do not install headers
# installHeaders(env.subst('$PREFIX')) # install to $PREFIX if specifically requested: like "scons /usr/local/include"
@@ -476,18 +476,13 @@
shutil.rmtree(link)
if not exists(link):
if lexists(link): os.remove(link) # remove dangling symlink
+ d=os.path.dirname(link)
+ if not exists(d): os.makedirs(d)
os.symlink(relpath(link,target),link)
yadeInc=join(buildDir,'include/yade')
mkSymlink(yadeInc,'.')
- #if not os.path.exists(yadeInc): os.makedirs(yadeInc)
import glob
- # old compat paths
- #for p in ['core','extra']+glob.glob('lib/*')+glob.glob('pkg/*')+glob.glob('gui'):
- # link=yadeInc+'/'+p.replace('/','-')
- # if os.path.isdir(p) and not os.path.exists(link):
- # if lexists(link): os.remove(link) # dangling symlink
- # os.symlink(relpath(link,p),link)
boostDir=buildDir+'/include/boost'
if not exists(boostDir): os.makedirs(boostDir)
if not env['haveForeach']:
=== modified file 'core/EnergyTracker.hpp'
--- core/EnergyTracker.hpp 2010-11-07 11:46:20 +0000
+++ core/EnergyTracker.hpp 2010-11-12 09:48:58 +0000
@@ -43,6 +43,7 @@
int id=-1; set(val,name,id);
}
void clear(){ energies.clear(); names.clear(); resetStep.clear();}
+ Real total(){ Real ret=0; size_t sz=energies.size(); for(size_t id=0; id<sz; id++) ret+=energies.get(id); return ret; }
py::list keys_py(){ py::list ret; FOREACH(pairStringInt p, names) ret.append(p.first); return ret; }
void resetResettables(){ size_t sz=energies.size(); for(size_t id=0; id<sz; id++){ if(resetStep[id]) energies.reset(id); } }
@@ -60,6 +61,7 @@
.def("__setitem__",&EnergyTracker::setItem_py,"Set energy value for given name (will create a non-resettable item, if it does not exist yet).")
.def("clear",&EnergyTracker::clear,"Clear all stored values.")
.def("keys",&EnergyTracker::keys_py,"Return defined energies.")
+ .def("total",&EnergyTracker::total,"Return sum of all energies.")
)
};
REGISTER_SERIALIZABLE(EnergyTracker);
=== modified file 'core/Scene.cpp'
--- core/Scene.cpp 2010-11-07 11:46:20 +0000
+++ core/Scene.cpp 2010-11-12 09:48:58 +0000
@@ -67,13 +67,19 @@
void Scene::moveToNextTimeStep(){
- if(needsInitializers){
+ if(runInternalConsistencyChecks){
+ runInternalConsistencyChecks=false;
checkStateTypes();
- FOREACH(shared_ptr<Engine> e, initializers){ e->scene=this; if(e->dead || !e->isActivated()) continue; e->action(); }
- forces.resize(bodies->size());
- needsInitializers=false;
+ forces.resize(bodies->size()); // optimization, not necessary
+ }
+ // substepping or not, update engines from _nextEngines, if defined
+ if(!_nextEngines.empty() && subStep<0){
+ engines=_nextEngines;
+ _nextEngines.clear();
}
if(!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
if(isPeriodic) cell->integrateAndUpdate(dt);
//forces.reset(); // uncomment if ForceResetter is removed
@@ -89,6 +95,7 @@
// ** 3. ** epilogue
iter++;
time+=dt;
+ subStep=-1;
} else {
/* IMPORTANT: take care to copy EXACTLY the same sequence as is in the block above !! */
if(TimingInfo::enabled){ TimingInfo::enabled=false; LOG_INFO("O.timingEnabled disabled, since O.subStepping is used."); }
=== modified file 'core/Scene.hpp'
--- core/Scene.hpp 2010-10-29 10:12:44 +0000
+++ core/Scene.hpp 2010-11-12 09:48:58 +0000
@@ -73,12 +73,12 @@
#endif
((bool,isPeriodic,false,Attr::readonly,"Whether periodic boundary conditions are active."))
((bool,trackEnergy,false,Attr::readonly,"Whether energies are being traced."))
- ((bool,needsInitializers,true,Attr::readonly,"Whether initializers will be run before the first step."))
+ ((bool,runInternalConsistencyChecks,true,Attr::hidden,"Run internal consistency check, right before the very first simulation step."))
((Body::id_t,selectedBody,-1,,"Id of body that is selected by the user"))
((list<string>,tags,,,"Arbitrary key=value associations (tags like mp3 tags: author, date, version, description etc.)"))
((vector<shared_ptr<Engine> >,engines,,Attr::hidden,"Engines sequence in the simulation."))
- ((vector<shared_ptr<Engine> >,initializers,,Attr::hidden,"Engines that will be run only once, before the first step."))
+ ((vector<shared_ptr<Engine> >,_nextEngines,,Attr::hidden,"Engines to be used from the next step on; is returned transparently by O.engines if in the middle of the loop (controlled by subStep>=0)."))
((shared_ptr<BodyContainer>,bodies,new BodyContainer,Attr::hidden,"Bodies contained in the scene."))
((shared_ptr<InteractionContainer>,interactions,new InteractionContainer,Attr::hidden,"All interactions between bodies."))
((shared_ptr<EnergyTracker>,energy,new EnergyTracker,Attr::hidden,"Energy values, if energy tracking is enabled."))
=== modified file 'pkg/common/GravityEngines.cpp'
--- pkg/common/GravityEngines.cpp 2010-11-07 11:46:20 +0000
+++ pkg/common/GravityEngines.cpp 2010-11-12 09:48:58 +0000
@@ -27,6 +27,7 @@
// skip clumps, only apply forces on their constituents
if(!b || b->isClump()) continue;
scene->forces.addForce(b->getId(),gravity*b->state->mass);
+ if(scene->trackEnergy) scene->energy->add(gravity.dot(b->state->pos)*b->state->mass,"gravPot",gravPotIx,/*reset at ever step*/true);
}
}
=== modified file 'pkg/common/GravityEngines.hpp'
--- pkg/common/GravityEngines.hpp 2010-11-07 11:46:20 +0000
+++ pkg/common/GravityEngines.hpp 2010-11-12 09:48:58 +0000
@@ -14,6 +14,7 @@
virtual void action();
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(GravityEngine,FieldApplier,"Engine applying constant acceleration to all bodies.",
((Vector3r,gravity,Vector3r::Zero(),,"Acceleration [kgmsâ»Â²]"))
+ ((int,gravPotIx,-1,(Attr::noSave|Attr::hidden),"Index for gravPot energy"))
,/*ctor*/,/*py*/
);
};
=== modified file 'pkg/dem/CapillaryTriaxialTest.cpp'
--- pkg/dem/CapillaryTriaxialTest.cpp 2010-11-12 08:03:16 +0000
+++ pkg/dem/CapillaryTriaxialTest.cpp 2010-11-12 09:48:58 +0000
@@ -414,9 +414,6 @@
// scene->engines.push_back(orientationIntegrator);
//scene->engines.push_back(triaxialstressController);
- scene->initializers.clear();
- scene->initializers.push_back(boundDispatcher);
-
}
=== modified file 'pkg/dem/Ip2_FrictMat_FrictMat_FrictPhys.cpp'
--- pkg/dem/Ip2_FrictMat_FrictMat_FrictPhys.cpp 2010-11-12 08:03:16 +0000
+++ pkg/dem/Ip2_FrictMat_FrictMat_FrictPhys.cpp 2010-11-12 09:48:58 +0000
@@ -41,7 +41,7 @@
//same for shear stiffness
Real Ks = 2*Ea*Ra*Va*Eb*Rb*Vb/(Ea*Ra*Va+Eb*Rb*Va);
- contactPhysics->frictionAngle = frictAngle ? std::min(mat1->frictionAngle,mat2->frictionAngle) : (*frictAngle)(mat1->id,mat2->id,mat1->frictionAngle,mat2->frictionAngle);
+ contactPhysics->frictionAngle = (!frictAngle) ? std::min(mat1->frictionAngle,mat2->frictionAngle) : (*frictAngle)(mat1->id,mat2->id,mat1->frictionAngle,mat2->frictionAngle);
contactPhysics->tangensOfFrictionAngle = std::tan(contactPhysics->frictionAngle);
contactPhysics->prevNormal = normal;
contactPhysics->kn = Kn;
=== modified file 'pkg/dem/NewtonIntegrator.cpp'
--- pkg/dem/NewtonIntegrator.cpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/NewtonIntegrator.cpp 2010-11-12 09:48:58 +0000
@@ -10,6 +10,7 @@
#include<yade/core/Scene.hpp>
#include<yade/pkg/dem/Clump.hpp>
#include<yade/pkg/common/VelocityBins.hpp>
+#include<yade/pkg/dem/Shop.hpp>
#include<yade/lib/base/Math.hpp>
YADE_PLUGIN((NewtonIntegrator));
@@ -180,6 +181,7 @@
Clump::moveMembers(b,scene);
}
saveMaximaVelocity(scene,id,state);
+ // if(scene->trackEnergy && (b->isStandalone() || b->isClumpMember())) scene->energy->add(Shop::kineticEnergy_singleParticle(scene,b),"kin",kinEnergyIx,/*non-incremental*/true);
// process callbacks
for(size_t i=0; i<callbacksSize; i++){
=== modified file 'pkg/dem/NewtonIntegrator.hpp'
--- pkg/dem/NewtonIntegrator.hpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/NewtonIntegrator.hpp 2010-11-12 09:48:58 +0000
@@ -56,6 +56,7 @@
((vector<shared_ptr<BodyCallback> >,callbacks,,,"List (std::vector in c++) of :yref:`BodyCallbacks<BodyCallback>` which will be called for each body as it is being processed."))
((Vector3r,prevCellSize,Vector3r(NaN,NaN,NaN),Attr::hidden,"cell size from previous step, used to detect change and find max velocity"))
((bool,warnNoForceReset,true,,"Warn when forces were not resetted in this step by :yref:`ForceResetter`; this mostly points to :yref:`ForceResetter` being forgotten incidentally and should be disabled only with a good reason."))
+ ((int,kinEnergyIx,-1,(Attr::hidden|Attr::noSave),"Index for kinetic energy in scene->energies."))
,
/*ctor*/
#ifdef YADE_OPENMP
=== modified file 'pkg/dem/STLImporterTest.cpp'
--- pkg/dem/STLImporterTest.cpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/STLImporterTest.cpp 2010-11-12 09:48:58 +0000
@@ -235,8 +235,6 @@
scene->engines.push_back(orientationIntegrator);
scene->engines.push_back(kinematic);
- scene->initializers.clear();
- scene->initializers.push_back(boundDispatcher);
}
=== modified file 'pkg/dem/Shop.cpp'
--- pkg/dem/Shop.cpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/Shop.cpp 2010-11-12 09:48:58 +0000
@@ -180,31 +180,34 @@
return (useMaxForce?maxF:meanF)/(sumF);
}
+Real Shop::kineticEnergy_singleParticle(Scene* scene,const shared_ptr<Body>& b){
+ const State* state(b->state.get());
+ // ½(mv²+ÏIÏ)
+ Real E=0;
+ if(scene->isPeriodic){
+ /* Only take in account the fluctuation velocity, not the mean velocity of homothetic resize. */
+ E=.5*state->mass*scene->cell->bodyFluctuationVel(state->pos,state->vel).squaredNorm();
+ } else {
+ E=.5*(state->mass*state->vel.squaredNorm());
+ }
+ if(b->isAspherical()){
+ Matrix3r T(state->ori);
+ // the tensorial expression http://en.wikipedia.org/wiki/Moment_of_inertia#Moment_of_inertia_tensor
+ // inertia tensor rotation from http://www.kwon3d.com/theory/moi/triten.html
+ Matrix3r mI; mI<<state->inertia[0],0,0, 0,state->inertia[1],0, 0,0,state->inertia[2];
+ E+=.5*state->angVel.transpose().dot((T.transpose()*mI*T)*state->angVel);
+ }
+ else { E+=state->angVel.dot(state->inertia.cwise()*state->angVel);}
+ return E;
+}
+
Real Shop::kineticEnergy(Scene* _scene, Body::id_t* maxId){
Scene* scene=_scene ? _scene : Omega::instance().getScene().get();
Real ret=0.;
Real maxE=0; if(maxId) *maxId=Body::ID_NONE;
- const bool isPeriodic=scene->isPeriodic;
FOREACH(const shared_ptr<Body>& b, *scene->bodies){
if(!b || !b->isDynamic()) continue;
- const State* state(b->state.get());
- // ½(mv²+ÏIÏ)
- Vector3r vel=b->state->vel;
- if(isPeriodic){
- /* Only take in account the fluctuation velocity, not the mean velocity of homothetic resize. */
- vel=scene->cell->bodyFluctuationVel(state->pos,vel);
- // create function in Cell that will compute velocity compensations etc for us
- // since it might be used in more places than just here (code audit needed)
- }
- Real E=.5*(state->mass*vel.squaredNorm());
- if(b->isAspherical()){
- Matrix3r T(state->ori);
- // the tensorial expression http://en.wikipedia.org/wiki/Moment_of_inertia#Moment_of_inertia_tensor
- // inertia tensor rotation from http://www.kwon3d.com/theory/moi/triten.html
- Matrix3r mI; mI<<state->inertia[0],0,0, 0,state->inertia[1],0, 0,0,state->inertia[2];
- E+=.5*state->angVel.transpose().dot((T.transpose()*mI*T)*state->angVel);
- }
- else { E+=state->angVel.dot(state->inertia.cwise()*state->angVel);}
+ Real E=Shop::kineticEnergy_singleParticle(scene,b);
if(maxId && E>maxE) { *maxId=b->getId(); maxE=E; }
ret+=E;
}
@@ -261,64 +264,6 @@
}
-/*! Create root body. */
-shared_ptr<Scene> Shop::scene(){
- return shared_ptr<Scene>(new Scene);
-}
-
-
-/*! Assign default set of actors (initializers and engines) to an existing Scene.
- */
-void Shop::rootBodyActors(shared_ptr<Scene> scene){
- // initializers
- scene->initializers.clear();
-
- shared_ptr<BoundDispatcher> boundDispatcher = shared_ptr<BoundDispatcher>(new BoundDispatcher);
- boundDispatcher->add(new Bo1_Sphere_Aabb);
- boundDispatcher->add(new Bo1_Box_Aabb);
- boundDispatcher->add(new Bo1_Tetra_Aabb);
- scene->initializers.push_back(boundDispatcher);
-
- //engines
- scene->engines.clear();
-
- if(getDefault<int>("param_timeStepUpdateInterval")>0){
- shared_ptr<GlobalStiffnessTimeStepper> sdecTimeStepper(new GlobalStiffnessTimeStepper);
- sdecTimeStepper->timeStepUpdateInterval=getDefault<int>("param_timeStepUpdateInterval");
- sdecTimeStepper->timeStepUpdateInterval=300;
- scene->engines.push_back(sdecTimeStepper);
- }
-
- scene->engines.push_back(shared_ptr<Engine>(new ForceResetter));
-
- scene->engines.push_back(boundDispatcher);
-
- scene->engines.push_back(shared_ptr<Engine>(new InsertionSortCollider));
-
- shared_ptr<IGeomDispatcher> interactionGeometryDispatcher(new IGeomDispatcher);
- interactionGeometryDispatcher->add(new Ig2_Sphere_Sphere_ScGeom);
- interactionGeometryDispatcher->add(new Ig2_Box_Sphere_ScGeom);
- interactionGeometryDispatcher->add(new Ig2_Tetra_Tetra_TTetraGeom);
- scene->engines.push_back(interactionGeometryDispatcher);
-
- shared_ptr<IPhysDispatcher> interactionPhysicsDispatcher(new IPhysDispatcher);
- interactionPhysicsDispatcher->add(new Ip2_FrictMat_FrictMat_FrictPhys);
- scene->engines.push_back(interactionPhysicsDispatcher);
-
- shared_ptr<ElasticContactLaw> constitutiveLaw(new ElasticContactLaw);
- scene->engines.push_back(constitutiveLaw);
-
- if(getDefault<Vector3r>("param_gravity")!=Vector3r(0,0,0)){
- shared_ptr<GravityEngine> gravityCondition(new GravityEngine);
- gravityCondition->gravity=getDefault<Vector3r>("param_gravity");
- scene->engines.push_back(gravityCondition);
- }
-
- shared_ptr<NewtonIntegrator> newton(new NewtonIntegrator);
- newton->damping=max(getDefault<double>("param_damping"),0.);
- scene->engines.push_back(newton);
-}
-
shared_ptr<FrictMat> Shop::defaultGranularMat(){
shared_ptr<FrictMat> mat(new FrictMat);
=== modified file 'pkg/dem/Shop.hpp'
--- pkg/dem/Shop.hpp 2010-11-07 11:46:20 +0000
+++ pkg/dem/Shop.hpp 2010-11-12 09:48:58 +0000
@@ -51,13 +51,6 @@
ensureInit(); //cerr<<"Shop: Setting `"<<key<<"'="<<value<<" (type `"<<typeid(valType).name()<<"')."<<endl;
defaults[key]=boost::any(value);}
- //! creates empty scene along with its parameters (bound etc.)
- static shared_ptr<Scene> scene();
- /*! creates engines and initilizers within given Scene: elastic contact law, with gravity, timestepper and damping.
- *
- * All parameters are take from Shop::defaults, which are user-settable.
- */
- static void rootBodyActors(shared_ptr<Scene>);
//! create default sphere, along with its bound etc.
static shared_ptr<Body> sphere(Vector3r center, Real radius, shared_ptr<Material> mat);
//! create default box with everything needed
@@ -101,6 +94,8 @@
//! Get unbalanced force of the whole simulation
static Real unbalancedForce(bool useMaxForce=false, Scene* _rb=NULL);
static Real kineticEnergy(Scene* _rb=NULL, Body::id_t* maxId=NULL);
+ static Real kineticEnergy_singleParticle(Scene* scene, const shared_ptr<Body>& b);
+
static Vector3r totalForceInVolume(Real& avgIsoStiffness, Scene *_rb=NULL);
=== modified file 'py/tests/omega.py'
--- py/tests/omega.py 2010-11-06 11:33:09 +0000
+++ py/tests/omega.py 2010-11-12 09:48:58 +0000
@@ -15,9 +15,52 @@
## TODO tests
class TestInteractions(unittest.TestCase): pass
class TestForce(unittest.TestCase): pass
-class TestEngines(unittest.TestCase): pass
class TestTags(unittest.TestCase): pass
+class TestEngines(unittest.TestCase):
+ def setUp(self): O.reset()
+ def testSubstepping(self):
+ 'Engines: substepping'
+ O.engines=[ForceResetter(),PyRunner(initRun=True,iterPeriod=1,command='pass'),GravityEngine()]
+ # value outside the loop
+ self.assert_(O.subStep==-1)
+ # O.subStep is meaningful when substepping
+ O.subStepping=True
+ O.step(); self.assert_(O.subStep==0)
+ O.step(); self.assert_(O.subStep==1)
+ # when substepping is turned off in the middle of the loop, the next step finishes the loop
+ O.subStepping=False
+ O.step(); self.assert_(O.subStep==-1)
+ print 'substep is',O.subStep
+ # subStep==0 inside the loop without substepping
+ O.engines=[PyRunner(initRun=True,iterPeriod=1,command='if O.subStep!=0: raise RuntimeError("O.subStep!=0 inside the loop with O.subStepping==False!")')]
+ O.step()
+ def testEnginesModificationInsideLoop(self):
+ 'Engines: can be modified inside the loop transparently.'
+ O.engines=[
+ PyRunner(initRun=True,iterPeriod=1,command='from yade import *; O.engines=[ForceResetter(),GravityEngine(),NewtonIntegrator()]'), # change engines here
+ ForceResetter() # useless engine
+ ]
+ O.subStepping=True
+ # run prologue and the first engine, which modifies O.engines
+ O.step(); O.step(); self.assert_(O.subStep==1)
+ self.assert_(len(O.engines)==3) # gives modified engine sequence transparently
+ self.assert_(len(O._nextEngines)==3)
+ self.assert_(len(O._currEngines)==2)
+ O.step(); O.step(); # run the 2nd ForceResetter, and epilogue
+ self.assert_(O.subStep==-1)
+ # start the next step, nextEngines should replace engines automatically
+ O.step()
+ self.assert_(O.subStep==0)
+ self.assert_(len(O._nextEngines)==0)
+ self.assert_(len(O.engines)==3)
+ self.assert_(len(O._currEngines)==3)
+ def testDead(self):
+ 'Engines: dead engines are not run'
+ O.engines=[PyRunner(dead=True,initRun=True,iterPeriod=1,command='pass')]
+ O.step(); self.assert_(O.engines[0].nDone==0)
+
+
class TestIO(unittest.TestCase):
def testSaveAllClasses(self):
'I/O: All classes can be saved and loaded with boost::serialization'
@@ -35,7 +78,6 @@
self.assert_(len(failed)==0,'Failed classes were: '+' '.join(failed))
-
class TestCell(unittest.TestCase):
def setUp(self):
O.reset(); O.periodic=True
=== modified file 'py/wrapper/yadeWrapper.cpp'
--- py/wrapper/yadeWrapper.cpp 2010-11-07 11:46:20 +0000
+++ py/wrapper/yadeWrapper.cpp 2010-11-12 09:48:58 +0000
@@ -422,12 +422,17 @@
}
}
- vector<shared_ptr<Engine> > engines_get(void){assertScene(); return OMEGA.getScene()->engines;}
- void engines_set(const vector<shared_ptr<Engine> >& egs){assertScene(); OMEGA.getScene()->engines.clear(); FOREACH(const shared_ptr<Engine>& e, egs) OMEGA.getScene()->engines.push_back(e); mapLabeledEntitiesToVariables(); }
- vector<shared_ptr<Engine> > initializers_get(void){assertScene(); return OMEGA.getScene()->initializers;}
- void initializers_set(const vector<shared_ptr<Engine> >& egs){assertScene(); OMEGA.getScene()->initializers.clear(); FOREACH(const shared_ptr<Engine>& e, egs) OMEGA.getScene()->initializers.push_back(e); mapLabeledEntitiesToVariables(); OMEGA.getScene()->needsInitializers=true; }
+ vector<shared_ptr<Engine> > engines_get(void){assertScene(); Scene* scene=OMEGA.getScene().get(); return scene->_nextEngines.empty()?scene->engines:scene->_nextEngines;}
+ void engines_set(const vector<shared_ptr<Engine> >& egs){
+ assertScene(); Scene* scene=OMEGA.getScene().get();
+ if(scene->subStep<0) scene->engines=egs; // not inside the engine loop right now, ok to update directly
+ else scene->_nextEngines=egs; // inside the engine loop, update _nextEngines; O.engines picks that up automatically, and Scene::moveToNextTimestep will put them in place of engines at the start of the next loop
+ mapLabeledEntitiesToVariables();
+ }
+ // raw access to engines/_nextEngines, for debugging
+ vector<shared_ptr<Engine> > currEngines_get(){ return OMEGA.getScene()->engines; }
+ vector<shared_ptr<Engine> > nextEngines_get(){ return OMEGA.getScene()->_nextEngines; }
-
pyBodyContainer bodies_get(void){assertScene(); return pyBodyContainer(OMEGA.getScene()->bodies); }
pyInteractionContainer interactions_get(void){assertScene(); return pyInteractionContainer(OMEGA.getScene()->interactions); }
@@ -518,7 +523,7 @@
python::class_<pyOmega>("Omega")
.add_property("iter",&pyOmega::iter,"Get current step number")
- .add_property("subStep",&pyOmega::subStep,"Get the current subStep number (only meaningful if O.subStepping==True)")
+ .add_property("subStep",&pyOmega::subStep,"Get the current subStep number (only meaningful if O.subStepping==True); -1 when outside the loop, otherwise either 0 (O.subStepping==False) or number of engine to be run (O.subStepping==True)")
.add_property("subStepping",&pyOmega::subStepping_get,&pyOmega::subStepping_set,"Get/set whether subStepping is active.")
.add_property("stopAtIter",&pyOmega::stopAtIter_get,&pyOmega::stopAtIter_set,"Get/set number of iteration after which the simulation will stop.")
.add_property("time",&pyOmega::time,"Return virtual (model world) time of the simulation.")
@@ -548,8 +553,9 @@
.def("plugins",&pyOmega::plugins_get,"Return list of all plugins registered in the class factory.")
.def("_sceneObj",&pyOmega::scene_get,"Return the :yref:`scene <Scene>` object. Debugging only, all (or most) :yref:`Scene` functionality is proxies through :yref:`Omega`.")
.add_property("engines",&pyOmega::engines_get,&pyOmega::engines_set,"List of engines in the simulation (Scene::engines).")
+ .add_property("_currEngines",&pyOmega::currEngines_get,"Currently running engines; debugging only!")
+ .add_property("_nextEngines",&pyOmega::nextEngines_get,"Engines for the next step, if different from the current ones, otherwise empty; debugging only!")
.add_property("miscParams",&pyOmega::miscParams_get,&pyOmega::miscParams_set,"MiscParams in the simulation (Scene::mistParams), usually used to save serializables that don't fit anywhere else, like GL functors")
- .add_property("initializers",&pyOmega::initializers_get,&pyOmega::initializers_set,"List of initializers (Scene::initializers).")
.add_property("bodies",&pyOmega::bodies_get,"Bodies in the current simulation (container supporting index access by id and iteration)")
.add_property("interactions",&pyOmega::interactions_get,"Interactions in the current simulation (container supporting index acces by either (id1,id2) or interactionNumber and iteration)")
.add_property("materials",&pyOmega::materials_get,"Shared materials; they can be accessed by id or by label")
=== modified file 'scripts/test/energy.py'
--- scripts/test/energy.py 2010-10-29 10:12:44 +0000
+++ scripts/test/energy.py 2010-11-12 09:48:58 +0000
@@ -12,10 +12,12 @@
PyRunner(iterPeriod=10,command='addPlotData()')
]
O.trackEnergy=True
-
-def addPlotData(): plot.addData(i=O.iter,**O.energy)
-
-plot.plots={'i':('elastPotential','plastDissip')}
+O.step() # to have energy categories
+
+def addPlotData():
+ plot.addData(i=O.iter,total=O.energy.total(),**O.energy)
+
+plot.plots={'i':['total',]+O.energy.keys()}
plot.plot(subPlots=True)
O.dt=utils.PWaveTimeStep()