yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #02676
[Branch ~yade-dev/yade/trunk] Rev 1894: 1. Add some introspection interfaces to Indexables and dispatchers, as needed for Programmer's ma...
------------------------------------------------------------
revno: 1894
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Sun 2009-12-13 20:27:57 +0100
message:
1. Add some introspection interfaces to Indexables and dispatchers, as needed for Programmer's manual (https://yade-dem.org/sphinx/prog.html#multiple-dispatch), remove dead code, some cleanups.
modified:
core/Dispatcher.hpp
core/Functor.hpp
core/Omega.cpp
core/Omega.hpp
lib/multimethods/DynLibDispatcher.hpp
lib/multimethods/Indexable.hpp
pkg/common/Engine/Dispatcher/InteractionGeometryFunctor.hpp
pkg/dem/meta/Tetra.hpp
py/utils.py
py/yadeWrapper/yadeWrapper.cpp
scripts/default-test.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 'core/Dispatcher.hpp'
--- core/Dispatcher.hpp 2009-12-11 11:38:18 +0000
+++ core/Dispatcher.hpp 2009-12-13 19:27:57 +0000
@@ -10,7 +10,9 @@
#include "Engine.hpp"
#include "Functor.hpp"
+#include<yade/core/Omega.hpp>
#include<yade/lib-multimethods/DynLibDispatcher.hpp>
+#include<boost/lexical_cast.hpp>
class Dispatcher : public Engine
{
@@ -47,6 +49,7 @@
virtual int getDimension() { throw; };
virtual string getBaseClassType(unsigned int ) { throw; };
+
protected:
virtual void postProcessAttributes(bool deserializing);
REGISTER_ATTRIBUTES(Engine,(functorNames)(functorArguments));
@@ -54,6 +57,29 @@
};
REGISTER_SERIALIZABLE(Dispatcher);
+/*! Function returning class name (as string) for given index and topIndexable (top-level indexable, such as Shape, Material and so on)
+This function exists solely for debugging, is quite slow: it has to traverse all classes and ask for inheritance information.
+It should be used primarily to convert indices to names in Dispatcher::dictDispatchMatrix?D; since it relies on Omega for RTTI,
+this code could not be in Dispatcher itself.
+*/
+template<class topIndexable>
+std::string Dispatcher_indexToClassName(int idx){
+ scoped_ptr<topIndexable> top(new topIndexable);
+ std::string topName=top->getClassName();
+ typedef std::pair<string,DynlibDescriptor> classItemType;
+ FOREACH(classItemType clss, Omega::instance().getDynlibsDescriptor()){
+ if(Omega::instance().isInheritingFrom_recursive(clss.first,topName) || clss.first==topName){
+ // create instance, to ask for index
+ shared_ptr<topIndexable> inst=dynamic_pointer_cast<topIndexable>(ClassFactory::instance().createShared(clss.first));
+ assert(inst);
+ if(inst->getClassIndex()<0 && inst->getClassName()!=top->getClassName()){
+ throw logic_error("Class "+inst->getClassName()+" didn't use REGISTER_CLASS_INDEX("+inst->getClassName()+","+top->getClassName()+") and/or forgot to call createIndex() in the ctor. [[ Please fix that! ]]");
+ }
+ if(inst->getClassIndex()==idx) return clss.first;
+ }
+ }
+ throw runtime_error("No class with index "+boost::lexical_cast<string>(idx)+" found (top-level indexable is "+topName+")");
+}
template
@@ -75,7 +101,21 @@
{
public :
- void dump(){ DynLibDispatcher<TYPELIST_1(baseClass),FunctorType,FunctorReturnType,FunctorArguments,autoSymmetry>::dumpDispatchMatrix1D(std::cout); }
+ typedef baseClass argType1;
+ typedef FunctorType functorType;
+ typedef DynLibDispatcher<TYPELIST_1(baseClass),FunctorType,FunctorReturnType,FunctorArguments,autoSymmetry> dispatcherBase;
+
+ shared_ptr<FunctorType> getFunctor(shared_ptr<baseClass>& arg){ return getExecutor(arg); }
+ python::dict dump(bool convertIndicesToNames){
+ python::dict ret;
+ FOREACH(const DynLibDispatcher_Item1D& item, dispatcherBase::dataDispatchMatrix1D()){
+ if(convertIndicesToNames){
+ string arg1=Dispatcher_indexToClassName<argType1>(item.ix1);
+ ret[python::make_tuple(arg1)]=item.functorName;
+ } else ret[python::make_tuple(item.ix1)]=item.functorName;
+ }
+ return ret;
+ }
virtual void add(FunctorType* eu){ add(shared_ptr<FunctorType>(eu)); }
virtual void add(shared_ptr<FunctorType> eu){
storeFunctorName(eu->get1DFunctorType1(),eu->getClassName(),eu);
@@ -145,7 +185,21 @@
>
{
public :
- void dump(){ DynLibDispatcher<TYPELIST_2(baseClass1,baseClass2),FunctorType,FunctorReturnType,FunctorArguments,autoSymmetry>::dumpDispatchMatrix2D(std::cout); }
+ typedef baseClass1 argType1;
+ typedef baseClass2 argType2;
+ typedef FunctorType functorType;
+ typedef DynLibDispatcher<TYPELIST_2(baseClass1,baseClass2),FunctorType,FunctorReturnType,FunctorArguments,autoSymmetry> dispatcherBase;
+ shared_ptr<FunctorType> getFunctor(shared_ptr<baseClass1>& arg1, shared_ptr<baseClass2>& arg2){ return getExecutor(arg1,arg2); }
+ python::dict dump(bool convertIndicesToNames){
+ python::dict ret;
+ FOREACH(const DynLibDispatcher_Item2D& item, dispatcherBase::dataDispatchMatrix2D()){
+ if(convertIndicesToNames){
+ string arg1=Dispatcher_indexToClassName<argType1>(item.ix1), arg2=Dispatcher_indexToClassName<argType2>(item.ix2);
+ ret[python::make_tuple(arg1,arg2)]=item.functorName;
+ } else ret[python::make_tuple(item.ix1,item.ix2)]=item.functorName;
+ }
+ return ret;
+ }
/* add functor by pointer: this is convenience for calls like foo->add(new SomeFunctor); */
virtual void add(FunctorType* eu){ add(shared_ptr<FunctorType>(eu)); }
/* add functor by shared pointer */
=== modified file 'core/Functor.hpp'
--- core/Functor.hpp 2009-12-09 16:43:25 +0000
+++ core/Functor.hpp 2009-12-13 19:27:57 +0000
@@ -58,8 +58,8 @@
{
public:
#define FUNCTOR2D(type1,type2) public: std::string get2DFunctorType1(void){return string(#type1);}; std::string get2DFunctorType2(void){return string(#type2);};
- virtual std::string get2DFunctorType1(void){throw runtime_error("Class "+this->getClassName()+" did not use FUNCTOR2D to declare its argument types?");}
- virtual std::string get2DFunctorType2(void){throw runtime_error("Class "+this->getClassName()+" did not use FUNCTOR2D to declare its argument types?");}
+ virtual std::string get2DFunctorType1(void){throw logic_error("Class "+this->getClassName()+" did not use FUNCTOR2D to declare its argument types?");}
+ virtual std::string get2DFunctorType2(void){throw logic_error("Class "+this->getClassName()+" did not use FUNCTOR2D to declare its argument types?");}
virtual vector<string> getFunctorTypes(){vector<string> ret; ret.push_back(get2DFunctorType1()); ret.push_back(get2DFunctorType2()); return ret;};
REGISTER_CLASS_AND_BASE(Functor2D,Functor FunctorWrapper);
/* do not REGISTER_ATTRIBUTES here, since we are template; derived classes should call REGISTER_ATTRIBUTES(Functor,(their)(own)(attributes)), bypassing Functor2D */
=== modified file 'core/Omega.cpp'
--- core/Omega.cpp 2009-12-04 23:07:34 +0000
+++ core/Omega.cpp 2009-12-13 19:27:57 +0000
@@ -181,6 +181,14 @@
return (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end());
}
+bool Omega::isInheritingFrom_recursive(const string& className, const string& baseClassName){
+ if (dynlibs[className].baseClasses.find(baseClassName)!=dynlibs[className].baseClasses.end()) return true;
+ FOREACH(const string& parent,dynlibs[className].baseClasses){
+ if(isInheritingFrom_recursive(parent,baseClassName)) return true;
+ }
+ return false;
+}
+
void Omega::loadPlugins(vector<string> pluginFiles){
FOREACH(const string& plugin, pluginFiles){
LOG_DEBUG("Loading plugin "<<plugin);
=== modified file 'core/Omega.hpp'
--- core/Omega.hpp 2009-12-04 23:07:34 +0000
+++ core/Omega.hpp 2009-12-13 19:27:57 +0000
@@ -129,6 +129,7 @@
void scanPlugins(vector<string> baseDirs);
void loadPlugins(vector<string> pluginFiles);
bool isInheritingFrom(const string& className, const string& baseClassName );
+ bool isInheritingFrom_recursive(const string& className, const string& baseClassName );
void setTimeStep(const Real);
Real getTimeStep();
=== modified file 'lib/multimethods/DynLibDispatcher.hpp'
--- lib/multimethods/DynLibDispatcher.hpp 2009-08-21 11:44:00 +0000
+++ lib/multimethods/DynLibDispatcher.hpp 2009-12-13 19:27:57 +0000
@@ -21,6 +21,7 @@
#include<yade/lib-loki/NullType.hpp>
+
#include<vector>
#include<list>
#include<string>
@@ -31,6 +32,8 @@
using namespace boost;
+struct DynLibDispatcher_Item2D{ int ix1, ix2; std::string functorName; DynLibDispatcher_Item2D(int a, int b, std::string c):ix1(a),ix2(b),functorName(c){}; };
+struct DynLibDispatcher_Item1D{ int ix1 ; std::string functorName; DynLibDispatcher_Item1D(int a, std::string c):ix1(a), functorName(c){}; };
///
/// base classes involved in multiple dispatch must be derived from Indexable
///
@@ -58,7 +61,6 @@
>
class DynLibDispatcher
{
-
// this template recursively defines a type for callBacks matrix, with required number of dimensions
private : template<class T > struct Matrix
{
@@ -161,20 +163,6 @@
private : typedef typename Impl::Parm14 Parm14;
private : typedef typename Impl::Parm15 Parm15;
- // Serialization stuff.. - FIXME - maybe this should be done in separate class...
-// bool deserializing;
-// // protected:
-// // vector<vector<string> > functorNames;
-// // list<shared_ptr<Executor> > functorArguments;
-// // typedef typename list<shared_ptr<Executor> >::iterator executorListIterator;
-
-// virtual void registerAttributes()
-// {
-// REGISTER_ATTRIBUTE_(functorNames);
-// if(functors.size() != 0)
-// REGISTER_ATTRIBUTE_(functors);
-// }
-
public : DynLibDispatcher()
{
// FIXME - static_assert( typeid(BaseClass1) == typeid(Parm1) ); // 1D
@@ -204,6 +192,13 @@
return callBacks[index1][index2];
}
+ shared_ptr<Executor> getExecutor(shared_ptr<BaseClass1>& arg1, shared_ptr<BaseClass2>& arg2){
+ if(arg1->getClassIndex()<0 || arg2->getClassIndex()<0) throw runtime_error("No functor for types "+arg1->getClassName()+" (index "+lexical_cast<string>(arg1->getClassIndex())+") + "+arg2->getClassName()+" (index "+lexical_cast<string>(arg2->getClassIndex())+"), since some of the indices is invalid (negative).");
+ int ix1,ix2;
+ if(locateMultivirtualFunctor2D(ix1,ix2,arg1,arg2)) return callBacks[ix1][ix2];
+ return shared_ptr<Executor>();
+ }
+
public : shared_ptr<Executor> getExecutor(const string& baseClassName)
{
@@ -218,6 +213,13 @@
return callBacks[index];
}
+ shared_ptr<Executor> getExecutor(shared_ptr<BaseClass1>& arg1){
+ int ix1;
+ if(arg1->getClassIndex()<0) throw runtime_error("No functor for type "+arg1->getClassName()+" (index "+lexical_cast<string>(arg1->getClassIndex())+"), since the index is invalid (negative).");
+ if(locateMultivirtualFunctor2D(ix1,arg1)) return callBacks[ix1];
+ return shared_ptr<Executor>();
+ }
+
public : shared_ptr<Executor> makeExecutor(string libName)
{
shared_ptr<Executor> executor;
@@ -241,53 +243,6 @@
return executor;
}
-// // void storeFunctorArguments(shared_ptr<Executor>& ex)
-// // {
-// // if(! ex) return;
-// // bool dupe = false;
-// // executorListIterator it = functorArguments.begin();
-// // executorListIterator itEnd = functorArguments.end();
-// // for( ; it != itEnd ; ++it )
-// // if( (*it)->getClassName() == ex->getClassName() )
-// // dupe = true;
-// //
-// // if(! dupe) functorArguments.push_back(ex);
-// // }
-// //
-// // shared_ptr<Executor> findFunctorArguments(string libName)
-// // {
-// // executorListIterator it = functorArguments.begin();
-// // executorListIterator itEnd = functorArguments.end();
-// // for( ; it != itEnd ; ++it )
-// // if( (*it)->getClassName() == libName )
-// // return *it;
-// //
-// // return shared_ptr<Executor>();
-// // }
-
-// add multivirtual function to 1D
-// // void postProcessDispatcher1D(bool d)
-// // {
-// // if(d)
-// // {
-// // deserializing = true;
-// // for(unsigned int i=0;i<functorNames.size();i++)
-// // add(functorNames[i][0],functorNames[i][1],findFunctorArguments(functorNames[i][1]));
-// // deserializing = false;
-// // }
-// // }
-
-// // void storeFunctorName( const string& baseClassName
-// // , const string& libName
-// // , shared_ptr<Executor>& ex)
-// // {
-// // vector<string> v;
-// // v.push_back(baseClassName);
-// // v.push_back(libName);
-// // functorNames.push_back(v);
-// // storeFunctorArguments(ex);
-// // }
-
public : void add1DEntry( string baseClassName, string libName, shared_ptr<Executor> ex = shared_ptr<Executor>())
{
@@ -349,31 +304,6 @@
}
-// add multivirtual function to 2D
-// // void postProcessDispatcher2D(bool d)
-// // {
-// // if(d)
-// // {
-// // deserializing = true;
-// // for(unsigned int i=0;i<functorNames.size();i++)
-// // add(functorNames[i][0],functorNames[i][1],functorNames[i][2],findFunctorArguments(functorNames[i][2]));
-// // deserializing = false;
-// // }
-// // }
-
-// // void storeFunctorName( const string& baseClassName1
-// // , const string& baseClassName2
-// // , const string& libName
-// // , shared_ptr<Executor>& ex) // 2D
-// // {
-// // vector<string> v;
-// // v.push_back(baseClassName1);
-// // v.push_back(baseClassName2);
-// // v.push_back(libName);
-// // functorNames.push_back(v);
-// // storeFunctorArguments(ex);
-// // }
-
public : void add2DEntry( string baseClassName1, string baseClassName2, string libName, shared_ptr<Executor> ex = shared_ptr<Executor>())
{
shared_ptr<BaseClass1> baseClass1 = YADE_PTR_CAST<BaseClass1>(ClassFactory::instance().createShared(baseClassName1));
@@ -455,22 +385,30 @@
swap=(bool)(callBacksInfo[ix1][ix2]);
return callBacks[ix1][ix2];
}
-
+ /*! Return representation of the dispatch matrix as vector of int,int,string (i.e. index1,index2,functor name) */
+ vector<DynLibDispatcher_Item2D> dataDispatchMatrix2D(){
+ vector<DynLibDispatcher_Item2D> ret; for(size_t i=0; i<callBacks.size(); i++){ for(size_t j=0; j<callBacks.size(); j++){ if(callBacks[i][j]) ret.push_back(DynLibDispatcher_Item2D(i,j,callBacks[i][j]->getClassName())); } }
+ return ret;
+ }
+ /*! Return representation of the dispatch matrix as vector of int,string (i.e. index,functor name) */
+ vector<DynLibDispatcher_Item1D> dataDispatchMatrix1D(){
+ vector<DynLibDispatcher_Item1D> ret; for(size_t i=0; i<callBacks.size(); i++){ if(callBacks[i]) ret.push_back(DynLibDispatcher_Item1D(i,callBacks[i]->getClassName())); }
+ return ret;
+ }
+ /*! Dump 2d dispatch matrix to given stream. */
std::ostream& dumpDispatchMatrix2D(std::ostream& out, const string& prefix=""){
- for(size_t i=0; i<callBacks.size(); i++){
- for(size_t j=0; j<callBacks.size(); j++){
- if(callBacks[i][j]) out<<prefix<<i<<"+"<<j<<" -> "<<callBacks[i][j]->getClassName()<<std::endl;
- }
- }
+ for(size_t i=0; i<callBacks.size(); i++){ for(size_t j=0; j<callBacks.size(); j++){
+ if(callBacks[i][j]) out<<prefix<<i<<"+"<<j<<" -> "<<callBacks[i][j]->getClassName()<<std::endl;
+ }}
return out;
}
+ /*! Dump 1d dispatch matrix to given stream. */
std::ostream& dumpDispatchMatrix1D(std::ostream& out, const string& prefix=""){
for(size_t i=0; i<callBacks.size(); i++){
- if(callBacks[i]) out<<prefix<<i<<" -> "<<callBacks[i]->getClassName()<<std::endl;
+ if(callBacks[i]) out<<prefix<<i<<" -> "<<callBacks[i]->getClassName()<<std::endl;
}
return out;
}
-
bool locateMultivirtualFunctor2D(int& index1, int& index2, shared_ptr<BaseClass1>& base1,shared_ptr<BaseClass2>& base2)
{
//#define _DISP_TRACE(msg) cerr<<"@DT@"<<__LINE__<<" "<<msg<<endl;
@@ -479,107 +417,50 @@
assert(index1>=0); assert(index2>=0);
assert((unsigned int)(index1)<callBacks.size()); assert((unsigned int)(index2)<callBacks[index1].size());
_DISP_TRACE("arg1: "<<base1->getClassName()<<"="<<index1<<"; arg2: "<<base2->getClassName()<<"="<<index2)
- #define _FIX_2D_DISPATCHES
- #ifdef _FIX_2D_DISPATCHES
- /* This is python pseudocode for the algorithm:
-
- def ff(x,sum): print x,sum-x,sum
- for dist in range(0,5):
- for ix1 in range(0,dist+1): ff(ix1,dist)
-
- Increase depth sum from 0 up and look for possible matches, of which sum of distances beween the argument and the declared functor arg type equals depth.
-
- Two matches are considered euqally good (ambiguous) if they have the same depth. That raises exception.
-
- If both indices are negative (reached the top of hierarchy for that indexable type) and nothing has been found for given depth, raise exception (undefined dispatch).
-
- FIXME: by the original design, callBacks don't distinguish between dispatch that was already looked for,
- but is undefined and dispatch that was never looked for before. This means that there can be lot of useless lookups;
- e.g. if MetaInteractingGeometry2AABB is not in BoundingVoumeMetaEngine, it is looked up at every step.
-
- */
- if(callBacks[index1][index2]){ _DISP_TRACE("Direct hit at ["<<index1<<"]["<<index2<<"] â "<<callBacks[index1][index2]->getClassName()); return true; }
- int foundIx1,foundIx2; int maxDp1=-1, maxDp2=-1;
- // if(base1->getBaseClassIndex(0)<0) maxDp1=0; if(base2->getBaseClassIndex(0)<0) maxDp2=0;
- for(int dist=1; ; dist++){
- bool distTooBig=true;
- foundIx1=foundIx2=-1; // found no dispatch at this depth yet
- for(int dp1=0; dp1<=dist; dp1++){
- int dp2=dist-dp1;
- if((maxDp1>=0 && dp1>maxDp1) || (maxDp2>=0 && dp2>maxDp2)) continue;
- _DISP_TRACE(" Trying indices with depths "<<dp1<<" and "<<dp2<<", dist="<<dist);
- int ix1=dp1>0?base1->getBaseClassIndex(dp1):index1, ix2=dp2>0?base2->getBaseClassIndex(dp2):index2;
- if(ix1<0) maxDp1=dp1; if(ix2<0) maxDp2=dp2;
- if(ix1<0 || ix2<0) continue; // hierarchy height exceeded in either dimension
- distTooBig=false;
- if(callBacks[ix1][ix2]){
- if(foundIx1!=-1 && callBacks[foundIx1][foundIx2]!=callBacks[ix1][ix2]){ // we found a callback, but there already was one at this distance and it was different from the current one
- cerr<<__FILE__<<":"<<__LINE__<<": ambiguous 2d dispatch ("<<"arg1="<<base1->getClassName()<<", arg2="<<base2->getClassName()<<", distance="<<dist<<"), dispatch matrix:"<<endl;
- dumpDispatchMatrix2D(cerr,"AMBIGUOUS: "); throw runtime_error("Ambiguous dispatch.");
- }
- foundIx1=ix1; foundIx2=ix2;
- callBacks[index1][index2]=callBacks[ix1][ix2]; callBacksInfo[index1][index2]=callBacksInfo[ix1][ix2];
- _DISP_TRACE("Found callback ["<<ix1<<"]["<<ix2<<"] â "<<callBacks[ix1][ix2]->getClassName());
- }
- }
- if(foundIx1!=-1) return true;
- if(distTooBig){ _DISP_TRACE("Undefined dispatch, dist="<<dist); return false; /* undefined dispatch */ }
- }
- #else
- #if 0
- if((unsigned)index1>=callBacks.size()) cerr<<__FILE__<<":"<<__LINE__<<" FATAL: Index out of range for class "<<base1->getClassName()<<" (index=="<<index1<<", callBacks.size()=="<<callBacks.size()<<endl;
- if((unsigned)index2>=callBacks[index2].size()) cerr<<__FILE__<<":"<<__LINE__<<" FATAL: Index out of range for class "<<base2->getClassName()<<" (index=="<<index2<<", callBacks[index1].size()=="<<callBacks[index1].size()<<endl;
- #endif
-
- if(callBacks[index1][index2]){
- _DISP_TRACE("Direct hit at ["<<index1<<"]["<<index2<<"] â "<<callBacks[index1][index2]->getClassName());
- return true;
- }
-
- int depth1=1, depth2=1;
- int index1_tmp=base1->getBaseClassIndex(depth1), index2_tmp = base2->getBaseClassIndex(depth2);
- _DISP_TRACE("base classes: "<<base1->getBaseClassName()<<"="<<index1_tmp<<", "<<base2->getBaseClassName()<<"="<<index2_tmp);
- if(index1_tmp == -1) {
- while(1){
- if(index2_tmp == -1){
- _DISP_TRACE("Returning FALSE");
- return false;
- }
- if(callBacks[index1][index2_tmp]){ // FIXME - this is not working, when index1 or index2 is out-of-boundary. I have to resize callBacks and callBacksInfo tables. - this should be a separate function to resize stuff
- callBacksInfo[index1][index2] = callBacksInfo[index1][index2_tmp];
- callBacks [index1][index2] = callBacks [index1][index2_tmp];
- // index2 = index2_tmp;
- _DISP_TRACE("Found callback ["<<index1<<"]["<<index2_tmp<<"] â "<<callBacks[index1][index2_tmp]->getClassName());
- return true;
- }
- index2_tmp = base2->getBaseClassIndex(++depth2);
- _DISP_TRACE("index2_tmp="<<index2_tmp<<" (pushed up)");
- }
- }
- else if(index2_tmp == -1) {
- while(1){
- if(index1_tmp == -1){
- _DISP_TRACE("Returning FALSE");
- return false;
- }
- if(callBacks[index1_tmp][index2]){
- callBacksInfo[index1][index2] = callBacksInfo[index1_tmp][index2];
- callBacks [index1][index2] = callBacks [index1_tmp][index2];
- // index1 = index1_tmp;
- _DISP_TRACE("Found callback ["<<index1_tmp<<"]["<<index2<<"] â "<<callBacks[index1_tmp][index2]->getClassName());
- return true;
- }
- index1_tmp = base1->getBaseClassIndex(++depth1);
- _DISP_TRACE("index1_tmp="<<index1_tmp<<" (pushed up)");
- }
- }
- //else if( index1_tmp != -1 && index2_tmp != -1 )
- _DISP_TRACE("UNDEFINED/AMBIGUOUS, dumping dispatch matrix");
- dumpDispatchMatrix2D(cerr);
- _DISP_TRACE("end matrix dump.")
- throw std::runtime_error("DynLibDispatcher: ambiguous or undefined dispatch for 2d multivirtual function, classes: "+base1->getClassName()+" "+base2->getClassName());
- //return false;
- #endif
+ /* This is python code for the algorithm:
+
+ def ff(x,sum): print x,sum-x,sum
+ for dist in range(0,5):
+ for ix1 in range(0,dist+1): ff(ix1,dist)
+
+ Increase depth sum from 0 up and look for possible matches, of which sum of distances beween the argument and the declared functor arg type equals depth.
+
+ Two matches are considered euqally good (ambiguous) if they have the same depth. That raises exception.
+
+ If both indices are negative (reached the top of hierarchy for that indexable type) and nothing has been found for given depth, raise exception (undefined dispatch).
+
+ FIXME: by the original design, callBacks don't distinguish between dispatch that was already looked for,
+ but is undefined and dispatch that was never looked for before. This means that there can be lot of useless lookups;
+ e.g. if MetaInteractingGeometry2AABB is not in BoundingVoumeMetaEngine, it is looked up at every step.
+
+ */
+ if(callBacks[index1][index2]){ _DISP_TRACE("Direct hit at ["<<index1<<"]["<<index2<<"] â "<<callBacks[index1][index2]->getClassName()); return true; }
+ int foundIx1,foundIx2; int maxDp1=-1, maxDp2=-1;
+ // if(base1->getBaseClassIndex(0)<0) maxDp1=0; if(base2->getBaseClassIndex(0)<0) maxDp2=0;
+ for(int dist=1; ; dist++){
+ bool distTooBig=true;
+ foundIx1=foundIx2=-1; // found no dispatch at this depth yet
+ for(int dp1=0; dp1<=dist; dp1++){
+ int dp2=dist-dp1;
+ if((maxDp1>=0 && dp1>maxDp1) || (maxDp2>=0 && dp2>maxDp2)) continue;
+ _DISP_TRACE(" Trying indices with depths "<<dp1<<" and "<<dp2<<", dist="<<dist);
+ int ix1=dp1>0?base1->getBaseClassIndex(dp1):index1, ix2=dp2>0?base2->getBaseClassIndex(dp2):index2;
+ if(ix1<0) maxDp1=dp1; if(ix2<0) maxDp2=dp2;
+ if(ix1<0 || ix2<0) continue; // hierarchy height exceeded in either dimension
+ distTooBig=false;
+ if(callBacks[ix1][ix2]){
+ if(foundIx1!=-1 && callBacks[foundIx1][foundIx2]!=callBacks[ix1][ix2]){ // we found a callback, but there already was one at this distance and it was different from the current one
+ cerr<<__FILE__<<":"<<__LINE__<<": ambiguous 2d dispatch ("<<"arg1="<<base1->getClassName()<<", arg2="<<base2->getClassName()<<", distance="<<dist<<"), dispatch matrix:"<<endl;
+ dumpDispatchMatrix2D(cerr,"AMBIGUOUS: "); throw runtime_error("Ambiguous dispatch.");
+ }
+ foundIx1=ix1; foundIx2=ix2;
+ callBacks[index1][index2]=callBacks[ix1][ix2]; callBacksInfo[index1][index2]=callBacksInfo[ix1][ix2];
+ _DISP_TRACE("Found callback ["<<ix1<<"]["<<ix2<<"] â "<<callBacks[ix1][ix2]->getClassName());
+ }
+ }
+ if(foundIx1!=-1) return true;
+ if(distTooBig){ _DISP_TRACE("Undefined dispatch, dist="<<dist); return false; /* undefined dispatch */ }
+ }
};
=== modified file 'lib/multimethods/Indexable.hpp'
--- lib/multimethods/Indexable.hpp 2009-01-27 02:19:40 +0000
+++ lib/multimethods/Indexable.hpp 2009-12-13 19:27:57 +0000
@@ -11,12 +11,16 @@
#pragma once
#include <boost/scoped_ptr.hpp>
+#include<stdexcept>
+#include<string>
/*! \brief Abstract interface for all Indexable class.
An indexable class is a class that will be managed by a MultiMethodManager.
The index the function getClassIndex() returns, corresponds to the index in the matrix where the class will be handled.
*/
+#define _THROW_NOT_OVERRIDDEN throw std::logic_error(std::string("Derived class did not override ")+__PRETTY_FUNCTION__+", use REGISTER_INDEX_COUNTER and REGISTER_CLASS_INDEX.")
+
class Indexable
{
protected :
@@ -26,102 +30,58 @@
Indexable ();
virtual ~Indexable ();
- virtual int& getClassIndex() { throw;}; /// Returns the id of the current class. This id is set by a multimethod manager
- virtual const int& getClassIndex() const { throw;};
- virtual int& getBaseClassIndex(int ) { throw;};
- virtual const int& getBaseClassIndex(int ) const { throw;};
-
- virtual const int& getMaxCurrentlyUsedClassIndex() const { throw;};
- virtual void incrementMaxCurrentlyUsedClassIndex() { throw;};
+ /// Returns the id of the current class. This id is set by a multimethod manager
+ virtual int& getClassIndex() { _THROW_NOT_OVERRIDDEN;};
+ virtual const int& getClassIndex() const { _THROW_NOT_OVERRIDDEN;};
+ virtual int& getBaseClassIndex(int ) { _THROW_NOT_OVERRIDDEN;};
+ virtual const int& getBaseClassIndex(int ) const { _THROW_NOT_OVERRIDDEN;};
+ virtual const int& getMaxCurrentlyUsedClassIndex() const { _THROW_NOT_OVERRIDDEN;};
+ virtual void incrementMaxCurrentlyUsedClassIndex() { _THROW_NOT_OVERRIDDEN;};
};
+#undef _THROW_NOT_OVERRIDDEN
+
// this macro is used by classes that are a dimension in multimethod matrix
-// this assert was removed, because I must ask Base class for it's own index.
-// assert(typeid(*this)==typeid(SomeClass));
-
-#define REGISTER_CLASS_INDEX(SomeClass,BaseClass) \
- private: static int& getClassIndexStatic() \
- { \
- static int index = -1; \
- return index; \
- } \
- public: virtual int& getClassIndex() \
- { \
- return getClassIndexStatic(); \
- } \
- public: virtual const int& getClassIndex() const \
- { \
- return getClassIndexStatic(); \
- } \
- \
- \
- public: virtual int& getBaseClassIndex(int depth) \
- { \
- static boost::scoped_ptr<BaseClass> baseClass(new BaseClass); \
- if(depth == 1) \
- return baseClass->getClassIndex(); \
- else \
- return baseClass->getBaseClassIndex(--depth); \
- } \
- public: virtual const int& getBaseClassIndex(int depth) const \
- { \
- static boost::scoped_ptr<BaseClass> baseClass(new BaseClass); \
- if(depth == 1) \
- return baseClass->getClassIndex(); \
- else \
- return baseClass->getBaseClassIndex(--depth); \
+#define REGISTER_CLASS_INDEX(SomeClass,BaseClass) \
+ private: static int& getClassIndexStatic() { static int index = -1; return index; } \
+ public: virtual int& getClassIndex() { return getClassIndexStatic(); } \
+ public: virtual const int& getClassIndex() const { return getClassIndexStatic(); } \
+ public: virtual int& getBaseClassIndex(int depth) { \
+ static boost::scoped_ptr<BaseClass> baseClass(new BaseClass); \
+ if(depth == 1) return baseClass->getClassIndex(); \
+ else return baseClass->getBaseClassIndex(--depth); \
+ } \
+ public: virtual const int& getBaseClassIndex(int depth) const { \
+ static boost::scoped_ptr<BaseClass> baseClass(new BaseClass); \
+ if(depth == 1) return baseClass->getClassIndex(); \
+ else return baseClass->getBaseClassIndex(--depth); \
}
// this macro is used by base class for classes that are a dimension in multimethod matrix
// to keep track of maximum number of classes of their kin. Multimethod matrix can't
-// count this number (ie. as a size of the matrix) - because there are many multimethod matrices!
+// count this number (ie. as a size of the matrix), as there are many multimethod matrices
-#define REGISTER_INDEX_COUNTER(SomeClass) \
- \
- private: static int& getClassIndexStatic() \
- { \
- static int index = -1; \
- return index; \
- } \
- public: virtual int& getClassIndex() \
- { \
- return getClassIndexStatic(); \
- } \
- public: virtual const int& getClassIndex() const \
- { \
- return getClassIndexStatic(); \
- } \
- public: virtual int& getBaseClassIndex(int) \
- { \
- throw; \
- } \
- public: virtual const int& getBaseClassIndex(int) const \
- { \
- throw; \
- } \
- \
- \
- private: static int& getMaxCurrentlyUsedIndexStatic() \
- { \
- static int maxCurrentlyUsedIndex = -1; \
- return maxCurrentlyUsedIndex; \
- } \
- public: virtual const int& getMaxCurrentlyUsedClassIndex() const \
- { \
- SomeClass * Indexable##SomeClass = 0; \
- Indexable##SomeClass = dynamic_cast<SomeClass*>(const_cast<SomeClass*>(this)); \
- assert(Indexable##SomeClass); \
- return getMaxCurrentlyUsedIndexStatic(); \
- } \
- public: virtual void incrementMaxCurrentlyUsedClassIndex() \
- { \
- SomeClass * Indexable##SomeClass = 0; \
- Indexable##SomeClass = dynamic_cast<SomeClass*>(this); \
- assert(Indexable##SomeClass); \
- int& max = getMaxCurrentlyUsedIndexStatic(); \
- max++; \
- } \
+#define REGISTER_INDEX_COUNTER(SomeClass) \
+ private: static int& getClassIndexStatic() { static int index = -1; return index; }\
+ public: virtual int& getClassIndex() { return getClassIndexStatic(); } \
+ public: virtual const int& getClassIndex() const { return getClassIndexStatic(); } \
+ public: virtual int& getBaseClassIndex(int) { throw std::logic_error("Class " #SomeClass " should not have called createIndex() in its ctor (since it is a top-level indexable, using REGISTER_INDEX_COUNTER"); } \
+ public: virtual const int& getBaseClassIndex(int) const { throw std::logic_error("Class " #SomeClass " should not have called createIndex() in its ctor (since it is a top-level indexable, using REGISTER_INDEX_COUNTER"); } \
+ private: static int& getMaxCurrentlyUsedIndexStatic() { static int maxCurrentlyUsedIndex = -1; return maxCurrentlyUsedIndex; } \
+ public: virtual const int& getMaxCurrentlyUsedClassIndex() const { \
+ SomeClass * Indexable##SomeClass = 0; \
+ Indexable##SomeClass = dynamic_cast<SomeClass*>(const_cast<SomeClass*>(this)); \
+ assert(Indexable##SomeClass); \
+ return getMaxCurrentlyUsedIndexStatic(); \
+ } \
+ public: virtual void incrementMaxCurrentlyUsedClassIndex() { \
+ SomeClass * Indexable##SomeClass = 0; \
+ Indexable##SomeClass = dynamic_cast<SomeClass*>(this); \
+ assert(Indexable##SomeClass); \
+ int& max = getMaxCurrentlyUsedIndexStatic(); \
+ max++; \
+ }
=== modified file 'pkg/common/Engine/Dispatcher/InteractionGeometryFunctor.hpp'
--- pkg/common/Engine/Dispatcher/InteractionGeometryFunctor.hpp 2009-12-06 22:02:12 +0000
+++ pkg/common/Engine/Dispatcher/InteractionGeometryFunctor.hpp 2009-12-13 19:27:57 +0000
@@ -27,6 +27,7 @@
\param State& first Body's State
\param State& second Body's State
\param Vector3r& second Body's relative shift (for periodicity)
+ \param bool & force force creation of the geometry, even if the interaction doesn't exist yet and the bodies are too far for regular contact (used from explicitAction)
\return shared_ptr<Interaction>& it returns the Interaction to be built (given as last argument to the function)
*/
=== modified file 'pkg/dem/meta/Tetra.hpp'
--- pkg/dem/meta/Tetra.hpp 2009-12-11 18:10:19 +0000
+++ pkg/dem/meta/Tetra.hpp 2009-12-13 19:27:57 +0000
@@ -49,12 +49,13 @@
Vector3r contactPoint;
Vector3r normal;
- TetraBang(): InteractionGeometry(){};
+ TetraBang() { createIndex(); };
virtual ~TetraBang(){};
protected:
REGISTER_ATTRIBUTES(InteractionGeometry,(penetrationVolume)(equivalentCrossSection)(contactPoint)(normal)(equivalentPenetrationDepth)(maxPenetrationDepthA)(maxPenetrationDepthB));
FUNCTOR2D(TetraMold,TetraMold);
REGISTER_CLASS_AND_BASE(TetraBang,InteractionGeometry);
+ REGISTER_CLASS_INDEX(TetraBang,InteractionGeometry);
};
REGISTER_SERIALIZABLE(TetraBang);
=== modified file 'py/utils.py'
--- py/utils.py 2009-12-11 18:10:19 +0000
+++ py/utils.py 2009-12-13 19:27:57 +0000
@@ -25,18 +25,17 @@
def saveVars(mark='',loadNow=False,**kw):
"""Save passed variables into the simulation so that it can be recovered when the simulation is loaded again.
- For example, variables a=5, b=66 and c=7.5e-4 are defined. To save those, use
-
- utils.saveVars(a=a,b=b,c=c)
-
- those variables will be save in the .xml file, when the simulation itself is saved. To recover those variables once
- the .xml is loaded again, use
-
- utils.loadVars(mark)
+ For example, variables a=5, b=66 and c=7.5e-4 are defined. To save those, use::
+
+ >>> utils.saveVars(a=a,b=b,c=c)
+
+ those variables will be save in the .xml file, when the simulation itself is saved. To recover those variables once the .xml is loaded again, use
+
+ >>> utils.loadVars(mark)
and they will be defined in the __builtin__ namespace (i.e. available from anywhere in the python code).
- If loadParam==True, variables will be loaded immediately after saving. That effectively makes **kw available in builtin namespace.
+ If *loadParam*==True, variables will be loaded immediately after saving. That effectively makes *\*\*kw* available in builtin namespace.
"""
import cPickle
Omega().tags['pickledPythonVariablesDictionary'+mark]=cPickle.dumps(kw)
@@ -104,36 +103,39 @@
`material`: int or string or Material instance
if int, O.materials[material] will be used; as a special case, if material==0 and there is no shared materials defined, utils.defaultMaterial() will be assigned to O.materials[0].
+ :return:
+ A Body instance with desired characteristics.
+
>>> O.reset()
>>> from yade import utils
Creating default shared material if none exists neither is given::
- >>> len(O.materials)
- 0
- >>> s0=utils.sphere([2,0,0],1)
- >>> len(O.materials)
- 1
+ >>> len(O.materials)
+ 0
+ >>> s0=utils.sphere([2,0,0],1)
+ >>> len(O.materials)
+ 1
Instance of material can be given::
- >>> s1=utils.sphere([0,0,0],1,wire=False,color=(0,1,0),material=ElasticMat(young=30e9,density=2e3))
- >>> s1.shape['wire']
- False
- >>> s1.shape['diffuseColor']
- Vector3(0,1,0)
- >>> s1.mat['density']
- 2000.0
+ >>> s1=utils.sphere([0,0,0],1,wire=False,color=(0,1,0),material=ElasticMat(young=30e9,density=2e3))
+ >>> s1.shape['wire']
+ False
+ >>> s1.shape['diffuseColor']
+ Vector3(0,1,0)
+ >>> s1.mat['density']
+ 2000.0
Material can be given by label::
- >>> O.materials.append(GranularMat(young=10e9,poisson=.11,label='myMaterial'))
- 1
- >>> s2=utils.sphere([0,0,2],1,material='myMaterial')
- >>> s2.mat['label']
- 'myMaterial'
- >>> s2.mat['poisson']
- 0.11
+ >>> O.materials.append(GranularMat(young=10e9,poisson=.11,label='myMaterial'))
+ 1
+ >>> s2=utils.sphere([0,0,2],1,material='myMaterial')
+ >>> s2.mat['label']
+ 'myMaterial'
+ >>> s2.mat['poisson']
+ 0.11
"""
b=Body()
@@ -190,7 +192,8 @@
:Parameters:
`vertices`: [Vector3,Vector3,Vector3]
coordinates of vertices in the global coordinate system.
- `noBound`: do not assign Body().bound
+ `noBound`:
+ do not assign Body().bound
See utils.sphere's documentation for meaning of other parameters."""
b=Body()
@@ -212,7 +215,8 @@
`wallMask`: bitmask
determines which walls will be created, in the order -x (1), +x (2), -y (4), +y (8), -z (16), +z (32).
The numbers are ANDed; the default 63 means to create all walls.
- `**kw`: passed to utils.facet.
+ `**kw`:
+ passed to utils.facet.
:Return:
List of facets forming the box.
@@ -573,10 +577,7 @@
"""
Read parameters from a file and assign them to __builtin__ variables.
- tableFile is a text file (with one value per blank-separated columns)
- tableLine is number of line where to get the values from
-
- The format of the file is as follows (commens starting with # and empty lines allowed)
+ The format of the file is as follows (commens starting with # and empty lines allowed)::
# commented lines allowed anywhere
name1 name2 ⦠# first non-blank line are column headings
@@ -585,15 +586,27 @@
val2 val2 ⦠# 2nd
â¦
- The name `description' is special and is assigned to Omega().tags['description']
-
- assigns Omega().tags['params']="name1=val1,name2=val2,â¦"
-
- assigns Omega().tags['defaultParams']="unassignedName1=defaultValue1,â¦"
-
- saves all parameters (default as well as settable) using saveVars('table')
-
- return value is the number of assigned parameters.
+ Assigned tags:
+
+ * *description* column is assigned to Omega().tags['description']; this column is synthesized if absent (see :ref:`TableParamReader`)
+ * Omega().tags['params']="name1=val1,name2=val2,â¦"
+ * Omega().tags['defaultParams']="unassignedName1=defaultValue1,â¦"
+
+ All parameters (default as well as settable) are saved using saveVars('table').
+
+ :parameters:
+ `tableFile`:
+ text file (with one value per blank-separated columns)
+ `tableLine`:
+ number of line where to get the values from.
+ `noTableOk`: bool
+ do not raise exception if the file cannot be open; use default values
+ `unknownOk`: bool
+ do not raise exception if unknown column name is found in the file; assign it as well
+
+ :return:
+ number of assigned parameters.
+
"""
tagsParams=[]
dictDefaults,dictParams={},{}
=== modified file 'py/yadeWrapper/yadeWrapper.cpp'
--- py/yadeWrapper/yadeWrapper.cpp 2009-12-11 18:10:19 +0000
+++ py/yadeWrapper/yadeWrapper.cpp 2009-12-13 19:27:57 +0000
@@ -151,7 +151,7 @@
}
body_id_t append(shared_ptr<Body> b){
// shoud be >=0, but Body is by default created with id 0... :-|
- if(b->getId()>0){ PyErr_SetString(PyExc_IndexError,("Body already has id "+lexical_cast<string>(b->getId())+"set; appending such body is not allowed.").c_str()); python::throw_error_already_set(); }
+ if(b->getId()>=0){ PyErr_SetString(PyExc_IndexError,("Body already has id "+lexical_cast<string>(b->getId())+"set; appending such body (for the second time) is not allowed.").c_str()); python::throw_error_already_set(); }
return proxee->insert(b);
}
vector<body_id_t> appendList(vector<shared_ptr<Body> > bb){
@@ -479,7 +479,7 @@
}
bool isChildClassOf(const string& child, const string& base){
- return (Omega::instance().isInheritingFrom(child,base));
+ return (Omega::instance().isInheritingFrom_recursive(child,base));
}
python::list plugins_get(){
@@ -600,17 +600,17 @@
}
// FIXME: those could be moved to the c++ classes themselves, right?
-template<typename DispatcherT, typename functorT>
-shared_ptr<DispatcherT> Dispatcher_ctor_list(const std::vector<shared_ptr<functorT> >& functors){
+template<typename DispatcherT>
+shared_ptr<DispatcherT> Dispatcher_ctor_list(const std::vector<shared_ptr<typename DispatcherT::functorType> >& functors){
shared_ptr<DispatcherT> instance(new DispatcherT);
- FOREACH(shared_ptr<functorT> functor,functors) instance->add(functor);
+ FOREACH(shared_ptr<typename DispatcherT::functorType> 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<Functor>& 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 Functor of the required type "+typeid(functorT).name()+"?"); ret.push_back(functorRightType); }
+template<typename DispatcherT>
+std::vector<shared_ptr<typename DispatcherT::functorType> > Dispatcher_functors_get(shared_ptr<DispatcherT> self){
+ std::vector<shared_ptr<typename DispatcherT::functorType> > ret;
+ FOREACH(const shared_ptr<Functor>& functor, self->functorArguments){ shared_ptr<typename DispatcherT::functorType> functorRightType(dynamic_pointer_cast<typename DispatcherT::functorType>(functor)); if(!functorRightType) throw logic_error("Internal error: Dispatcher of type "+self->getClassName()+" did not contain Functor of the required type "+typeid(typename DispatcherT::functorType).name()+"?"); ret.push_back(functorRightType); }
return ret;
}
// FIXME: and this one as well
@@ -622,21 +622,19 @@
return instance;
}
-template<typename someIndexable>
-int Indexable_getClassIndex(const shared_ptr<someIndexable> i){return i->getClassIndex();}
-//template<typename someIndexable>
-//int Indexable_getBaseClassIndex(const shared_ptr<someIndexable> i){return i->getBaseClassIndex(1);}
-template<typename someIndexable>
-vector<int> Indexable_getClassIndices(const shared_ptr<someIndexable> i){
- int depth=1; vector<int> ret;
- ret.push_back(i->getClassIndex());
+template<typename TopIndexable>
+int Indexable_getClassIndex(const shared_ptr<TopIndexable> i){return i->getClassIndex();}
+template<typename TopIndexable>
+python::list Indexable_getClassIndices(const shared_ptr<TopIndexable> i, bool convertToNames){
+ int depth=1; python::list ret; int idx0=i->getClassIndex();
+ if(convertToNames) ret.append(Dispatcher_indexToClassName<TopIndexable>(idx0));
+ else ret.append(idx0);
+ if(idx0<0) return ret; // don't continue and call getBaseClassIndex(), since we are at the top already
while(true){
- //cerr<<"depth="<<depth;
- int idx=i->getBaseClassIndex(depth);
- //cerr<<", idx="<<idx<<endl;
+ int idx=i->getBaseClassIndex(depth++);
+ if(convertToNames) ret.append(Dispatcher_indexToClassName<TopIndexable>(idx));
+ else ret.append(idx);
if(idx<0) return ret;
- ret.push_back(idx);
- depth++;
}
}
@@ -828,16 +826,16 @@
.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<Dispatcher>, noncopyable >(#DispatcherT).def("__init__",python::make_constructor(Dispatcher_ctor_list<DispatcherT,functorT>)).add_property("functors",&Dispatcher_functors_get<DispatcherT,functorT>).def("dump",&DispatcherT::dump);
- EXPOSE_DISPATCHER(BoundDispatcher,BoundFunctor)
- EXPOSE_DISPATCHER(InteractionGeometryDispatcher,InteractionGeometryFunctor)
- EXPOSE_DISPATCHER(InteractionPhysicsDispatcher,InteractionPhysicsFunctor)
+ #define EXPOSE_DISPATCHER(DispatcherT) python::class_<DispatcherT, shared_ptr<DispatcherT>, python::bases<Dispatcher>, noncopyable >(#DispatcherT).def("__init__",python::make_constructor(Dispatcher_ctor_list<DispatcherT>)).add_property("functors",&Dispatcher_functors_get<DispatcherT>).def("dispMatrix",&DispatcherT::dump,python::arg("names")=true,"Return dictionary with contents of the dispatch matrix.").def("dispFunctor",&DispatcherT::getFunctor,"Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws.");
+ EXPOSE_DISPATCHER(BoundDispatcher)
+ EXPOSE_DISPATCHER(InteractionGeometryDispatcher)
+ EXPOSE_DISPATCHER(InteractionPhysicsDispatcher)
#ifdef YADE_PHYSPAR
- EXPOSE_DISPATCHER(StateMetaEngine,StateEngineUnit)
- EXPOSE_DISPATCHER(PhysicalActionDamper,PhysicalActionDamperUnit)
- EXPOSE_DISPATCHER(PhysicalActionApplier,PhysicalActionApplierUnit)
+ EXPOSE_DISPATCHER(StateMetaEngine)
+ EXPOSE_DISPATCHER(PhysicalActionDamper)
+ EXPOSE_DISPATCHER(PhysicalActionApplier)
#endif
- EXPOSE_DISPATCHER(LawDispatcher,LawFunctor)
+ EXPOSE_DISPATCHER(LawDispatcher)
#undef EXPOSE_DISPATCHER
#define EXPOSE_FUNCTOR(FunctorT) python::class_<FunctorT, shared_ptr<FunctorT>, python::bases<Functor>, noncopyable>(#FunctorT).def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<FunctorT>));
@@ -855,7 +853,7 @@
#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)
// expose indexable class, with access to the index
- #define EXPOSE_CXX_CLASS_IX(className) EXPOSE_CXX_CLASS(className).add_property("classIndex",&Indexable_getClassIndex<className>,"Return class index of this instance.").add_property("classIndices",&Indexable_getClassIndices<className>,"Return list of indices of base classes, starting from the class instance itself, then immediate parent and so on to the top-level indexable at last.")
+ #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.")
EXPOSE_CXX_CLASS(Body)
// mold and geom are deprecated:
=== modified file 'scripts/default-test.py'
--- scripts/default-test.py 2009-12-06 17:18:16 +0000
+++ scripts/default-test.py 2009-12-13 19:27:57 +0000
@@ -89,8 +89,9 @@
reportText='\n'.join([80*'#'+'\n'+r[0]+': '+r[1]+'\n'+80*'#'+'\n'+r[2] for r in reports])
if mailTo and mailFrom:
from email.mime.text import MIMEText
+ import yade.config
msg=MIMEText(reportText)
- msg['Subject']="Automated crash report for "+yade.runtime.executable+": "+",".join([r[0] for r in reports])
+ msg['Subject']="Automated crash report for Yade "+yade.config.revision+": "+",".join([r[0] for r in reports])
msg['From']=mailFrom
msg['To']=mailTo
msg['Reply-To']='yade-dev@xxxxxxxxxxxxxxxxxxx'