6 Finite Element Models

6.9 Muscle activated FEM models

Finite element muscle models are an extension to regular FEM models. As such, everything previously discussed for regular FEM models also applies to FEM muscles. Muscles have additional properties that allow them to contract when activated. There are two types of muscles supported:

Fibre-based:

Point-to-point muscle fibres are embedded in the model.

Material-based:

An auxiliary material is added to the constitutive law to embed muscle properties.

In this section, both types will be described.

6.9.1 FemMuscleModel

The main class for FEM-based muscles is FemMuscleModel, a subclass of FemModel3d. It differs from a basic FEM model in that it has the new property

Property Description
muscleMaterial An object that adds an activation-dependent ‘muscle’ term to the constitutive law.

This is a delegate object of type MuscleMaterial, described in detail in Section 6.10.3, that computes activation-dependent stress and stiffness in the muscle. In addition to this property, FemMuscleModel adds two new lists of subcomponents:

bundles


Groupings of muscle sub-units (fibres or elements) that can be activated.

exciters


Components that control the activation of a set of bundles or other exciters.

6.9.1.1 Bundles


Muscle bundles allow for a muscle to be partitioned into separate groupings of fibres/elements, where each bundle can be activated independently. They are implemented in the class MuscleBundle. Bundles have three key properties:

Property Description
excitation Activation level of the muscle, a\in[0,1].
fibresActive Enable/disable “fibre-based” muscle components.
muscleMaterial An object that adds an activation-dependent ‘muscle’ term to the constitutive law (Section 6.10.3).

The excitation property controls the level of muscle activation, with zero being no muscle action, and one being fully activated. The fibresActive property is a boolean variable that controls whether or not to treat any contained fibres as point-to-point-like muscles (“fibre-based”). If false, the fibres are ignored. The third property, muscleMaterial, allows for a MuscleMaterial to be specified per bundle. By default, its value is inherited from FemMuscleModel.

Once a muscle bundle is created, muscle sub-units must be assigned to it. These are either point-to-point fibres, or material-based muscle element descriptors. The two types will be covered in Sections 6.9.2 and 6.9.3, respectively.

6.9.1.2 Exciters


A MuscleExciter component enables you to simultaneously activate a group of “excitation components”. This includes: point-to-point muscles, muscle bundles, muscle fibres, material-based muscle elements, and other muscle exciters. Components that can be excited all implement the ExcitationComponent interface. To add or remove a component to the exciter, use

  addTarget (ExcitationComponent ex);    // adds a component to the exciter
  addTarget (ExcitationComponent ex,     // adds a component with a gain factor
      double gain);
  removeTarget (ExcitationComponent ex); // removes a component

If a gain factor is specified, the activation is scaled by the gain for that component.

6.9.2 Fibre-based muscles

In fibre-based muscles, a set of point-to-point muscle fibres are added between FEM nodes or markers. Each fibre is assigned an AxialMuscleMaterial, just like for regular point-to-point muscles (Section 4.5.1). Note that these muscle materials typically have a “rest length” property, that will likely need to be adjusted for each fibre. Once the set of fibres are added to a MuscleBundle, they need to be enabled. This is done by setting the fibresActive property of the bundle to true.

Fibres are added to a MuscleBundle using one of the functions:

addFibre( Muscle muscle );              // adds a point-to-point fibre
Muscle addFibre( Point p0, Point p1,    // creates and adds a fibre
    AxialMuscleMaterial mat);

The latter returns the newly created Muscle fibre. The following code snippet demonstrates how to create a fibre-based MuscleBundle and add it to an FEM muscle.

1 // Create a muscle bundle
2 MuscleBundle bundle = new MuscleBundle("fibres");
3 Point3d[] fibrePoints = ...   //create a sequential list of points
4
5 // Add fibres
6 Point pPrev = fem.addMarker(fibrePoints[0]);    // create an FEM marker
7 for (int i=1; i<=fibrePoints.length; i++) {
8    Point pNext = fem.addMarker(fibrePoint[i]);
9
10    // Create fibre material
11    double l0 = pNext.distance(pPrev);           // rest length
12    AxialMuscleMaterial fibreMat =
13          new BlemkerAxialMuscle(
14                1.4*l0, l0, 3000, 0, 0);
15
16    // Add a fibre between pPrev and pNext
17    bundle.addFibre(pPrev, pNext, fibreMat);     // add fibre to bundle
18    pPrev = pNext;
19 }
20
21 // Enable use of fibres (default is disabled)
22 bundle.setFibresActive(true);
23 fem.addMuscleBundle(bundle);                    // add the bundle to fem

In these fibre-based muscles, force is only exerted between the anchor points of the fibres; it is a discrete approximation. These models are typically more stable than material-based ones.

6.9.3 Material-based muscles

In material-based muscles, the constitutive law is augmented with additional terms to account for muscle-specific properties. This is a continuous representation within the model.

The basic building block for a material-based muscle bundle is a MuscleElementDesc. This object contains a reference to a FemElement3d, a MuscleMaterial, and either a single direction or set of directions that specify the direction of contraction. If a single direction is specified, then it is assumed the entire element contracts in the same direction. Otherwise, a direction can be specified for each integration point within the element. A null direction signals that there is no muscle at the corresponding point. This allows for a sub-element resolution for muscle definitions. The positions of integration points for a given element can be obtained with:

// loop through all integration points for a given element
for ( IntegrationPoint3d ipnt : elem.getIntegrationPoints() ) {
   Point3d curPos = new Point3d();
   Point3d restPos = new Point3d();
   ipnt.computePosition (curPos, elem);          // computes current position
   ipnt.computeRestPosition (restPos, elem);     // computes rest position
}

By default, the MuscleMaterial is inherited from the bundle’s material property. Muscle materials are described in detail in Section 6.10.3 and include GenericMuscle, BlemkerMuscle, and FullBlemkerMuscle. The Blemker-type materials are based on [5].

Elements can be added to a muscle bundle using one of the methods:

// Adds a muscle element
addElement (MuscleElementDesc elem);
// Creates and adds a muscle element
MuscleElementDesc addElement (FemElement3d elem, Vector3d dir);
// Sets a direction per integration point
MuscleElementDesc addElement (FemElement3d elem, Vector3d[] dirs);

The following snippet demonstrates how to create and add a material-based muscle bundle:

1 // Create muscle bundle
2 MuscleBundle bundle = new MuscleBundle("embedded");
3
4 // Muscle material
5 MuscleMaterial muscleMat = new BlemkerMuscle(
6       1.4, 1.0, 3000, 0, 0);
7 bundle.setMuscleMaterial(muscleMat);
8
9 // Muscle direction
10 Vector3d dir = Vector3d.X_UNIT;
11
12 // Add elements to bundle
13 for (FemElement3d elem : beam.getElements()) {
14    bundle.addElement(elem, dir);
15 }
16
17 // Add bundle to model
18 beam.addMuscleBundle(bundle);

6.9.4 Example: toy FEM muscle model

Figure 6.15: ToyMuscleFem, showing the deformation from setting the muscle excitations in the control panel.

A simple example showing an FEM with material-based muscles is given by artisynth.demos.tutorial.ToyMuscleFem. It consists of a hex-element beam, with 12 muscles added in groups along its length, allowing it to flex in the x-z plane. A frame object is also attached to the right end. The code for the model, without the package and include directives, is listed below:

1 public class ToyMuscleFem extends RootModel {
2
3    protected MechModel myMech;      // overall mechanical model
4    protected FemMuscleModel myFem;  // FEM muscle model
5    protected Frame myFrame;         // frame attached to the FEM
6
7    public void build (String[] args) throws IOException {
8       myMech = new MechModel ("mech");
9       myMech.setGravity (0, 0, 0);
10       addModel (myMech);
11
12       // create a FemMuscleModel and then create a hex grid with it.
13       myFem = new FemMuscleModel ("fem");
14       FemFactory.createHexGrid (
15          myFem, /*wx*/1.2, /*wy*/0.3, /*wz*/0.3, /*nx*/12, /*ny*/3, /*nz*/3);
16       // give it a material with Poisson’s ratio 0 to allow it to compress
17       myFem.setMaterial (new LinearMaterial (100000, 0.0));
18       // fem muscles will be material-based, using a SimpleForceMuscle
19       myFem.setMuscleMaterial (new SimpleForceMuscle(/*maxstress=*/100000));
20       // set density + particle and stiffness damping for optimal stability
21       myFem.setDensity (100.0);
22       myFem.setParticleDamping (1.0);
23       myFem.setStiffnessDamping (1.0);
24       myMech.addModel (myFem);
25
26       // fix the nodes on the left side
27       for (FemNode3d n : myFem.getNodes()) {
28          Point3d pos = n.getPosition();
29          if (pos.x == -0.6) {
30             n.setDynamic (false);
31          }
32       }
33       // Create twelve muscle bundles, bottom to top and left to right. Muscles
34       // are material-based, each with a set of 9 elements in the x-y plane and
35       // a rest direction parallel to the x axis.
36       Point3d pe = new Point3d(); // element center point
37       for (int sec=0; sec<4; sec++) {
38          for (int k=0; k<3; k++) {
39             MuscleBundle bundle = new MuscleBundle();
40             // locate elements based on their center positions
41             pe.set (-0.55+sec*0.3, -0.1, -0.1+k*0.1);
42             for (int i=0; i<3; i++) {
43                pe.y = -0.1;
44                for (int j=0; j<3; j++) {
45                   FemElement3d e = myFem.findNearestVolumetricElement(null, pe);
46                   bundle.addElement (e, Vector3d.X_UNIT);
47                   pe.y += 0.1;
48                }
49                pe.x += 0.1;
50             }
51             // set the line color for each bundle using a color from the probe
52             // display palette.
53             RenderProps.setLineColor (
54                bundle, PlotTraceInfo.getPaletteColors()[sec*3+k]);
55             myFem.addMuscleBundle (bundle);
56          }
57       }
58       // create a panel for controlling all 12 muscle excitations
59       ControlPanel panel = new ControlPanel ();
60       for (MuscleBundle b : myFem.getMuscleBundles()) {
61          LabeledComponentBase c = panel.addWidget (
62             "excitation "+b.getNumber(), b, "excitation");
63          // color the exciter labels using the muscle bundle color
64          c.setLabelFontColor (b.getRenderProps().getLineColor());
65       }
66       addControlPanel (panel);
67
68       // create and attach a frame to the right end of the FEM
69       myFrame = new Frame();
70       myFrame.setPose (new RigidTransform3d (0.45, 0, 0));
71       myMech.addFrame (myFrame);
72       myMech.attachFrame (myFrame, myFem); // attach to the FEM
73
74       // render properties:
75       // show muscle bundles by rendering activation directions within elements
76       RenderProps.setLineWidth (myFem.getMuscleBundles(), 4);
77       myFem.setDirectionRenderLen (0.6); //
78       // draw frame by showing its coordinate axis
79       myFrame.setAxisLength (0.3);
80       myFrame.setAxisDrawStyle (AxisDrawStyle.ARROW);
81       // set FEM line and surface colors to blue-gray
82       RenderProps.setLineColor (myFem, new Color (0.7f, 0.7f, 1f));
83       RenderProps.setFaceColor (myFem, new Color (0.7f, 0.7f, 1f));
84       // render FEM surface transparent
85       myFem.setSurfaceRendering (SurfaceRender.Shaded);
86       RenderProps.setAlpha (myFem.getSurfaceMeshComp(), 0.4);
87    }
88 }

Within the build() method, the mech model is created in the usual way (lines 8-10). Gravity is turned off to give the muscles greater control over the FEM model’s configuration. The MechModel reference is stored in the class field myMech to enable any subclasses to have easy access to it; the same will be done for the FEM model and the attached frame.

The FEM model itself is created at lines (12-24). An instance of FemMuscleModel is created and then passed to FemFactory.createHexGrid(); this allows the model to be an instance of FemMuscleModel instead of FemModel3d. The model is assigned a linear material with Poisson’s ratio of 0 to allow it to be easily compressed. Muscle bundles will be material-based and will all use the same SimpleForceMuscle material that is assigned to the model’s muscleMaterial property. Density and damping parameters are defined so as to improve model stability when muscles are excited. Once the model is created, its left-hand nodes are fixed to provide anchoring (lines 27-32).

Muscle bundles are created at lines 36-58. There are 12 of them, arranged in three vertical layers and four horizontal sections. Each bundle is populated with 9 adjacent elements in the x-y plane. To find these elements, their center positions are calculated and then passed to the FEM method findNearestVolumetricElement(). The element is then added to the bundle with a resting activation direction parallel to the x axis. For visualization, each bundle’s line color is set to a distinct color from the numeric probe display palette, based on the bundle’s number (lines 53-54).

After the bundles have been added to the FEM model, a control is created to allow interactive control of their excitations (lines 88-95). Each widget is labeled excitation N, where N is the bundle number, and the label is colored to match the bundle’s line color. Finally, a frame is created and attached to the FEM model (lines 59-62), and render properties are set at lines 106-115: Muscle bundles are drawn by showing the activation direction in each element; the frame is displayed as a solid arrow with axis lengths of 0.3; the FEM line and face colors are set to blue-gray, and the surface is rendered and made transparent.

To run this example in ArtiSynth, select All demos > tutorial > ToyMuscleFem from the Models menu. Running the model and adjusting the exciters in the control panel will cause the FEM model to deform in various ways (Figure 6.15).

6.9.5 Example: comparison with two beam examples

Figure 6.16: FemMuscleBeams model loaded into ArtiSynth.

An example comparing a fibre-based and a material-based muscle is shown in Figure 6.16. The code can be found in artisynth.demos.tutorial.FemMuscleBeams. There are two FemMuscleModel beams in the model: one fibre-based, and one material-based. Each has three muscle bundles: one at the top (red), one in the middle (green), and one at the bottom (blue). In the figure, both muscles are fully activated. Note the deformed shape of the beams. In the fibre-based one, since forces only act between point on the fibres, the muscle seems to bulge. In the material-based muscle, the entire continuous volume contracts, leading to a uniform deformation.

Material-based muscles are more realistic. However, this often comes at the cost of stability. The added terms to the constitutive law are highly nonlinear, which may cause numerical issues as elements become highly contracted or highly deformed. Fibre-based muscles are, in general, more stable. However, they can lead to bulging and other deformation artifacts due to their discrete nature.