Adding an IGeomFunctor subclass

Asked by Kneib François on 2011-04-20

Hi all,

I would like to add a "Ig2_Sphere_ChainedCylinder_CylScGeom" subclass named "Ig2_Sphere_ChainedCylinder_ScGeom6D". (exactly like it works with "Ig2_Sphere_Sphere_ScGeom6D")
I have made the subclass in the "Cylinder.hpp" and "Cylinder.cpp" files and the compilation with scons is ok.
But in python, when I add Ig2_Sphere_ChainedCylinder_ScGeom6D in the InteractionLoop's list, I get this error :

"[Ig2_ChainedCylinder_ChainedCylinder_ScGeom6D(), Ig2_Sphere_ChainedCylinder_ScGeom6D(), Ig2_Sphere_Sphere_ScGeom6D(),Ig2_Box_Sphere_ScGeom()],
NameError: name 'Ig2_Sphere_ChainedCylinder_ScGeom6D' is not defined"

I'm using yade-trunk branch, version bzr2798

Thanks for your help

Francois

Question information

Language:
English Edit question
Status:
Solved
For:
Yade Edit question
Assignee:
No assignee Edit question
Solved by:
Kneib François
Solved:
2011-05-30
Last query:
2011-05-30
Last reply:
2011-05-11

First, double-check all macros and declarations and make sure that you
correctly use them for the new functor, like:
YADE_PLUGIN(...
FUNCTOR2D(...
DEFINE_FUNCTOR_ORDER_2D(...
YADE_CLASS_BASE_DOC_ATTRS(...
REGISTER_SERIALIZABLE(...
etc.

Ok I checked that and now my new Ig2_Sphere_ChainedCylinder_ScGeom6D is recognized in Yade.
Now I have a segmentation error when the CohFrictMat sphere touch the CohFrictMat cylinder.
Here's my Ig2_Sphere_ChainedCylinder_ScGeom6D::go method :

bool Ig2_Sphere_ChainedCylinder_ScGeom6D::go( const shared_ptr<Shape>& cm1, const shared_ptr<Shape>& cm2, const State& state1, const State& state2, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>& c)
{
 bool isNew = !c->geom;
 if (Ig2_Sphere_ChainedCylinder_CylScGeom::go(cm1,cm2,state1,state2,shift2,force,c)){//the 3 DOFS from ScGeom are updated here
   if (isNew) {//generate a 6DOF interaction from the 3DOF one generated by Ig2_Sphere_Sphere_ScGeom
   shared_ptr<ScGeom6D> sc (new ScGeom6D());
   *(YADE_PTR_CAST<ScGeom>(sc)) = *(YADE_PTR_CAST<ScGeom>(c->geom));
   c->geom=sc;}
  if (updateRotations) {YADE_PTR_CAST<ScGeom6D>(c->geom)->precomputeRotations(state1,state2,true,creep);}
  return true;
 }
 else return false;
}

I In fact when the updateRotations method is called, I put "true" instead of isnew so Yade never have to compute the rotation moments.
Maybe it's not the right way ...

Hard to tell where the segfault comes from. It can even be a problem in
your script. Recompile with debug symbols to get more info ("scons
debug=1" or "yade --debug --rebuild") .

Ok, I have launched Yade in debug mode.
Before the contact between a cohfrictmat sphere and a cohfrictmat cylinder
there is no problem.
When the contact occurs, I have a lot of messages (see attached file
log.txt). But I don't know how to use this log and why is there 4 threads ?
(I thought I was running Yade in one openmp 's thread mode).
The script that I use is called Cylindre_Sphere.py (see attached)

Tx

You can't attach files to a comment in launchpad unfortunately. See if
you have a "upload file" button in the interface, else send a mail to
yade-users directly with the attached files.
4 threads is ok (python interpreter, Qt view, etc.), it doesn't mean you
are actually using more than one processor.
Try and find which thread triggers the crash in the log (should point to
a yade *.cpp line).

Ok, I can't send a liked file, so there is the links for my two files :

Cylindres_Spheres.py :
http://download.grenoble.cemagref.fr/lcxx

log.txt :
http://download.grenoble.cemagref.fr/5uktzjp5r

Tx

The relevant thread is the one doing the simulation loop (thread 2 in your case - read from bottom to top):

#7 0x00007f2137c6a941 in *__GI___assert_fail (assertion=0x7f2123fdaef4 "px != 0", file=<value optimized out>, line=418, function=0x7f2123fdbde0 "T* boost::shared_ptr< <template-parameter-1-1> >::operator->() const [with T = CylScGeom]") at assert.c:81
#8 0x00007f2123e3859d in boost::shared_ptr<CylScGeom>::operator-> (this=0x7f2100ddd4e0) at /usr/include/boost/smart_ptr/shared_ptr.hpp:418
#9 0x00007f2123dba59d in Ig2_Sphere_ChainedCylinder_CylScGeom::go (this=0x3632950, cm1=..., cm2=..., state1=..., state2=..., shift2=..., force=@0x7f2100ddd8ab, c=...) at pkg/common/Cylinder.cpp:83
#10 0x00007f2123dbbbd1 in Ig2_Sphere_ChainedCylinder_ScGeom6D::go (this=0x3632950, cm1=..., cm2=..., state1=..., state2=..., shift2=..., force=@0x7f2100ddd8ab, c=...) at pkg/common/Cylinder.cpp:187

It seems you use a null pointer at line 83 (since it's a modified
version of the file, I can't check which line exactly).

Regarding the rotation, if you don't want it computed, it's enough to
turn "updateRotation" false in Ig2_Sphere_ChainedCylinder_ScGeom6D.

I realize another problem now: if you want 6D interaction between
spheres and cylinders, you need to generate a 6D version of CylScGeom,
not ScGeom.
There is maybe a conversion problem somewhere due to that, and leading
to the crash.
Basically, you need something very similar to
Ig2_Sphere_ChainedCylinder_CylScGeom::go, but generating a CylScGeom6D
instead of a CylScGeom; with CylScGeom6D inheriting from ScGeom6D.

I hope it helps.

Hi,

If I summarize, the problem is :
I'm trying to apply Ig2_Sphere_ChainedCylinder_CylScGeom::go to a 6D contact's geometry but this method is only designed for a 3D geometry.
So even if I don't want to compute the rotation's moments, you think I need :
- a modified version of Ig2_Sphere_ChainedCylinder_CylScGeom::go who can support the 6D contact's geometry
- an adapted 6d contact's geometry between a sphere and a cylinder

Tx

Ok, I thought about the question I here's what I've done :

I created CylScGeom6D, a child of CylScGeom. I put in it the same rotation's properties than in ScGeom6D, but I have set updateRotation to false. This solution is very nice because I don't have to re-write the big Ig2_Sphere_ChainedCylinder_CylScGeom::go method.

In my simulation I make a Sphere falling on a chainedcylinder. There is no problem if I switch setCohesionOnNewContact to false (that's the great thing), but I have a segmentation fault otherwise.

I think I need a new Law2 now : Law2_CylScGeom6D_CohFrictPhys_CohesionMoment()
This law should be very similar to Law2_ScGeom6D_CohFrictPhys_CohesionMoment().

My question is : do I have to write a new law or can I use a cast or something like that ?
I did't really understand how the YADE_CAST or YADE_PTR_CAST works ...

Thanks

Hi François,

Sorry for not replying earlier.
I think I underestimated the need for a
Law2_CylScGeom6D_CohFrictPhys_CohesionMoment in previous discussions.

The BIG difference between Law2_CylSc* and all other laws existing in
Yade is that this law modelizes an interaction between 3 bodies (1
sphere + 2 cylinders nodes), not just 2 like others.
As a consequence, unfortunately, you need to write
Law2_CylScGeom6D_CohFrictPhys_CohesionMoment() that will ultimately
merge the features of Law2_ScGeom6D_CohFrictPhys_CohesionMoment
(codesion+moment) AND Law2_CylScGeom_FrictPhys_CundallStrack (ternary
interaction).

If you only need cohesion however (not moment), it is not so hard. The
ugly part is you will need to copy-paste the bigest part of
Law2_CylScGeom_FrictPhys_CundallStrack, then change the few lines that
have to be changed: fn can be negative, and maxFs is not just friction*fn

Ok thanks, I'm looking at that and I've done this :

I created the Law2_CylScGeom6D_CohFrictPhys_CohesionMoment class, child of LawFunctor. I have done that in the CohesiveFrictionalContactLaw.hpp/cpp files to avoid adding things at the big Cylinder.cpp file.
The new class is the same as Law2_CylScGeom_FrictPhys_CundallStrack, I just changed the names and the beginning by that :

CylScGeom6D* geom = static_cast<CylScGeom6D*>(ig.get());
CohFrictPhys* phys = static_cast<CohFrictPhys*>(ip.get());

And the hpp declaration is like the CohesiveFrictionalContactLaw one (just changing the names).

Unfortunately scons gave this error :

/usr/include/boost/smart_ptr/shared_ptr.hpp: In constructor 'boost::shared_ptr< <template-parameter-1-1> >::shared_ptr(const boost::shared_ptr<Y>&, boost::detail::dynamic_cast_tag) [with Y = IGeom, T = CylScGeom6D]':
/usr/include/boost/smart_ptr/shared_ptr.hpp:522: instantiated from 'boost::shared_ptr<X> boost::dynamic_pointer_cast(const boost::shared_ptr<U>&) [with T = CylScGeom6D, U = IGeom]'
/home/francoisk/build-trunk/include/yade/pkg/dem/CohesiveFrictionalContactLaw.hpp:81: instantiated from here
/usr/include/boost/smart_ptr/shared_ptr.hpp:259: error: cannot dynamic_cast 'r->boost::shared_ptr<IGeom>::px' (of type 'class IGeom* const') to type 'struct CylScGeom6D*' (target is not pointer or reference to complete type)

Where CohesiveFrictionalContactLaw.hpp:81 is : FUNCTOR2D(CylScGeom6D,CohFrictPhys);

I checked the YADE_PLUGIN, FUNCTOR2D, YADE_CLASS_BASE_DOC_ATTRS and REGISTER_SERIALIZABLE stuffs.

Do you know why I have this error, and maybe how can I solve it ?

Tx

> I created the Law2_CylScGeom6D_CohFrictPhys_CohesionMoment class, child of LawFunctor. I have done that in the CohesiveFrictionalContactLaw.hpp/cpp files to avoid adding things at the big Cylinder.cpp file.
> The new class is the same as Law2_CylScGeom_FrictPhys_CundallStrack, I just changed the names and the beginning by that :
>
> CylScGeom6D* geom = static_cast<CylScGeom6D*>(ig.get());
> CohFrictPhys* phys = static_cast<CohFrictPhys*>(ip.get());
All right.
> And the hpp declaration is like the CohesiveFrictionalContactLaw one
> (just changing the names).
>
>
> Unfortunately scons gave this error :
>
> /usr/include/boost/smart_ptr/shared_ptr.hpp: In constructor 'boost::shared_ptr< <template-parameter-1-1> >::shared_ptr(const boost::shared_ptr<Y>&, boost::detail::dynamic_cast_tag) [with Y = IGeom, T = CylScGeom6D]':
> /usr/include/boost/smart_ptr/shared_ptr.hpp:522: instantiated from 'boost::shared_ptr<X> boost::dynamic_pointer_cast(const boost::shared_ptr<U>&) [with T = CylScGeom6D, U = IGeom]'
> /home/francoisk/build-trunk/include/yade/pkg/dem/CohesiveFrictionalContactLaw.hpp:81: instantiated from here
> /usr/include/boost/smart_ptr/shared_ptr.hpp:259: error: cannot dynamic_cast 'r->boost::shared_ptr<IGeom>::px' (of type 'class IGeom* const') to type 'struct CylScGeom6D*' (target is not pointer or reference to complete type)
Is this the full output?

Random ideas:
- Did you forget to define a virtual by any chance? Like this in
Cylinder.cpp : CylScGeom::~CylScGeom(){}
- Why IGeom is seen as a "class" while CylScGeom6D is seen as "struct"?
- Ho wait... aren't you just trying to cast a const to not-const?

It is difficult to guess without seeing the code.

B

Ok, I think I found the answer (note that CylScGeom6D is defined in Cylinder.hpp) : I imported Cylinder.hpp in CohesiveFrictionalContactLaw.cpp instead of .hpp file. I remember I made this because I obtained a dependency cycle error, which I by-pass with :

#ifndef ScGeom6D
#include<yade/pkg/common/Cylinder.hpp>
#endif

(I never known I it really works ...)
Now I import Cylinder.hpp in the CohesiveFrictionalContactLaw.hpp file, but I get this dependency cycle error :

(...)
cp -f py/ymport.py lib/yade-trunk/py/yade/ymport.py
scons: done building targets.

scons: *** Found dependency cycle(s):
  lib/yade-trunk/plugins/libCylinder.so -> /home/francoisk/build-trunk/libplugins.so -> lib/yade-trunk/plugins/libplugins.so -> /home/francoisk/build-trunk/libCylinder.so -> lib/yade-trunk/plugins/libCylinder.so
  /home/francoisk/build-trunk/libplugins.so -> lib/yade-trunk/plugins/libplugins.so -> /home/francoisk/build-trunk/libCylinder.so -> lib/yade-trunk/plugins/libCylinder.so -> /home/francoisk/build-trunk/libplugins.so
  lib/yade-trunk/plugins/libplugins.so -> /home/francoisk/build-trunk/libCylinder.so -> lib/yade-trunk/plugins/libCylinder.so -> /home/francoisk/build-trunk/libplugins.so -> lib/yade-trunk/plugins/libplugins.so
  Internal Error: no cycle found for node lib/yade-trunk/plugins (<SCons.Node.FS.Dir instance at 0x3c07e60>) in state pending
  Internal Error: no cycle found for node lib/yade-trunk/py (<SCons.Node.FS.Dir instance at 0x4844908>) in state pending

File "/usr/lib/scons/SCons/Taskmaster.py", line 1024, in cleanup
(end)

How can I get rid of that ?

Tx

Hum ...
Please don't think about this dependency cycle's question for the moment.
I think I made some big mistakes with Kdevelop. I will check all this afternoon, and inform you later.

> Hum ...
> Please don't think about this dependency cycle's question for the moment.
Good to hear, because I was puzzled. ;-)

I checked all, and now I have exactly the same error.
If I include Cylinder.hpp in FrictionalCohesionMoment.hpp, I have the Cycle Dependence error.
If I don't include it or include it in FrictionalCohesionMoment.cpp, I have the cast error (think it's normal, because in this case it doesn't know the CylScGeom6D class).
Viewing the error message, the include cycle is between libplugins.so and libCylinder.so. I have no idea of what this mean.
If you want my code I can send it, I just modified Cylinder.hpp/cpp and FrictionalCohesionMoment.hpp/cpp.

Jan just reported a similar problem, this is strange.
Send me your files, I'll try them with bzr2852 (my last update).

Bruno

It compiles without problems here. I guess some temporary scons build
files are messed up. Try scons --clean and recompile everything.
Considering including the files you modify frequently in hotPlugins
(scons -h).

Oups, I forgot uncommenting some lines. I commented them to compile yade and performing some tests.

Can you try to uncomment the Cylinder importation in CohesiveFrictionalContactLaw.cpp (line 15) and recompile ?

Thanks

Please send files that are supposed to compile.
I uncommented line 15, then I got to uncomment many other lines, but
still "error: 'CylScGeom6D' was not declared in this scope".

I don't understand the reason why you still have this error, but I compiled from nothing this morning. That's what I've done :
- deleted yade-trunk directory
- downloaded the last yade version from here : https://www.yade-dem.org/source/
- extracted yade in my home
- replaced 4 original files by this ones : http://download.grenoble.cemagref.fr/nuivr4exf (in yade/pkg/dem and yade/pkg/common). Now you don't have to uncomment anything.
- copied the scons.profile-default file in yade/ (see the .zip file)
- gone to yade folder and write just scons.
- waited a few minutes -> dependency cycle error

Now if I comment the importation of Cylinder.hpp in CohesiveFrictionalContactLaw.hpp (not cpp) the compilation works good.
I apologies for not having been very understandable yesterday.

Tx

I have the same error now.
It is an internal scons bug it seems, and it happens after the full build.
I'm still curious, but practically you can ignore the message and run
yade normally.

Ok. The problem is that the compilation goes until the end but when I launch Yade I got this error :

Welcome to Yade unknown
Traceback (most recent call last):
  File "/home/francoisk/yade/bin/yade-trunk", line 118, in <module>
    import yade
  File "/home/francoisk/yade//lib/yade-trunk/py/yade/__init__.py", line 59, in <module>
    boot.initialize(plugins,config.confDir)
ImportError: No module named wrapper

The "solution" : I put the Law2 directly in Cylinder.cpp/hpp like you did for the other cylinder's laws. Now the compilation is OK. I'm working on the law algorithm now, maybe I will have some new questions later.

Thanks a lot :-)

Hi

I'm now creating the new Law2 : Law2_CylScGeom6D_CohFrictPhys_CohesionMoment.
For the moment I just copied the Law2_CylScGeom_FrictPhys_CundallStrack one, just changing the 2 lines in the go method :

CylScGeom6D* geom= static_cast<CylScGeom6D*>(ig.get());
CohFrictPhys* phys = static_cast<CohFrictPhys*>(ip.get());

I declared this class and method just like Law2_CylScGeom_FrictPhys_CundallStrack in the Cylinder.hpp, cpp (and I didn't forgot the FUNCTOR2D(CylScGeom6D,CohFrictPhys)).

I added some cout<<"test"<<endl; lines to see if the go method is used, and it appears that even if the contact is a CylScgeom6D - CohFrictPhys one, it's the Law2_CylScGeom_FrictPhys_CundallStrack::go method who is used. (I turned the setCohesionOnNewContacts option to True.)

Isn't it weird ?

Here you can see my simple python script and the Cylinder.cpp/hpp files : http://download.grenoble.cemagref.fr/a3ina

Think I understood.
CylScGeom6D is a child of CylScGeom. I was happy because it was a way not to re-write the Ig2_Sphere_ChainedCylinder_CylScGeom::go method (see message #9).
But this method creates a CylScGeom geometry, not a CylScGeom6D => the corresponding Law2 is used.

... I begin to understand how it works.

Hi,

I have a new segmentation error now ... It happens when the cohfrictmat sphere touches the cohfrictmat cylinder. The debug mode gave this assertion error :

python: /home/francoisk/yade/pkg/common/InteractionLoop.cpp :147 : virtual void InteractionLoop::action(): L'assertion « I->phys » a échoué.
(...)
#7 0x00007f90ba720941 in *__GI___assert_fail (assertion=0x7f90a53e6316 "I->phys", file=<value optimized out>, line=146, function=0x7f90a53e6240 "virtual void InteractionLoop::action()") at assert.c:81

This error should only appears when the physics of a contact doesn't exist, isn't it ?

So I looked in Ip2_CohFrictMat_CohFrictMat_CohFrictPhys class, and I've seen that a cast is made :

ScGeom6D* geom = YADE_CAST<ScGeom6D*>(interaction->geom.get());

I think the geometry that I use (CylScGeom6D) enters in conflict with that so the physic of the contact is never initialized.

Do you have an idea for solving this ?

I notice that :
- I can't include Cylinder.hpp in Ip2_CohFrictMat_CohFrictMat_CohFrictPhys.cpp because of the same dependency cycle error as below.
- I think I can't re-write an Ip2_CohFrictMat_CohFrictMat_CohFrictPhys class specially for cylinders because the functor linking two CohFrictMat will be doubled.

Thanks

Ok I found a solution, CylScGeom6D is a child of ScGeom6D directly, so the physic is the right one to apply the Law2.