Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/******************************************************************************
/******************************************************************************
* SOFA, Simulation Open-Framework Architecture *
* (c) 2021 INRIA, USTL, UJF, CNRS, MGH *
* *
Expand Down
12 changes: 12 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,17 @@ py::object getForceField(Node *self, unsigned int index)
}



py::object getLinearSolver(Node *self, unsigned int index)
{
auto* ls = self->linearSolver.get(index);
if (ls) {
return PythonFactory::toPython(sofa::core::castToBase(ls));
}
return py::none();
}


py::object getMechanicalState(Node *self)
{
sofa::core::behavior::BaseMechanicalState* state = self->mechanicalState.get();
Expand Down Expand Up @@ -721,6 +732,7 @@ void moduleAddNode(py::module &m) {
p.def("getMass", &getMass, sofapython3::doc::sofa::core::Node::getMass);
p.def("hasODESolver", &hasODESolver, sofapython3::doc::sofa::core::Node::hasODESolver);
p.def("getForceField", &getForceField, sofapython3::doc::sofa::core::Node::getForceField);
p.def("getLinearSolver", &getLinearSolver, sofapython3::doc::sofa::core::Node::getLinearSolver);
p.def("getMechanicalState", &getMechanicalState, sofapython3::doc::sofa::core::Node::getMechanicalState);
p.def("getMechanicalMapping", &getMechanicalMapping, sofapython3::doc::sofa::core::Node::getMechanicalMapping);
p.def("sendEvent", &sendEvent, sofapython3::doc::sofa::core::Node::sendEvent);
Expand Down
7 changes: 7 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,13 @@ static auto getForceField =
:type index: unsigned int.
)";

static auto getLinearSolver =
R"(
Get the linear solver of a node, given an index.
:param index: index of the linear solver
:type index: unsigned int.
)";

static auto getMechanicalState =
R"(
Get the mechanical state of the node.
Expand Down
4 changes: 2 additions & 2 deletions examples/stlib/PrefabScene_beginner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from stlib.materials.deformable import Deformable
from stlib.geometries.cube import CubeParameters
from stlib.geometries.file import FileParameters
from splib.simulation.headers import setupLagrangianCollision
from splib.simulation.headers import setupLagrangianHeader
from splib.simulation.linear_solvers import addLinearSolver
from splib.simulation.ode_solvers import addImplicitODE

Expand All @@ -15,7 +15,7 @@ def addSolvers(root):
def createScene(root):
root.gravity = [0, 0, -9.81]

setupLagrangianCollision(root)
setupLagrangianHeader(root)
addSolvers(root)

rigidParams = Rigid.getParameters()
Expand Down
8 changes: 3 additions & 5 deletions examples/stlib/SofaScene.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from fontTools.afmLib import preferredAttributeOrder

from stlib.geometries.plane import PlaneParameters
from stlib.geometries.file import FileParameters
from stlib.geometries.extract import ExtractParameters
Expand All @@ -8,7 +6,7 @@
from stlib.entities import Entity, EntityParameters
from stlib.visual import Visual, VisualParameters
from splib.core.enum_types import CollisionPrimitive, ElementType, ConstitutiveLaw
from splib.simulation.headers import setupLagrangianCollision, setupDefaultHeader
from splib.simulation.headers import setupLagrangianHeader, setupDefaultHeader
from splib.simulation.ode_solvers import addImplicitODE
from splib.simulation.linear_solvers import addLinearSolver
import dataclasses
Expand All @@ -20,7 +18,7 @@ def createScene(root):
##Solvers
# setupDefaultHeader(root, displayFlags = "showVisualModels",backgroundColor=[0.8, 0.8, 0.8, 1],
# parallelComputing = True)
setupLagrangianCollision(root, displayFlags = "showVisualModels",backgroundColor=[0.8, 0.8, 0.8, 1],
setupLagrangianHeader(root, displayFlags = "showVisualModels",backgroundColor=[0.8, 0.8, 0.8, 1],
parallelComputing = True,alarmDistance=0.3, contactDistance=0.02,
frictionCoef=0.5, tolerance=1.0e-4, maxIterations=20)
##Environement
Expand Down Expand Up @@ -99,7 +97,7 @@ def createScene(root):
SParams.material.parameters = [200, 0.45]

def SAddMaterial(node):
DeformableBehaviorParameters.addDeformableMaterial(node)
DeformableBehaviorParameters.addMaterial(node)
#TODO deal with that is a more smooth way in the material directly
node.addObject("LinearSolverConstraintCorrection", name="ConstraintCorrection", linearSolver=SNode.LinearSolver.linkpath, ODESolver=SNode.ODESolver.linkpath)

Expand Down
99 changes: 99 additions & 0 deletions examples/stlib/node_modifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from stlib.geometries.plane import PlaneParameters
from stlib.geometries.file import FileParameters
from stlib.geometries.extract import ExtractParameters
from stlib.materials.deformable import DeformableBehaviorParameters
from stlib.collision import Collision, CollisionParameters
from stlib.entities import Entity, EntityParameters
from stlib.visual import Visual, VisualParameters
from splib.core.enum_types import CollisionPrimitive, ElementType, ConstitutiveLaw
from splib.simulation.headers import setupLagrangianHeader, setupDefaultHeader
from splib.simulation.ode_solvers import addImplicitODE
from splib.simulation.linear_solvers import addLinearSolver
import dataclasses
import numpy as np


from stlib.node_modifiers import NodeModifier
from stlib.node_modifiers.footers import SimulationSolversParameters, SimulationSettingsParameters
from stlib.node_modifiers.attachments import FixConstraintParameters, AttachmentConstraintParameters

def createScene(root):
root.gravity=[0,0,9.81]
root.dt=0.01

##Environement
plane1_collisionParams = CollisionParameters()
plane1_collisionParams.name = "UP"
plane1_collisionParams.primitives = [CollisionPrimitive.TRIANGLES]
plane1_collisionParams.kwargs = {"TriangleCollision" : {"moving" : False, "simulated" : False}}
plane1_collisionParams.geometry = PlaneParameters(center=np.array([15,0,5]),
normal=np.array([0,0,-1]),
lengthNormal=np.array([0, 1, 0]),
lengthNbEdge=1,
widthNbEdge=2,
lengthSize=30,
widthSize=70)
plane1 = root.add(Collision, parameters = plane1_collisionParams)
# TODO being able to reuse already loaded geometry of current prefab to add any new sub prefab
# We need to enable to directly pass a link to an already existing prefab in place of a prefab parameter object
plane1_visu = plane1.addChild("Visu")
plane1_visu.addObject("OglModel", name="VisualModel", src="@../Geometry/container")


### Logo
ModelsNode = root.addChild("ModelsNode")

LogoParams = EntityParameters(name = "Logo1",
geometry = FileParameters(filename="mesh/SofaScene/Logo.vtk"),
material = DeformableBehaviorParameters(),
collision = CollisionParameters(geometry = FileParameters(filename="mesh/SofaScene/LogoColli.sph")),
visual = VisualParameters(geometry = FileParameters(filename="mesh/SofaScene/LogoVisu.obj")))

LogoParams.geometry.elementType = ElementType.TETRAHEDRA
LogoParams.material.constitutiveLawType = ConstitutiveLaw.ELASTIC
LogoParams.material.parameters = [200, 0.4]
LogoParams.material.massDensity = 0.003261
LogoParams.collision.primitives = [CollisionPrimitive.SPHERES]
#TODO make this flawless with spheres. Here collisions elements are not in the topology and a link is to be made between the loader and the collision object
LogoParams.collision.kwargs = {"SphereCollision" : {"radius" : "@Geometry/loader.listRadius"}}
LogoParams.visual.color = [0.7, .35, 0, 0.8]

Logo = ModelsNode.add(Entity, parameters = LogoParams)



### S
SParams = EntityParameters()
SParams.name = "S"
SParams.geometry = FileParameters(filename="mesh/SofaScene/S.vtk")
SParams.geometry.elementType = ElementType.TETRAHEDRA
SParams.material = DeformableBehaviorParameters()
SParams.material.constitutiveLawType = ConstitutiveLaw.ELASTIC
SParams.material.parameters = [200, 0.45]
SParams.material.massDensity = 0.011021
SParams.collision = CollisionParameters()
SParams.collision.primitives = [CollisionPrimitive.TRIANGLES]
# # #TODO: to fix link issues for extracted geometry, it might be better to give source geometry relative link + parameters
## TODO: not working with static container because the init order is always wrong so that the triangle vector is always empty when initializing the container
SParams.collision.geometry = ExtractParameters(destinationType=ElementType.TRIANGLES, sourceParameters=SParams.geometry)
SParams.visual = VisualParameters()
SParams.visual.geometry = FileParameters(filename="mesh/SofaScene/SVisu.obj")
SParams.visual.color = [0.7, .7, 0.7, 0.8]

S = ModelsNode.add(Entity, parameters = SParams)

#TODO make the name automatically match the modifier type if none is given
root.add(NodeModifier, on = [ModelsNode], parameters = SimulationSolversParameters(constantSparsity=False))

root.add(NodeModifier, on = [root], parameters = SimulationSettingsParameters(displayFlags = ["showVisualModels", "showInteractionForceFields"],
enableCollisionDetection = True,
useLagrangian = True,
parallelComputing = False,
alarmDistance=0.3, contactDistance=0.02,
frictionCoef=0.5, tolerance=1.0e-4, maxIterations=20))

Logo.add(NodeModifier, on = [Logo], parameters = FixConstraintParameters( boxROIs=[[-1, -2, -13, 3, 2, -7]]))
Logo.add(NodeModifier, on = [Logo], parameters = FixConstraintParameters( boxROIs=[[-100, -2, -13, -300, 2, -7]]))
ModelsNode.add(NodeModifier, on = [S, Logo], parameters = AttachmentConstraintParameters(name = "AttachmentConstraintParameters", indices1=[26,20,119,121], indices2=[722,732,574,573], stiffness=0.5, damping=0.0,
length=[((9.43-9.35)**2 + (-.44-0.48)**2 + (-6.01+6.56)**2)**(0.5) ]))

4 changes: 2 additions & 2 deletions splib/Testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from splib.simulation.linear_solvers import *
from splib.mechanics.linear_elasticity import *
Comment thread
bakpaul marked this conversation as resolved.
from splib.mechanics.mass import *
from splib.mechanics.fix_points import *
from splib.mechanics.attachment import *
from splib.topology.loader import *
from splib.core.node_wrapper import *

Expand All @@ -16,7 +16,7 @@ def createScene(rootNode):
rootNode.dt = 0.03
rootNode.gravity = [0,-9.81,0]

setupLagrangianCollision(rootNode,requiredPlugins={"pluginName":['Sofa.Component.Constraint.Projective',
setupLagrangianHeader(rootNode,requiredPlugins={"pluginName":['Sofa.Component.Constraint.Projective',
'Sofa.Component.Engine.Select',
'Sofa.Component.LinearSolver.Direct',
'Sofa.Component.Mass',
Expand Down
2 changes: 1 addition & 1 deletion splib/mechanics/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__all__ = ["linear_elasticity","hyperelasticity","fix_points","collision_model","mass"]
__all__ = ["linear_elasticity","hyperelasticity","attachment","collision_model","mass"]
18 changes: 18 additions & 0 deletions splib/mechanics/fix_points.py → splib/mechanics/attachment.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,21 @@ def addFixation(node,type:ConstraintType,boxROIs=DEFAULT_VALUE, sphereROIs=DEFAU
case _:
print('Contraint type is either ConstraintType.PROJECTIVE, ConstraintType.WEAK or ConstraintType.LAGRANGIAN')
return



@ReusableMethod
def attachObjects(node, type:ConstraintType, object1, object2, indices1, indices2, stiffness=DEFAULT_VALUE, damping=DEFAULT_VALUE, lengths=DEFAULT_VALUE, **kwargs):
match type:
case ConstraintType.WEAK:
node.addObject("SpringForceField", name="attachment", object1=object1, object2=object2, indices1=indices1, indices2=indices2, stiffness=stiffness, damping=damping, lengths=lengths, **kwargs)
return
case ConstraintType.PROJECTIVE:
node.addObject("AttachProjectiveConstraint", name="attachment", object1=object1, object2=object2, indices1=indices1, indices2=indices2, **kwargs)
return
case ConstraintType.LAGRANGIAN:
node.addObject("BilateralLagrangianConstraint", name="attachment", object1=object1, object2=object2, first_point=indices1, second_point=indices2, **kwargs)
return
case _:
print('Contraint type is either ConstraintType.PROJECTIVE, ConstraintType.WEAK or ConstraintType.LAGRANGIAN')
return
33 changes: 18 additions & 15 deletions splib/simulation/headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def setupDefaultHeader(node, displayFlags = "showVisualModels", backgroundColor=


@ReusableMethod
def setupPenalityCollisionHeader(node, displayFlags = "showVisualModels",backgroundColor=[1,1,1,1], stick=False, parallelComputing=False, alarmDistance=DEFAULT_VALUE, contactDistance=DEFAULT_VALUE, **kwargs):
def setupPenalityHeader(node, displayFlags = "showVisualModels",backgroundColor=[1,1,1,1], stick=False, parallelComputing=False, alarmDistance=DEFAULT_VALUE, contactDistance=DEFAULT_VALUE, **kwargs):
node.addObject('VisualStyle', displayFlags=displayFlags)
node.addObject('BackgroundSetting', color=backgroundColor)

Expand Down Expand Up @@ -67,16 +67,16 @@ def setupPenalityCollisionHeader(node, displayFlags = "showVisualModels",backgr
node.addObject(parallelPrefix+'BVHNarrowPhase', name="narrowPhase", **kwargs)

if(stick):
node.addObject('CollisionResponse',name="ContactManager", response="BarycentricStickContact",**kwargs)
node.addObject('CollisionResponse',name="ContactManager", response="StickContactForceField",**kwargs)
else:
node.addObject('CollisionResponse',name="ContactManager", response="BarycentricPenalityContact",**kwargs)
node.addObject('CollisionResponse',name="ContactManager", response="PenalityContactForceField",**kwargs)
node.addObject('LocalMinDistance' ,name="Distance", alarmDistance=alarmDistance, contactDistance=contactDistance, **kwargs)

return node


@ReusableMethod
def setupLagrangianCollision(node, displayFlags = "showVisualModels",backgroundColor=[1,1,1,1], parallelComputing=False, stick=False, alarmDistance=DEFAULT_VALUE, contactDistance=DEFAULT_VALUE, frictionCoef=0.0, tolerance=0.0, maxIterations=100, **kwargs):
def setupLagrangianHeader(node, enableCollision = True, displayFlags = "showVisualModels",backgroundColor=[1,1,1,1], parallelComputing=False, stick=False, alarmDistance=DEFAULT_VALUE, contactDistance=DEFAULT_VALUE, frictionCoef=0.0, tolerance=0.0, maxIterations=100, **kwargs):
node.addObject('VisualStyle', displayFlags=displayFlags)
node.addObject('BackgroundSetting', color=backgroundColor)

Expand Down Expand Up @@ -107,21 +107,24 @@ def setupLagrangianCollision(node, displayFlags = "showVisualModels",background
if(parallelComputing):
parallelPrefix="Parallel"

node.addObject('CollisionPipeline', name="collisionPipeline",
**kwargs)
if enableCollision:
node.addObject('CollisionPipeline', name="collisionPipeline",
**kwargs)

node.addObject(parallelPrefix+'BruteForceBroadPhase', name="broadPhase",
**kwargs)
node.addObject(parallelPrefix+'BruteForceBroadPhase', name="broadPhase",
**kwargs)

node.addObject(parallelPrefix+'BVHNarrowPhase', name="narrowPhase",
**kwargs)
node.addObject(parallelPrefix+'BVHNarrowPhase', name="narrowPhase",
**kwargs)

if(stick):
node.addObject('CollisionResponse',name="ContactManager", response="StickContactConstraint", responseParams="tol="+str(tolerance),**kwargs)
else:
node.addObject('CollisionResponse',name="ContactManager", response="FrictionContactConstraint", responseParams="mu="+str(frictionCoef),**kwargs)

node.addObject('NewProximityIntersection' ,name="Distance", alarmDistance=alarmDistance, contactDistance=contactDistance, **kwargs)

if(stick):
node.addObject('CollisionResponse',name="ContactManager", response="StickContactConstraint", responseParams="tol="+str(tolerance),**kwargs)
else:
node.addObject('CollisionResponse',name="ContactManager", response="FrictionContactConstraint", responseParams="mu="+str(frictionCoef),**kwargs)

node.addObject('NewProximityIntersection' ,name="Distance", alarmDistance=alarmDistance, contactDistance=contactDistance, **kwargs)
node.addObject('BlockGaussSeidelConstraintSolver',name="ConstraintSolver", tolerance=tolerance, maxIterations=maxIterations, multithreading=parallelComputing,**kwargs)
node.addObject("ConstraintAttachButtonSetting")

Expand Down
Loading
Loading