yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #04095
[Branch ~yade-dev/yade/trunk] Rev 2174: 1. Clarify error message i Law2 functor is not found (thanks, Chiara)
------------------------------------------------------------
revno: 2174
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Fri 2010-04-23 13:23:15 +0200
message:
1. Clarify error message i Law2 functor is not found (thanks, Chiara)
2. Make static attributes initialized by values provided in YADE_CLASS_BASE_DOC_STATICATTRS
3. documentation fixes here and there
modified:
core/main/main.py.in
lib/serialization/Serializable.cpp
lib/serialization/Serializable.hpp
pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp
pkg/common/RenderingEngine/Gl1_Sphere.cpp
py/_eudoxos.cpp
py/plot.py
py/timing.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/main/main.py.in'
--- core/main/main.py.in 2010-04-09 11:25:18 +0000
+++ core/main/main.py.in 2010-04-23 11:23:15 +0000
@@ -127,7 +127,7 @@
banner='[[ ^L clears screen, ^U kills line.'+(' F12 controller, F11 3d view, F10 both, F9 generator, F8 plot.' if qtEnabled else '')+' ]]',
rc_override=dict( # ipython options, see e.g. http://www.cv.nrao.edu/~rreid/casa/tips/ipy_user_conf.py
prompt_in1='Yade [\#]: ',
- prompt_in2=' .\D.. ',
+ prompt_in2=' .\D.: ',
prompt_out=" -> [\#]: ",
separate_in='0',
separate_out='0',
=== modified file 'lib/serialization/Serializable.cpp'
--- lib/serialization/Serializable.cpp 2010-03-28 21:22:25 +0000
+++ lib/serialization/Serializable.cpp 2010-04-23 11:23:15 +0000
@@ -11,7 +11,7 @@
#include "Serializable.hpp"
-void Serializable::pyRegisterClass(boost::python::object _scope) const {
+void Serializable::pyRegisterClass(boost::python::object _scope) {
if(!checkPyClassRegistersItself("Serializable")) return;
boost::python::scope thisScope(_scope);
python::class_<Serializable, shared_ptr<Serializable>, noncopyable >("Serializable")
=== modified file 'lib/serialization/Serializable.hpp'
--- lib/serialization/Serializable.hpp 2010-04-20 08:55:02 +0000
+++ lib/serialization/Serializable.hpp 2010-04-23 11:23:15 +0000
@@ -135,8 +135,11 @@
template<> struct py_wrap_ref<Matrix3r>: public boost::true_type{};
};
#define _DEF_READWRITE_BY_VALUE(thisClass,attr,doc) add_property(/*attr name*/BOOST_PP_STRINGIZE(attr),/*read access*/boost::python::make_getter(&thisClass::attr,boost::python::return_value_policy<boost::python::return_by_value>()),/*write access*/boost::python::make_setter(&thisClass::attr,boost::python::return_value_policy<boost::python::return_by_value>()),/*docstring*/doc)
+/* Huh, add_static_property does not support doc argument (add_property does); if so, use add_property for now at least... */
+#define _DEF_READWRITE_BY_VALUE_STATIC(thisClass,attr,doc) _DEF_READWRITE_BY_VALUE(thisClass,attr,doc)
// the conditional should be eliminated by compiler at compile-time, as it depends only on types, not their values
#define _DEF_READWRITE_CUSTOM(thisClass,attr,doc) { if(yade::py_wrap_ref<typeof(thisClass::attr)>::value) _classObj.def_readwrite(BOOST_PP_STRINGIZE(attr),&thisClass::attr,doc); else _classObj._DEF_READWRITE_BY_VALUE(thisClass,attr,doc); }
+#define _DEF_READWRITE_CUSTOM_STATIC(thisClass,attr,doc) { if(yade::py_wrap_ref<typeof(thisClass::attr)>::value) _classObj.def_readwrite(BOOST_PP_STRINGIZE(attr),&thisClass::attr,doc); else _classObj._DEF_READWRITE_BY_VALUE_STATIC(thisClass,attr,doc); }
// macros for deprecated attribute access
// gcc<=4.3 is not able to compile this code; we will just not generate any code for deprecated attributes in such case
@@ -173,7 +176,7 @@
REGISTER_ATTRIBUTES_DEPREC(thisClass,baseClass,BOOST_PP_SEQ_FOR_EACH(_STRIPDOC2,thisClass,attrs),deprec) \
REGISTER_CLASS_AND_BASE(thisClass,baseClass) \
/* accessors for deprecated attributes, with warnings */ BOOST_PP_SEQ_FOR_EACH(_ACCESS_DEPREC,thisClass,deprec) \
- /* python class registration */ virtual void pyRegisterClass(python::object _scope) const { if(!checkPyClassRegistersItself(#thisClass)) return; boost::python::scope thisScope(_scope); YADE_SET_DOCSTRING_OPTS; boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable> _classObj(#thisClass,docString); _classObj.def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<thisClass>)).def("clone",&Serializable_clone<thisClass>,python::arg("attrs")=python::dict()); BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEF,thisClass,attrs); (void) _classObj BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEPREC_DEF,thisClass,deprec); (void) _classObj extras ; }
+ /* python class registration */ virtual void pyRegisterClass(python::object _scope) { if(!checkPyClassRegistersItself(#thisClass)) return; boost::python::scope thisScope(_scope); YADE_SET_DOCSTRING_OPTS; boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable> _classObj(#thisClass,docString); _classObj.def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<thisClass>)).def("clone",&Serializable_clone<thisClass>,python::arg("attrs")=python::dict()); BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEF,thisClass,attrs); (void) _classObj BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEPREC_DEF,thisClass,deprec); (void) _classObj extras ; }
// use later: void must_use_both_YADE_CLASS_BASE_DOC_ATTRS_and_YADE_PLUGIN();
// #define YADE_CLASS_BASE_DOC_ATTRS_PY(thisClass,baseClass,docString,attrs,extras) YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,attrs,,extras)
@@ -193,16 +196,19 @@
_YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,BOOST_PP_SEQ_FOR_EACH(_STRIPDECL4,~,attrDecls),deprec,extras)
#define _DEF_READWRITE_STATIC(thisClass,attr,doc)
-#define _STATATTR_PY(x,thisClass,z) _DEF_READWRITE_CUSTOM(thisClass,BOOST_PP_TUPLE_ELEM(4,1,z),/*docstring*/ "|ystatic| :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "` " BOOST_PP_TUPLE_ELEM(4,3,z))
+#define _STATATTR_PY(x,thisClass,z) _DEF_READWRITE_CUSTOM_STATIC(thisClass,BOOST_PP_TUPLE_ELEM(4,1,z),/*docstring*/ "|ystatic| :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "` " BOOST_PP_TUPLE_ELEM(4,3,z))
#define _STATATTR_DECL(x,y,z) static BOOST_PP_TUPLE_ELEM(4,0,z) BOOST_PP_TUPLE_ELEM(4,1,z);
#define _STRIP_TYPE_DEFAULT_DOC(x,y,z) (BOOST_PP_TUPLE_ELEM(4,1,z))
+#define _STATATTR_SET(x,thisClass,z) thisClass::BOOST_PP_TUPLE_ELEM(4,1,z)=BOOST_PP_TUPLE_ELEM(4,2,z);
#define YADE_CLASS_BASE_DOC_STATICATTRS(thisClass,baseClass,docString,attrs)\
public: BOOST_PP_SEQ_FOR_EACH(_STATATTR_DECL,~,attrs) /* attribute declarations */ \
/* no ctor */ \
REGISTER_CLASS_AND_BASE(thisClass,baseClass); \
REGISTER_ATTRIBUTES(baseClass,BOOST_PP_SEQ_FOR_EACH(_STRIP_TYPE_DEFAULT_DOC,~,attrs)) \
- virtual void pyRegisterClass(python::object _scope) const { if(!checkPyClassRegistersItself(#thisClass)) return; boost::python::scope thisScope(_scope); YADE_SET_DOCSTRING_OPTS; \
+ /* called only at class registration, to set initial values; storage still has to be alocated in the cpp file! */ \
+ void initSetStaticAttributesValue(void){ BOOST_PP_SEQ_FOR_EACH(_STATATTR_SET,thisClass,attrs); } \
+ virtual void pyRegisterClass(python::object _scope) { if(!checkPyClassRegistersItself(#thisClass)) return; initSetStaticAttributesValue(); boost::python::scope thisScope(_scope); YADE_SET_DOCSTRING_OPTS; \
boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable> _classObj(#thisClass,docString); \
BOOST_PP_SEQ_FOR_EACH(_STATATTR_PY,thisClass,attrs); \
}
@@ -341,7 +347,7 @@
// that means that the class doesn't register itself properly
virtual bool checkPyClassRegistersItself(const std::string& thisClassName) const;
// perform class registration; overridden in all classes
- virtual void pyRegisterClass(boost::python::object _scope) const;
+ virtual void pyRegisterClass(boost::python::object _scope);
//! update attributes from dictionary
void pyUpdateAttrs(const boost::python::dict& d);
=== modified file 'pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp'
--- pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp 2010-04-09 11:25:18 +0000
+++ pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp 2010-04-23 11:23:15 +0000
@@ -139,7 +139,7 @@
if(!I->functorCache.constLaw){
I->functorCache.constLaw=lawDispatcher->getFunctor2D(I->interactionGeometry,I->interactionPhysics,swap);
if(!I->functorCache.constLaw){
- LOG_FATAL("getFunctor2D returned empty functor for #"<<I->getId1()<<"+"<<I->getId2()<<", types "<<I->interactionGeometry->getClassName()<<"="<<I->interactionGeometry->getClassIndex()<<" and "<<I->interactionPhysics->getClassName()<<"="<<I->interactionPhysics->getClassIndex());
+ LOG_FATAL("None of given Law2 functors can handle interaction #"<<I->getId1()<<"+"<<I->getId2()<<", types geom:"<<I->interactionGeometry->getClassName()<<"="<<I->interactionGeometry->getClassIndex()<<" and phys:"<<I->interactionPhysics->getClassName()<<"="<<I->interactionPhysics->getClassIndex()<<" (LawDispatcher::getFunctor2D returned empty functor)");
//abort();
exit(1);
}
=== modified file 'pkg/common/RenderingEngine/Gl1_Sphere.cpp'
--- pkg/common/RenderingEngine/Gl1_Sphere.cpp 2010-03-27 22:18:10 +0000
+++ pkg/common/RenderingEngine/Gl1_Sphere.cpp 2010-04-23 11:23:15 +0000
@@ -10,11 +10,11 @@
#include<yade/pkg-common/Sphere.hpp>
#include<yade/lib-opengl/OpenGLWrapper.hpp>
-bool Gl1_Sphere::wire=false;
-bool Gl1_Sphere::stripes=false;
-bool Gl1_Sphere::glutNormalize=true;
-int Gl1_Sphere::glutSlices=12;
-int Gl1_Sphere::glutStacks=6;
+bool Gl1_Sphere::wire;
+bool Gl1_Sphere::stripes;
+bool Gl1_Sphere::glutNormalize;
+int Gl1_Sphere::glutSlices;
+int Gl1_Sphere::glutStacks;
vector<Vector3r> Gl1_Sphere::vertices, Gl1_Sphere::faces;
int Gl1_Sphere::glSphereList=-1;
=== modified file 'py/_eudoxos.cpp'
--- py/_eudoxos.cpp 2010-04-18 20:46:54 +0000
+++ py/_eudoxos.cpp 2010-04-23 11:23:15 +0000
@@ -252,7 +252,7 @@
// cleanup
~InteractionLocator(){ locator->Delete(); points->Delete(); grid->Delete(); }
- py::list intrsWithinDistance(const Vector3r& pt, Real radius){
+ py::list intrsAroundPt(const Vector3r& pt, Real radius){
vtkIdList *ids=vtkIdList::New();
locator->FindPointsWithinRadius(radius,(const double*)(&pt),ids);
int numIds=ids->GetNumberOfIds();
@@ -263,6 +263,29 @@
}
return ret;
}
+ python::tuple macroAroundPt(const Vector3r& pt, Real radius){
+ Matrix3r ss(Matrix3r::ZERO);
+ vtkIdList *ids=vtkIdList::New();
+ locator->FindPointsWithinRadius(radius,(const double*)(&pt),ids);
+ int numIds=ids->GetNumberOfIds();
+ Real omegaCumm=0, kappaCumm=0;
+ for(int k=0; k<numIds; k++){
+ const shared_ptr<Interaction>& I(intrs[ids->GetId(k)]);
+ Dem3DofGeom* geom=YADE_CAST<Dem3DofGeom*>(I->interactionGeometry.get());
+ CpmPhys* phys=YADE_CAST<CpmPhys*>(I->interactionPhysics.get());
+ Real d=(geom->se31.position-geom->se32.position).Length(); // current contact length
+ const Vector3r& n=geom->normal;
+ const Real& A=phys->crossSection;
+ const Vector3r& sigmaT=phys->sigmaT;
+ const Real& sigmaN=phys->sigmaN;
+ for(int i=0; i<3; i++) for(int j=0;j<3; j++){
+ ss[i][j]+=d*A*(sigmaN*n[i]*n[j]+.5*(sigmaT[i]*n[j]+sigmaT[j]*n[i]));
+ }
+ omegaCumm+=phys->omega; kappaCumm+=phys->kappaD;
+ }
+ ss*=1/((4/3.)*Mathr::PI*pow(radius,3));
+ return py::make_tuple(ss,omegaCumm/numIds,kappaCumm/numIds);
+ }
py::tuple getBounds(){ return py::make_tuple(mn,mx);}
int getCnt(){ return cnt; }
};
@@ -277,7 +300,8 @@
py::def("testNumpy",testNumpy);
#ifdef YADE_VTK
py::class_<InteractionLocator>("InteractionLocator","Locate all (real) interactions in space by their :yref:`contact point<Dem3DofGeom::contactPoint>`. When constructed, all real interactions are spatially indexed (uses vtkPointLocator internally). Use intrsWithinDistance to use those data. \n\n.. note::\n\tData might become inconsistent with real simulation state if simulation is being run between creation of this object and spatial queries.")
- .def("intrsWithinDistance",&InteractionLocator::intrsWithinDistance,((python::arg("point"),python::arg("maxDist"))),"Return list of real interactions that are not further than *maxDist* from *point*.")
+ .def("intrsAroundPt",&InteractionLocator::intrsAroundPt,((python::arg("point"),python::arg("maxDist"))),"Return list of real interactions that are not further than *maxDist* from *point*.")
+ .def("macroAroundPt",&InteractionLocator::macroAroundPt,((python::arg("point"),python::arg("maxDist"))),"Return tuple of averaged stress tensor (as Matrix3), average omega and average kappa values.")
.add_property("bounds",&InteractionLocator::getBounds,"Return coordinates of lower and uppoer corner of axis-aligned abounding box of all interactions")
.add_property("count",&InteractionLocator::getCnt,"Number of interactions held")
;
@@ -287,5 +311,5 @@
python::init<Real,int,Real>((python::arg("dH_dTheta"),python::arg("axis")=0,python::arg("theta0")=0),":Parameters:\n\n\tdH_dTheta: float\n\t\tSpiral inclination, i.e. height increase per 1 radian turn;\n\taxis: int\n\t\tAxis of rotation (0=x,1=y,2=z)\n\ttheta: float\n\t\tSpiral angle at zero height (theta intercept)\n\n")
)
.def("intrsAroundPt",&SpiralInteractionLocator2d::intrsAroundPt,(python::arg("pt2d"),python::arg("radius")),"Return list of interaction objects that are not further from *pt2d* than *radius* in the projection plane")
- .def("macroStressAroundPt",&SpiralInteractionLocator2d::macroStressAroundPt,(python::arg("pt2d"),python::arg("radius")),"Compute macroscopic stress around given point, rotating the interaction to the projection plane first. The formula used is\n\n.. math::\n\n \\sigma_{ij}=\\frac{1}{V}\\sum_{IJ}d^{IJ}A^{IJ}\\left[\\sigma^{N,IJ}n_i^{IJ}n_j^{IJ}+\\frac{1}{2}\\left(\\sigma_i^{T,IJ}n_j^{IJ}+\\sigma_j^{T,IJ}n_i^{IJ}\\right)\\right]\n\nwhere the sum is taken over volume $V$ containing interactions $IJ$ between spheres $I$ and $J$;\n* $i$, $j$ indices denote Cartesian components of vectors and tensors,\n* $d^{IJ}$ is current distance between spheres $I$ and $J$,\n* $A^{IJ}$ is area of contact $IJ$,\n* $n$ is interaction normal (unit vector pointing from center of $I$ to the center of $J$)\n* $\\sigma^{N,IJ}$ is normal stress (as scalar) in contact $IJ$,\n* $\\sigma^{T,IJ}$ is shear stress in contact $IJ$ in global coordinates.\n\n$\\sigma^{T}$ and $n$ are transformed by angle $\\theta$ as given by :yref:`utils.spiralProject`.");
+ .def("macroStressAroundPt",&SpiralInteractionLocator2d::macroStressAroundPt,(python::arg("pt2d"),python::arg("radius")),"Compute macroscopic stress around given point, rotating the interaction to the projection plane first. The formula used is\n\n.. math::\n\n \\sigma_{ij}=\\frac{1}{V}\\sum_{IJ}d^{IJ}A^{IJ}\\left[\\sigma^{N,IJ}n_i^{IJ}n_j^{IJ}+\\frac{1}{2}\\left(\\sigma_i^{T,IJ}n_j^{IJ}+\\sigma_j^{T,IJ}n_i^{IJ}\\right)\\right]\n\nwhere the sum is taken over volume $V$ containing interactions $IJ$ between spheres $I$ and $J$;\n\n* $i$, $j$ indices denote Cartesian components of vectors and tensors,\n* $d^{IJ}$ is current distance between spheres $I$ and $J$,\n* $A^{IJ}$ is area of contact $IJ$,\n* $n$ is interaction normal (unit vector pointing from center of $I$ to the center of $J$)\n* $\\sigma^{N,IJ}$ is normal stress (as scalar) in contact $IJ$,\n* $\\sigma^{T,IJ}$ is shear stress in contact $IJ$ in global coordinates.\n\n$\\sigma^{T}$ and $n$ are transformed by angle $\\theta$ as given by :yref:`yade.utils.spiralProject`.");
}
=== modified file 'py/plot.py'
--- py/plot.py 2010-04-10 15:11:48 +0000
+++ py/plot.py 2010-04-23 11:23:15 +0000
@@ -1,9 +1,7 @@
# encoding: utf-8
# 2008 © Václav Šmilauer <eudoxos@xxxxxxxx>
"""
-Module containing utility functions for plotting inside yade.
-
-Experimental, interface may change (even drastically).
+Module containing utility functions for plotting inside yade. See :ysrc:`scripts/simple-scene-plot.py` or :ysrc:`examples/concrete/uniax.py` for example of usage.
"""
import matplotlib
@@ -13,25 +11,24 @@
matplotlib.rc('axes',grid=True) # put grid in all figures
import pylab
-
-data={} # global, common for all plots: {'name':[value,...],...}
+"""Global dictionary containing all data values, common for all plots, in the form {'name':[value,...],...}. Data should be added using plot.addData function. All [value,...] columns have the same length, they are padded with NaN if unspecified."""
+# dictionary x-name -> (yspec,...), where yspec is either y-name or (y-name,'line-specification')
plots={} # dictionary x-name -> (yspec,...), where yspec is either y-name or (y-name,'line-specification')
"Dictionary converting names in data to human-readable names (TeX names, for instance); if a variable is not specified, it is left untranslated."
labels={}
#plotLines={} # dictionary x-name -> Line2d objects (that hopefully still correspond to yspec in plots)
def reset():
+ "Reset all plot-related variables (data, plots, labels)"
global data, plots, labels # plotLines
data={}; plots={}; # plotLines={};
pylab.close('all')
def resetData():
+ "Reset all plot data; keep plots and labels intact."
global data
data={}
-# we could have a yplot class, that would hold: (yspec,...), (Line2d,Line2d,...) ?
-
-plotDataCollector=None
from yade.wrapper import *
def splitData():
=== modified file 'py/timing.py'
--- py/timing.py 2010-03-25 13:24:10 +0000
+++ py/timing.py 2010-04-23 11:23:15 +0000
@@ -73,25 +73,25 @@
.. code-block:: none
- Name Count Time Rel. time
- -------------------------------------------------------------------------------------------------------
- ForceResetter 400 9449μs 0.01%
- BoundingVolumeMetaEngine 400 1171770μs 1.15%
- PersistentSAPCollider 400 9433093μs 9.24%
- InteractionGeometryMetaEngine 400 15177607μs 14.87%
- InteractionPhysicsMetaEngine 400 9518738μs 9.33%
- ConstitutiveLawDispatcher 400 64810867μs 63.49%
- ef2_Spheres_Brefcom_BrefcomLaw
- setup 4926145 7649131μs 15.25%
- geom 4926145 23216292μs 46.28%
- material 4926145 8595686μs 17.14%
- rest 4926145 10700007μs 21.33%
- TOTAL 50161117μs 100.00%
- "damper" 400 1866816μs 1.83%
- "strainer" 400 21589μs 0.02%
- "plotDataCollector" 160 64284μs 0.06%
- "damageChecker" 9 3272μs 0.00%
- TOTAL 102077490μs 100.00%
+ Name Count Time Rel. time
+ ------------------------------------------------------------------------------------
+ ForceResetter 400 9449μs 0.01%
+ BoundingVolumeMetaEngine 400 1171770μs 1.15%
+ PersistentSAPCollider 400 9433093μs 9.24%
+ InteractionGeometryMetaEngine 400 15177607μs 14.87%
+ InteractionPhysicsMetaEngine 400 9518738μs 9.33%
+ ConstitutiveLawDispatcher 400 64810867μs 63.49%
+ ef2_Spheres_Brefcom_BrefcomLaw
+ setup 4926145 7649131μs 15.25%
+ geom 4926145 23216292μs 46.28%
+ material 4926145 8595686μs 17.14%
+ rest 4926145 10700007μs 21.33%
+ TOTAL 50161117μs 100.00%
+ "damper" 400 1866816μs 1.83%
+ "strainer" 400 21589μs 0.02%
+ "plotDataCollector" 160 64284μs 0.06%
+ "damageChecker" 9 3272μs 0.00%
+ TOTAL 102077490μs 100.00%
"""
print 'Name'.ljust(_statCols['label'])+' '+'Count'.rjust(_statCols['count'])+' '+'Time'.rjust(_statCols['time'])+' '+'Rel. time'.rjust(_statCols['relTime'])
=== modified file 'py/yadeWrapper/yadeWrapper.cpp'
--- py/yadeWrapper/yadeWrapper.cpp 2010-04-19 10:18:42 +0000
+++ py/yadeWrapper/yadeWrapper.cpp 2010-04-23 11:23:15 +0000
@@ -200,6 +200,7 @@
long countReal(){ long ret=0; FOREACH(const shared_ptr<Interaction>& I, *proxee){ if(I->isReal()) ret++; } return ret; }
bool serializeSorted_get(){return proxee->serializeSorted;}
void serializeSorted_set(bool ss){proxee->serializeSorted=ss;}
+ void eraseNonReal(){ proxee->eraseNonReal(); }
};
class pyForceContainer{
@@ -584,6 +585,7 @@
.def("nth",&pyInteractionContainer::pyNth,"Return n-th interaction from the container (usable for picking random interaction).")
.def("withBody",&pyInteractionContainer::withBody,"Return list of real interactions of given body.")
.def("withBodyAll",&pyInteractionContainer::withBodyAll,"Return list of all (real as well as non-real) interactions of given body.")
+ .def("eraseNonReal",&pyInteractionContainer::eraseNonReal,"Erase all interactions that are not :yref:`real <InteractionContainer.isReal>`.")
.add_property("serializeSorted",&pyInteractionContainer::serializeSorted_get,&pyInteractionContainer::serializeSorted_set)
.def("clear",&pyInteractionContainer::clear,"Remove all interactions");
python::class_<pyInteractionIterator>("InteractionIterator",python::init<pyInteractionIterator&>())