Has ProjectedGaussSeidelConstraintSolver and VisualVectorField been removed?
My version is v25.06, and I encountered an error in the example-forcefield.py file.
It's the opposite. Both mentioned components are new in the master branch. I guess your version of example-forcefield.py is newer than v25.06.
See the warning in https://sofa-framework.github.io/doc/plugins/build-a-plugin-from-sources/
sorry, the error regarding the title occurred in the file access_contact_forces.py. The error message is as follows:[SofaRuntime] ValueError: Object type ProjectedGaussSeidelConstraintSolver<> was not created The component 'ProjectedGaussSeidelConstraintSolver' cannot be found in the factory. But the following object(s) exist: : LCPConstraintSolver (61% match) : GenericConstraintSolver (61% match) : LineProjectiveConstraint (60% match) ,
I downloaded the latest version from the official website.
https://github.com/sofa-framework/SofaPython3/blob/master/examples/access_contact_forces.py
The change related to ProjectedGaussSeidelConstraintSolver is from 9 hours ago. You're not using v25.06, but the master branch.
I understand. Thank you. I have also made changes based on the master branch, and it works on my version now:
# Required import for python
import Sofa
import numpy as np
import math
# Main function taking a boolean as parameter to choose whether or not to use the GUI
def main(use_gui=True):
import SofaImGui
import Sofa.Gui
root = Sofa.Core.Node("root")
createScene(root)
Sofa.Simulation.initRoot(root)
if not use_gui:
import SofaQt
for iteration in range(10):
Sofa.Simulation.animate(root, root.dt.value)
else:
Sofa.Gui.GUIManager.Init("myscene", "imgui")
Sofa.Gui.GUIManager.createGUI(root, __file__)
Sofa.Gui.GUIManager.SetDimension(1080, 1080)
Sofa.Gui.GUIManager.MainLoop(root)
Sofa.Gui.GUIManager.closeGUI()
def createScene(root):
root.gravity=[0, -9.81, 0]
root.dt=0.02
root.addObject("RequiredPlugin", pluginName=[ 'Sofa.Component.Collision.Detection.Algorithm',
'Sofa.Component.Collision.Detection.Intersection', 'Sofa.Component.Collision.Geometry',
'Sofa.Component.Collision.Response.Contact', 'Sofa.Component.Constraint.Projective',
'Sofa.Component.IO.Mesh','Sofa.Component.LinearSolver.Iterative',
'Sofa.Component.Mapping.Linear', 'Sofa.Component.Mass', 'Sofa.Component.ODESolver.Backward',
'Sofa.Component.SolidMechanics.FEM.Elastic','Sofa.Component.StateContainer',
'Sofa.Component.Topology.Container.Dynamic','Sofa.Component.Visual',
'Sofa.GL.Component.Rendering3D','Sofa.Component.Constraint.Lagrangian.Correction',
'Sofa.Component.Constraint.Lagrangian.Solver', 'Sofa.Component.MechanicalLoad',
'Sofa.Component.LinearSolver.Direct','Sofa.Component.AnimationLoop'
])
root.addObject('FreeMotionAnimationLoop')
# Constraint solver computing the constraint/contact forces, stored in the constraint space (normal , tangential_1, tangential_2)
# Changed from ProjectedGaussSeidelConstraintSolver to GenericConstraintSolver
constraint_solver = root.addObject('GenericConstraintSolver', maxIterations=1000, tolerance=1e-6, computeConstraintForces=True)
root.addObject('VisualStyle', displayFlags="showCollisionModels hideVisualModels showForceFields")
root.addObject('CollisionPipeline', name="collision_pipeline")
root.addObject('BruteForceBroadPhase', name="broad_phase")
root.addObject('BVHNarrowPhase', name="narrow_phase")
root.addObject('DiscreteIntersection')
root.addObject('CollisionResponse', name="collision_response", response="FrictionContactConstraint", responseParams="mu=0.1")
root.addObject('MeshOBJLoader', name="load_liver_surface", filename="mesh/liver-smooth.obj")
liver = root.addChild('Liver')
liver.addObject('EulerImplicitSolver', name="cg_odesolver", rayleighStiffness=0.1, rayleighMass=0.1)
liver.addObject('SparseLDLSolver', name="linear_solver", template="CompressedRowSparseMatrixMat3x3d")
liver.addObject('MeshGmshLoader', name="loader_liver_volume", filename="mesh/liver.msh")
liver.addObject('TetrahedronSetTopologyContainer', name="topo", src="@loader_liver_volume")
# Liver MechanicalObject where the constraint/contact forces will be stored in the (x,y,z) coordinate system
liverMO = liver.addObject('MechanicalObject', name="dofs", src="@loader_liver_volume")
liver.addObject('TetrahedronSetGeometryAlgorithms', template="Vec3d", name="geom_algo")
liver.addObject('DiagonalMass', name="mass", massDensity=1.0)
liver.addObject('TetrahedralCorotationalFEMForceField', template="Vec3d", name="FEM", method="large", poissonRatio=0.3, youngModulus=3000, computeGlobalMatrix=False)
liver.addObject('FixedProjectiveConstraint', name="fixed_constraint", indices=[3,39,64])
liver.addObject('LinearSolverConstraintCorrection')
visu = liver.addChild('Visu')
visu.addObject('OglModel', name="visual_model", src="@../../load_liver_surface")
visu.addObject('BarycentricMapping', name="visual_mapping", input="@../dofs", output="@visual_model")
surf = liver.addChild('Surf')
surf.addObject('SphereLoader', name="loader_sphere_model", filename="mesh/liver.sph")
surf.addObject('MechanicalObject', name="spheres", position="@loader_sphere_model.position")
surf.addObject('SphereCollisionModel', name="collision_model", listRadius="@loader_sphere_model.listRadius")
surf.addObject('BarycentricMapping', name="collision_mapping", input="@../dofs", output="@spheres")
particle = root.addChild('Particle')
particle.addObject('EulerImplicitSolver')
particle.addObject('CGLinearSolver', threshold=1e-09, tolerance=1e-09, iterations=200)
# Particle MechanicalObject where the constraint/contact forces will be stored in the (x,y,z) coordinate system
particleMO = particle.addObject('MechanicalObject', showObject=True, position=[-2, 10, 0, 0, 0, 0, 1], name=f'particle_DoFs', template='Rigid3d')
particle.addObject('UniformMass', totalMass=1)
particle.addObject('ConstantForceField', name="CFF", totalForce=[0, -1, 0, 0, 0, 0] )
particle.addObject('SphereCollisionModel', name="SCM", radius=1.0 )
particle.addObject('UncoupledConstraintCorrection')
# Python controller accessing and displaying the contact forces in the ConstantForceField
root.addObject(AccessContactForces('AccessContactForces', name='AccessContactForces',
constraint_solver=constraint_solver,
soft_liver=liverMO,
root_node=root))
class AccessContactForces(Sofa.Core.Controller):
def __init__(self, *args, **kwargs):
Sofa.Core.Controller.__init__(self, *args, **kwargs)
self.constraint_solver = kwargs.get("constraint_solver")
self.soft_liver = kwargs.get("soft_liver")
self.root_node = kwargs.get("root_node")
def onAnimateEndEvent(self, event):
lambda_vector = self.constraint_solver.constraintForces.value
# If there is a contact
if(len(lambda_vector) > 0):
print(f"At time = {round(self.root_node.time.value,3)}, forces in the contact space (n, t1, t2) equals:\n {lambda_vector} ")
# Get the contact forces in the (x,y,z) coordinate system
contact_forces = self.soft_liver.getData("lambda").value
print(f" Contact forces in (x,y,z) coordinates:\n {-contact_forces}")
# If no contact
else:
pass
# Function used only if this script is called from a python environment
if __name__ == '__main__':
main(True)