Writing new Ip2 functor / order of contact partners

Asked by Bettina Suhr on 2021-05-19

Dear all,

Currently, I try to write a new Ip2 functor and after some trouble I have a general question on the order of two contacting particles in the interaction class.

Say I have:
spheres with myMaterial
pfacets with FrictMat
facets with FrictMat

In my engine I have the following:
InteractionLoop(
[Ig2_Sphere_PFacet_ScGridCoGeom(),
Ig2_Facet_Sphere_ScGeom(),],
[Ip2_FrictMat_myMaterial_myPhysics()],
[Law2_ ScGridCoGeom _myPhysics_someLaw(),
Law2_ ScGeom _myPhysics_someOtherLaw()]
)

In this example, I have only one Ip2 functor, which should handle contacts between spheres/pfacets and facets/spheres.
The Ip2_FrictMat_myMaterial_myPhysics functor is passed two pointers b1, b2 to the material of the two contact partners. In my case, these materials are different.

Is the order of the contact partners determined by the Ig2 functor?

With some debugging, it seems that for sphere/pfacet contacts, b1 points to myMaterial and b2 to FrictMat. In contrast, for facet/sphere contacts, b1 points to FrictMat and b2 to myMaterial.

As the materials have different types of parameters, this is a problem for me.
Do you have any suggestions how I can solve this? Can I check the class to which b1, b2 are pointing?
I tried coding additionally an Ip2_myMaterial_FrictMat_myPhysics functor, but this isn’t chosen for sphere/pfacet contacts, instead the old Ip2_FrictMat_myMaterial_myPhysics functor is used.

Any help would be appreciated.

Best regards,
Bettina

Question information

Language:
English Edit question
Status:
Solved
For:
Yade Edit question
Assignee:
No assignee Edit question
Solved by:
Jan Stránský
Solved:
Last query:
Last reply:
Revision history for this message
Vasileios Angelidakis (vsangelidakis) said :
#1

Hi Bettina,

The order of contact partners is determined inside the Ig2 functors using:

FUNCTOR2D(Shape1,Shape2);
DEFINE_FUNCTOR_ORDER_2D(Shape1,Shape2);

as in [1]. Your example also shows the same behaviour.

Currently this DEFINE_FUNCTOR_ORDER_2D is not used in any other Ip2 functors, but it could be worthwhile trying: DEFINE_FUNCTOR_ORDER_2D(FrictMat,myMaterial) when defining your Ip2_FrictMat_myMaterial_myPhysics class in its header file. More info on DEFINE_FUNCTOR_ORDER_2D in [2,3].

Hope this helps,

Vasileios

[1] https://gitlab.com/yade-dev/trunk/-/blob/master/pkg/dem/Ig2_Facet_Sphere_ScGeom.hpp#L43-44
[2] https://gitlab.com/yade-dev/trunk/-/blob/master/lib/multimethods/FunctorWrapper.hpp
[3] https://gitlab.com/yade-dev/trunk/-/blob/master/lib/multimethods/DynLibDispatcher.hpp

Revision history for this message
Bettina Suhr (bettina-suhr) said :
#2

Hi Vasileios,

Thank you for the explanation, now I understand better why I have this problem.

Your suggestion to use the DEFINE_FUNCTOR_ORDER_2D sounded like an elegant solution, unfortunately it doesn’t work. The behaviour remains unchanged, even when I put the DEFINE_FUNCTOR_ORDER_2D(FrictMat,myMaterial) command.

Any other Idea how I could solve this problem?

Can I check to which class b1, b2 are pointing?

Best regards,
Bettina

Revision history for this message
Best Jan Stránský (honzik) said :
#3

Hello,

to test the specific instance, you can dynamic_cast the pointer and test if the cast was successful or not, something like:

/////
Ip2_FrictMat_myMaterial_myPhysics :: go(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction) {
   MyMaterial myMatTest* = dynamic_cast<MyMaterial*>(b2.get());
   if (!myMatTest) { // b2 is not MyMaterial instance
      std::swap(b1,b2);
   }
   /// now b1 is FrictMat and b2 is MyMaterial
   ...
}
/////

A (non-Yade) illustration MWE:
////// g++ test.cpp -o test && ./test
#include<iostream>
#include<memory>
class Base { public: virtual ~Base(){} };
class Derived1 : public Base {};
class Derived2 : public Base {};
int main() {
   std::shared_ptr<Base> b1(new Derived1());
   std::shared_ptr<Base> b2(new Derived2());
   //
   Base* base1 = dynamic_cast<Base*>(b1.get());
   if (base1) std::cout << "base1 is Base\n";
   else std::cout << "base1 is NOT Base\n";
   //
   Base* base2 = dynamic_cast<Base*>(b2.get());
   if (base2) std::cout << "base2 is Base\n";
   else std::cout << "base2 is NOT Base\n";
   //
   Derived1* d11 = dynamic_cast<Derived1*>(b1.get());
   if (d11) std::cout << "b1 is Derived1\n";
   else std::cout << "b1 is NOT Derived1\n";
   //
   Derived2* d21 = dynamic_cast<Derived2*>(b1.get());
   if (d21) std::cout << "b1 is Derived2\n";
   else std::cout << "b1 is NOT Derived2\n";
   //
   //
   Derived1* d12 = dynamic_cast<Derived1*>(b2.get());
   if (d12) std::cout << "b1 is Derived1\n";
   else std::cout << "b1 is NOT Derived1\n";
   //
   Derived2* d22 = dynamic_cast<Derived2*>(b2.get());
   if (d22) std::cout << "b2 is Derived2\n";
   else std::cout << "b2 is NOT Derived2\n";
   return 0;
}
//////

Cheers
Jan

Revision history for this message
Bettina Suhr (bettina-suhr) said :
#4

Thank you, Jan! The dynamic cast works really fine.
The std::swap caused a compilation error, but it was easy to avoid the swap command, after knowing which pointer is which one.

Best regards,
Bettina

Revision history for this message
Bettina Suhr (bettina-suhr) said :
#5

Thanks Jan Stránský, that solved my question.