Motions#

Learn how to create and customize animations using the veux.Motion class. This page covers how to create, configure, and display animations of structural simulations performed with OpenSeesRT.

class Motion#

Examples#

import numpy as np
import veux
from math import sin, cos

# ---------------------------------------------------------
# 1) Build a simple finite element "beam" for visualization
# ---------------------------------------------------------
def create_simple_beam(ndm=3):
    """
    Creates a trivial 3D beam model with a fixed support at node 1
    and a free end at node 2, just for demonstration.
    Returns the model object.
    """
    import opensees.openseespy as ops

    length = 1.0
    # Create a model with 2 nodes, each having 6 DOF (3D)
    model = ops.Model(ndm=ndm, ndf=6)
    model.node(1, (0.0, 0.0, 0.0))
    model.node(2, (length, 0.0, 0.0))

    # Fix node 1
    model.fix(1, 1,1,1, 1,1,1)

    # Just a dummy section & element so we can visualize a 'beam'
    E, I = 1.0, 2.0
    sec_tag = 1
    model.section("FrameElastic", sec_tag, "-E", E, "-G", 1.0, "-A", 2.0,
                  "-J", 2.0, "-Iy", I, "-Iz", I, "-Ay", 2.0, "-Az", 2.0)
    transf_tag = 1
    model.geomTransf("Linear", transf_tag, 0, 0, 1)
    model.element("ElasticBeamColumn", 1, (1, 2),
                  section=sec_tag,
                  transform=transf_tag)

    return model

# ---------------------------------------------------------
# 2) Create an Artist for drawing the beam
# ---------------------------------------------------------
model = create_simple_beam()
artist = veux.create_artist(model,
                            vertical=2,  # y-axis is 'vertical' in this setup
                            model_config=dict(
                                extrude_outline="square",
                                extrude_scale=0.5
                            ))
artist.draw_axes()
artist.draw_outlines()

# ---------------------------------------------------------
# 3) Define exact (closed-form) solutions for rotation & position
#    under a constant moment M about the z-axis
# ---------------------------------------------------------
E, I = 1.0, 2.0
L    = 1.0

def exact_position_rotation(M):
    """
    Returns two callable objects:
    - position(node) -> (x, y, z)
    - rotation(node) -> (qx, qy, qz, qw) with scalar last
    representing the beam's deformation under a constant moment M.
    """
    def position(node):
        # nodeCoord(1) -> (0.0, 0.0, 0.0)
        # nodeCoord(2) -> (L,   0.0, 0.0)
        xi = model.nodeCoord(node)[0]
        theta = xi * M / (E * I)

        # For M = 0, avoid dividing by zero
        if abs(M) < 1e-12:
            return (xi, 0.0, 0.0)

        x_def = xi + (E * I / M) * sin(theta)
        y_def = (E * I / M) * (cos(theta) - 1.0)
        return (x_def, y_def, 0.0)

    def rotation(node):
        xi = model.nodeCoord(node)[0]
        theta = xi * M / (E * I)
        # Rotation about z-axis by angle theta:
        # quaternion with scalar last -> (0, 0, sin(theta/2), cos(theta/2))
        return (0.0, 0.0, sin(theta / 2.0), cos(theta / 2.0))

    return position, rotation

# ---------------------------------------------------------
# 4) Animate using veux.Motion
#    We vary M from 0 to 2 (dimensionless) to show large rotations
# ---------------------------------------------------------
from veux.motion import Motion

motion = Motion(artist)
moments = np.linspace(0, 2.0, 50)
for M in moments:
    pos_func, rot_func = exact_position_rotation(M)
    # Draw the beam outlines at this "load" configuration
    motion.draw_outlines(position=pos_func, rotation=rot_func)
    motion.advance()

# Insert the motion into the canvas and serve interactively
motion.add_to(artist.canvas)
veux.serve(artist)