← Back to team overview

yade-dev team mailing list archive

[svn] r1915 - in trunk: gui/py py/yadeWrapper scripts

 

Author: eudoxos
Date: 2009-08-04 08:38:03 +0200 (Tue, 04 Aug 2009)
New Revision: 1915

Modified:
   trunk/gui/py/PythonUI_rc.py
   trunk/py/yadeWrapper/yadeWrapper.cpp
   trunk/scripts/simple-scene-parallel.py
Log:
1. All different yade types are real python types now. They have their properties defined at startup. One can say O.bodies[0].shape.diffuseColor instead of O.bodies[0].shape['diffuseColor'] now. It also works much better with ipython tab-completion. It is not sure whether we will be able ever to deprecate the old object['attribute'] syntax.
2. Wrap ParallelEngine in python, and finish Dispatcher wraps as well.



Modified: trunk/gui/py/PythonUI_rc.py
===================================================================
--- trunk/gui/py/PythonUI_rc.py	2009-08-03 19:56:37 UTC (rev 1914)
+++ trunk/gui/py/PythonUI_rc.py	2009-08-04 06:38:03 UTC (rev 1915)
@@ -21,28 +21,58 @@
 	for bb in ret:
 		ret2|=listChildClassesRecursive(bb)
 	return ret | ret2
+
 # not sure whether __builtins__ is the right place?
-_dd=__builtins__.__dict__
-_allClasses=set(listChildClassesRecursive('Serializable'))
+_proxyNamespace=__builtins__.__dict__
+# all classes that we want to handle at this point
+_allSerializables=set(listChildClassesRecursive('Serializable'))
+# classes that cannot be instantiated in python directly, and will have no properties generated for them
+_noPropsClasses=set(['InteractionContainer','BodyContainer','EngineUnit','Engine','MetaEngine'])
+# We call some classes differently in python than in c++
+_classTranslations={'FileGenerator':'Preprocessor'}
+# classes that have special wrappers; only the most-bottom ones
+_pyRootClasses=set([
+	'StandAloneEngine','DeusExMachina','GeometricalModel','InteractingGeometry','PhysicalParameters','BoundingVolume','InteractingGeometry','InteractionPhysics','FileGenerator',
+	'BoundingVolumeEngineUnit','GeometricalModelEngineUnit','InteractingGeometryEngineUnit','InteractionGeometryEngineUnit','InteractionPhysicsEngineUnit','PhysicalParametersEngineUnit','PhysicalActionDamperUnit','PhysicalActionApplierUnit','ConstitutiveLaw'])
+# classes for which proxies were already created
 _proxiedClasses=set()
-_classTranslations={'FileGenerator':'Preprocessor'}
 
-for root in [
-	'StandAloneEngine','DeusExMachina','GeometricalModel','InteractingGeometry','PhysicalParameters','BoundingVolume','InteractingGeometry','InteractionPhysics','FileGenerator',
-		# functors
-		'BoundingVolumeEngineUnit','GeometricalModelEngineUnit','InteractingGeometryEngineUnit','InteractionGeometryEngineUnit','InteractionPhysicsEngineUnit','PhysicalParametersEngineUnit','PhysicalActionDamperUnit','PhysicalActionApplierUnit','ConstitutiveLaw'
-	]:
-	root2=root if (root not in _classTranslations.keys()) else _classTranslations[root]
+# create types for all classes that yade defines: first those deriving from some root classes
+for root0 in _pyRootClasses:
+	root=root0 if (root0 not in _classTranslations.keys()) else _classTranslations[root0]
+	rootType=yade.wrapper.__dict__[root]
 	for p in listChildClassesRecursive(root):
-		#class argStorage:
-		#	def __init__(self,_root,_class): self._root,self._class=_root,_class
-		#	def __call__(self,*args): return yade.wrapper.__dict__[self._root](self._class,*args)
-		#if root=='MetaEngine': _dd[p]=argStorage(root2,p)
-		_dd[p]=lambda __r_=root2,__p_=p,**kw : yade.wrapper.__dict__[__r_](__p_,**kw) # eval(root2)(p,kw)
+		_proxyNamespace[p]=type(p,(rootType,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
 		_proxiedClasses.add(p)
-#_dd['Generic']=yade.wrapper.Serializable
-for p in _allClasses-_proxiedClasses: # wrap classes that don't derive from any specific root class, just from Serializable
-	_dd[p]=lambda __p_=p,**kw: yade.wrapper.Serializable(__p_,**kw)
+# create types for classes that derive just from Serializable
+for p in _allSerializables-_proxiedClasses-_pyRootClasses:
+	_proxyNamespace[p]=type(p,(Serializable,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
+# create class properties for yade serializable attributes, i.e. access object['attribute'] as object.attribute
+for c0 in _allSerializables-_noPropsClasses:
+	c=c0 if (c0 not in _classTranslations.keys()) else _classTranslations[c0]
+	cls=eval(c) # ugly: create instance; better lookup some namespace (builtins? globals?)
+	for k in cls().keys(): # must be instantiated so that attributes can be retrieved
+		setattr(cls,k,property(lambda self,__k_=k:self.__getitem__(__k_),lambda self,val,__k_=k:self.__setitem__(__k_,val)))
+
+
+
+### deprecated code, may be removed in 2010 ;-)
+if 0:
+	for root0 in _pyRootClasses:
+		root=root0 if (root0 not in _classTranslations.keys()) else _classTranslations[root0]
+		for p in listChildClassesRecursive(root):
+			#class argStorage:
+			#	def __init__(self,_root,_class): self._root,self._class=_root,_class
+			#	def __call__(self,*args): return yade.wrapper.__dict__[self._root](self._class,*args)
+			#if root=='MetaEngine': _proxyNamespace[p]=argStorage(root2,p)
+			_proxyNamespace[p]=lambda __r_=root,__p_=p,**kw : yade.wrapper.__dict__[__r_](__p_,**kw) # eval(root2)(p,kw)
+			_proxiedClasses.add(p)
+	# wrap classes that don't derive from any specific root class, have no proxy and need it
+	for p in _allSerializables-_proxiedClasses-pyRootClasses:
+		_proxyNamespace[p]=lambda __p_=p,**kw: yade.wrapper.Serializable(__p_,**kw)
+
+	for p in _allSerializables-_proxiedClasses-pyRootClasses:
+		_proxyNamespace[p]=lambda __p_=p,**kw: yade.wrapper.Serializable(__p_,**kw)
 ### end wrappers
 
 #### HANDLE RENAMED CLASSES ####
@@ -63,8 +93,8 @@
 		def __init__(self,_old,_new): self.old,self.new=_old,_new
 		def __call__(self,*args,**kw):
 			import warnings; warnings.warn("Class `%s' was renamed to `%s', update your code!"%(self.old,self.new),DeprecationWarning,stacklevel=2);
-			return _dd[self.new](*args,**kw)
-	_dd[oldName]=warnWrap(oldName,renamed[oldName])
+			return _proxyNamespace[self.new](*args,**kw)
+	_proxyNamespace[oldName]=warnWrap(oldName,renamed[oldName])
 
 
 

Modified: trunk/py/yadeWrapper/yadeWrapper.cpp
===================================================================
--- trunk/py/yadeWrapper/yadeWrapper.cpp	2009-08-03 19:56:37 UTC (rev 1914)
+++ trunk/py/yadeWrapper/yadeWrapper.cpp	2009-08-04 06:38:03 UTC (rev 1915)
@@ -123,39 +123,6 @@
 #endif
 
 
-#if 0
-BASIC_PY_PROXY(pyGeneric,Serializable);
-python::list anyEngines_get(const vector<shared_ptr<Engine> >&);
-void anyEngines_set(vector<shared_ptr<Engine> >&, python::object);
-
-BASIC_PY_PROXY_HEAD(pyParallelEngine,ParallelEngine)
-	pyParallelEngine(python::list slaves){init("ParallelEngine"); slaves_set(slaves);}
-	void slaves_set(python::list slaves){
-		shared_ptr<ParallelEngine> me=dynamic_pointer_cast<ParallelEngine>(proxee); if(!me) throw runtime_error("Proxied class not a ParallelEngine. (WTF?)");
-		int len=python::len(slaves);
-		me->slaves=ParallelEngine::slaveContainer(); // empty the container
-		for(int i=0; i<len; i++){
-			python::extract<python::list> grpMaybe(slaves[i]);
-			python::list grpList;
-			if(grpMaybe.check()){ grpList=grpMaybe(); }
-			else{ /* we got a standalone thing; let's wrap it in list */ grpList.append(slaves[i]); }
-			vector<shared_ptr<Engine> > grpVec;
-			anyEngines_set(grpVec,grpList);
-			me->slaves.push_back(grpVec);
-		}
-	}
-	python::list slaves_get(void){	
-		shared_ptr<ParallelEngine> me=dynamic_pointer_cast<ParallelEngine>(proxee); if(!me) throw runtime_error("Proxied class not a ParallelEngine. (WTF?)");
-		python::list ret;
-		FOREACH(vector<shared_ptr<Engine > >& grp, me->slaves){
-			python::list rret=anyEngines_get(grp);
-			if(python::len(rret)==1){ ret.append(rret[0]); } else ret.append(rret);
-		}
-		return ret;
-	}
-BASIC_PY_PROXY_TAIL;
-#endif
-
 class pyBodyContainer{
 	public:
 	const shared_ptr<BodyContainer> proxee;
@@ -491,8 +458,6 @@
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(STLImporter_import_overloads,py_import,1,3);
 
 
-
-
 /*****************************************************************************
 ********** New helper functions */
 void Serializable_updateAttrs(const shared_ptr<Serializable>& self, const python::dict& d){
@@ -509,7 +474,6 @@
 	}
 	return ret; 
 }
-
 std::string Serializable_pyStr(const shared_ptr<Serializable>& self) {
 	return "<"+self->getClassName()+" instance at "+lexical_cast<string>(self.get())+">";
 }
@@ -548,8 +512,14 @@
 	FOREACH(shared_ptr<functorT> functor,functors) instance->add(functor);
 	return instance;
 }
-
 // FIXME: this one as well
+template<typename DispatcherT, typename functorT>
+std::vector<shared_ptr<functorT> > Dispatcher_functors_get(shared_ptr<DispatcherT> self){
+	std::vector<shared_ptr<functorT> > ret;
+	FOREACH(const shared_ptr<EngineUnit>& functor, self->functorArguments){ shared_ptr<functorT> functorRightType(dynamic_pointer_cast<functorT>(functor)); if(!functorRightType) throw logic_error("Internal error: Dispatcher of type "+self->getClassName()+" did not contain EngineUnit of the required type "+typeid(functorT).name()+"?"); ret.push_back(functorRightType); }
+	return ret;
+}
+// FIXME: and this one as well
 shared_ptr<InteractionDispatchers> InteractionDispatchers_ctor_lists(const std::vector<shared_ptr<InteractionGeometryEngineUnit> >& gff, const std::vector<shared_ptr<InteractionPhysicsEngineUnit> >& pff, const std::vector<shared_ptr<ConstitutiveLaw> >& cff){
 	shared_ptr<InteractionDispatchers> instance(new InteractionDispatchers);
 	FOREACH(shared_ptr<InteractionGeometryEngineUnit> gf, gff) instance->geomDispatcher->add(gf);
@@ -557,6 +527,29 @@
 	FOREACH(shared_ptr<ConstitutiveLaw> cf, cff) instance->constLawDispatcher->add(cf);
 	return instance;
 }
+// ParallelEngine
+void ParallelEngine_slaves_set(shared_ptr<ParallelEngine> self, const python::list& slaves){
+	int len=python::len(slaves);
+	self->slaves=ParallelEngine::slaveContainer(); // empty the container
+	for(int i=0; i<len; i++){
+		python::extract<std::vector<shared_ptr<Engine> > > serialGroup(slaves[i]);
+		if (serialGroup.check()){ self->slaves.push_back(serialGroup()); continue; }
+		python::extract<shared_ptr<Engine> > serialAlone(slaves[i]);
+		if (serialAlone.check()){ vector<shared_ptr<Engine> > aloneWrap; aloneWrap.push_back(serialAlone()); self->slaves.push_back(aloneWrap); continue; }
+		PyErr_SetString(PyExc_TypeError,"List elements must be either\n (a) sequences of engines to be executed one after another\n(b) alone engines.");
+		python::throw_error_already_set();
+	}
+}
+python::list ParallelEngine_slaves_get(shared_ptr<ParallelEngine> self){
+	python::list ret;
+	FOREACH(vector<shared_ptr<Engine > >& grp, self->slaves){
+		if(grp.size()==1) ret.append(python::object(grp[0]));
+		else ret.append(python::object(grp));
+	}
+	return ret;
+}
+shared_ptr<ParallelEngine> ParallelEngine_ctor_list(const python::list& slaves){ shared_ptr<ParallelEngine> instance(new ParallelEngine); ParallelEngine_slaves_set(instance,slaves); return instance; }
+
 // injected methods
 Vector3r PhysicalParameters_displ_get(const shared_ptr<PhysicalParameters>& pp){return pp->se3.position-pp->refSe3.position;}
 Vector3r PhysicalParameters_rot_get  (const shared_ptr<PhysicalParameters>& pp){Quaternionr relRot=pp->refSe3.orientation.Conjugate()*pp->se3.orientation; Vector3r axis; Real angle; relRot.ToAxisAngle(axis,angle); return axis*angle;  }
@@ -666,7 +659,7 @@
 	python::class_<pyBexContainer>("BexContainer",python::init<pyBexContainer&>())
 		.def("f",&pyBexContainer::force_get)
 		.def("t",&pyBexContainer::torque_get)
-		.def("m",&pyBexContainer::torque_get) // for compatibility with ActionContainer
+		.def("m",&pyBexContainer::torque_get)
 		.def("move",&pyBexContainer::move_get)
 		.def("rot",&pyBexContainer::rot_get)
 		.def("addF",&pyBexContainer::force_add)
@@ -674,73 +667,6 @@
 		.def("addMove",&pyBexContainer::move_add)
 		.def("addRot",&pyBexContainer::rot_add);
 
-// keep for a while for reference, to make sure everything is wrapped as it was before
-#if 0
-	BASIC_PY_PROXY_WRAPPER(pyStandAloneEngine,"StandAloneEngine")
-		TIMING_PROPS(pyStandAloneEngine);
-	BASIC_PY_PROXY_WRAPPER(pyMetaEngine,"MetaEngine")
-		.add_property("functors",&pyMetaEngine::functors_get,&pyMetaEngine::functors_set)
-		TIMING_PROPS(pyMetaEngine)
-		.def(python::init<string,python::list>());
-	BASIC_PY_PROXY_WRAPPER(pyParallelEngine,"ParallelEngine")
-		.add_property("slaves",&pyParallelEngine::slaves_get,&pyParallelEngine::slaves_set)
-		.def(python::init<python::list>());
-	BASIC_PY_PROXY_WRAPPER(pyDeusExMachina,"DeusExMachina")
-		TIMING_PROPS(pyDeusExMachina);
-	BASIC_PY_PROXY_WRAPPER(pyInteractionDispatchers,"InteractionDispatchers")
-		.def(python::init<python::list,python::list,python::list>())
-		.add_property("geomDispatcher",&pyInteractionDispatchers::geomDispatcher_get)
-		.add_property("physDispatcher",&pyInteractionDispatchers::physDispatcher_get)
-		.add_property("constLawDispatcher",&pyInteractionDispatchers::constLawDispatcher_get)
-		TIMING_PROPS(pyInteractionDispatchers);
-	BASIC_PY_PROXY_WRAPPER(pyEngineUnit,"EngineUnit")
-		.add_property("timingDeltas",&pyEngineUnit::timingDeltas_get)
-		.add_property("bases",&pyEngineUnit::bases_get);
-
-	#undef TIMING_PROPS
-
-	BASIC_PY_PROXY_WRAPPER(pyGeometricalModel,"GeometricalModel");
-	BASIC_PY_PROXY_WRAPPER(pyInteractingGeometry,"InteractingGeometry");
-	BASIC_PY_PROXY_WRAPPER(pyPhysicalParameters,"PhysicalParameters")	
-		.add_property("blockedDOFs",&pyPhysicalParameters::blockedDOFs_get,&pyPhysicalParameters::blockedDOFs_set)
-		.add_property("pos",&pyPhysicalParameters::pos_get,&pyPhysicalParameters::pos_set)
-		.add_property("ori",&pyPhysicalParameters::ori_get,&pyPhysicalParameters::ori_set)
-		.add_property("refPos",&pyPhysicalParameters::refPos_get,&pyPhysicalParameters::refPos_set)
-		.add_property("displ",&pyPhysicalParameters::displ_get)
-		.add_property("rot",&pyPhysicalParameters::rot_get)
-		;
-	BASIC_PY_PROXY_WRAPPER(pyBoundingVolume,"BoundingVolume")	
-		.add_property("min",&pyBoundingVolume::min_get)
-		.add_property("max",&pyBoundingVolume::max_get);
-	BASIC_PY_PROXY_WRAPPER(pyInteractionGeometry,"InteractionGeometry");
-	BASIC_PY_PROXY_WRAPPER(pyInteractionPhysics,"InteractionPhysics");
-
-	BASIC_PY_PROXY_WRAPPER(pyGeneric,"Generic");
-
-	BASIC_PY_PROXY_WRAPPER(pyBody,"Body")
-		.add_property("shape",&pyBody::shape_get,&pyBody::shape_set)
-		.add_property("mold",&pyBody::mold_get,&pyBody::mold_set)
-		.add_property("bound",&pyBody::bound_get,&pyBody::bound_set)
-		.add_property("phys",&pyBody::phys_get,&pyBody::phys_set)
-		.add_property("dynamic",&pyBody::dynamic_get,&pyBody::dynamic_set)
-		.add_property("id",&pyBody::id_get)
-		.add_property("mask",&pyBody::mask_get,&pyBody::mask_set)
-		.add_property("isStandalone",&pyBody::isStandalone)
-		.add_property("isClumpMember",&pyBody::isClumpMember)
-		.add_property("isClump",&pyBody::isClump);
-
-	BASIC_PY_PROXY_WRAPPER(pyInteraction,"Interaction")
-		.add_property("phys",&pyInteraction::phys_get,&pyInteraction::phys_set)
-		.add_property("geom",&pyInteraction::geom_get,&pyInteraction::geom_set)
-		.add_property("id1",&pyInteraction::id1_get)
-		.add_property("id2",&pyInteraction::id2_get)
-		.add_property("isReal",&pyInteraction::isReal_get);
-
-	BASIC_PY_PROXY_WRAPPER(pyFileGenerator,"Preprocessor")
-		.def("generate",&pyFileGenerator::generate)
-		.def("load",&pyFileGenerator::load);
-#endif
-
 	python::class_<pySTLImporter>("STLImporter")
 	    .def("open",&pySTLImporter::open)
 	    .add_property("number_of_facets",&pySTLImporter::number_of_facets)
@@ -750,13 +676,13 @@
 //////////////////////////////////////////////////////////////
 ///////////// proxyless wrappers 
 
-	/* TODO: bases for functors; functors for dispatchers; ParallelEngine (?) */
-
 	python::class_<Serializable, shared_ptr<Serializable>, noncopyable >("Serializable")
-		.add_property("name",&Serializable::getClassName).def("__str__",&Serializable_pyStr).def("postProcessAttributes",&Serializable::postProcessAttributes)
-		.def("dict",&Serializable::pyDict).def("__getitem__",&Serializable::pyGetAttr).def("__setitem__",&Serializable::pySetAttr).def("has_key",&Serializable::pyHasKey).def("keys",&Serializable::pyKeys).
-		def("updateAttrs",&Serializable_updateAttrs).def("updateExistingAttrs",&Serializable_updateExistingAttrs)
+		.add_property("name",&Serializable::getClassName).def("__str__",&Serializable_pyStr).def("__repr__",&Serializable_pyStr).def("postProcessAttributes",&Serializable::postProcessAttributes)
+		.def("dict",&Serializable::pyDict).def("__getitem__",&Serializable::pyGetAttr).def("__setitem__",&Serializable::pySetAttr).def("has_key",&Serializable::pyHasKey).def("keys",&Serializable::pyKeys)
+		.def("updateAttrs",&Serializable_updateAttrs).def("updateExistingAttrs",&Serializable_updateExistingAttrs)
 		.def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<Serializable>))
+		// aliases for __getitem__ and __setitem__, but they are used by the property generator code and can be useful if we deprecate the object['attr'] type of access
+		.def("_prop_get",&Serializable::pyGetAttr).def("_prop_set",&Serializable::pySetAttr)
 		;
 	python::class_<Engine, shared_ptr<Engine>, python::bases<Serializable>, noncopyable >("Engine",python::no_init)
 		.add_property("execTime",&Engine_timingInfo_nsec_get,&Engine_timingInfo_nsec_set)
@@ -770,8 +696,16 @@
 	python::class_<MetaEngine, shared_ptr<MetaEngine>, python::bases<Engine>, noncopyable>("MetaEngine",python::no_init);
 	python::class_<TimingDeltas, shared_ptr<TimingDeltas>, noncopyable >("TimingDeltas").add_property("data",&TimingDeltas_pyData).def("reset",&TimingDeltas::reset);
 
-	python::class_<InteractionDispatchers,shared_ptr<InteractionDispatchers>, python::bases<Engine>, noncopyable >("InteractionDispatchers").def("__init__",python::make_constructor(InteractionDispatchers_ctor_lists));
-	#define EXPOSE_DISPATCHER(DispatcherT,functorT) python::class_<DispatcherT, shared_ptr<DispatcherT>, python::bases<MetaEngine>, noncopyable >(#DispatcherT).def("__init__",python::make_constructor(Dispatcher_ctor_list<DispatcherT,functorT>));
+	python::class_<InteractionDispatchers,shared_ptr<InteractionDispatchers>, python::bases<Engine>, noncopyable >("InteractionDispatchers")
+		.def("__init__",python::make_constructor(InteractionDispatchers_ctor_lists))
+		.def_readonly("geomDispatcher",&InteractionDispatchers::geomDispatcher)
+		.def_readonly("physDispatcher",&InteractionDispatchers::physDispatcher)
+		.def_readonly("constLawDispatcher",&InteractionDispatchers::constLawDispatcher);
+	python::class_<ParallelEngine,shared_ptr<ParallelEngine>, python::bases<Engine>, noncopyable>("ParallelEngine")
+		.def("__init__",python::make_constructor(ParallelEngine_ctor_list))
+		.add_property("slaves",&ParallelEngine_slaves_get,&ParallelEngine_slaves_set);
+
+	#define EXPOSE_DISPATCHER(DispatcherT,functorT) python::class_<DispatcherT, shared_ptr<DispatcherT>, python::bases<MetaEngine>, noncopyable >(#DispatcherT).def("__init__",python::make_constructor(Dispatcher_ctor_list<DispatcherT,functorT>)).add_property("functors",&Dispatcher_functors_get<DispatcherT,functorT>);
 		EXPOSE_DISPATCHER(BoundingVolumeMetaEngine,BoundingVolumeEngineUnit)
 		EXPOSE_DISPATCHER(GeometricalModelMetaEngine,GeometricalModelEngineUnit)
 		EXPOSE_DISPATCHER(InteractingGeometryMetaEngine,InteractingGeometryEngineUnit)
@@ -794,7 +728,6 @@
 		EXPOSE_FUNCTOR(PhysicalActionApplierUnit)
 		EXPOSE_FUNCTOR(ConstitutiveLaw)
 	#undef EXPOSE_FUNCTOR
-
 		
 	#define EXPOSE_CXX_CLASS_RENAMED(cxxName,pyName) python::class_<cxxName,shared_ptr<cxxName>, python::bases<Serializable>, noncopyable>(#pyName).def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<cxxName>))
 	#define EXPOSE_CXX_CLASS(className) EXPOSE_CXX_CLASS_RENAMED(className,className)
@@ -812,7 +745,9 @@
 		.add_property("isClump",&Body::isClump);
 	EXPOSE_CXX_CLASS(InteractingGeometry);
 	EXPOSE_CXX_CLASS(GeometricalModel);
-	EXPOSE_CXX_CLASS(BoundingVolume);
+	EXPOSE_CXX_CLASS(BoundingVolume)
+		.def_readonly("min",&BoundingVolume::min)
+		.def_readonly("max",&BoundingVolume::max);
 	EXPOSE_CXX_CLASS(PhysicalParameters)
 		.add_property("blockedDOFs",&PhysicalParameters::blockedDOFs_vec_get,&PhysicalParameters::blockedDOFs_vec_set)
 		.add_property("pos",&PhysicalParameters_pos_get,&PhysicalParameters_pos_set)

Modified: trunk/scripts/simple-scene-parallel.py
===================================================================
--- trunk/scripts/simple-scene-parallel.py	2009-08-03 19:56:37 UTC (rev 1914)
+++ trunk/scripts/simple-scene-parallel.py	2009-08-04 06:38:03 UTC (rev 1915)
@@ -25,11 +25,10 @@
 	#  implementation of openMP in gcc: http://gcc.gnu.org/projects/gomp/
 	#
 	ParallelEngine([
+		# BexResetter will run in parallel with the second group of BoundingVolumeMEtaEngine+PersistentSAPCollider
 		BexResetter(),
-		[
-			BoundingVolumeMetaEngine([InteractingSphere2AABB(),InteractingBox2AABB(),MetaInteractingGeometry2AABB()]),
-			InsertionSortCollider(),
-		]
+		# Engines within the group will be run serially, however
+		[BoundingVolumeMetaEngine([InteractingSphere2AABB(),InteractingBox2AABB(),MetaInteractingGeometry2AABB()]),	PersistentSAPCollider(),]
 	]),
 	InteractionGeometryMetaEngine([InteractingSphere2InteractingSphere4SpheresContactGeometry(),InteractingBox2InteractingSphere4SpheresContactGeometry()]),
 	InteractionPhysicsMetaEngine([SimpleElasticRelationships()]),
@@ -44,5 +43,5 @@
 O.bodies.append(utils.box(center=[0,0,0],extents=[.5,.5,.5],dynamic=False,color=[1,0,0],young=30e9,poisson=.3,density=2400))
 O.bodies.append(utils.sphere([0,0,2],1,color=[0,1,0],young=30e9,poisson=.3,density=2400))
 O.dt=.5*utils.PWaveTimeStep()
-
+O.saveTmp()
 #o.run(100000); o.wait(); print o.iter/o.realtime,"iterations/sec"