Commit 584e5e48 authored by Václav Šmilauer's avatar Václav Šmilauer
Browse files

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
parent 4354e00d
......@@ -127,7 +127,7 @@ if 1:
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',
......
......@@ -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")
......
......@@ -135,8 +135,11 @@ namespace yade{
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 @@ namespace yade{
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 @@ namespace yade{
_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 @@ public :
// 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);
......
......@@ -139,7 +139,7 @@ void InteractionDispatchers::action(){
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);
}
......
......@@ -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;
......
......@@ -252,7 +252,7 @@ class InteractionLocator{
// 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 @@ class InteractionLocator{
}
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 @@ BOOST_PYTHON_MODULE(_eudoxos){
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 @@ BOOST_PYTHON_MODULE(_eudoxos){
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`.");
}
# encoding: utf-8
# 2008 © Václav Šmilauer <eudoxos@arcig.cz>
"""
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 @@ import matplotlib
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():
......
......@@ -73,25 +73,25 @@ def stats():
.. 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'])
......
......@@ -200,6 +200,7 @@ class pyInteractionContainer{
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 @@ BOOST_PYTHON_MODULE(wrapper)
.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&>())
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment