22 January 2019 at 15 h 02 min #12856
There is a soft tissue on a surface. What property should I change so that the soft tissue won’t slip on the surface when I apply a force on it?
Zahra22 January 2019 at 16 h 53 min #12857
In SOFA, the simulation of friction between objects is based on the Coulomb friction cone: https://scaron.info/teaching/friction-cones.html
In order to take friction into account within your SOFA scene, you’ll have to use a collision response of type ‘FrictionContact’ and specify its friction coefficient ‘mu’. The value of ‘mu’ should be close to 1.0 to avoid your soft tissue to slip along the surface.
Here is the XML syntax:
<CollisionResponse response="FrictionContact" responseParams="mu=0.8"/>
And here is the Python syntax:
rootNode.createObject('CollisionResponse', response='FrictionContact', responseParams='mu=0.8')
Antonin.23 January 2019 at 11 h 07 min #12869
Thank you for your explanation. I tried your suggestion, but it didn’t work. Even when there is no force other than the gravity, the object is rotating on the surface.
For more clarity, I share my python script below. I would appreciate if you kindly have a look on it.
The input mesh and the python script:
Zahra25 January 2019 at 11 h 19 min #12904
Sorry for the late answer. I saw your python script and I understand why it does not work. In fact, I omitted to give you important details about FrictionContact:
FrictionContact only works when combined with the FreeMotionAnimationLoop component and not DefaultAnimationLoop. To clarify, the contacts are solved through a penalty function when you use DefaultAnimationLoop, whereas FreeMotionAnimationLoop is dedicated to solve the contacts through constraint resolutions.
Using FrictionContact means building what we call a Complementarity Problem (CP) which is basically a system of Lagrange constraints. However, it is necessary to explicitly specify a ConstraintSolver into your SOFA scene. The most common choice is the GenericConstraintSolver.
rootNode.createObject('GenericConstraintSolver', maxIt='10000', tolerance='1e-7')
To finish, the ConstraintSolver needs to know how to compute the constraint compliance matrix W of the colliding objects and how to apply the correction forces resulting from the constraint resolution. This operation is described by ConstraintCorrection components you have to place into your SOFA scene next to each of your MechanicalObjects. Often, we use UncoupledConstraintCorrection.
... Liver.createObject('UncoupledConstraintCorrection') ... surface_fine.createObject('UncoupledConstraintCorrection')
It exists some scene examples about FrictionContact in the folder ‘examples/Components/constraint’ from the SOFA source code. It could helps you.
Additionnally, you may read the SOFA documentation about Lagrange constraints in the case you want to go deeper into the subject : https://www.sofa-framework.org/community/doc/main-principles/constraints/lagrange-constraint/
By the way, CollisionResponse is actually an alias for DefaultContactManager, which can be confusing… Using one or another instanciates the exact same SOFA component 😉
Hope it helps.
Antonin.10 February 2019 at 14 h 17 min #13021
Thank you very much for your thorough reply. I also apologize for the delay in response as since then, I was out of the lab for a while.
I considered the points you have mentioned, I also checked out the examples in the SOFA source. However, it did n’t work again. I am wondering if I ignore any necessary component.
I appreciate if you have a look on my code:
The .gmsh file:
Thank you for your time, and best regards,
Zahra10 February 2019 at 19 h 16 min #13022
In your python file scene, you have to remove the DefaultContactManager at line 22. The component CollisionResponse at line 24 is its substitute.
Your soft tissue ‘surface_fine’ (node) must owns at least a collision model like TTriangleModel and a TriangularFEMForceField in order to take into account the weight of your object and its elastic properties. As your attempt, you could write:
surface_fine.createObject('TriangularFEMForceField', name='triangularFEMFF5', template='Vec3d', poissonRatio='0.3', youngModulus='60') surface_fine.createObject('TTriangleModel', name='tTriangleModel15', template='Vec3d')
In addition, your tissue must owns a MechanicalObject which will contains the positions and velocities associated to the degrees of freedom of your tissue’s triangular mesh. More importantly, it will contains the displacements resulting from the constraint corrections, that’s why it is required. Moreover, the force fields also act on MechanicalObjects, so your object can’t moves if it does not owns a MechanicalObject.
Of course, an UncoupledConstraintCorrection must be added to your soft tissue too.
Hope it helps 😉
Antonin.13 February 2019 at 11 h 53 min #13031
Thank you very much for your reply. Your way in explaining is very educative to me.
I have a question here. The reason for using “surface_fine” part in my code just is to extract the surface of the tissue, but I do not want it to have a real skin. If I add mechanicalObject, TriangularFEMForceField and TTriangleModel to the surface_fine node, it means that the tissue has a skin on it. If I do not add them, there wouldn’t be any friction, right? Is there any way I can solve this issue?
Zahra14 February 2019 at 15 h 36 min #13039
Thank you very much for your reply. Your way in explaining is very educative to me.
The reason for using “surface_fine” part in my code just is to extract the surface of the tissue, but I do not want it to have a real skin. If I add mechanicalObject, TriangularFEMForceField and TTriangleModel to the surface_fine node, it means that the tissue has a skin on it.
I think there is a misunderstanding out there. In physics simulation, it is important to differenciate:
- the collision detection stage which notifies the emerging interaction between the 2 objects and outputs inter-penetration information called collision response.
- the contact solving stage which uses the collision response as input in order to apply a motion correction to avoid inter-penetration while eventually considering another physical parameters like friction.
In SOFA, TTriangleModel is a component which is only used for the “narrow-phase” of the collision detection stage. The correction forces, which result from the contact solving stage (or constraint correction stage in our case), will be applied on the points of the mesh (which correspond to the degrees of freedom of your tissue) regardless of the kind of collision model(s) you use, in order to rectify the motion of the object. Using TTriangleModel, TPointModel or TLineModel will only have a slight impact on the collision response.
From this explanation, using the mentionned combinaison MechanicalObject, TriangularFEMForceField, and TTriangleModel does not means your object have a real skin. In this configuration, your tissue is a discretized surface like you wish. TTriangleModel does not add a shell around the surface if it is what you think. The same logic applies for the MechanicalObject, the latter will only contains information about the points belonging to the discretized surface. Besides, TTriangleFEMForceField manages the deformation of your object knowing its elements are triangles. The volume of the object and its internal forces are not considered unlike the use of tetraedra elements. So for me, using triangles like you do is completely appropriate to simulate your tissue surface. I don’t see any issue but maybe there is something I didn’t catch in your scenario.
If I do not add them, there wouldn’t be any friction, right? Is there any way I can solve this issue?
Actually, in SOFA, each point of your model have an associated friction coefficient. Fortunately, in your setup, all your individual coefficients are set on the same hard value (mu=0.9) which simplify the simulation. As I said above, the correction forces will be applied on the points of your mesh, even if your mesh is a no-closed mesh. So normally, friction will be considered in this configuration.
Hope it helps.
Antonin.10 March 2019 at 14 h 43 min #13191
Thank you so much for your explanation, and I again must apologize for this delay in responding. I will try your hints and give you the feedback as soon as possible.
Zahra17 April 2019 at 15 h 45 min #13415
I hope you are still willing to guide me, sorry I could hardly concentrate on the work.
I tried your hints, but I still doesn’t succeed. I guess the problem comes from the incorrect link for the position of the triangular mesh in the MechanicalObject component, but I don’t know how to set a correct linking. Would you please guide me through this?
You can find the modified python script in below:
Thank you in advance,
Zahra28 April 2019 at 18 h 35 min #1343530 April 2019 at 16 h 05 min #13444
I need to simulate the friction between a surface and a soft tissue so that the tissue won’t slip on the surface. For this purpose, @Antonin advised me to use the following components:
On the root node:
– CollisionResponse with mu close to 1 (I used mu=0.9)
He also suggested adding MechanicalObject not just in the liver node but also on the surface node, and adding the UncoupledConstraintCorrection component for each MechanicalObject. For the simulation, he mentioned that I should use TetrahedralCorotationalFEMForceField for the liver node and also TriangularFEMForceField for the surface node.
His suggestion resulted in this:
but it still doesn’t work. I guess the problem comes from the incorrect link for the position of the triangular mesh in the MechanicalObject component, but I don’t know how to set a correct linking.
Thanks for your help in advance,
Zahra4 May 2019 at 8 h 30 min #13457
Below you can find a working case.
But before I have some questions:
– there is no constraints in your scene (no collision, uni/bilateralconstraints), do you intend to add it later ? If no, the use of the GenericConstraintSolver is not required
– the TopologicalMapping does not handle a MechanicalObject in the child (triangular) node
#!/usr/bin/env python2 # -*- coding: utf-8 -*- """ Created on Wed Jan 23 13:13:55 2019 @author: zahra """ import Sofa def createScene(rootNode): rootNode.createObject('RequiredPlugin', name='SofaPython') rootNode.createObject('VisualStyle', displayFlags='showForceFields hideVisual') rootNode.createObject('DefaultPipeline', name='CollisionPipeline', verbose='0') rootNode.createObject('BruteForceDetection', name='N2') rootNode.createObject('FreeMotionAnimationLoop') rootNode.createObject('DefaultContactManager', response='FrictionContact', responseParams='mu=0.9') rootNode.createObject('DiscreteIntersection', name='discreteIntersection1') rootNode.createObject('GenericConstraintSolver', maxIt='10000', tolerance='1e-7') # rootNode/Liver Liver = rootNode.createChild('Liver') Liver.depend = 'topo dofs' Liver.createObject('EulerImplicitSolver', name='cg_odesolver', printLog='0') Liver.createObject('CGLinearSolver', threshold='1e-09', tolerance='1e-09', name='linear solver', iterations='25', template='GraphScattered') Liver.createObject('MeshGmshLoader', tetrahedraGroups=' -1 0 38144', name='loader', filename='mesh/livertetra7509.msh') Liver.createObject('TetrahedronSetTopologyContainer', email@example.com', firstname.lastname@example.org', email@example.com', name='topo', firstname.lastname@example.org') Liver.createObject('MechanicalObject', force='0 0 0', name='dofs', template='Vec3d', email@example.com', velocity='0 0 0', externalForce='0 0 0', restScale='1') Liver.createObject('UncoupledConstraintCorrection') Liver.createObject('TetrahedronSetGeometryAlgorithms', drawColorEdges='0.4 1 0.298039 1', showIndicesScale='0.01', name='GeomAlgo', showPointIndices='0', template='Vec3d') Liver.createObject('DiagonalMass', massDensity='1', name='computed using mass density', template='Vec3d') Liver.createObject('TetrahedralCorotationalFEMForceField', poissonRatio='0.4', name='FEM', computeGlobalMatrix='0', method='large', template='Vec3d', youngModulus='120') Liver.createObject('PlaneForceField', name='planeFF0', template='Vec3d', normal='0 1 0', stiffness='10000',draw='1', drawSize='8') Liver.createObject('ConstantForceField', indices='27', name='constantFF0', template='Vec3d', forces='0 0 0') Liver.createObject('TetrahedronSetTopologyModifier', name='tetrahedronSetTopologyModifier9') Liver.createObject('TetrahedronSetTopologyAlgorithms', name='tetrahedronSetTopologyAlgorithms10', template='Vec3d') # rootNode/Liver/surface_fine surface_fine = Liver.createChild('surface_fine') surface_fine.createObject('TriangleSetTopologyContainer', name='triangleSetTopologyContainer0') surface_fine.createObject('TriangleSetTopologyModifier', name='triangleSetTopologyModifier1') surface_fine.createObject('TriangleSetTopologyAlgorithms', name='triangleSetTopologyAlgorithms2', template='Vec3d') surface_fine.createObject('TriangleSetGeometryAlgorithms', name='triangleSetGeometryAlgorithms3', template='Vec3d') # surface_fine.createObject('MechanicalObject', force='0 0 0', name='dofs2', template='Vec3d', position='@./', velocity='0 0 0', externalForce='0 0 0', restScale='1') surface_fine.createObject('Tetra2TriangleTopologicalMapping', input='@../', name='tetra2TriangleTopologicalMapping4', output='@triangleSetTopologyContainer0') surface_fine.createObject('TriangularFEMForceField', name='triangularFEMFF5', template='Vec3d', poissonRatio='0.4', youngModulus='120') # surface_fine.createObject('TriangularBendingSprings', name='triangularBendingSprings6', template='Vec3d') surface_fine.createObject('TTriangleModel', name='tTriangleModel15', template='Vec3d') # surface_fine.createObject('TrianglePressureForceField', name='trianglePressureFF22', template='Vec3d') # surface_fine.createObject('UncoupledConstraintCorrection') # surface_fine.createObject('MeshExporter', exportEveryNumberOfSteps='0', quads='0', name='meshExporter0', format='gmsh', exportAtEnd='1', filename='L1s_sofa', exportAtBegin='0', tetras='0', hexas='0', edges='0', triangles='1', listening='0') # rootNode/Liver/surface_fine/visu_surface_fine visu_surface_fine = surface_fine.createChild('visu_surface_fine') visu_surface_fine.createObject('OglModel', sfactor='GL_SRC_ALPHA', blendEquation='GL_FUNC_ADD', name='oglModel18', template='ExtVec3d', dfactor='GL_ONE_MINUS_SRC_ALPHA', material='Default Diffuse 1 0.74902 0.74902 0.74902 1 Ambient 1 0.592157 0.2 0.2 1 Specular 0 1 1 1 1 Emissive 0 0 0 0 0 Shininess 0 45 ', primitiveType='DEFAULT') visu_surface_fine.createObject('IdentityMapping', input='@../', name='identityMap20', template='Vec3d,ExtVec3d', output='@./') Liver.createObject('ClipPlane', name='clipplane', normal='1 0 0') return 0;
Hugo6 May 2019 at 14 h 42 min #13460
Thank you very much for the working code.
Regarding using constraints, I’m not sure about it. If I use fixed constraints, should I need GenericConstraintSolver?
I also tried the documentation to understand if I may later need to use collision, uni/bilateralconstraints (as I am not familiar with their usage), but the documentation on those subjects is not complete yet.
As I’m not an expert in Mechanics, I am wondering if the above code is enough for simulating a resting tissue on a surface with a friction between them. I appreciate if you kindly guide me regarding that.
Zahra8 May 2019 at 18 h 48 min #13464
FixedConstraint are projective constraints and do not require a constraint resolution through Lagrange multipliers. Therefore, if it is the only constraint, you don’t need a FreeAnimationLoop, GenericConstraintSolver nor a ConstraintCorrection.
But I need to check if friction can still be computed this way.
Indeed, documentation is still missing on uni/bilateralconstraints (it’s almost the last pages to do!). I will work on it as soon as I can.
Hugo11 May 2019 at 17 h 34 min #13473
- You must be logged in to reply to this topic.