18 May 2018 at 10:51 #11060
I’m trying to get the position values of a certain point of a MechanicalObject at each timestep in a scene with Python in order to create a curve of the position vs the time. I found the example componentDataIO_write.py and componentDataIO_read.py but I did not find the explanation of the components used in the documentation.
Does anybody know how to get that value with Python ?
Thank’s for your help18 May 2018 at 17:49 #11062
thanks for your question!
I will answer you through an example. I wrote a scene and a Python script below doing what you expect.
First the scene is very basic and just call a Python script (which makes the scene initialization):
<Node name="root" dt="0.01" > <RequiredPlugin name='SofaPython'/> <PythonScriptController filename="pythonController.py" classname="PrintPosition" listening="1"/> </Node>
then the script creates the scene and access the data during the simulation:
# require sofa to run import Sofa # use os library to take the path to the mesh folder import os class PrintPosition(Sofa.PythonScriptController): #called once the script is loaded def createGraph(self,rootNode): self.rootNode = rootNode self.dotNode = rootNode.createChild('dot') self.dotNode.createObject('EulerImplicit', firstOrder='0', rayleighStiffness="0.2", rayleighMass="0.2") self.dotNode.createObject('CGLinearSolver', iterations='100', tolerance='1e-9', threshold='1e-9') self.dotNode.createObject('MeshVTKLoader', name='loader', filename='/data/Softwares/sofa/src/master/forum/zygote-demo/data/large-intestin.vtu') self.dotNode.createObject('TetrahedronSetTopologyContainer', src='@loader', name='container') self.dotNode.createObject('MechanicalObject', name='myMechanicalObject', template='Vec3d', showObject='1') self.dotNode.createObject('TetrahedronSetTopologyModifier') self.dotNode.createObject('TetrahedronSetTopologyAlgorithms', template='Vec3d') self.dotNode.createObject('TetrahedronSetGeometryAlgorithms', template='Vec3d') self.dotNode.createObject('UniformMass', totalmass='10') self.dotNode.createObject('TetrahedronFEMForceField', template='Vec3d', name='FEM', method='large', poissonRatio='3000', youngModulus='0.5e-3') self.dotNode.createObject('OglModel') # create pointer towards the MechanicalObject self.myMechanicalObjectPointer = self.dotNode.getObject('myMechanicalObject') return 0; #called on each animation step def onBeginAnimationStep(self, dt): #do whatever you want at the beginning of the step t = self.rootNode.findData('time').value return 0; #called on each animation step def onEndAnimationStep(self, dt): #access the 'position' state vector myMOpositions = self.myMechanicalObjectPointer.findData('position').value # print the first value of the DOF 0 (Vec3 : x,y,z) x y z print str(myMOpositions)+' '+str(myMOpositions)+' '+str(myMOpositions) return 0;
The important part of the script focus on the MechanicalObject (“myMechanicalObject”), you create a pointer towards it in the initGraph() function (“myMechanicalObjectPointer”).
Then, during the simulation (at the end of each step in the onEndAnimationStep() function), you can recover the values of your DOFs (here the position Vec3d of your object).
Note that you can also modify on the fly a data, e.g. modify the elasticity:
self.dotNode.getObject('FEM').findData('youngModulus').value = 0.2
Do this help you?18 May 2018 at 18:43 #11065
It’s perfect thank you ! I just have a last question about the point you can access. How can you find the label of the point ? I mean that I want to choose a specific point of the mesh, so how to proceed ? Do I have to look inside the mesh file and find the good line for the point and that’s the label I have to use in x here
Thank’s for you help !18 May 2018 at 18:48 #11066
This is indeed a solution.
Another solution is to sort the point that you want to track at the beginning of the simulation. Once you selected them and saved their IDs in the Python script you can read them in the same way.
Hugo23 May 2018 at 16:02 #1107923 May 2018 at 18:06 #11089
I just tried to implement the code you proposed and it’s working. I made a loop to find the point at the end of my shape (the point with the biggest x coordinate) before the beginning of the scene :
def bwdInitGraph(self,node): # find the position at the end of the shape (which has the biggest x coordinate) Positions = self.MechaNode.findData('position').value max = 0 for i in range(len(Positions)): if Positions[i] > max: self.pos = i max = Positions[i] print(self.pos) print(Positions[self.pos]) return 0
After that, I just displayed the value at each time step like that :
# called on each animation step (end) def onEndAnimationStep(self, dt): # access the 'position' state vector Positions = self.MechaNode.findData('position').value # print the value of the DOF self.pos (Vec3 : x,y,z) x for 0, y for 1, z for 2 print str(Positions[self.pos]) return 0
Thank’s for your help !21 October 2021 at 11:48 #20677
I would like to change the vertex positions on the fly from Python.
However, when I run
self.object.findData('position').value = 0.2
ValueError: assignment destination is read-only. I can read the value without any issues.
Has the API been changed? What should I do instead?
I would like to do it directly from Python because I want to have more control. Thus, no PartialLinearMovementConstraint or similar.
Thank you for your help!21 October 2021 at 16:23 #20679
I think I have figured it out:
with self.object.position.writeableArray() as wa: wa[0, 0] = 0.2
does what I want21 October 2021 at 16:23 #20680
It appears like I double posted my last answer. Sorry
- You must be logged in to reply to this topic.