6 Finite Element Models

6.6 Frame attachments

It is also possible to attach frame components, including rigid bodies, directly to FEM models, using the attachment component FrameFem3dAttachment. Analogously to PointFem3dAttachment, the attachment is implemented by connecting the frame to a set of FEM nodes, and attachments can be either element-based or nodal-based. The frame’s origin is computed in the same way as for point attachments, using a weighted sum of node positions (Equation 6.3), while the orientation is computed using a polar decomposition on a deformation gradient determined from either element shape functions (for element-based attachments) or a Procrustes type analysis using nodal rest positions (for nodal-based attachments).

An element-based attachment can be created using either a code fragment of the form

   FrameFem3dAttachment ax = new FrameFem3dAttachment(frame);
   ax.setFromElement (frame.getPose(), elem);
   mech.addAttachment (ax);

or, equivalently, the attachFrame() method in MechModel:

   mech.attachFrame (frame, elem);

This attaches the frame frame to the nodes of the FEM element elem. As with PointFem3dAttachment, if the frame’s origin is not inside the element, it may not be possible to accurately compute the internal nodal weights, in which case setFromElement() will return false.

In order to have the appropriate element located automatically, one can instead use

   FrameFem3dAttachment ax = new FrameFem3dAttachment(frame);
   ax.setFromFem (frame.getPose(), fem);
   mech.addAttachment (ax);

or, equivalently,

   mech.attachFrame (frame, fem);

As with point-to-FEM attachments, it may be desirable to create a nodal-based attachment in which the nodes and weights are not tied to a specific element. The reasons for this are generally the same as with nodal-based point attachments (Section 6.4.8): the need to distribute the forces and moments acting on the frame across a broader set of element nodes. Also, element-based frame attachments use element shape functions to determine the frame’s orientation, which may produce slightly asymmetric results if the frame’s origin is located particularly close to a specific node.

FrameFem3dAttachment provides several methods for explicitly specifying nodes and weights. The signatures for these include:

  void setFromNodes (RigidTransform3d TFW, FemNode[] nodes, double[] weights)
  void setFromNodes (RigidTransform3d TFW, Collection<FemNode> nodes,
                        VectorNd weights)
  boolean setFromNodes (RigidTransform3d TFW, FemNode[] nodes)
  boolean setFromNodes (RigidTransform3d TFW, Collection<FemNode> nodes)

Unlike their counterparts in PointFem3dAttachment, the first two methods also require the current desired pose of the frame TFW (in world coordinates). This is because while nodes and weights will unambiguously specify the frame’s origin, they do not specify the desired orientation.

6.6.1 Example: attaching frames to an FEM beam

Figure 6.12: FrameFemAttachment loaded into ArtiSynth and run until stable.

A model illustrating how to connect frames to an FEM model is defined in

  artisynth.demos.tutorial.FrameFemAttachment

It creates an FEM beam, along with a rigid body block and a massless coordinate frame, that are then attached to the beam using nodal and element-based attachments. The build method is shown below:

1    public void build (String[] args) {
2
3       MechModel mech = new MechModel ("mech");
4       addModel (mech);
5
6       // create and add FEM beam
7       FemModel3d fem = FemFactory.createHexGrid (null, 1.0, 0.2, 0.2, 6, 3, 3);
8       fem.setMaterial (new LinearMaterial (500000, 0.33));
9       RenderProps.setLineColor (fem, Color.BLUE);
10       RenderProps.setLineWidth (mech, 2);
11       mech.addModel (fem);
12       // fix leftmost nodes of the FEM
13       for (FemNode3d n : fem.getNodes()) {
14          if ((n.getPosition().x-(-0.5)) < 1e-8) {
15             n.setDynamic (false);
16          }
17       }
18
19       // create and add rigid body box
20       RigidBody box = RigidBody.createBox (
21          "box", 0.25, 0.1, 0.1, /*density=*/1000);
22       mech.add (box);
23
24       // create a basic frame and set its pose and axis length
25       Frame frame = new Frame();
26       frame.setPose (new RigidTransform3d (0.4, 0, 0, 0, Math.PI/4, 0));
27       frame.setAxisLength (0.3);
28       mech.addFrame (frame);
29
30       mech.attachFrame (frame, fem); // attach using element-based attachment
31
32       // attach the box to the FEM, using all the nodes of elements 31 and 32
33       HashSet<FemNode3d> nodes = collectNodes (fem, new int[] { 22, 31 });
34       FrameFem3dAttachment attachment = new FrameFem3dAttachment(box);
35       attachment.setFromNodes (box.getPose(), nodes);
36       mech.addAttachment (attachment);
37
38       // render the attachment nodes for the box as spheres
39       for (FemNode n : attachment.getNodes()) {
40          RenderProps.setSphericalPoints (n, 0.007, Color.GREEN);
41       }
42    }

Lines 3-22 create a MechModel and populate it with an FEM beam and a rigid body box. Next, a basic Frame is created, with a specified pose and an axis length of 0.3 (to allow it to be seen), and added to the MechModel (lines 25-28). It is then attached to the FEM beam using an element-based attachment (line 30). Meanwhile, the box is attached to using a nodal-based attachment, created from all the nodes associated with elements 22 and 31 (lines 33-36). Finally, all attachment nodes are set to be rendered as green spheres (lines 39-41).

To run this example in ArtiSynth, select All demos > tutorial > FrameFemAttachment from the Models menu. Running the model will cause it to settle into the state shown in Figure 6.12. Forces can interactively be applied to the attached block and frame using the pull tool, causing the FEM model to deform (see the section “Pull Manipulation” in the ArtiSynth User Interface Guide).

6.6.2 Adding joints to FEM models

The ability to connect frames to FEM models, as described in Section 6.6, makes it possible to interconnect different FEM models directly using joints, as described in Section 3.3. This is done internally by using FrameFem3dAttachments to connect frames C and D of the joint (Figure 3.8) to their respective FEM models.

As indicated in Section 3.3.3, most joints have a constructor of the form

  JointType (bodyA, bodyB, TDW);

that creates a joint connecting bodyA to bodyB, with the initial pose of the D frame given (in world coordinates) by TDW. The same body and transform settings can be made on an existing joint using the method setBodies(bodyA, bodyB, TDW). For these constructors and methods, it is possible to specify FEM models for bodyA and/or bodyB. Internally, the joint then creates a FrameFem3dAttachment to connect frame C and/or D of the joint (See Figure 3.8) to the corresponding FEM model.

However, unlike joints involving rigid bodies or frames, there are no associated {\bf T}_{CA} or {\bf T}_{DB} transforms (since there is no fixed frame within an FEM to define such transforms). Methods or constructors which utilize {\bf T}_{CA} or {\bf T}_{DB} can therefore not be used with FEM models.

6.6.3 Example: two FEM beams connected by a joint

Figure 6.13: JointedFemBeams loaded into ArtiSynth and run until stable.

A model connecting two FEM beams by a joint is defined in

  artisynth.demos.tutorial.JointedFemBeams

It creates two FEM beams and connects them via a special slotted-revolute joint. The build method is shown below:

1    public void build (String[] args) {
2
3       MechModel mech = new MechModel ("mechMod");
4       addModel (mech);
5
6       double stiffness = 5000;
7       // create first fem beam and fix the leftmost nodes
8       FemModel3d fem1 = addFem (mech, 2.4, 0.6, 0.4, stiffness);
9       for (FemNode3d n : fem1.getNodes()) {
10          if (n.getPosition().x <= -1.2) {
11             n.setDynamic(false);
12          }
13       }
14       // create the second fem beam and shift it 1.5 to the right
15       FemModel3d fem2 = addFem (mech, 2.4, 0.4, 0.4, 0.1*stiffness);
16       fem2.transformGeometry (new RigidTransform3d (1.5, 0, 0));
17
18       // create a slotted revolute joint that connects the two fem beams
19       RigidTransform3d TDW = new RigidTransform3d(0.5, 0, 0, 0, 0, Math.PI/2);
20       SlottedRevoluteJoint joint = new SlottedRevoluteJoint (fem2, fem1, TDW);
21       mech.addBodyConnector (joint);
22
23       // set ranges and rendering properties for the joint
24       joint.setShaftLength (0.8);
25       joint.setMinX (-0.5);
26       joint.setMaxX (0.5);
27       joint.setSlotDepth (0.63);
28       joint.setSlotWidth (0.08);
29       RenderProps.setFaceColor (joint, myJointColor);
30    }

Lines 3-16 create a MechModel and populates it with two FEM beams, fem1 and fem2, using an auxiliary method addFem() defined in the model source file. The leftmost nodes of fem1 are set fixed. A SlottedRevoluteJoint is then created to interconnect fem1 and fem2 at a location specified by TDW (lines 19-21). Lines 24-29 set some parameters for the joint, along with various render properties.

To run this example in ArtiSynth, select All demos > tutorial > JointedFemBeams from the Models menu. Running the model will cause it drop and flex under gravity, as shown in 6.13. Forces can interactively be applied to the beams using the pull tool (see the section “Pull Manipulation” in the ArtiSynth User Interface Guide).