Provide easy-to-use, extensible software for modeling, simulating, controlling, and analyzing the neuromusculoskeletal system.
-
Bryce Killen
- Posts: 104
- Joined: Mon Nov 24, 2014 7:12 pm
Post
by Bryce Killen » Wed Apr 17, 2019 8:39 pm
Hi All,
I am working with OpenSim 3.3 in Windows 10 with the Python API. I am trying to replicate a function I have in Matlab in Python. Where I am running in to trouble is when running the same function in Python, to return a joint associated with a body, it is returned as Swig Object rather than an opensim.Joint
Matlab Code:
Code: Select all
currModel = Model('dir/to/OpenSim/Model.osim')
bodySet = currModel.getBodySet()
femRBody = bodySet.get('femur_r')
femJ = femRBody.getJoint()
Python Code:
Code: Select all
currModel = osim.Model('dir/to/OpenSim/Model.osim')
bodySet = currModel.getBodySet()
femRBody = bodySet.get('femur_r')
femJ = femRBody.getJoint()
As mentioend above, in Maltab femJ is an opensim object but in python it is a swig object. I have tried using safeDownCast to return it as a a openims.Joint in Python but to no avail.
I have only been able to find the following forum post in regards to the same problem (
https://simtk.org/plugins/phpBB/viewto ... t=0&view= ), but with no solution posted.Note that for the problem I am trying to solve, I cannot simply pull the joint from the jointSet because I do not always know the name of the joint.
If anyone has any suggestions it would be greatly appreciated.
Best
Bryce
Tags:
-
Dimitar Stanev
- Posts: 1096
- Joined: Fri Jan 31, 2014 5:14 am
Post
by Dimitar Stanev » Thu Apr 18, 2019 10:42 am
When you get the joint from the body you have the following type returned:
Code: Select all
In [30]: model.getBodySet().get('femur_r').getJoint()
Out[31]: <Swig Object of type 'Joint *' at 0x7f59ca18f120>
which cannot be used to access the joint information. On the other hand if you get the joint from the joint set:
Code: Select all
[32]: model.getJointSet().get('hip_r')
Out[33]: <opensim.opensim.Joint; proxy of <Swig Object of type 'OpenSim::Joint *' at 0x7f59ca18f1b0> >
then you can access the data of the joint without any problem.
-
Bryce Killen
- Posts: 104
- Joined: Mon Nov 24, 2014 7:12 pm
Post
by Bryce Killen » Thu Apr 18, 2019 3:06 pm
Hi Dimitar,
Thanks for your reply. I understand that I can only use the functions associated with the type that is returned. I was just a bit perplexed as when doing it in MATLAB , I am returned a OpenSim Joint type object.
Is there anyway I can go from the Swig object -> OpenSim joint object.
Basically what I am trying to do is return the joints an MTU spans, and I am doign this by testing the bodies it crosses then going through the joint associated with the bodies and "working down the tree" until I get to the insertion body. This was previously implemented in matlab but I need to use it in python.
I currently have a big stack of hard coded "if" statements for a subset of the possible origin body and insertion body combinations, but of course if I move to a different model or changes are made, the body and joint lists may also change.
If I cannot get the Joint type returned from OpenSim like in Matlab, do you have any suggestions/ideas on how I could implement this without hard coding the possible combinations ?
Thanks again
Bryce
-
Dimitar Stanev
- Posts: 1096
- Joined: Fri Jan 31, 2014 5:14 am
Post
by Dimitar Stanev » Fri Apr 19, 2019 12:14 am
It seems that this issue is a limitation of v3.3. I suppose in 4.0 it should be resolved. You can do the following:
Code: Select all
currModel = osim.Model('dir/to/OpenSim/Model.osim')
bodySet = currModel.getBodySet()
femRBody = bodySet.get('femur_r')
femJ = femRBody.getJoint()
return currModel.getJointSet().get(femJ.getName())
I have done something similar (e.g., calculate the joints/coordinates that are spanned by each muscle) in order to derive a symbolic expression for the muscle moment arm:
Code: Select all
def find_intermediate_joints(origin_body, insertion_body, model_tree, joints):
"""Finds the intermediate joints between two bodies.
Parameters
----------
origin_body: string
first body in the model tree
insertion_body: string
last body in the branch
model_tree: list of dictionary relations {parent, joint, child}
joints: list of strings
intermediate joints
"""
if origin_body == insertion_body:
return True
children = filter(lambda x: x['parent'] == origin_body, model_tree)
for child in children:
found = find_intermediate_joints(child['child'], insertion_body,
model_tree, joints)
if found:
joints.append(child['joint'])
return True
return False
def calculate_spanning_muscle_coordinates(model_file, results_dir):
"""Calculates the coordinates that are spanned by each muscle. Useful for
reducing the required computation of the muscle moment arm matrix.
"""
model = opensim.Model(model_file)
state = model.initSystem()
# construct model tree (parent body - joint - child body)
model_tree = []
for i in range(0, model.getJointSet().getSize()):
joint = model.getJointSet().get(i)
model_tree.append({
'parent': joint.getParentName(),
'joint': joint.getName(),
'child': joint.getBody().getName()
})
ordered_body_set = []
for i in range(0, model.getBodySet().getSize()):
ordered_body_set.append(model.getBodySet().get(i).getName())
# get the coordinates that are spanned by the muscles
muscle_coordinates = {}
for i in range(0, model.getMuscles().getSize()):
muscle = model.getMuscles().get(i)
path = muscle.getGeometryPath().getPathPointSet()
muscle_bodies = []
for j in range(0, path.getSize()):
point = path.get(j)
muscle_bodies.append(point.getBodyName())
# remove duplicate bodies and sort by multibody tree order
muscle_bodies = list(set(muscle_bodies))
muscle_bodies = sorted(muscle_bodies,
key=lambda x: ordered_body_set.index(x))
# find intermediate joints
assert(len(muscle_bodies) > 1)
joints = []
find_intermediate_joints(muscle_bodies[0], muscle_bodies[-1],
model_tree, joints)
# find spanning coordinates
muscle_coordinates[muscle.getName()] = []
for joint in joints:
joint = model.getJointSet().get(joint)
for c in range(0, joint.get_CoordinateSet().getSize()):
coordinate = joint.get_CoordinateSet().get(c)
if coordinate.isDependent(state):
continue
muscle_coordinates[muscle.getName()].append(coordinate.getName())
# write results to file
with open(results_dir + 'muscle_coordinates.csv', 'w') as csv_file:
for key, values in muscle_coordinates.items():
csv_file.write(key)
for value in values:
csv_file.write(';' + value)
csv_file.write('\n')
-
jimmy d
- Posts: 1375
- Joined: Thu Oct 04, 2007 11:51 pm
Post
by jimmy d » Fri Apr 19, 2019 7:32 am
Dimitar is correct-- this is just a function of how the swig wrapping was built during the 3.3 build. The issue is likely that we wrapped Body before Joint for Python, so Body doesnt know anything about Joint. There isnt really a solution other than looping through the joints in the joint set.
-
Bryce Killen
- Posts: 104
- Joined: Mon Nov 24, 2014 7:12 pm
Post
by Bryce Killen » Mon Apr 22, 2019 3:54 am
HI guys,
James, thanks for the clarification
Dimitar, thanks for the information and the example code, I will have a look and see if I can implement something similar.
Thanks
Bryce