Commit 0f03c68c authored by Chiara Modenese's avatar Chiara Modenese
Browse files

1. Add LawTester class for prescribing displacements on interactions...

1. Add LawTester class for prescribing displacements on interactions precisely, see scripts/test/law-test.py
2. plot now displays the last point as a bullet 
3. Rename Interaction{Geometry,Physics} to I{Geom,Phys}; rename related classes as well (functors etc)
4. Rename Interaction::interaction{Geometry,Physics} to Interaction::{geom,phys}
5. Add Vector3.normalized() to the eigen wrapper
6. Add framework for arbitrary rendering hooks (GLDrawExtra) run from OpenGLRenderer at the end of the rendering routine (not yet fully tested)
parent 30c59b26
......@@ -646,8 +646,7 @@ env.Install('$PREFIX/share/doc/yade$SUFFIX-doc/',['examples','scripts','doc'])
### check if combinedFiles is different; if so, force rebuild of all of them
combinedFilesMd5New=md5.md5(open(combinedFiles).read()).hexdigest()
if combinedFilesMd5!=combinedFilesMd5New:
if not os.path.exists(combinedFiles) or combinedFilesMd5!=md5.md5(open(combinedFiles).read()).hexdigest():
print 'Rebuilding combined files, since the md5 has changed.'
combs=[l.split(':')[0] for l in open(combinedFiles)]
for c in combs:
......
......@@ -13,17 +13,17 @@
#include<yade/lib-multimethods/Indexable.hpp>
#include<yade/core/Dispatcher.hpp>
class InteractionGeometry : public Serializable, public Indexable
class IGeom : public Serializable, public Indexable
{
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(InteractionGeometry,Serializable,"Geometrical configuration of interaction",
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(IGeom,Serializable,"Geometrical configuration of interaction",
/*no attrs*/,
/*ctor*/,
/*py*/
YADE_PY_TOPINDEXABLE(InteractionGeometry)
YADE_PY_TOPINDEXABLE(IGeom)
);
REGISTER_INDEX_COUNTER(InteractionGeometry);
REGISTER_INDEX_COUNTER(IGeom);
};
REGISTER_SERIALIZABLE(InteractionGeometry);
REGISTER_SERIALIZABLE(IGeom);
......@@ -13,15 +13,15 @@
#include<yade/lib-multimethods/Indexable.hpp>
#include<yade/core/Dispatcher.hpp>
class InteractionPhysics : public Serializable, public Indexable
class IPhys : public Serializable, public Indexable
{
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(InteractionPhysics,Serializable,"Physical (material) properties of :yref:`interaction<Interaction>`.",
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(IPhys,Serializable,"Physical (material) properties of :yref:`interaction<Interaction>`.",
/*attrs*/,
/*ctor*/,
/*py*/YADE_PY_TOPINDEXABLE(InteractionPhysics)
/*py*/YADE_PY_TOPINDEXABLE(IPhys)
);
REGISTER_INDEX_COUNTER(InteractionPhysics);
REGISTER_INDEX_COUNTER(IPhys);
};
REGISTER_SERIALIZABLE(InteractionPhysics);
REGISTER_SERIALIZABLE(IPhys);
......@@ -20,19 +20,19 @@ void Interaction::init(){
isNeighbor = true;//NOTE : TriangulationCollider needs that
iterMadeReal=-1;
functorCache.geomExists=true;
//functorCache.geom=shared_ptr<InteractionGeometryFunctor>(); functorCache.phys=shared_ptr<InteractionPhysicsFunctor>(); functorCache.constLaw=shared_ptr<LawFunctor>();
//functorCache.geom=shared_ptr<IGeomFunctor>(); functorCache.phys=shared_ptr<IPhysFunctor>(); functorCache.constLaw=shared_ptr<LawFunctor>();
}
void Interaction::reset(){
interactionGeometry=shared_ptr<InteractionGeometry>();
interactionPhysics=shared_ptr<InteractionPhysics>();
geom=shared_ptr<IGeom>();
phys=shared_ptr<IPhys>();
init();
}
void Interaction::swapOrder(){
if(interactionGeometry || interactionPhysics){
throw std::logic_error("Bodies in interaction cannot be swapped if they have interactionGeometry or interactionPhysics.");
if(geom || phys){
throw std::logic_error("Bodies in interaction cannot be swapped if they have geom or phys.");
}
std::swap(id1,id2);
cellDist*=-1;
......
......@@ -4,23 +4,23 @@
#pragma once
#include<yade/lib-serialization/Serializable.hpp>
// keep those two here, template instantiation & boost::python gets broken otherwise, e.g. https://bugs.launchpad.net/bugs/618766
#include<yade/core/InteractionGeometry.hpp>
#include<yade/core/InteractionPhysics.hpp>
#include<yade/core/IGeom.hpp>
#include<yade/core/IPhys.hpp>
#include<yade/core/Body.hpp>
class InteractionGeometryFunctor;
class InteractionPhysicsFunctor;
class IGeomFunctor;
class IPhysFunctor;
class LawFunctor;
class Scene;
class Interaction : public Serializable
{
private :
friend class InteractionPhysicsDispatcher;
friend class IPhysDispatcher;
friend class InteractionLoop;
public :
bool isReal() const {return (bool)interactionGeometry && (bool)interactionPhysics;}
bool isReal() const {return (bool)geom && (bool)phys;}
//! If this interaction was just created in this step (for the constitutive law, to know that it is the first time there)
bool isFresh(Scene* rb);
......@@ -45,13 +45,13 @@ class Interaction : public Serializable
// Therefore, geomExists must be initialized to true first (done in Interaction::reset() called from ctor).
bool geomExists;
#ifdef YADE_DEVIRT_FUNCTORS
// is a InteractionGeometryFunctor::StaticFuncPtr, but we would have to #include a file from pkg-common here
// is a IGeomFunctor::StaticFuncPtr, but we would have to #include a file from pkg-common here
// cast at those few places instead, for now
void* geomPtr;
#endif
// shared_ptr's are initialized to NULLs automagically
shared_ptr<InteractionGeometryFunctor> geom;
shared_ptr<InteractionPhysicsFunctor> phys;
shared_ptr<IGeomFunctor> geom;
shared_ptr<IPhysFunctor> phys;
shared_ptr<LawFunctor> constLaw;
} functorCache;
......@@ -63,14 +63,12 @@ class Interaction : public Serializable
YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Interaction,Serializable,"Interaction between pair of bodies.",
((Body::id_t,id1,0,Attr::readonly,":yref:`Id<Body::id>` of the first body in this interaction."))
((Body::id_t,id2,0,Attr::readonly,":yref:`Id<Body::id>` of the first body in this interaction."))
((long,iterMadeReal,-1,,"Step number at which the interaction was fully (in the sense of interactionGeometry and interactionPhysics) created. (Should be touched only by :yref:`InteractionPhysicsDispatcher` and :yref:`InteractionLoop`, therefore they are made friends of Interaction"))
((shared_ptr<InteractionGeometry>,interactionGeometry,,,"Geometry part of the interaction."))
((shared_ptr<InteractionPhysics>,interactionPhysics,,,"Physical (material) part of the interaction."))
((long,iterMadeReal,-1,,"Step number at which the interaction was fully (in the sense of geom and phys) created. (Should be touched only by :yref:`IPhysDispatcher` and :yref:`InteractionLoop`, therefore they are made friends of Interaction"))
((shared_ptr<IGeom>,geom,,,"Geometry part of the interaction."))
((shared_ptr<IPhys>,phys,,,"Physical (material) part of the interaction."))
((Vector3i,cellDist,Vector3i(0,0,0),,"Distance of bodies in cell size units, if using periodic boundary conditions; id2 is shifted by this number of cells from its :yref:`State::pos` coordinates for this interaction to exist. Assigned by the collider.\n\n.. warning::\n\t(internal) cellDist must survive Interaction::reset(), it is only initialized in ctor. Interaction that was cancelled by the constitutive law, was reset() and became only potential must have the priod information if the geometric functor again makes it real. Good to know after few days of debugging that :-)")),
/* ctor */ init(),
/*py*/
.def_readwrite("geom",&Interaction::interactionGeometry,"Shorthand for :yref:`Interaction::interactionGeometry`")
.def_readwrite("phys",&Interaction::interactionPhysics,"Shorthand for :yref:`Interaction::interactionPhysics`")
.add_property("isReal",&Interaction::isReal,"True if this interaction has both geom and phys; False otherwise.")
);
};
......
......@@ -140,7 +140,7 @@ struct compPtrInteraction{
void InteractionContainer::preSave(InteractionContainer&){
FOREACH(const shared_ptr<Interaction>& I, *this){
if(I->interactionGeometry || I->interactionPhysics) interaction.push_back(I);
if(I->geom || I->phys) interaction.push_back(I);
// since requestErase'd interactions have no interaction physics/geom, they are not saved
}
if(serializeSorted) std::sort(interaction.begin(),interaction.end(),compPtrInteraction());
......
......@@ -93,7 +93,7 @@ class InteractionContainer: public Serializable{
This should be called only in rare cases that collider is not used but still interactions should be erased.
Otherwise collider should decide on a case-by-case basis, which interaction to erase for good and which to keep in the potential state
(without interactionGeometry and interactionPhysics).
(without geom and phys).
This function doesn't lock pendingEraseMutex, as it is (supposedly) called from no-parallel sections only once per iteration
*/
......
......@@ -9,11 +9,11 @@
#include<yade/core/Functor.hpp>
#include<yade/core/GlobalEngine.hpp>
#include<yade/core/Interaction.hpp>
#include<yade/core/InteractionGeometry.hpp>
#include<yade/core/InteractionPhysics.hpp>
#include<yade/core/IGeom.hpp>
#include<yade/core/IPhys.hpp>
#include<yade/core/Material.hpp>
#include<yade/core/PartialEngine.hpp>
#include<yade/core/Shape.hpp>
#include<yade/core/State.hpp>
#include<yade/core/TimeStepper.hpp>
YADE_PLUGIN((Body)(Bound)(Cell)(Dispatcher)(Engine)(FileGenerator)(Functor)(GlobalEngine)(Interaction)(InteractionGeometry)(InteractionPhysics)(Material)(PartialEngine)(Shape)(State)(TimeStepper));
YADE_PLUGIN((Body)(Bound)(Cell)(Dispatcher)(Engine)(FileGenerator)(Functor)(GlobalEngine)(Interaction)(IGeom)(IPhys)(Material)(PartialEngine)(Shape)(State)(TimeStepper));
......@@ -178,9 +178,9 @@ Results of using Verlet distance depend highly on the nature of simulation and c
Creating interaction between particles
================================================
Collision detection described above is only approximate. Exact collision detection depends on the geometry of individual particles and is handled separately. In Yade terminology, the :yref:`Collider` creates only *potential* interactions; potential interactions are evaluated exactly using specialized algorithms for collision of two spheres or other combinations. Exact collision detection must be run at every timestep since it is at every step that particles can change their mutual position (the collider is only run sometimes if the Verlet distance optimization is in use). Some exact collision detection algorithms are described in :ref:`sect-strain-evaluation`; in Yade, they are implemented in classes deriving from :yref:`InteractionGeometryFunctor` (prefixed with ``Ig2``).
Collision detection described above is only approximate. Exact collision detection depends on the geometry of individual particles and is handled separately. In Yade terminology, the :yref:`Collider` creates only *potential* interactions; potential interactions are evaluated exactly using specialized algorithms for collision of two spheres or other combinations. Exact collision detection must be run at every timestep since it is at every step that particles can change their mutual position (the collider is only run sometimes if the Verlet distance optimization is in use). Some exact collision detection algorithms are described in :ref:`sect-strain-evaluation`; in Yade, they are implemented in classes deriving from :yref:`IGeomFunctor` (prefixed with ``Ig2``).
Besides detection of geometrical overlap (which corresponds to :yref:`InteractionGeometry` in Yade), there are also non-geometrical properties of the interaction to be determined (:yref:`InteractionPhysics`). In Yade, they are computed for every new interaction by calling a functor deriving from :yref:`InteractionPhysicsFunctor` (prefixed with ``Ip2``) which accepts the given combination of :yref:`Material` types of both particles.
Besides detection of geometrical overlap (which corresponds to :yref:`IGeom` in Yade), there are also non-geometrical properties of the interaction to be determined (:yref:`IPhys`). In Yade, they are computed for every new interaction by calling a functor deriving from :yref:`IPhysFunctor` (prefixed with ``Ip2``) which accepts the given combination of :yref:`Material` types of both particles.
Stiffnesses
-----------
......@@ -437,7 +437,7 @@ The constitutive law presented here is the most usual DEM formulation, originall
In DEM generally, some constitutive laws are expressed using strains and stresses while others prefer displacement/force formulation. The law described here falls in the latter category.
When new contact is established (discussed in :ref:`sect-simulation-loop`) it has its properties (:yref:`InteractionPhysics`) computed from :yref:`Materials<Material>` associated with both particles. In the simple case of frictional material :yref:`FrictMat`, :yref:`Ip2_FrictMat_FrictMat_FrictPhys` creates a new :yref:`FrictPhys` instance, which defines normal stiffness $K_N$, shear stiffness $K_T$ and friction angle $\phi$.
When new contact is established (discussed in :ref:`sect-simulation-loop`) it has its properties (:yref:`IPhys`) computed from :yref:`Materials<Material>` associated with both particles. In the simple case of frictional material :yref:`FrictMat`, :yref:`Ip2_FrictMat_FrictMat_FrictPhys` creates a new :yref:`FrictPhys` instance, which defines normal stiffness $K_N$, shear stiffness $K_T$ and friction angle $\phi$.
At each step, given normal and shear displacements $u_N$, $\uT$, normal and shear forces are computed (if $u_N>0$, the contact is deleted without generating any forces):
......@@ -884,7 +884,7 @@ This algorithm is implemented in :yref:`InsertionSortCollider` and is used whene
Exact collision detection
^^^^^^^^^^^^^^^^^^^^^^^^^
When the collider detects approximate contact (on the :yref:`Aabb` level) and the contact does not yet exist, it creates *potential* contact, which is subsequently checked by exact collision algorithms (depending on the combination of :yref:`Shapes<Shape>`). Since particles can interact over many periodic cells (recall we never change their positions in simulation space), the collider embeds the relative cell coordinate of particles in the interaction itself (:yref:`Interaction.cellDist`) as an *integer* vector $c$. Multiplying current cell size $\mat{T}\vec{s}$ by $c$ component-wise, we obtain particle offset $\Delta \vec{x}$ in aperiodic $R^3$; this value is passed (from :yref:`InteractionLoop`) to the functor computing exact collision (:yref:`InteractionGeometryFunctor`), which adds it to the position of the particle :yref:`Interaction.id2`.
When the collider detects approximate contact (on the :yref:`Aabb` level) and the contact does not yet exist, it creates *potential* contact, which is subsequently checked by exact collision algorithms (depending on the combination of :yref:`Shapes<Shape>`). Since particles can interact over many periodic cells (recall we never change their positions in simulation space), the collider embeds the relative cell coordinate of particles in the interaction itself (:yref:`Interaction.cellDist`) as an *integer* vector $c$. Multiplying current cell size $\mat{T}\vec{s}$ by $c$ component-wise, we obtain particle offset $\Delta \vec{x}$ in aperiodic $R^3$; this value is passed (from :yref:`InteractionLoop`) to the functor computing exact collision (:yref:`IGeomFunctor`), which adds it to the position of the particle :yref:`Interaction.id2`.
By storing the integral offset $c$, $\Delta\vec{x}$ automatically updates as cell parameters change.
......
......@@ -313,11 +313,11 @@ Interactions
:yref:`Interactions<Interaction>` are always between pair of bodies; usually, they are created by the collider based on spatial proximity; they can, however, be created explicitly and exist independently of distance. Each interaction has 2 components:
:yref:`InteractionGeometry`
:yref:`IGeom`
holding geometrical configuration of the two particles in collision; it is updated automatically as the particles in question move and can be queried for various geometrical characteristics, such as penetration distance or shear strain.
Based on combination of types of :yref:`Shapes<Shape>` of the particles, there might be different storage requirements; for that reason, a number of derived classes exists, e.g. for representing geometry of contact between :yref:`Sphere+Sphere<Dem3DofGeom_SphereSphere>`, :yref:`Facet+Sphere<Dem3DofGeom_FacetSphere>` etc.
:yref:`InteractionPhysics`
:yref:`IPhys`
representing non-geometrical features of the interaction; some are computed from :yref:`Materials<Material>` of the particles in contact using some averaging algorithm (such as contact stiffness from Young's moduli of particles), others might be internal variables like damage.
Suppose now interactions have been already created. We can access them by the id pair:
......@@ -457,21 +457,21 @@ The next part, reading
hides 3 internal dispatchers within the :yref:`InteractionLoop` engine; they all operate on interactions and are, for performance reasons, put together:
:yref:`InteractionGeometryDispatcher`
uses the first set of functors (``Ig2``), which are dispatched based on combination of ``2`` :yref:`Shapes<Shapes>` objects. Dispatched functor resolves exact collision configuration and creates :yref:`InteractionGeometry<Interaction::interactionGeometry>` (whence ``Ig`` in the name) associated with the interaction, if there is collision. The functor might as well fail on approximate interactions, indicating there is no real contact between the bodies, even if they did overlap in the approximate collision detection.
uses the first set of functors (``Ig2``), which are dispatched based on combination of ``2`` :yref:`Shapes<Shapes>` objects. Dispatched functor resolves exact collision configuration and creates :yref:`IGeom<Interaction::geom>` (whence ``Ig`` in the name) associated with the interaction, if there is collision. The functor might as well fail on approximate interactions, indicating there is no real contact between the bodies, even if they did overlap in the approximate collision detection.
#. The first functor, :yref:`Ig2_Sphere_Sphere_Dem3DofGeom`, is called on interaction of 2 :yref:`Spheres<Sphere>` and creates :yref:`Dem3DofGeom` instance, if appropriate.
#. The second functor, :yref:`Ig2_Facet_Sphere_Dem3DofGeom`, is called for interaction of :yref:`Facet` with :yref:`Sphere` and might create (again) a :yref:`Dem3DofGeom` instance.
All ``Ig2`` functors derive from :yref:`InteractionGeometryFunctor` (they are documented at the same place).
All ``Ig2`` functors derive from :yref:`IGeomFunctor` (they are documented at the same place).
:yref:`InteractionPhysicsDispatcher`
dispatches to the second set of functors based on combination of ``2`` :yref:`Materials<Material>`; these functors return return :yref:`InteractionPhysics` instance (the ``Ip`` prefix). In our case, there is only 1 functor used, :yref:`Ip2_FrictMat_FrictMat_FrictPhys`, which create :yref:`FrictPhys` from 2 :yref:`FrictMat's<FrictMat>`.
dispatches to the second set of functors based on combination of ``2`` :yref:`Materials<Material>`; these functors return return :yref:`IPhys` instance (the ``Ip`` prefix). In our case, there is only 1 functor used, :yref:`Ip2_FrictMat_FrictMat_FrictPhys`, which create :yref:`FrictPhys` from 2 :yref:`FrictMat's<FrictMat>`.
``Ip2`` functors are derived from :yref:`InteractionPhysicsFunctor`.
``Ip2`` functors are derived from :yref:`IPhysFunctor`.
:yref:`LawDispatcher`
dispatches to the third set of functors, based on combinations of :yref:`InteractionGeometry` and :yref:`InteractionPhysics` (wherefore ``2`` in their name again) of each particular interaction, created by preceding functors. The ``Law2`` functors represent "constitutive law"; they resolve the interaction by computing forces on the interacting bodies (repulsion, attraction, shear forces, …) or otherwise update interaction state variables.
dispatches to the third set of functors, based on combinations of :yref:`IGeom` and :yref:`IPhys` (wherefore ``2`` in their name again) of each particular interaction, created by preceding functors. The ``Law2`` functors represent "constitutive law"; they resolve the interaction by computing forces on the interacting bodies (repulsion, attraction, shear forces, …) or otherwise update interaction state variables.
``Law2`` functors all inherit from :yref:`LawFunctor`.
......
......@@ -259,17 +259,17 @@ Dispatchers
.. _dispatcher-names:
===================================== ================ ============================ =========================== ================================== ===============
dispatcher arity dispatch types created type functor type functor prefix
===================================== ================ ============================ =========================== ================================== ===============
:yref:`BoundDispatcher` 1 :yref:`Shape` :yref:`Bound` :yref:`BoundFunctor` ``Bo1``
:yref:`InteractionGeometryDispatcher` 2 (symetric) 2 × :yref:`Shape` :yref:`InteractionGeometry` :yref:`InteractionGeometryFunctor` ``Ig2``
:yref:`InteractionPhysicsDispatcher` 2 (symetric) 2 × :yref:`Material` :yref:`InteractionPhysics` :yref:`InteractionPhysicsFunctor` ``Ip2``
:yref:`LawDispatcher` 2 (asymetric) :yref:`InteractionGeometry`, *(none)* :yref:`LawFunctor` ``Law2``
:yref:`InteractionPhysics`
===================================== ================ ============================ =========================== ================================== ===============
Respective abstract functors for each dispatchers are :yref:`BoundFunctor`, :yref:`InteractionGeometryFunctor`, :yref:`InteractionPhysicsFunctor` and :yref:`LawFunctor`.
========================== ================ ====================== ============== ===================== ===============
dispatcher arity dispatch types created type functor type functor prefix
========================== ================ ====================== ============== ===================== ===============
:yref:`BoundDispatcher` 1 :yref:`Shape` :yref:`Bound` :yref:`BoundFunctor` ``Bo1``
:yref:`IGeomDispatcher` 2 (symetric) 2 × :yref:`Shape` :yref:`IGeom` :yref:`IGeomFunctor` ``Ig2``
:yref:`IPhysDispatcher` 2 (symetric) 2 × :yref:`Material` :yref:`IPhys` :yref:`IPhysFunctor` ``Ip2``
:yref:`LawDispatcher` 2 (asymetric) :yref:`IGeom` *(none)* :yref:`LawFunctor` ``Law2``
:yref:`IPhys`
========================== ================ ====================== ============== ===================== ===============
Respective abstract functors for each dispatchers are :yref:`BoundFunctor`, :yref:`IGeomFunctor`, :yref:`IPhysFunctor` and :yref:`LawFunctor`.
Functors
Functor name is composed of 3 parts, separated by underscore.
......@@ -897,11 +897,11 @@ There are currenly 4 predefined dispatchers (see `dispatcher-names`_) and corres
Example: InteractionGeometryDispatcher
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Let's take (the most complicated perhaps) :yref:`InteractionGeometryDispatcher`. :yref:`InteractionGeometryFunctor`, which is dispatched based on types of 2 :yref:`Shape` instances (a :yref:`Functor`), takes a number of arguments and returns bool. The functor "call" is always provided by its overridden ``Functor::go`` method; it always receives the dispatched instances as first argument(s) (2 × ``const shared_ptr<Shape>&``) and a number of other arguments it needs:
Let's take (the most complicated perhaps) :yref:`InteractionGeometryDispatcher`. :yref:`IGeomFunctor`, which is dispatched based on types of 2 :yref:`Shape` instances (a :yref:`Functor`), takes a number of arguments and returns bool. The functor "call" is always provided by its overridden ``Functor::go`` method; it always receives the dispatched instances as first argument(s) (2 × ``const shared_ptr<Shape>&``) and a number of other arguments it needs:
.. code-block:: c++
class InteractionGeometryFunctor: public Functor2D<
class IGeomFunctor: public Functor2D<
bool, //return type
TYPELIST_7(const shared_ptr<Shape>&, // 1st class for dispatch
const shared_ptr<Shape>&, // 2nd class for dispatch
......@@ -920,12 +920,12 @@ The dispatcher is declared as follows:
class InteractionGeometryDispatcher: public Dispatcher2D<
Shape, // 1st class for dispatch
Shape, // 2nd class for dispatch
InteractionGeometryFunctor, // functor type
IGeomFunctor, // functor type
bool, // return type of the functor
// follow argument types for functor call
// they must be exactly the same as types
// given to the InteractionGeometryFunctor above.
// given to the IGeomFunctor above.
TYPELIST_7(const shared_ptr<Shape>&,
const shared_ptr<Shape>&,
const State&,
......@@ -943,20 +943,20 @@ The dispatcher is declared as follows:
>
{ /* … */ }
Functor derived from InteractionGeometryFunctor must then
Functor derived from IGeomFunctor must then
* override the ::go method with appropriate arguments (they must match exactly types given to ``TYPELIST_*`` macro);
* declare what types they should be dispatched for, and in what order if they are not the same.
.. code-block:: c++
class Ig2_Facet_Sphere_Dem3DofGeom: public InteractionGeometryFunctor{
class Ig2_Facet_Sphere_Dem3DofGeom: public IGeomFunctor{
public:
// override the InteractionGeometryFunctor::go
// override the IGeomFunctor::go
// (it is really inherited from FunctorWrapper template,
// therefore not declare explicitly in the
// InteractionGeometryFunctor declaration as such)
// IGeomFunctor declaration as such)
// since dispatcher dispatches only for declared types
// (or types derived from them), we can do
// static_cast<Facet>(shape1) and static_cast<Sphere>(shape2)
......@@ -1008,8 +1008,8 @@ Top-level Indexable used by
============================ ===========================
:yref:`Shape` :yref:`BoundFunctor`, :yref:`InteractionGeometryDispatcher`
:yref:`Material` :yref:`InteractionPhysicsDispatcher`
:yref:`InteractionPhysics` :yref:`LawDispatcher`
:yref:`InteractionGeometry` :yref:`LawDispatcher`
:yref:`IPhys` :yref:`LawDispatcher`
:yref:`IGeom` :yref:`LawDispatcher`
============================ ===========================
The top-level Indexable must use the ``REGISTER_INDEX_COUNTER`` macro, which sets up the machinery for identifying types of derived classes; they must then use the ``REGISTER_CLASS_INDEX`` macro *and* call ``createIndex()`` in their constructor. For instance, taking the :yref:`Shape` class (which is a top-level Indexable):
......@@ -1305,8 +1305,8 @@ Timing within engines (and functors) is based on :yref:`TimingDeltas` class. It
.. code-block:: c++
void Law2_Dem3DofGeom_CpmPhys_Cpm::go(shared_ptr<InteractionGeometry>& _geom,
shared_ptr<InteractionPhysics>& _phys,
void Law2_Dem3DofGeom_CpmPhys_Cpm::go(shared_ptr<IGeom>& _geom,
shared_ptr<IPhys>& _phys,
Interaction* I,
Scene* scene)
{
......@@ -1375,9 +1375,9 @@ Yade provides 3d rendering based on [QGLViewer]_. It is not meant to be full-fea
.. warning:: There are 2 possible causes of crash, which are not prevented because of serious performance penalty that would result:
#. access to :yref:`BodyContainer`, in particular deleting bodies from simulation; this is a rare operation, though.
#. deleting Interaction::interactionPhysics or Interaction::interactionGeometry.
#. deleting Interaction::phys or Interaction::geom.
Renderable entities (:yref:`Shape`, :yref:`State`, :yref:`Bound`, :yref:`InteractionGeometry`, :yref:`InteractionPhysics`) have their associated `OpenGL functors`_. An entity is rendered if
Renderable entities (:yref:`Shape`, :yref:`State`, :yref:`Bound`, :yref:`IGeom`, :yref:`IPhys`) have their associated `OpenGL functors`_. An entity is rendered if
#. Rendering such entities is enabled by appropriate attribute in :yref:`OpenGLRenderingEngine`
#. Functor for that particular entity type is found via the :ref:`dispatch mechanism<multiple-dispatch>`.
......@@ -1520,7 +1520,7 @@ As with BodyContainer, iteration over interactions should use the ``FOREACH`` ma
/* … */
}
Again, note the usage const reference for ``i``. The check ``if(!i->isReal())`` filters away interactions that exist only *potentially*, i.e. there is only :yref:`Bound` overlap of the two bodies, but not (yet) overlap of bodies themselves. The ``i->isReal()`` function is equivalent to ``i->interactionGeometry && i->interactionPhysics``. Details are again explained in :ref:`interaction-flow`.
Again, note the usage const reference for ``i``. The check ``if(!i->isReal())`` filters away interactions that exist only *potentially*, i.e. there is only :yref:`Bound` overlap of the two bodies, but not (yet) overlap of bodies themselves. The ``i->isReal()`` function is equivalent to ``i->geom && i->phys``. Details are again explained in :ref:`interaction-flow`.
In some cases, such as OpenMP-loops requiring integral index (OpenMP >= 3.0 allows parallelization using random-access iterator as well), you need to iterate over interaction indices instead:
......@@ -1590,10 +1590,10 @@ Creating and removing interactions is a rather delicate topic and number of comp
Terminologically, we distinguish
potential interactions,
having neither :yref:`geometry<Interaction::interactionGeometry>` nor :yref:`physics<Interaction::interactionPhysics>`. :yref:`Interaction.isReal` can be used to query the status (``Interaction::isReal()`` in c++).
having neither :yref:`geometry<Interaction::geom>` nor :yref:`physics<Interaction::phys>`. :yref:`Interaction.isReal` can be used to query the status (``Interaction::isReal()`` in c++).
real interactions,
having both :yref:`geometry<Interaction::interactionGeometry>` and :yref:`physics<Interaction::interactionPhysics>`. Below, we shall discuss the possibility of interactions that only have geometry but no physics.
having both :yref:`geometry<Interaction::geom>` and :yref:`physics<Interaction::phys>`. Below, we shall discuss the possibility of interactions that only have geometry but no physics.
During each step in the simulation, the following operations are performed on interactions in a typical simulation:
......@@ -1605,24 +1605,24 @@ During each step in the simulation, the following operations are performed on in
#. Collider erases interactions that were requested for being erased (see below).
#. :yref:`InteractionLoop` (via :yref:`InteractionGeometryDispatcher`) calls appropriate :yref:`InteractionGeometryFunctor` based on :yref:`Shape` combination of both bodies, if such functor exists. For real interactions, the functor updates associated :yref:`InteractionGeometry`. For potential interactions, the functor returns
#. :yref:`InteractionLoop` (via :yref:`InteractionGeometryDispatcher`) calls appropriate :yref:`IGeomFunctor` based on :yref:`Shape` combination of both bodies, if such functor exists. For real interactions, the functor updates associated :yref:`IGeom`. For potential interactions, the functor returns
``false``
if there is no geometrical overlap, and the interaction will stillremain potential-only
``true``
if there is geometrical overlap; the functor will have created an :yref:`InteractionGeometry` in such case.
if there is geometrical overlap; the functor will have created an :yref:`IGeom` in such case.
.. note ::
For *real* interactions, the functor *must* return ``true``, even if there is no more spatial overlap between bodies. If you wish to delete an interaction without geometrical overlap, you have to do this in the :yref:`LawFunctor`.
This behavior is deliberate, since different :yref:`laws<LawFunctor>` have different requirements, though ideally using relatively small number of generally useful :yref:`geometry functors<InteractionGeometryFunctor>`.
This behavior is deliberate, since different :yref:`laws<LawFunctor>` have different requirements, though ideally using relatively small number of generally useful :yref:`geometry functors<IGeomFunctor>`.
.. note::
If there is no functor suitable to handle given combination of :yref:`shapes<Shape>`, the interaction will be left in potential state, without raising any error.
#. For real interactions (already existing or jsut created in last step), :yref:`InteractionLoop` (via :yref:`InteractionPhysicsDispatcher`) calls appropriate :yref:`InteractionPhysicsFunctor` based on :yref:`Material` combination of both bodies. The functor *must* update (or create, if it doesn't exist yet) associated :yref:`InteractionPhysics` instance. It is an error if no suitable functor is found, and an exception will be thrown.
#. For real interactions (already existing or jsut created in last step), :yref:`InteractionLoop` (via :yref:`InteractionPhysicsDispatcher`) calls appropriate :yref:`IPhysFunctor` based on :yref:`Material` combination of both bodies. The functor *must* update (or create, if it doesn't exist yet) associated :yref:`IPhys` instance. It is an error if no suitable functor is found, and an exception will be thrown.
#. For real interactions, :yref:`InteractionLoop` (via :yref:`LawDispatcher`) calls appropriate :yref:`LawFunctor` based on combintation of :yref:`InteractionGeometry` and :yref:`InteractionPhysics` of the interaction. Again, it is an error if no functor capable of handling it is found.
#. For real interactions, :yref:`InteractionLoop` (via :yref:`LawDispatcher`) calls appropriate :yref:`LawFunctor` based on combintation of :yref:`IGeom` and :yref:`IPhys` of the interaction. Again, it is an error if no functor capable of handling it is found.
#. :yref:`LawDispatcher` can decide that an interaction should be removed (such as if bodies get too far apart for non-cohesive laws; or in case of complete damage for damage models). This is done by calling
......@@ -1635,7 +1635,7 @@ During each step in the simulation, the following operations are performed on in
Creating interactions explicitly
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Interactions may still be created explicitly with :yref:`yade.utils.createInteraction`, without any spatial requirements. This function searches current engines for dispatchers and uses them. :yref:`InteractionGeometryFunctor` is called with the ``force`` parameter, obliging it to return ``true`` even if there is no spatial overlap.
Interactions may still be created explicitly with :yref:`yade.utils.createInteraction`, without any spatial requirements. This function searches current engines for dispatchers and uses them. :yref:`IGeomFunctor` is called with the ``force`` parameter, obliging it to return ``true`` even if there is no spatial overlap.
Associating Material and State types
......
......@@ -374,7 +374,7 @@ In some cases, you might want to create rigid aggregate of individual particles
Creating interactions
======================
In typical cases, interactions are created during simulations as particles collide. This is done by a :yref:`Collider` detecting approximate contact between particles and then an :yref:`InteractionGeometryFunctor` detecting exact collision.
In typical cases, interactions are created during simulations as particles collide. This is done by a :yref:`Collider` detecting approximate contact between particles and then an :yref:`IGeomFunctor` detecting exact collision.
Some material models (such as the :yref:`concrete model<Law2_Dem3DofGeom_CpmPhys_Cpm>`) rely on initial interaction network which is denser than geometrical contact of spheres: sphere's radii as "enlarged" by a dimensionless factor called *interaction radius* (or *interaction ratio*) to create this initial network. This is done typically in this way (see :ysrc:`examples/concrete/uniax.py` for an example):
......@@ -521,7 +521,7 @@ There are other colliders as well, though their usage is only experimental:
Ig2 functors
^^^^^^^^^^^^^
``Ig2`` functor choice (all of the derive from :yref:`InteractionGeometryFunctor`) depends on
``Ig2`` functor choice (all of the derive from :yref:`IGeomFunctor`) depends on
#. shape combinations that should collide;
for instance::
......@@ -537,7 +537,7 @@ Ig2 functors
Again, missing combination will cause given shape combinations to freely interpenetrate one another.
#. :yref:`InteractionGeometry` type accepted by the ``Law2`` functor (below); it is the first part of functor's name after ``Law2`` (for instance, :yref:`Law2_Dem3DofGeom_CpmPhys_Cpm` accepts :yref:`Dem3DofGeom`). This is (for most cases) either :yref:`Dem3DofGeom` (total shear formulation) or :yref:`ScGeom` (incremental shear formulation). For :yref:`ScGeom`, the above example would simply change to::
#. :yref:`IGeom` type accepted by the ``Law2`` functor (below); it is the first part of functor's name after ``Law2`` (for instance, :yref:`Law2_Dem3DofGeom_CpmPhys_Cpm` accepts :yref:`Dem3DofGeom`). This is (for most cases) either :yref:`Dem3DofGeom` (total shear formulation) or :yref:`ScGeom` (incremental shear formulation). For :yref:`ScGeom`, the above example would simply change to::
InteractionLoop([
Ig2_Sphere_Sphere_ScGeom(),
......@@ -547,11 +547,11 @@ Ig2 functors
Ip2 functors
^^^^^^^^^^^^
``Ip2`` functors (deriving from :yref:`InteractionPhysicsFunctor`) must be chosen depending on
``Ip2`` functors (deriving from :yref:`IPhysFunctor`) must be chosen depending on
#. :yref:`Material` combinations within the simulation. In most cases, ``Ip2`` functors handle 2 instances of the same :yref:`Material` class (such as :yref:`Ip2_FrictMat_FrictMat_FrictPhys` for 2 bodies with :yref:`FrictMat`)
#. :yref:`InteractionPhysics` accepted by the constitutive law (``Law2`` functor), which is the second part of the ``Law2`` functor's name (e.g. :yref:`Law2_ScGeom_FrictPhys_Basic` accepts :yref:`FrictPhys`)
#. :yref:`IPhys` accepted by the constitutive law (``Law2`` functor), which is the second part of the ``Law2`` functor's name (e.g. :yref:`Law2_ScGeom_FrictPhys_Basic` accepts :yref:`FrictPhys`)
.. note:: Unlike with ``Bo1`` and ``Ig2`` functors, unhandled combination of :yref:`Materials<Material>` is an error condition signaled by an exception.
......@@ -560,9 +560,9 @@ Law2 functor(s)
``Law2`` functor was the ultimate criterion for the choice of ``Ig2`` and ``Ig2`` functors; there are no restrictions on its choice in itself, as it only applies forces without creating new objects.
In most simulations, only one ``Law2`` functor will be in use; it is possible, though, to have several of them, dispatched based on combination of :yref:`InteractionGeometry` and :yref:`InteractionPhysics` produced previously by ``Ig2`` and ``Ip2`` functors respectively (in turn based on combination of :yref:`Shapes<Shape>` and :yref:`Materials<Material>`).
In most simulations, only one ``Law2`` functor will be in use; it is possible, though, to have several of them, dispatched based on combination of :yref:`IGeom` and :yref:`IPhys` produced previously by ``Ig2`` and ``Ip2`` functors respectively (in turn based on combination of :yref:`Shapes<Shape>` and :yref:`Materials<Material>`).
.. note:: As in the case of ``Ip2`` functors, receiving a combination of :yref:`InteractionGeometry` and :yref:`InteractionPhysics` which is not handled by any ``Law2`` functor is an error.
.. note:: As in the case of ``Ip2`` functors, receiving a combination of :yref:`IGeom` and :yref:`IPhys` which is not handled by any ``Law2`` functor is an error.
Examples
^^^^^^^^
......@@ -575,7 +575,7 @@ Suppose we want to use the :yref:`Law2_ScGeom_FrictPhys_Basic` constitutive law.
#. the ``Ig2`` functors most create :yref:`ScGeom`. Since we have :yref:`spheres<Sphere>` and :yref:`walls<Wall>` in the simulation, we will need functors accepting :yref:`Sphere` + :yref:`Sphere` and :yref:`Wall` + :yref:`Sphere` combinations. We don't want interactions between walls themselves (as a matter of fact, there is no such functor anyway). That gives us :yref:`Ig2_Sphere_Sphere_ScGeom` and ``Ig2_Wall_Sphere_ScGeom`` (as a matter of facet, there is no such functor now, although it is `planned <https://blueprints.launchpad.net/yade/+spec/walls-spheres-contact-geometry>`_)
#. the ``Ip2`` functors should create :yref:`FrictPhys`. Looking at :yref:`InteractionPhysicsFunctors<InteractionPhysicsFunctor>`, there is only :yref:`Ip2_FrictMat_FrictMat_FrictPhys`. That obliges us to use :yref:`FrictMat` for particles.
#. the ``Ip2`` functors should create :yref:`FrictPhys`. Looking at :yref:`InteractionPhysicsFunctors<IPhysFunctor>`, there is only :yref:`Ip2_FrictMat_FrictMat_FrictPhys`. That obliges us to use :yref:`FrictMat` for particles.
The result will be therefore::
......
......@@ -122,12 +122,12 @@ Class reference (yade.wrapper module)
"""+
sect('Bodies','',['Body','Shape','State','Material','Bound'])+
sect('Interactions','',['Interaction','InteractionGeometry','InteractionPhysics'])+
sect('Interactions','',['Interaction','IGeom','IPhys'])+
sect('Global engines','',['FieldApplier','Collider','BoundaryController','GlobalEngine'],reverse=True)+
sect('Partial engines','',['PartialEngine'])+
sect('Bounding volume creation','',['BoundFunctor','BoundDispatcher'])+
sect('Interaction Geometry creation','',['InteractionGeometryFunctor','InteractionGeometryDispatcher'])+
sect('Interaction Physics creation','',['InteractionPhysicsFunctor','InteractionPhysicsDispatcher'])+
sect('Interaction Geometry creation','',['IGeomFunctor','IGeomDispatcher'])+
sect('Interaction Physics creation','',['IPhysFunctor','IPhysDispatcher'])+
sect('Constitutive laws','',['LawFunctor','LawDispatcher'])+
sect('Callbacks','',['BodyCallback','IntrCallback'])+
sect('Preprocessors','',['FileGenerator'])+
......
......@@ -9,8 +9,8 @@ o=Omega()
o.engines=[
ForceResetter(),
InsertionSortCollider([Bo1_Sphere_Aabb(),Bo1_Box_Aabb()]),
InteractionGeometryDispatcher([Ig2_Sphere_Sphere_ScGeom(),Ig2_Box_Sphere_ScGeom()]),
InteractionPhysicsDispatcher([Ip2_FrictMat_FrictMat_FrictPhys()]),
IGeomDispatcher([Ig2_Sphere_Sphere_ScGeom(),Ig2_Box_Sphere_ScGeom()]),
IPhysDispatcher([Ip2_FrictMat_FrictMat_FrictPhys()]),
ElasticContactLaw(),
GlobalStiffnessTimeStepper(defaultDt=1e-4,active=True,timeStepUpdateInterval=500),
AxialGravityEngine(axisPoint=(0,0,0),axisDirection=(1,0,0),acceleration=1e4),
......
......@@ -26,7 +26,7 @@ o.engines=[
## Decide whether the potential collisions are real; if so, create geometry information about each potential collision.
## Here, the decision about which EngineUnit to use depends on types of _both_ bodies.
## Note that there is no EngineUnit for box-box collision. They are not implemented.
InteractionGeometryDispatcher([
IGeomDispatcher([
Ig2_Sphere_Sphere_ScGeom(),
Ig2_Box_Sphere_ScGeom()
]),
......@@ -34,7 +34,7 @@ o.engines=[
## This may consist in deriving contact rigidity from elastic moduli of each body, for example.
## The purpose is that the contact may be "solved" without reference to related bodies,
## only with the information contained in contact geometry and physics.
InteractionPhysicsDispatcher([Ip2_FrictMat_FrictMat_FrictPhys()]),
IPhysDispatcher([Ip2_FrictMat_FrictMat_FrictPhys()]),
## "Solver" of the contact, also called (consitutive) law.
## Based on the information in interaction physics and geometry, it applies corresponding forces on bodies in interaction.
ElasticContactLaw(),
......
......@@ -296,8 +296,8 @@ class SerializableEditor(QFrame):
'Real':float,'float':float,'double':float,
'Vector3r':Vector3,'Matrix3r':Matrix3,'Se3r':Se3FakeType,
'string':str,
'BodyCallback':BodyCallback,'IntrCallback':IntrCallback,'BoundFunctor':BoundFunctor,'InteractionGeometryFunctor':InteractionGeometryFunctor,'InteractionPhysicsFunctor':InteractionPhysicsFunctor,'LawFunctor':LawFunctor,
'GlShapeFunctor':GlShapeFunctor,'GlStateFunctor':GlStateFunctor,'GlInteractionGeometryFunctor':GlInteractionGeometryFunctor,'GlInteractionPhysicsFunctor':GlInteractionPhysicsFunctor,'GlBoundFunctor':GlBoundFunctor
'BodyCallback':BodyCallback,'IntrCallback':IntrCallback,'BoundFunctor':BoundFunctor,'IGeomFunctor':IGeomFunctor,'IPhysFunctor':IPhysFunctor,'LawFunctor':LawFunctor,
'GlShapeFunctor':GlShapeFunctor,'GlStateFunctor':GlStateFunctor,'GlIGeomFunctor':GlIGeomFunctor,'GlIPhysFunctor':GlIPhysFunctor,'GlBoundFunctor':GlBoundFunctor,'GlExtraDrawer':GlExtraDrawer
}
for T,ret in vecMap.items():
if vecTest(T,cxxT):
......
......@@ -87,7 +87,7 @@ class ControllerClass(QWidget,Ui_Controller):
self.generatorCombo.addItem(c)
def addRenderers(self):
self.displayCombo.addItem('OpenGLRenderer'); afterSep=1
for bc in ('GlShapeFunctor','GlStateFunctor','GlBoundFunctor','GlInteractionGeometryFunctor','GlInteractionPhysicsFunctor'):
for bc in ('GlShapeFunctor','GlStateFunctor','GlBoundFunctor','GlIGeomFunctor','GlIPhysFunctor'):
if afterSep>0: self.displayCombo.insertSeparator(10000); afterSep=0
for c in yade.system.childClasses(bc) | set([bc]):
inst=eval(c+'()');
......
......@@ -2,17 +2,17 @@
// © 2008 Václav Šmilauer <eudoxos@arcig.cz>
#pragma once
#include<yade/core/InteractionPhysics.hpp>
#include<yade/core/IPhys.hpp>
class NormPhys:public InteractionPhysics {
class NormPhys:public IPhys {
public:
virtual ~NormPhys();
YADE_CLASS_BASE_DOC_ATTRS_CTOR(NormPhys,InteractionPhysics,"Abstract class for interactions that have normal stiffness.",
YADE_CLASS_BASE_DOC_ATTRS_CTOR(NormPhys,IPhys,"Abstract class for interactions that have normal stiffness.",
((Real,kn,NaN,,"Normal stiffness"))
((Vector3r,normalForce,Vector3r::Zero(),,"Normal force after previous step (in global coordinates).")),
createIndex();
);
REGISTER_CLASS_INDEX(NormPhys,InteractionPhysics);
REGISTER_CLASS_INDEX(NormPhys,IPhys);
};
REGISTER_SERIALIZABLE(NormPhys);
......
......@@ -28,7 +28,7 @@ unsigned int ChainedState::currentChain=0;
//!Sphere-cylinder or cylinder-cylinder not implemented yet, see Ig2_ChainedCylinder_ChainedCylinder_ScGeom and test/chained-cylinder-spring.py
#ifdef YADE_DEVIRT_FUNCTORS
bool Ig2_Sphere_ChainedCylinder_CylScGeom::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){ throw runtime_error("Do not call Ig2_Sphere_ChainedCylinder_CylScGeom::go, use getStaticFunctorPtr and call that function instead."); }
bool Ig2_Sphere_ChainedCylinder_CylScGeom::goStatic(InteractionGeometryFunctor* _self, 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 Ig2_Sphere_ChainedCylinder_CylScGeom::goStatic(IGeomFunctor* _self, 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){
const Ig2_Sphere_ChainedCylinder_CylScGeom* self=static_cast<Ig2_Sphere_ChainedCylinder_CylScGeom*>(_self);
const Real& interactionDetectionFactor=self->interactionDetectionFactor;
#else
......@@ -45,9 +45,9 @@ bool Ig2_Sphere_ChainedCylinder_CylScGeom::go( const shared_ptr<Shape>& cm1,
Real penetrationDepthSq=pow(interactionDetectionFactor*(s1->radius+s2->radius),2) - normal.squaredNorm();
if (penetrationDepthSq>0 || c->isReal() || force){
shared_ptr<ScGeom> scm;
bool isNew = !c->interactionGeometry;
if(!isNew) scm=YADE_PTR_CAST<ScGeom>(c->interactionGeometry);
else { scm=shared_ptr<ScGeom>(new ScGeom()); c->interactionGeometry=scm; }
bool isNew = !c->geom;
if(!isNew) scm=YADE_PTR_CAST<ScGeom>(c->geom);
else { scm=shared_ptr<ScGeom>(new ScGeom()); c->geom=scm; }
Real norm=normal.norm(); normal/=norm; // normal is unit vector now
Real penetrationDepth