Joint as Swig Object not opensim.Joint

Provide easy-to-use, extensible software for modeling, simulating, controlling, and analyzing the neuromusculoskeletal system.
POST REPLY
User avatar
Bryce Killen
Posts: 104
Joined: Mon Nov 24, 2014 7:12 pm

Joint as Swig Object not opensim.Joint

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:

User avatar
Dimitar Stanev
Posts: 1096
Joined: Fri Jan 31, 2014 5:14 am

Re: Joint as Swig Object not opensim.Joint

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.

User avatar
Bryce Killen
Posts: 104
Joined: Mon Nov 24, 2014 7:12 pm

Re: Joint as Swig Object not opensim.Joint

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

User avatar
Dimitar Stanev
Posts: 1096
Joined: Fri Jan 31, 2014 5:14 am

Re: Joint as Swig Object not opensim.Joint

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')


User avatar
jimmy d
Posts: 1375
Joined: Thu Oct 04, 2007 11:51 pm

Re: Joint as Swig Object not opensim.Joint

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.

User avatar
Bryce Killen
Posts: 104
Joined: Mon Nov 24, 2014 7:12 pm

Re: Joint as Swig Object not opensim.Joint

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

POST REPLY