← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 1978: 1. Fix numpy_boost and TesselationWrapper

 

------------------------------------------------------------
revno: 1978
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Thu 2010-01-21 08:53:17 +0100
message:
  1. Fix numpy_boost and TesselationWrapper
  2. Start moving python registration code inside classes themselves. That should allow proper class hierarchy in python as well as (faster) object.attribute access instead of hacky object['attribute']. Please report errors you might encounter.
  3. Resurrect Dem6DofGeom, doesn't work for now.
added:
  lib/pyutil/raw_constructor.hpp
modified:
  core/Body.hpp
  core/Cell.hpp
  core/Material.hpp
  core/Omega.cpp
  core/main/main.py.in
  lib/pyutil/numpy.hpp
  lib/pyutil/numpy_boost.hpp
  lib/serialization/Serializable.cpp
  lib/serialization/Serializable.hpp
  pkg/common/DataClass/Material/ElastMat.cpp
  pkg/common/DataClass/Material/ElastMat.hpp
  pkg/common/Engine/PartialEngine/GravityEngines.hpp
  pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.cpp
  pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.hpp
  pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.cpp
  pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.hpp
  pkg/dem/Engine/GlobalEngine/ElasticContactLaw.cpp
  pkg/dem/Engine/GlobalEngine/ElasticContactLaw.hpp
  pkg/dem/Engine/GlobalEngine/MicroMacroAnalyser.cpp
  pkg/dem/Engine/GlobalEngine/TesselationWrapper.cpp
  pkg/dem/Engine/GlobalEngine/TesselationWrapper.hpp
  pkg/dem/meta/ConcretePM.hpp
  py/SConscript
  py/system.py
  py/yadeWrapper/yadeWrapper.cpp


--
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 'core/Body.hpp'
--- core/Body.hpp	2009-12-18 09:48:16 +0000
+++ core/Body.hpp	2010-01-21 07:53:17 +0000
@@ -100,26 +100,18 @@
 		Body ();
 		Body (body_id_t newId, int newGroup);
 
-		// Serialization
-	protected:
-		REGISTER_ATTRIBUTES(Serializable,
-			(id)
-			(groupMask)
-			(isDynamic)
-			#ifdef YADE_PHYSPAR
-				(physicalParameters)
-			#else
-				(material)
-				(state)
-			#endif
-			#ifdef YADE_GEOMETRICALMODEL
-				(geometricalModel)
-			#endif
-			(shape)
-			(bound)
-			(clumpId)
-		);
-
-	REGISTER_CLASS_AND_BASE(Body,Serializable);
+	// Serialization
+	//protected:
+	//	REGISTER_ATTRIBUTES(Serializable,(id)(groupMask)(isDynamic)(material)(state)(shape)(bound)(clumpId));
+	//REGISTER_CLASS_AND_BASE(Body,Serializable);
+	YADE_CLASS_BASE_ATTRS_PY(Body,Serializable,(id)(groupMask)(isDynamic)(material)(state)(shape)(bound)(clumpId),
+		.def_readwrite("mat",&Body::material)
+		.def_readwrite("dynamic",&Body::isDynamic)
+		.def_readonly("id",&Body::id) // should overwrite def_readwrite("id",...) earlier
+		.def_readwrite("mask",&Body::groupMask)
+		.add_property("isStandalone",&Body::isStandalone)
+		.add_property("isClumpMember",&Body::isClumpMember)
+		.add_property("isClump",&Body::isClump);
+	);
 };
 REGISTER_SERIALIZABLE(Body);

=== modified file 'core/Cell.hpp'
--- core/Cell.hpp	2009-12-30 17:38:37 +0000
+++ core/Cell.hpp	2010-01-21 07:53:17 +0000
@@ -94,7 +94,7 @@
 		Real norm=x/sz; period=(int)floor(norm); return (norm-period)*sz;
 	}
 	void postProcessAttributes(bool deserializing){ if(deserializing) integrateAndUpdate(0); }
-	REGISTER_ATTRIBUTES(Serializable,(refSize)(trsf)(velGrad));
-	REGISTER_CLASS_AND_BASE(Cell,Serializable);
+	YADE_CLASS_BASE_ATTRS_PY(Cell,Serializable,(refSize)(trsf)(velGrad),.def_readonly("size",&Cell::getSize_copy));
+	//void pyRegisterClass() const { boost::python::class_<Cell,shared_ptr<Cell>,boost::python::bases<Serializable>,boost::noncopyable>("Cell").def_readwrite("refSize",&Cell::refSize) ; }
 };
 REGISTER_SERIALIZABLE(Cell);

=== modified file 'core/Material.hpp'
--- core/Material.hpp	2009-12-11 12:37:44 +0000
+++ core/Material.hpp	2010-01-21 07:53:17 +0000
@@ -15,7 +15,7 @@
 class Material: public Serializable, public Indexable{
 	public:
 		Material(): id(-1), density(1000){ }
-		~Material();
+		virtual ~Material();
 		//! global id of the material; if >= 0, the material is shared and can be found under this index in Scene::materials
 		//! (necessary since yade::serialization doesn't track shared pointers)
 		int id;
@@ -41,8 +41,11 @@
 		static const shared_ptr<Material> byLabel(const std::string& label, Scene* scene=NULL);
 		static const shared_ptr<Material> byLabel(const std::string& label, shared_ptr<Scene> scene) {return byLabel(label,scene.get());}
 
-	REGISTER_CLASS_AND_BASE(Material,Serializable);
-	REGISTER_ATTRIBUTES(Serializable,(id)(label)(density));
+	//REGISTER_CLASS_AND_BASE(Material,Serializable);
+	//REGISTER_ATTRIBUTES(Serializable,(id)(label)(density));
+	YADE_CLASS_BASE_ATTRS_PY(Material,Serializable,(id)(label)(density),
+		.def("newAssocState",&Material::newAssocState)
+	);
 	REGISTER_INDEX_COUNTER(Material);
 };
 REGISTER_SERIALIZABLE(Material);

=== modified file 'core/Omega.cpp'
--- core/Omega.cpp	2009-12-13 19:27:57 +0000
+++ core/Omega.cpp	2010-01-21 07:53:17 +0000
@@ -25,6 +25,7 @@
 #include<boost/algorithm/string.hpp>
 #include<boost/thread/mutex.hpp>
 #include<boost/version.hpp>
+#include<boost/python.hpp>
 
 #include<cxxabi.h>
 
@@ -139,6 +140,8 @@
 
 void Omega::buildDynlibDatabase(const vector<string>& dynlibsList){	
 	LOG_DEBUG("called with "<<dynlibsList.size()<<" plugins.");
+	boost::python::object wrapperScope=boost::python::import("yade.wrapper");
+	std::list<string> pythonables;
 	FOREACH(string name, dynlibsList){
 		shared_ptr<Factorable> f;
 		try {
@@ -150,12 +153,34 @@
 			for(int i=0;i<f->getBaseClassNumber();i++){
 				dynlibs[name].baseClasses.insert(f->getBaseClassName(i));
 			}
+			if(dynlibs[name].isSerializable) pythonables.push_back(name);
 		}
 		catch (FactoryError& e){
 			/* FIXME: this catches all errors! Some of them are not harmful, however:
 			 * when a class is not factorable, it is OK to skip it; */	
 		}
 	}
+	// handle Serializable specially
+	Serializable().pyRegisterClass(wrapperScope);
+	/* python classes must be registered such that base classes come before derived ones;
+	for now, just loop until we succeed; proper solution will be to build graphs of classes
+	and traverse it from the top. It will be done once all classes are pythonable. */
+	for(int i=0; i<100; i++){
+		std::list<string> done;
+		for(std::list<string>::iterator I=pythonables.begin(); I!=pythonables.end(); ){
+			shared_ptr<Serializable> s=static_pointer_cast<Serializable>(ClassFactory::instance().createShared(*I));
+			try{
+				s->pyRegisterClass(wrapperScope);
+				//cerr<<"{"<<*I<<"}"<<endl;
+				std::list<string>::iterator prev=I++;
+				pythonables.erase(prev);
+			} catch (boost::python::error_already_set& w){
+				if(getenv("YADE_DEBUG")) cerr<<"["<<*I<<"]";
+				boost::python::handle_exception();
+				I++;
+			}
+		}
+	}
 
 	map<string,DynlibDescriptor>::iterator dli    = dynlibs.begin();
 	map<string,DynlibDescriptor>::iterator dliEnd = dynlibs.end();

=== modified file 'core/main/main.py.in'
--- core/main/main.py.in	2010-01-15 09:21:57 +0000
+++ core/main/main.py.in	2010-01-21 07:53:17 +0000
@@ -37,6 +37,7 @@
 # other parts we will need soon
 import yade.config
 import yade.wrapper
+import yade.ww
 import yade.log
 import yade.system
 #import yade.plot

=== modified file 'lib/pyutil/numpy.hpp'
--- lib/pyutil/numpy.hpp	2010-01-01 15:21:30 +0000
+++ lib/pyutil/numpy.hpp	2010-01-21 07:53:17 +0000
@@ -1,5 +1,5 @@
 // 2009 © Václav Šmilauer <eudoxos@xxxxxxxx
-
+#pragma once
 #include"numpy_boost.hpp"
 
 // helper macro do assign Vector3r values to a subarray

=== modified file 'lib/pyutil/numpy_boost.hpp'
--- lib/pyutil/numpy_boost.hpp	2010-01-01 15:21:30 +0000
+++ lib/pyutil/numpy_boost.hpp	2010-01-21 07:53:17 +0000
@@ -47,7 +47,7 @@
 #include <complex>
 #include <algorithm>
 
-namespace detail {
+namespace numpy_boost_detail {
   template<class T>
   class numpy_type_map {
   public:
@@ -143,7 +143,7 @@
   {
     PyArrayObject* a;
 
-    a = (PyArrayObject*)PyArray_FromObject(obj, detail::numpy_type_map<T>::typenum, NDims, NDims);
+    a = (PyArrayObject*)PyArray_FromObject(obj, numpy_boost_detail::numpy_type_map<T>::typenum, NDims, NDims);
     if (a == NULL) {
       // TODO: Extract Python exception
       throw numpy_boost_exception();
@@ -170,7 +170,7 @@
 
     boost::detail::multi_array::copy_n(extents, NDims, shape);
 
-    a = (PyArrayObject*)PyArray_SimpleNew(NDims, shape, detail::numpy_type_map<T>::typenum);
+    a = (PyArrayObject*)PyArray_SimpleNew(NDims, shape, numpy_boost_detail::numpy_type_map<T>::typenum);
     if (a == NULL) {
       // TODO: Extract Python exception
       throw numpy_boost_exception();

=== added file 'lib/pyutil/raw_constructor.hpp'
--- lib/pyutil/raw_constructor.hpp	1970-01-01 00:00:00 +0000
+++ lib/pyutil/raw_constructor.hpp	2010-01-21 07:53:17 +0000
@@ -0,0 +1,21 @@
+#pragma once
+#include<boost/python.hpp>
+#include<boost/python/raw_function.hpp>
+// many thanks to http://markmail.org/message/s4ksg6nfspw2wxwd
+namespace boost { namespace python { namespace detail {
+	template <class F> struct raw_constructor_dispatcher{
+		raw_constructor_dispatcher(F f): f(make_constructor(f)) {}
+		PyObject* operator()(PyObject* args, PyObject* keywords)
+		{
+			 borrowed_reference_t* ra = borrowed_reference(args); object a(ra);
+			 return incref(object(f(object(a[0]),object(a.slice(1,len(a))),keywords ? dict(borrowed_reference(keywords)) : dict())).ptr() );
+		}
+		private: object f;
+	};
+	}
+	template <class F> object raw_constructor(F f, std::size_t min_args = 0){
+		return detail::make_raw_function(objects::py_function(detail::raw_constructor_dispatcher<F>(f),mpl::vector2<void, object>(),min_args+1,(std::numeric_limits<unsigned>::max)()));
+	}
+}} // namespace boost::python
+
+

=== modified file 'lib/serialization/Serializable.cpp'
--- lib/serialization/Serializable.cpp	2009-12-25 14:46:48 +0000
+++ lib/serialization/Serializable.cpp	2010-01-21 07:53:17 +0000
@@ -10,6 +10,7 @@
 
 #include "Serializable.hpp"
 
+
 void Serializable::pyUpdateAttrs(const python::dict& d){
 	python::list l=d.items(); size_t ll=python::len(l);
 	for(size_t i=0; i<ll; i++){

=== modified file 'lib/serialization/Serializable.hpp'
--- lib/serialization/Serializable.hpp	2009-12-25 14:46:48 +0000
+++ lib/serialization/Serializable.hpp	2010-01-21 07:53:17 +0000
@@ -29,6 +29,7 @@
 #include<vector>
 #include<iostream>
 #include<yade/lib-factory/Factorable.hpp>
+#include<yade/lib-pyutil/raw_constructor.hpp>
 #include"SerializationExceptions.hpp"
 #include"Archive.hpp"
 
@@ -84,6 +85,7 @@
 #define _PYKEYS_ATTR(x,y,z) ret.append(BOOST_PP_STRINGIZE(z));
 #define _PYHASKEY_ATTR(x,y,z) if(key==BOOST_PP_STRINGIZE(z)) return true;
 #define _PYDICT_ATTR(x,y,z) ret[BOOST_PP_STRINGIZE(z)]=boost::python::object(z);
+#define _PYCLASS_DEF(x,thisClass,z) .def_readwrite(BOOST_PP_STRINGIZE(z),&thisClass::z)
 
 #define REGISTER_ATTRIBUTES(baseClass,attrs) protected: void registerAttributes(){ baseClass::registerAttributes(); BOOST_PP_SEQ_FOR_EACH(_REGISTER_ATTRIBUTES_REPEAT,~,attrs) } _REGISTER_BOOST_ATTRIBUTES(baseClass,attrs) \
 	public: boost::python::object pyGetAttr(const std::string& key) const{ BOOST_PP_SEQ_FOR_EACH(_PYGET_ATTR,~,attrs); return baseClass::pyGetAttr(key); } \
@@ -92,6 +94,14 @@
 	bool pyHasKey(const std::string& key) const { BOOST_PP_SEQ_FOR_EACH(_PYHASKEY_ATTR,~,attrs); return baseClass::pyHasKey(key); } \
 	boost::python::dict pyDict() const { boost::python::dict ret; BOOST_PP_SEQ_FOR_EACH(_PYDICT_ATTR,~,attrs); ret.update(baseClass::pyDict()); return ret; }
 
+#define YADE_CLASS_BASE_ATTRS_PY(thisClass,baseClass,attrs,extras) \
+	REGISTER_ATTRIBUTES(baseClass,attrs) \
+	REGISTER_CLASS_AND_BASE(thisClass,baseClass) \
+	virtual void pyRegisterClass(python::object _scope) const { if(getClassName()!=#thisClass) return; boost::python::scope thisScope(_scope); boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable>(#thisClass).def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<thisClass>)).def("clone",&Serializable_clone<thisClass>,python::arg("attrs")=python::dict()) BOOST_PP_SEQ_FOR_EACH(_PYCLASS_DEF,thisClass,attrs) extras ; }
+
+#define YADE_CLASS_BASE_ATTRS(thisClass,baseClass,attrs) \
+	YADE_CLASS_BASE_ATTRS_PY(thisClass,baseClass,attrs,)
+
 
 // for both fundamental and non-fundamental cases
 #define REGISTER_SERIALIZABLE_GENERIC(name,isFundamental) 						\
@@ -107,6 +117,41 @@
 	REGISTER_FACTORABLE(sname);								\
 	REGISTER_SERIALIZABLE_DESCRIPTOR(name,sname,SerializableTypes::CUSTOM_CLASS,isFundamental);
 
+// helper functions
+template <typename T>
+shared_ptr<T> Serializable_ctor_kwAttrs(const python::tuple& t, const python::dict& d){
+	if(python::len(t)>1) throw runtime_error("Zero or one (and not more) non-keyword string argument required");
+	string clss;
+	if(python::len(t)==1){
+		python::extract<string> clss_(t[0]); if(!clss_.check()) throw runtime_error("First argument (if given) must be a string.");
+		clss=clss_();
+	}
+	shared_ptr<T> instance;
+	if(clss.empty()){ instance=shared_ptr<T>(new T); }
+	else{
+		shared_ptr<Factorable> instance0=ClassFactory::instance().createShared(clss);
+		if(!instance0) throw runtime_error("Invalid class `"+clss+"' (not created by ClassFactory).");
+		instance=dynamic_pointer_cast<T>(instance0);
+		if(!instance) throw runtime_error("Invalid class `"+clss+"' (unable to cast to typeid `"+typeid(T).name()+"')");
+	}
+	instance->pyUpdateAttrs(d);
+	return instance;
+}
+
+template <typename T>
+shared_ptr<T> Serializable_clone(const shared_ptr<T>& self, const python::dict& d){
+	shared_ptr<Factorable> inst0=ClassFactory::instance().createShared(self->getClassName());
+	if(!inst0) throw runtime_error("Invalid class `"+self->getClassName()+"' (not created by ClassFactory).");
+	shared_ptr<T> inst=dynamic_pointer_cast<T>(inst0);
+	if(!inst) throw runtime_error("Invalid class `"+self->getClassName()+"' (unable to cast to typeid `"+typeid(T).name()+"')");
+	inst->pyUpdateAttrs(self->pyDict());
+	// if d not empty (how to test that?)
+	inst->pyUpdateAttrs(d);
+	inst->postProcessAttributes(/*deserializing*/true);
+	return inst;
+}
+
+
 
 class Serializable : public Factorable
 {
@@ -134,6 +179,19 @@
 		virtual boost::python::list pyKeys() const {return ::pyKeys(); };
 		virtual bool pyHasKey(const std::string& key) const {return ::pyHasKey(key);}
 		virtual boost::python::dict pyDict() const { return ::pyDict(); }
+		virtual void pyRegisterClass(boost::python::object _scope) const {
+			// hack (string comparison), to catch method that is not overridden
+			if(getClassName()!="Serializable"){ if(getenv("YADE_DEBUG")){std::cerr<<"WARN: class "+getClassName()+" did not register with YADE_CLASS_BASE_ATTRS"<<std::endl;} /* throw logic_error("Class "+getClassName()+" did not register with YADE_CLASS_BASE_ATTRS."); */ return; }
+			// called properly
+			boost::python::scope thisScope(_scope); 
+			python::class_<Serializable, shared_ptr<Serializable>, noncopyable >("Serializable")
+				.add_property("name",&Serializable::getClassName).def("__str__",&Serializable::pyStr).def("__repr__",&Serializable::pyStr).def("postProcessAttributes",&Serializable::postProcessAttributes,(python::arg("deserializing")=true))
+				.def("dict",&Serializable::pyDict).def("__getitem__",&Serializable::pyGetAttr).def("__setitem__",&Serializable::pySetAttr).def("has_key",&Serializable::pyHasKey).def("keys",&Serializable::pyKeys)
+				.def("updateAttrs",&Serializable::pyUpdateAttrs).def("updateExistingAttrs",&Serializable::pyUpdateExistingAttrs)
+				.def("clone",&Serializable_clone<Serializable>,python::arg("attrs")=python::dict())
+				.def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<Serializable>))
+				;
+		}
 		
 		//! update attributes from dictionary
 		void pyUpdateAttrs(const boost::python::dict& d);

=== modified file 'pkg/common/DataClass/Material/ElastMat.cpp'
--- pkg/common/DataClass/Material/ElastMat.cpp	2010-01-10 09:09:32 +0000
+++ pkg/common/DataClass/Material/ElastMat.cpp	2010-01-21 07:53:17 +0000
@@ -1,4 +1,5 @@
 // 2009 © Václav Šmilauer <eudoxos@xxxxxxxx>
 #include<yade/pkg-common/ElastMat.hpp>
+YADE_PLUGIN((ElastMat)(FrictMat));
 ElastMat::~ElastMat(){}
 FrictMat::~FrictMat(){}

=== modified file 'pkg/common/DataClass/Material/ElastMat.hpp'
--- pkg/common/DataClass/Material/ElastMat.hpp	2010-01-10 09:09:32 +0000
+++ pkg/common/DataClass/Material/ElastMat.hpp	2010-01-21 07:53:17 +0000
@@ -9,8 +9,9 @@
 	Real poisson;
 	ElastMat(): young(1e9),poisson(.25) { createIndex(); }
 	virtual ~ElastMat();
-	REGISTER_ATTRIBUTES(Material,(young)(poisson));
-	REGISTER_CLASS_AND_BASE(ElastMat,Material);
+	//REGISTER_ATTRIBUTES(Material,(young)(poisson));
+	//REGISTER_CLASS_AND_BASE(ElastMat,Material);
+	YADE_CLASS_BASE_ATTRS(ElastMat,Material,(young)(poisson));
 	REGISTER_CLASS_INDEX(ElastMat,Material);
 };
 REGISTER_SERIALIZABLE(ElastMat);
@@ -21,8 +22,9 @@
 	Real frictionAngle;
 	FrictMat(): frictionAngle(.5){ createIndex(); }
 	virtual ~FrictMat();
-	REGISTER_ATTRIBUTES(ElastMat,(frictionAngle));
-	REGISTER_CLASS_AND_BASE(FrictMat,ElastMat);
+	//REGISTER_ATTRIBUTES(ElastMat,(frictionAngle));
+	//REGISTER_CLASS_AND_BASE(FrictMat,ElastMat);
+	YADE_CLASS_BASE_ATTRS(FrictMat,ElastMat,(frictionAngle));
 	REGISTER_CLASS_INDEX(FrictMat,ElastMat);
 };
 REGISTER_SERIALIZABLE(FrictMat);

=== modified file 'pkg/common/Engine/PartialEngine/GravityEngines.hpp'
--- pkg/common/Engine/PartialEngine/GravityEngines.hpp	2009-12-11 18:10:19 +0000
+++ pkg/common/Engine/PartialEngine/GravityEngines.hpp	2010-01-21 07:53:17 +0000
@@ -11,8 +11,7 @@
 		GravityEngine(): gravity(Vector3r::ZERO){};
 		virtual ~GravityEngine(){};
 		virtual void action(Scene*);
-	REGISTER_ATTRIBUTES(GlobalEngine,(gravity));
-	REGISTER_CLASS_AND_BASE(GravityEngine,GlobalEngine);
+	YADE_CLASS_BASE_ATTRS(GravityEngine,GlobalEngine,(gravity));
 };
 REGISTER_SERIALIZABLE(GravityEngine);
 
@@ -32,10 +31,7 @@
 		CentralGravityEngine(){ reciprocal=false; }
 		virtual ~CentralGravityEngine(){};
 		virtual void action(Scene*);
-	protected:
-		REGISTER_ATTRIBUTES(GlobalEngine,(centralBody)(accel)(reciprocal));
-		REGISTER_CLASS_NAME(CentralGravityEngine);
-		REGISTER_BASE_CLASS_NAME(GlobalEngine);
+	YADE_CLASS_BASE_ATTRS(CentralGravityEngine,GlobalEngine,(centralBody)(accel)(reciprocal));
 };
 REGISTER_SERIALIZABLE(CentralGravityEngine);
 
@@ -53,10 +49,7 @@
 		AxialGravityEngine(){ }
 		virtual ~AxialGravityEngine(){};
 		virtual void action(Scene*);
-	protected:
-		REGISTER_ATTRIBUTES(GlobalEngine,(axisPoint)(axisDirection)(acceleration));
-		REGISTER_CLASS_NAME(AxialGravityEngine);
-		REGISTER_BASE_CLASS_NAME(GlobalEngine);
+	YADE_CLASS_BASE_ATTRS(AxialGravityEngine,GlobalEngine,(axisPoint)(axisDirection)(acceleration));
 };
 REGISTER_SERIALIZABLE(AxialGravityEngine);
 

=== modified file 'pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.cpp'
--- pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.cpp	2009-12-19 07:16:06 +0000
+++ pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.cpp	2010-01-21 07:53:17 +0000
@@ -2,11 +2,11 @@
 
 #include<yade/pkg-common/Sphere.hpp>
 #include<yade/core/Omega.hpp>
-YADE_PLUGIN((Dem3DofGeom_SphereSphere)
+YADE_PLUGIN((Dem3DofGeom_SphereSphere)(Dem6DofGeom_SphereSphere)
 	#ifdef YADE_OPENGL
 		(Gl1_Dem3DofGeom_SphereSphere)
 	#endif
-	(Ig2_Sphere_Sphere_Dem3DofGeom));
+	(Ig2_Sphere_Sphere_Dem3DofGeom)(Ig2_Sphere_Sphere_Dem6DofGeom));
 
 
 Dem3DofGeom_SphereSphere::~Dem3DofGeom_SphereSphere(){}
@@ -92,6 +92,27 @@
 	}
 }
 
+
+Dem6DofGeom_SphereSphere::~Dem6DofGeom_SphereSphere(){}
+
+Vector3r Dem6DofGeom_SphereSphere::relRotVector() const{
+	// FIXME: this is not correct, as it assumes normal will not change (?)
+	Quaternionr relOri12=ori1.Conjugate()*ori2;
+	Quaternionr oriDiff=initRelOri12.Conjugate()*relOri12;
+	Vector3r axis; Real angle;
+	oriDiff.ToAxisAngle(axis,angle);
+	if(angle>Mathr::PI)angle-=Mathr::TWO_PI;
+	// cerr<<axis<<";"<<angle<<";"<<ori1<<";"<<ori2<<";"<<oriDiff<<endl;
+	return angle*axis;
+}
+
+void Dem6DofGeom_SphereSphere::bendTwistAbs(Vector3r& bend, Real& twist){
+	const Vector3r& relRot=relRotVector();
+	twist=relRot.Dot(normal);
+	bend=relRot-twist*normal;
+}
+
+
 #ifdef YADE_OPENGL
 	#include<yade/lib-opengl/OpenGLWrapper.hpp>
 	#include<yade/lib-opengl/GLUtils.hpp>
@@ -146,9 +167,10 @@
 			}
 		}
 	}
-	CREATE_LOGGER(Ig2_Sphere_Sphere_Dem3DofGeom);
 #endif
 
+CREATE_LOGGER(Ig2_Sphere_Sphere_Dem3DofGeom);
+
 bool Ig2_Sphere_Sphere_Dem3DofGeom::go(const shared_ptr<Shape>& cm1, const shared_ptr<Shape>& cm2, const State& state1, const State& state2, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>& c){
 	Sphere *s1=static_cast<Sphere*>(cm1.get()), *s2=static_cast<Sphere*>(cm2.get());
 	Vector3r normal=(state2.pos+shift2)-state1.pos;
@@ -183,3 +205,19 @@
 	return true;
 }
 
+CREATE_LOGGER(Ig2_Sphere_Sphere_Dem6DofGeom);
+bool Ig2_Sphere_Sphere_Dem6DofGeom::go(const shared_ptr<Shape>& cm1, const shared_ptr<Shape>& cm2, const State& state1, const State& state2, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>& c){
+	bool hadIntrGeom=c->interactionGeometry;
+	if(!Ig2_Sphere_Sphere_Dem3DofGeom::go(cm1,cm2,state1,state2,shift2,force,c)) return false;
+	// HACK: dem3dof functor creates a dem3dof instance; we need to copy-construct dem6dof from it instead
+	// proper solution would be to factor out the computation part from the dem3dof to separate functions and call those from here, or make the dem3dof functor templated on the dem3dof/dem6dof
+	if(!hadIntrGeom){
+		assert(c->interactionGeometry);
+		assert(c->interactionGeometry->getClassName()=="Dem3DofGeom_SphereSphere");
+		const shared_ptr<Dem6DofGeom_SphereSphere> geom(new Dem6DofGeom_SphereSphere(*YADE_CAST<Dem3DofGeom_SphereSphere*>(c->interactionGeometry.get())));
+		geom->initRelOri12=state1.ori.Conjugate()*state2.ori;
+		c->interactionGeometry=geom;
+		//TRVAR3(geom->refLength,geom->contactPoint,geom->initRelOri12)
+	}
+	return true;
+}

=== modified file 'pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.hpp'
--- pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.hpp	2009-12-19 07:16:06 +0000
+++ pkg/dem/DataClass/InteractionGeometry/Dem3DofGeom_SphereSphere.hpp	2010-01-21 07:53:17 +0000
@@ -43,6 +43,22 @@
 };
 REGISTER_SERIALIZABLE(Dem3DofGeom_SphereSphere);
 
+class Dem6DofGeom_SphereSphere: public Dem3DofGeom_SphereSphere{
+	public:
+		// initial relative orientation, used for bending and twist computation
+		Quaternionr initRelOri12;
+	// return relative rotation, composed of both bend and twist
+	Vector3r relRotVector() const;
+	virtual void bendTwistAbs(Vector3r& bend, Real& twist);
+	virtual ~Dem6DofGeom_SphereSphere();
+	Dem6DofGeom_SphereSphere(const Dem3DofGeom_SphereSphere& ss): Dem3DofGeom_SphereSphere(ss){ createIndex(); }
+	Dem6DofGeom_SphereSphere(){ createIndex(); }
+	REGISTER_ATTRIBUTES(Dem3DofGeom_SphereSphere,(initRelOri12));
+	REGISTER_CLASS_AND_BASE(Dem6DofGeom_SphereSphere,Dem3DofGeom_SphereSphere);
+	REGISTER_CLASS_INDEX(Dem6DofGeom_SphereSphere,Dem3DofGeom_SphereSphere);
+};
+REGISTER_SERIALIZABLE(Dem6DofGeom_SphereSphere);
+
 #ifdef YADE_OPENGL
 	#include<yade/pkg-common/GLDrawFunctors.hpp>
 	class Gl1_Dem3DofGeom_SphereSphere:public GlInteractionGeometryFunctor{
@@ -73,3 +89,14 @@
 };
 REGISTER_SERIALIZABLE(Ig2_Sphere_Sphere_Dem3DofGeom);
 
+class Ig2_Sphere_Sphere_Dem6DofGeom: public Ig2_Sphere_Sphere_Dem3DofGeom{
+	public:
+		virtual bool go(const shared_ptr<Shape>& cm1, const shared_ptr<Shape>& cm2, const State& state1, const State& state2, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>& c);
+		virtual bool goReverse(	const shared_ptr<Shape>&, const shared_ptr<Shape>&, const State&, const State&, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>&){throw runtime_error("goReverse on symmetric functor should never be called!");}
+	FUNCTOR2D(Sphere,Sphere);
+	DEFINE_FUNCTOR_ORDER_2D(Sphere,Sphere);
+	REGISTER_CLASS_AND_BASE(Ig2_Sphere_Sphere_Dem6DofGeom,Ig2_Sphere_Sphere_Dem3DofGeom);
+	REGISTER_ATTRIBUTES(Ig2_Sphere_Sphere_Dem3DofGeom,/* no attrs */);
+	DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(Ig2_Sphere_Sphere_Dem6DofGeom);

=== modified file 'pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.cpp'
--- pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.cpp	2009-11-21 12:46:54 +0000
+++ pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.cpp	2010-01-21 07:53:17 +0000
@@ -1,5 +1,6 @@
 #include"DemXDofGeom.hpp"
-YADE_PLUGIN((Dem3DofGeom));
+YADE_PLUGIN((Dem3DofGeom)(Dem6DofGeom));
 Real Dem3DofGeom::displacementN(){throw;}
 Dem3DofGeom::~Dem3DofGeom(){}
+Dem6DofGeom::~Dem6DofGeom(){}
 GenericSpheresContact::~GenericSpheresContact(){}

=== modified file 'pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.hpp'
--- pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.hpp	2009-12-13 20:11:31 +0000
+++ pkg/dem/DataClass/InteractionGeometry/DemXDofGeom.hpp	2010-01-21 07:53:17 +0000
@@ -56,13 +56,14 @@
 };
 REGISTER_SERIALIZABLE(Dem3DofGeom);
 
-#if 0
+#if 1
 /*! Abstract class for providing torsion and bending, in addition to inherited normal and shear strains. */
 class Dem6DofGeom: public Dem3DofGeom {
 	public:
 		//! rotations perpendicular to the normal (bending; in global coords) and parallel with the normal (torsion)
-		void bendingTorsionAbs(Vector3r& bend, Real& tors)=0;
-		void bendingTorsionRel(Vector3r& bend, Real& tors){ bendingTorsionAbs(bend,tors); bend/=refLength; tors/=refLength;}
+		virtual void bendTwistAbs(Vector3r& bend, Real& twist) {throw std::logic_error("bendTwistAbs not overridden in derived class.");};
+		void bendTwistRel(Vector3r& bend, Real& twist){ bendTwistAbs(bend,twist); bend/=refLength; twist/=refLength;}
+		virtual ~Dem6DofGeom();
 	REGISTER_CLASS_AND_BASE(Dem6DofGeom,Dem3DofGeom);
 	REGISTER_ATTRIBUTES(Dem3DofGeom, /*nothing*/);
 };

=== modified file 'pkg/dem/Engine/GlobalEngine/ElasticContactLaw.cpp'
--- pkg/dem/Engine/GlobalEngine/ElasticContactLaw.cpp	2010-01-10 09:09:32 +0000
+++ pkg/dem/Engine/GlobalEngine/ElasticContactLaw.cpp	2010-01-21 07:53:17 +0000
@@ -14,7 +14,7 @@
 #include<yade/core/Scene.hpp>
 #include<yade/core/Scene.hpp>
 
-YADE_PLUGIN((Law2_ScGeom_FrictPhys_Basic)(Law2_Dem3DofGeom_FrictPhys_Basic)(ElasticContactLaw));
+YADE_PLUGIN((Law2_ScGeom_FrictPhys_Basic)(Law2_Dem3DofGeom_FrictPhys_Basic)(ElasticContactLaw)(Law2_Dem6DofGeom_FrictPhys_Beam));
 
 ElasticContactLaw::ElasticContactLaw() : InteractionSolver()
 {
@@ -109,15 +109,33 @@
 }
 
 // same as elasticContactLaw, but using Dem3DofGeom
-void Law2_Dem3DofGeom_FrictPhys_Basic::go(shared_ptr<InteractionGeometry>& ig, shared_ptr<InteractionPhysics>& ip, Interaction* contact, Scene* rootBody){
+void Law2_Dem3DofGeom_FrictPhys_Basic::go(shared_ptr<InteractionGeometry>& ig, shared_ptr<InteractionPhysics>& ip, Interaction* contact, Scene*){
 	Dem3DofGeom* geom=static_cast<Dem3DofGeom*>(ig.get());
 	FrictPhys* phys=static_cast<FrictPhys*>(ip.get());
 	Real displN=geom->displacementN();
-	if(displN>0){ rootBody->interactions->requestErase(contact->getId1(),contact->getId2()); return; }
+	if(displN>0){ scene->interactions->requestErase(contact->getId1(),contact->getId2()); return; }
 	phys->normalForce=phys->kn*displN*geom->normal;
 	Real maxFsSq=phys->normalForce.SquaredLength()*pow(phys->tangensOfFrictionAngle,2);
 	Vector3r trialFs=phys->ks*geom->displacementT();
 	if(trialFs.SquaredLength()>maxFsSq){ geom->slipToDisplacementTMax(sqrt(maxFsSq)); trialFs*=sqrt(maxFsSq/(trialFs.SquaredLength()));}
 	phys->shearForce=trialFs;
-	applyForceAtContactPoint(phys->normalForce+trialFs,geom->contactPoint,contact->getId1(),geom->se31.position,contact->getId2(),geom->se32.position,rootBody);
+	applyForceAtContactPoint(phys->normalForce+trialFs,geom->contactPoint,contact->getId1(),geom->se31.position,contact->getId2(),geom->se32.position,scene);
+}
+
+// same as elasticContactLaw, but using Dem3DofGeom
+void Law2_Dem6DofGeom_FrictPhys_Beam::go(shared_ptr<InteractionGeometry>& ig, shared_ptr<InteractionPhysics>& ip, Interaction* contact, Scene* scene){
+	// normal & shear forces
+	Dem6DofGeom* geom=static_cast<Dem6DofGeom*>(ig.get());
+	FrictPhys* phys=static_cast<FrictPhys*>(ip.get());
+	Real displN=geom->displacementN();
+	phys->normalForce=phys->kn*displN*geom->normal;
+	phys->shearForce=phys->ks*geom->displacementT();
+	applyForceAtContactPoint(phys->normalForce+phys->shearForce,geom->contactPoint,contact->getId1(),geom->se31.position,contact->getId2(),geom->se32.position,scene);
+	// bend&twist:
+	Vector3r bend; Real twist;
+	geom->bendTwistAbs(bend,twist);
+	Vector3r tt=bend*phys->kn+geom->normal*twist*phys->kn;
+	cerr<<twist<<";"<<bend<<endl;
+	scene->forces.addTorque(contact->getId1(),tt);
+	scene->forces.addTorque(contact->getId2(),-tt);
 }

=== modified file 'pkg/dem/Engine/GlobalEngine/ElasticContactLaw.hpp'
--- pkg/dem/Engine/GlobalEngine/ElasticContactLaw.hpp	2010-01-10 09:09:32 +0000
+++ pkg/dem/Engine/GlobalEngine/ElasticContactLaw.hpp	2010-01-21 07:53:17 +0000
@@ -53,13 +53,23 @@
 */
 class Law2_Dem3DofGeom_FrictPhys_Basic: public LawFunctor{
 	public:
-		virtual void go(shared_ptr<InteractionGeometry>& _geom, shared_ptr<InteractionPhysics>& _phys, Interaction* I, Scene* rootBody);
+		virtual void go(shared_ptr<InteractionGeometry>& _geom, shared_ptr<InteractionPhysics>& _phys, Interaction* I, Scene*);
 		FUNCTOR2D(Dem3DofGeom,FrictPhys);
 		REGISTER_CLASS_AND_BASE(Law2_Dem3DofGeom_FrictPhys_Basic,LawFunctor);
 		REGISTER_ATTRIBUTES(LawFunctor,/*nothing here*/);
 };
 REGISTER_SERIALIZABLE(Law2_Dem3DofGeom_FrictPhys_Basic);
 
+/* Class for demonstrating beam-like behavior of the contact (normal, shear, bend and twist) */
+class Law2_Dem6DofGeom_FrictPhys_Beam: public LawFunctor{
+	public:
+		virtual void go(shared_ptr<InteractionGeometry>& _geom, shared_ptr<InteractionPhysics>& _phys, Interaction* I, Scene*);
+		FUNCTOR2D(Dem6DofGeom,FrictPhys);
+		REGISTER_CLASS_AND_BASE(Law2_Dem6DofGeom_FrictPhys_Beam,LawFunctor);
+		REGISTER_ATTRIBUTES(LawFunctor,/*nothing here*/);
+};
+REGISTER_SERIALIZABLE(Law2_Dem6DofGeom_FrictPhys_Beam);
+
 class ElasticContactLaw : public InteractionSolver
 {
 /// Attributes

=== modified file 'pkg/dem/Engine/GlobalEngine/MicroMacroAnalyser.cpp'
--- pkg/dem/Engine/GlobalEngine/MicroMacroAnalyser.cpp	2010-01-16 14:54:28 +0000
+++ pkg/dem/Engine/GlobalEngine/MicroMacroAnalyser.cpp	2010-01-21 07:53:17 +0000
@@ -14,7 +14,6 @@
 #include<yade/core/Scene.hpp>
 #include <yade/pkg-common/Sphere.hpp>
 #include "MicroMacroAnalyser.hpp"
-#include<yade/pkg-dem/TesselationWrapper.hpp>
 #include<yade/lib-triangulation/KinematicLocalisationAnalyser.hpp>
 #include<yade/lib-triangulation/TriaxialState.h>
 #include <yade/lib-triangulation/Tenseur3.h>

=== modified file 'pkg/dem/Engine/GlobalEngine/TesselationWrapper.cpp'
--- pkg/dem/Engine/GlobalEngine/TesselationWrapper.cpp	2010-01-16 14:54:28 +0000
+++ pkg/dem/Engine/GlobalEngine/TesselationWrapper.cpp	2010-01-21 07:53:17 +0000
@@ -7,7 +7,7 @@
 *************************************************************************/
 
 ///FIXME : this include breaks compilation, see commented "numpy" code at the end of the file
-//#include<yade/lib-pyutil/numpy.hpp>
+#include<yade/lib-pyutil/numpy.hpp>
 
 //#include "CGAL/constructions/constructions_on_weighted_points_cartesian_3.h"
 //#include<yade/lib-triangulation/KinematicLocalisationAnalyser.hpp>
@@ -392,26 +392,26 @@
 		int dim1[]={bodiesDim};
 		int dim2[]={bodiesDim,9};
 		/// This is the code that needs numpy include
-		//numpy_boost<body_id_t,1> id(dim1);
-// 		boost::python::numpy_boost<double,1> vol(dim1);
-// 		boost::python::numpy_boost<double,1> poro(dim1);
-// 		boost::python::numpy_boost<double,2> def(dim2);
-// 		//FOREACH(const shared_ptr<Body>& b, *scene->bodies){
-// 		for (CGT::RTriangulation::Finite_vertices_iterator  V_it = Tri.finite_vertices_begin(); V_it !=  Tri.finite_vertices_end(); V_it++) {
-// 			id[]=V_it->info().id()
-// 			//if(!b) continue;
-// 			const body_id_t id = V_it->info().id();
-// 			Real sphereVol = 4.188790 * std::pow ( ( V_it->point().weight() ),1.5 );// 4/3*PI*R³ = 4.188...*R³
-// 			vol[id]=V_it->info().v();			
-// 			poro[id]=(V_it->info().v() - sphereVol)/V_it->info().v();
-// 			//if (deformation) MATRIX3R_TO_NUMPY(def[id],ParticleDeformation[id]);
-// 			cerr << V_it->info().v()<<" "<<ParticleDeformation[id]<<endl;
-// 		}
-// 		python::dict ret;
-// 		ret["vol"]=vol;
-// 		ret["poro"]=poro;
-// 		if (deformation) ret["def"]=def;		
-// 		return ret;
+		numpy_boost<body_id_t,1> id(dim1);
+ 		numpy_boost<double,1> vol(dim1);
+ 		numpy_boost<double,1> poro(dim1);
+ 		numpy_boost<double,2> def(dim2);
+ 		//FOREACH(const shared_ptr<Body>& b, *scene->bodies){
+ 		for (CGT::RTriangulation::Finite_vertices_iterator  V_it = Tri.finite_vertices_begin(); V_it !=  Tri.finite_vertices_end(); V_it++) {
+ 			//id[]=V_it->info().id()
+ 			//if(!b) continue;
+ 			const body_id_t id = V_it->info().id();
+ 			Real sphereVol = 4.188790 * std::pow ( ( V_it->point().weight() ),1.5 );// 4/3*PI*R³ = 4.188...*R³
+ 			vol[id]=V_it->info().v();			
+ 			poro[id]=(V_it->info().v() - sphereVol)/V_it->info().v();
+ 			//if (deformation) MATRIX3R_TO_NUMPY(def[id],ParticleDeformation[id]);
+ 			//cerr << V_it->info().v()<<" "<<ParticleDeformation[id]<<endl;
+ 		}
+ 		python::dict ret;
+ 		ret["vol"]=vol;
+ 		ret["poro"]=poro;
+ 		if (deformation) ret["def"]=def;		
+ 		return ret;
 }
 
 /// Needed somewhere?

=== modified file 'pkg/dem/Engine/GlobalEngine/TesselationWrapper.hpp'
--- pkg/dem/Engine/GlobalEngine/TesselationWrapper.hpp	2010-01-16 14:54:28 +0000
+++ pkg/dem/Engine/GlobalEngine/TesselationWrapper.hpp	2010-01-21 07:53:17 +0000
@@ -14,7 +14,7 @@
 #include<yade/lib-triangulation/Tesselation.h>
 //#include<yade/lib-pyutil/numpy.hpp>
 #include<boost/python.hpp>
-#include"MicroMacroAnalyser.hpp"
+#include<yade/pkg-dem/MicroMacroAnalyser.hpp>
 #include<yade/extra/boost_python_len.hpp>
 
 /*! \class TesselationWrapper

=== modified file 'pkg/dem/meta/ConcretePM.hpp'
--- pkg/dem/meta/ConcretePM.hpp	2010-01-10 09:09:32 +0000
+++ pkg/dem/meta/ConcretePM.hpp	2010-01-21 07:53:17 +0000
@@ -98,8 +98,9 @@
 		};
 		virtual shared_ptr<State> newAssocState() const { return shared_ptr<State>(new CpmState); }
 		virtual bool stateTypeOk(State* s) const { return (bool)dynamic_cast<CpmState*>(s); }
-		REGISTER_ATTRIBUTES(FrictMat,(G_over_E)(sigmaT)(neverDamage)(epsCrackOnset)(relDuctility)(dmgTau)(dmgRateExp)(plTau)(plRateExp)(isoPrestress));
-		REGISTER_CLASS_AND_BASE(CpmMat,FrictMat);
+		//REGISTER_ATTRIBUTES(FrictMat,(G_over_E)(sigmaT)(neverDamage)(epsCrackOnset)(relDuctility)(dmgTau)(dmgRateExp)(plTau)(plRateExp)(isoPrestress));
+		//REGISTER_CLASS_AND_BASE(CpmMat,FrictMat);
+		YADE_CLASS_BASE_ATTRS(CpmMat,FrictMat,(G_over_E)(sigmaT)(neverDamage)(epsCrackOnset)(relDuctility)(dmgTau)(dmgRateExp)(plTau)(plRateExp)(isoPrestress));
 		REGISTER_CLASS_INDEX(CpmMat,FrictMat);
 };
 REGISTER_SERIALIZABLE(CpmMat);

=== modified file 'py/SConscript'
--- py/SConscript	2009-12-13 20:30:13 +0000
+++ py/SConscript	2010-01-21 07:53:17 +0000
@@ -33,8 +33,9 @@
 	env.File('system.py'),
 	env.File('export.py'),
 	env.File('post2d.py'),
+	env.File('ww.py'),
 	env.SharedLibrary('wrapper',['yadeWrapper/yadeWrapper.cpp'],SHLIBPREFIX='',LIBS=['PythonUI']+linkPlugins(['Shop','BoundDispatcher','InteractionGeometryDispatcher','InteractionPhysicsDispatcher','LawDispatcher','InteractionDispatchers','ParallelEngine','Clump','STLImporter',]+(['GeometricalModelMetaEngine','InteractingGeometryMetaEngine',] if 'geometricalmodel' in env['features'] else [])+(['StateMetaEngine',] if 'physpar' in env['features'] else []))),
-	env.SharedLibrary('_customConverters',['yadeWrapper/customConverters.cpp'],SHLIBPREFIX='',LIBS=env['LIBS']+linkPlugins(Split("BoundFunctor InteractionGeometryFunctor InteractionPhysicsFunctor LawFunctor")+(['GeometricalModelEngineUnit','InteractingGeometryEngineUnit'] if 'geometricalmodel' in env['features'] else [])+(['PhysicalActionDamperUnit','PhysicalActionApplierUnit','StateEngineUnit'] if 'physpar' in env['features'] else [])))
+	env.SharedLibrary('_customConverters',['yadeWrapper/customConverters.cpp'],SHLIBPREFIX='',LIBS=env['LIBS']+linkPlugins(Split("BoundFunctor InteractionGeometryFunctor InteractionPhysicsFunctor LawFunctor")))
 ])
 env.Install('$PREFIX/lib/yade$SUFFIX/py/yade/tests',[
 	env.File('__init__.py','tests'),

=== modified file 'py/system.py'
--- py/system.py	2010-01-10 09:09:32 +0000
+++ py/system.py	2010-01-21 07:53:17 +0000
@@ -126,12 +126,14 @@
 		except KeyError:
 			print 'WARNING: class %s not defined'%root
 		for p in childClasses(root):
+			if proxyNamespace.has_key(p): continue
 			proxyNamespace[p]=type(p,(rootType,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
 			_proxiedClasses.add(p)
 		# inject wrapped class itself into proxyNamespace
 		proxyNamespace[root]=rootType
 	# classes that derive just from Serializable: the remaining ones
 	for p in _allSerializables-_proxiedClasses-_pyRootClasses:
+		if proxyNamespace.has_key(p): continue
 		proxyNamespace[p]=type(p,(wrapper.Serializable,),{'__init__': lambda self,__subType_=p,*args,**kw: super(type(self),self).__init__(__subType_,*args,**kw)})
 	# deprecated names
 	for oldName in _deprecated.keys():

=== modified file 'py/yadeWrapper/yadeWrapper.cpp'
--- py/yadeWrapper/yadeWrapper.cpp	2010-01-15 09:21:57 +0000
+++ py/yadeWrapper/yadeWrapper.cpp	2010-01-21 07:53:17 +0000
@@ -26,6 +26,7 @@
 #include<yade/lib-base/Logging.hpp>
 #include<yade/lib-serialization-xml/XMLFormatManager.hpp>
 #include<yade/lib-pyutil/gil.hpp>
+#include<yade/lib-pyutil/raw_constructor.hpp>
 #include<yade/core/Omega.hpp>
 #include<yade/core/ThreadRunner.hpp>
 #include<yade/core/FileGenerator.hpp>
@@ -54,6 +55,7 @@
 #include<yade/pkg-dem/Shop.hpp>
 #include<yade/pkg-dem/Clump.hpp>
 
+
 using namespace boost;
 using namespace std;
 
@@ -281,7 +283,7 @@
 			try { return Material::byLabel(label,scene);	}
 			catch (std::runtime_error& e){ PyErr_SetString(PyExc_KeyError,e.what()); python::throw_error_already_set(); /* never reached; avoids warning */ throw; }
 		}
-		int append(shared_ptr<Material>& m){ scene->materials.push_back(m); m->id=scene->materials.size()-1; return m->id; }
+		int append(shared_ptr<Material> m){ scene->materials.push_back(m); m->id=scene->materials.size()-1; return m->id; }
 		vector<int> appendList(vector<shared_ptr<Material> > mm){ vector<int> ret; FOREACH(shared_ptr<Material>& m, mm) ret.push_back(append(m)); return ret; }
 		int len(){ return (int)scene->materials.size(); }
 };
@@ -556,39 +558,6 @@
 	return instance;
 }
 
-template <typename T>
-shared_ptr<T> Serializable_ctor_kwAttrs(const python::tuple& t, const python::dict& d){
-	if(python::len(t)>1) throw runtime_error("Zero or one (and not more) non-keyword string argument required");
-	string clss;
-	if(python::len(t)==1){
-		python::extract<string> clss_(t[0]); if(!clss_.check()) throw runtime_error("First argument (if given) must be a string.");
-		clss=clss_();
-	}
-	shared_ptr<T> instance;
-	if(clss.empty()){ instance=shared_ptr<T>(new T); }
-	else{
-		shared_ptr<Factorable> instance0=ClassFactory::instance().createShared(clss);
-		if(!instance0) throw runtime_error("Invalid class `"+clss+"' (not created by ClassFactory).");
-		instance=dynamic_pointer_cast<T>(instance0);
-		if(!instance) throw runtime_error("Invalid class `"+clss+"' (unable to cast to typeid `"+typeid(T).name()+"')");
-	}
-	instance->pyUpdateAttrs(d);
-	return instance;
-}
-
-template <typename T>
-shared_ptr<T> Serializable_clone(const shared_ptr<T>& self, const python::dict& d){
-	shared_ptr<Factorable> inst0=ClassFactory::instance().createShared(self->getClassName());
-	if(!inst0) throw runtime_error("Invalid class `"+self->getClassName()+"' (not created by ClassFactory).");
-	shared_ptr<T> inst=dynamic_pointer_cast<T>(inst0);
-	if(!inst) throw runtime_error("Invalid class `"+self->getClassName()+"' (unable to cast to typeid `"+typeid(T).name()+"')");
-	inst->pyUpdateAttrs(self->pyDict());
-	// if d not empty (how to test that?)
-	inst->pyUpdateAttrs(d);
-	inst->postProcessAttributes(/*deserializing*/true);
-	return inst;
-}
-
 // stupid; Dispatcher is not a template, hence converting this into a real constructor would be complicated; keep it here.
 template<typename DispatcherT>
 shared_ptr<DispatcherT> Dispatcher_ctor_list(const std::vector<shared_ptr<typename DispatcherT::functorType> >& functors){
@@ -632,23 +601,6 @@
 void FileGenerator_generate(const shared_ptr<FileGenerator>& fg, string outFile){ fg->setFileName(outFile); fg->setSerializationLibrary("XMLFormatManager"); bool ret=fg->generateAndSave(); LOG_INFO((ret?"SUCCESS:\n":"FAILURE:\n")<<fg->message); if(ret==false) throw runtime_error("Generator reported error: "+fg->message); };
 void FileGenerator_load(const shared_ptr<FileGenerator>& fg){ string xml(Omega::instance().tmpFilename()+".xml.bz2"); LOG_DEBUG("Using temp file "<<xml); FileGenerator_generate(fg,xml); pyOmega().load(xml); }
 
-// many thanks to http://markmail.org/message/s4ksg6nfspw2wxwd
-namespace boost { namespace python { namespace detail {
-	template <class F> struct raw_constructor_dispatcher{
-		raw_constructor_dispatcher(F f): f(make_constructor(f)) {}
-		PyObject* operator()(PyObject* args, PyObject* keywords)
-		{
-			 borrowed_reference_t* ra = borrowed_reference(args); object a(ra);
-			 return incref(object(f(object(a[0]),object(a.slice(1,len(a))),keywords ? dict(borrowed_reference(keywords)) : dict())).ptr() );
-		}
-		private: object f;
-	};
-	}
-	template <class F> object raw_constructor(F f, std::size_t min_args = 0){
-		return detail::make_raw_function(objects::py_function(detail::raw_constructor_dispatcher<F>(f),mpl::vector2<void, object>(),min_args+1,(std::numeric_limits<unsigned>::max)()));
-	}
-}} // namespace boost::python
-
 BOOST_PYTHON_MODULE(wrapper)
 {
 	python::scope().attr("__doc__")="Wrapper for c++ internals of yade.";
@@ -760,7 +712,8 @@
 
 //////////////////////////////////////////////////////////////
 ///////////// proxyless wrappers 
-
+	Serializable().pyRegisterClass(python::scope());
+#if 0
 	python::class_<Serializable, shared_ptr<Serializable>, noncopyable >("Serializable")
 		.add_property("name",&Serializable::getClassName).def("__str__",&Serializable::pyStr).def("__repr__",&Serializable::pyStr).def("postProcessAttributes",&Serializable::postProcessAttributes,(python::arg("deserializing")=true))
 		.def("dict",&Serializable::pyDict).def("__getitem__",&Serializable::pyGetAttr).def("__setitem__",&Serializable::pySetAttr).def("has_key",&Serializable::pyHasKey).def("keys",&Serializable::pyKeys)
@@ -770,6 +723,7 @@
 		// 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)
 		;
+#endif
 	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)
 		.add_property("execCount",&Engine_timingInfo_nExec_get,&Engine_timingInfo_nExec_set)
@@ -782,7 +736,7 @@
 		.add_property("bases",&Functor::getFunctorTypes);
 	python::class_<Dispatcher, shared_ptr<Dispatcher>, python::bases<Engine>, noncopyable>("Dispatcher",python::no_init);
 	python::class_<TimingDeltas, shared_ptr<TimingDeltas>, noncopyable >("TimingDeltas").add_property("data",&TimingDeltas::pyData).def("reset",&TimingDeltas::reset);
-
+#if 0
 	python::class_<Cell,shared_ptr<Cell>, python::bases<Serializable>, noncopyable>("Cell",python::no_init)
 		.def_readwrite("refSize",&Cell::refSize)
 		.def_readwrite("trsf",&Cell::trsf)
@@ -791,7 +745,7 @@
 		//.def_readwrite("Hsize",&Cell::Hsize)
 		//.add_property("size",&Cell::getSize,python::return_value_policy<python::return_internal_referece>()
 	;
-
+#endif
 	python::class_<InteractionDispatchers,shared_ptr<InteractionDispatchers>, python::bases<Engine>, noncopyable >("InteractionDispatchers")
 		.def("__init__",python::make_constructor(InteractionDispatchers_ctor_lists))
 		.def_readonly("geomDispatcher",&InteractionDispatchers::geomDispatcher)
@@ -820,6 +774,7 @@
 	// expose indexable class, with access to the index
 	#define EXPOSE_CXX_CLASS_IX(className) EXPOSE_CXX_CLASS(className).add_property("dispIndex",&Indexable_getClassIndex<className>,"Return class index of this instance.").def("dispHierarchy",&Indexable_getClassIndices<className>,(python::arg("names")=true),"Return list of dispatch classes (from down upwards), starting with the class instance itself, top-level indexable at last. If names is true (default), return class names rather than numerical indices.")
 
+#if 0
 	EXPOSE_CXX_CLASS(Body)
 		// mold and geom are deprecated:
 		.add_property("mold",&Body_shape_deprec_get,&Body_shape_deprec_set)
@@ -834,14 +789,17 @@
 		.add_property("isStandalone",&Body::isStandalone)
 		.add_property("isClumpMember",&Body::isClumpMember)
 		.add_property("isClump",&Body::isClump);
+#endif
 	EXPOSE_CXX_CLASS_IX(Shape);
 	EXPOSE_CXX_CLASS_IX(Bound)
 		.def_readonly("min",&Bound::min)
 		.def_readonly("max",&Bound::max);
+#if 0
 	EXPOSE_CXX_CLASS_IX(Material)
 		.def_readwrite("label",&Material::label)
 		.def("newAssocState",&Material::newAssocState)
 		;
+#endif
 	EXPOSE_CXX_CLASS(State)
 		.add_property("blockedDOFs",&State::blockedDOFs_vec_get,&State::blockedDOFs_vec_set)
 		.add_property("pos",&State::pos_get,&State::pos_set)