Question on Spine Moment

Hello AnyBody community,

I am currently investigating the biomechanics of the spine and I am using AnyBody.8.0.x as well as AMMR4-Beta. The model that I am using is Plug-in-gait_MultiTrial_StandingRef with flexible thoracic model, incorporating simple muscles+ligaments+non linear disc+soft rhythm for all 3 spine region. They are driven by mocap data, reflecting ADL movements.

I am trying to programme 'NetMoment' calculation for each of the discretised vertebral level and I have been looking at the past forum posts on the topic particularly this. I am attracted to this method because all the relevant muscles in any particular intervertebral joint will be taken into account through #include MuscleList.any by the AnyForceMomentMeasure2 class and saves me from retyping all the muscles again for every level.

My question will be, if I am going to code the moment at L3/L4 level (using AnyForceMomentMeasure2), do I need to include all the segments from lower limbs (foot/talus/shank/patella/thigh/pelvis/sacrum/L5/L4/L3) or only from pelvis (sacrum/pelvis/L5/L4/L3) given there is already 'Hand of God' residual implemented at the pelvis?

Also, do I need to include the ribs if I am calculating the moment in thoracic level?

Thank you.

Kind regards,
Faizal

Hi Faizal,

I think the approach sounds correct. But it depends on what you want to include in "NetMoment". As an example, you can see how the moments for joints in the leg are calculated.

The post you referred to is an old post and I will recommend you use Object Pointers and search functions for including segments and force elements (muscles, ligaments, etc.) instead of writing muscles in a muscle list. First of all, using search function (ObjSearch, and so on), you will avoid typing the list of all the muscles. Secondly, this will also make your code a little bit more robust in case you change the body model configuration. You can search for different types of objects and then include them in a single list using arrcat.

I would suggest including the thighs so that you get the effect of psoas muscles.

Likewise, if you are using the flexible thorax, then it would make sense to include the ribs for moments in the thoracic level as some muscles attach to the ribs.

Best regards,
Dave

1 Like

Hi Dave,

Thank you for your reply.

I have coded 'NetMoment' for L3/L4 joint level as per your suggestions. It is as below.

AnyForceMomentMeasure2 NetMomentAtL3L4 = {
      AnyRefFrame &ref = Main.HumanModel.BodyModel.Trunk.Segments.L4Seg.L3L4JntNode.RotNode;
      IncludeSegments = {
        &Main.HumanModel.BodyModel.Right.Leg.Seg.Foot,
        &Main.HumanModel.BodyModel.Right.Leg.Seg.Talus,
        &Main.HumanModel.BodyModel.Right.Leg.Seg.Shank,
        &Main.HumanModel.BodyModel.Right.Leg.Seg.Patella,
        &Main.HumanModel.BodyModel.Right.Leg.Seg.Thigh,
        &Main.HumanModel.BodyModel.Left.Leg.Seg.Foot,
        &Main.HumanModel.BodyModel.Left.Leg.Seg.Talus,
        &Main.HumanModel.BodyModel.Left.Leg.Seg.Shank,
        &Main.HumanModel.BodyModel.Left.Leg.Seg.Patella,
        &Main.HumanModel.BodyModel.Left.Leg.Seg.Thigh,
        &Main.HumanModel.BodyModel.Trunk.Segments.SacrumSeg,
        &Main.HumanModel.BodyModel.Trunk.Segments.PelvisSeg,
        &Main.HumanModel.BodyModel.Trunk.Segments.L5Seg,
        &Main.HumanModel.BodyModel.Trunk.Segments.L4Seg
      };
      AnyObjectPtrArray pArrJntReactions = {
        &Main.HumanModel.BodyModel.Right.Leg.Jnt.Hip.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Right.Leg.Jnt.Knee.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Right.Leg.Jnt.Ankle.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Right.Leg.Jnt.SubTalar.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Right.Leg.Jnt.PatellaFemur.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Right.Leg.Jnt.PatellaMovement.Reaction,
        &Main.HumanModel.BodyModel.Left.Leg.Jnt.Hip.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Left.Leg.Jnt.Knee.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Left.Leg.Jnt.Ankle.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Left.Leg.Jnt.SubTalar.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Left.Leg.Jnt.PatellaFemur.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Left.Leg.Jnt.PatellaMovement.Reaction,
        &Main.HumanModel.BodyModel.Trunk.Joints.Lumbar.SacrumPelvis.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Trunk.Joints.Lumbar.L5Sacrum.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Trunk.Joints.Lumbar.L4L5.Constraints.Reaction,
        &Main.HumanModel.BodyModel.Trunk.Joints.Lumbar.L3L4.Constraints.Reaction
      };  
      IncludeForces = arrcat(
      ObjSearch("Main.HumanModel.BodyModel.*.Leg.Mus.*", "AnyMuscle"),
      ObjSearch("Main.HumanModel.BodyModel.Trunk.Muscles.*.*.*", "AnyMuscle"),
      ObjSearchRecursive("Main.HumanModel.BodyModel.Trunk.JointMuscles", "*", "AnyMuscle"),
      pArrJntReactions
      );
      AnyVec3 Mlocal = M*Main.HumanModel.BodyModel.Trunk.Segments.L4Seg.L3L4JntNode.RotNode.Axes;
    };

  AnyVar LateralBendingOnL4 = Main.Studies.InverseDynamicStudy.OncoEngLoadingAnalysis.Lumbar.NetMomentAtL3L4.Mlocal[0]; // Positive to the right lateral bending
    AnyVar AxialRotationMomentOnL4 = Main.Studies.InverseDynamicStudy.OncoEngLoadingAnalysis.Lumbar.NetMomentAtL3L4.Mlocal[1]; // Positive to the right axial turning
      AnyVar FlexionExtensionMomentOnL4 = Main.Studies.InverseDynamicStudy.OncoEngLoadingAnalysis.Lumbar.NetMomentAtL3L4.Mlocal[2]; // Positive in extension direction

I am just wondering if there are other elements that I still haven't considered (e.g. disc?).

I am not the best programmer around but I tried :sweat_smile: So, I am also just wondering if you think the code could be improved to be more concise (as I am planning to measure moments in all level in lumbar and thoracic).

Let me know. Thank you very much.

Kind regards,
Faizal

Hi Faizal,

On a quick look, it looks to be all good. Do you have shoulder-arm muscles in your model? If yes, then you should include those also. You also mentioned about disc stiffness and ligaments. One of the things you can do is to run the same model without muscles and compare the results. In the model without muscles, you can find joint moment measures in selected outputs (only for lumbar and cervical level).

The thing that worries me is that it can get cumbersome when you come to the thoracic segments, because of all the ribs. I can't really say how to make the cut and which ribs to include at each joint. There are also the abdominal layers and the diaphragm model. As you can imagine, it's not so simple and there is a chance that we miss something.

To make the code more concise, you could use the object search function also for searching for joint reactions and segments. Especially the legs could be easily condensed by using *. And all the code related to legs and including muscles could be in a shared file, so you include that for all the instances.

While using object search helps in making the code concise and more robust since you don't have to manually write down all the list, and it is resilient to changes in body model configuration, the same is also a small drawback as it will not complain if it doesn't find all the objects. So, you may miss something with these changes and you may see different results than before and it can be hard to diagnose that.

Best regards,
Dave

1 Like

Hi Dave,

Thank you for your reply and comments.

Now, I understand that I could make the code even simpler when you suggested to use ObjSearch further.

I have programmed the code for NetMoment in all the lumbar joint levels and the model has been successfully loaded and simulated.

However, when I tried to programmed NetMoment for thoracic spine, I realised that all the thoracic vertebral segments are missing the new rotated reference node (as clarified here). And when I programmed this myself, I also then realised that the location for anterior and posterior superior endplate nodes are not defined in ThoracicNode.any file for all thoracic level except for T1.

I am happy to code the anterior and posterior endplate nodes in the individual thoracic vertebrae, but I do not know the source for the information of this nodes' coordinate position. I noticed that these nodes are defined in cervical and lumbar and they are distinctive at every level.

Would you be able to point and direct me where I could gather the position of the nodes so I could programme this?

Thank you.

Kind regards,
Faizal

Hi Faizal,

That is right, the nodes and joint reaction force at the thoracic level is still missing. It's on our to-do list, and we will get to it soon. :wink:

You can see the code in the segments file and the values in the model parameters file. Generally, the idea behind is to capture the orientation of the superior endplate of a vertebra. This is done by using RotMat with 3 points. The points are picked on the source stl files (be careful to use the unscaled stl files: export the surface from a model with scaling none). Probably the most important are the anterior and posterior points, that must be on the endplate surface and on the same "planar" sort of surface of the endplate. Then, there is one on the right side that is picked but is expressed in a way to get the offset from the midpoint of the anterior and posterior endplate nodes. This helps in ensuring it has the same x coordinate as the midpoint of the anterior and posterior nodes. Then, we can use the RotMat with 3 points (the origin: midpoint of anterior and posterior endplate nodes, anterior posterior axis defined by anterior node, and the medio lateral axis defined by a vector from the origin to the difference between right and left node on the endplate.

If you would like, I would also encourage you make fork the AMMR beta repository and make a pull request with your changes. Of course, there is no pressure to do that :slight_smile:

Best regards,
Dave

1 Like

Hi Dave,

Thank you for the explanation! I am happy to take a punt on programming the nodes for the thoracic spine. I can see all other nodes for muscle attachments have been defined; it is just the endplate nodes that missing and that is what I am planning to do. I got a few more questions though before I do this:-

  1. I reckon I know how to export the surface mode now based on this post. I presumed when you said 'unscaled' stl, the 'Scaling Factor' should be 1.0 and the 'Reference Frame' selection is 'local' instead of 'global'? I believe the there might be a slight change in the export settings because of the change of class from DrwSurf to BoneDraw for the Trunk. I also just realised that all of the thoracic vertebrae have the same origin point, i.e. at the bottom of T12, from my observation of the code and supported by this post.
  2. My next question would be whether the anterior/posterior/medial nodes are encoded in the stl source itself or do I have to define these points myself from the stl rendering (literally, pick a point on the endplate surface to be a node)? Does this mean, if I have to pick the point myself, I need to render all 12 vertebrae at the same time in order to identify the coordinate for those ant/post/med nodes since they all will need to be referring to the common origin? Following on that, do you have any suggestion which software that I could use to render the stl files so I could identify the coordinate of the point that is being picked? At the moment, I am thinking of just using Solidworks, but I haven't tried it yet.

I hope my questions are not too trivial as I am still discovering!

Thank you.

Kind regards,
Faizal

Hi Faizal,

Happy to read that you are willing to do some of this programming. It will really help you understand the body model more :slight_smile:

  1. You are right about how to export a surface. What I meant by scaling none is to set the BM statement #define BM_SCALING _SCALING_NONE_. This will ensure you export the unscaled stl. And yes, please export them in local system.
  2. The stl is simply a mesh made from a bunch of vertices. It doesn't contain specific points with names that you can then access. It just has vertices and you access the coordinates by indexing through the array (that's a simplified description). So, like you say, you literally have to pick a point on the stl rendering. Normally, we would open the stl file in some software (SolidWorks is just fine for that, or I can also suggest Meshlab, which is open source). Then, in the software, you find a tool for picking points and noting the coordinates of these picked points. These coordinates are then saved in the ModelParameters. And then you make nodes out of these model parameters using the Scale function in the sRel. Remember to visualize these nodes in your model (also with some scaling) to verify that they are correct, I don't think it matters if you load all the vertebrae together or individually. Whatever is more convenient for you.

Best regards,
Dave

1 Like