ObjectGenericODE2

A system of \(n\) second order ordinary differential equations (ODE2), having a mass matrix, damping/gyroscopic matrix, stiffness matrix and generalized forces. It can combine generic nodes, or node points. User functions can be used to compute mass matrix and generalized forces depending on given coordinates. NOTE: all matrices, vectors, etc. must have the same dimensions \(n\) or \((n \times n)\), or they must be empty \((0 \times 0)\), except for the mass matrix which always needs to have dimensions \((n \times n)\).

Interface

Parameters

The parameters of the item; in a dictionary, its type is ‘GenericODE2’:

name

type

size

default

description

name

String

‘’

objects’s unique name

nodeNumbers

ArrayNodeIndex

[]

(symbol: \(\mathbf{n}_n = [n_0,\,\ldots,\,n_n]\tp\)) node numbers which provide the coordinates for the object (consecutively as provided in this list)

massMatrix

PyMatrixContainer

[]

(symbol: \(\Mm \in \Rcal^{n \times n}\)) mass matrix of object as MatrixContainer (or numpy array / list of lists)

stiffnessMatrix

PyMatrixContainer

[]

(symbol: \(\Km \in \Rcal^{n \times n}\)) stiffness matrix of object as MatrixContainer (or numpy array / list of lists); NOTE that (dense/sparse triplets) format must agree with dampingMatrix and jacobianUserFunction

dampingMatrix

PyMatrixContainer

[]

(symbol: \(\Dm \in \Rcal^{n \times n}\)) damping matrix of object as MatrixContainer (or numpy array / list of lists); NOTE that (dense/sparse triplets) format must agree with stiffnessMatrix and jacobianUserFunction

forceVector

NumpyVector

[]

(symbol: \(\fv \in \Rcal^{n}\)) generalized force vector added to RHS

forceUserFunction

ObjectGenericODE2ForceUserFunction

0

(symbol: \(\fv_{user} \in \Rcal^{n}\)) A Python user function which computes the generalized user force vector for the ODE2 equations; see description below

massMatrixUserFunction

ObjectGenericODE2MassMatrixUserFunction

0

(symbol: \(\Mm_{user} \in \Rcal^{n\times n}\)) A Python user function which computes the mass matrix instead of the constant mass matrix given in \(\Mm\); return numpy array or MatrixContainer; see description below

jacobianUserFunction

ObjectGenericODE2JacobianUserFunction

0

(symbol: \(\Jm_{user} \in \Rcal^{n\times n}\)) A Python user function which computes the jacobian, i.e., the derivative of the left-hand-side object equation w.r.t. the coordinates (times \(f_{ODE2}\)) and w.r.t. the velocities (times \(f_{ODE2_t}\)). Terms on the RHS must be subtracted from the LHS equation; the respective terms for the stiffness matrix and damping matrix are automatically added; see description below

coordinateIndexPerNode

ArrayIndex

[]

this list contains the local coordinate index for every node, which is needed, e.g., for markers; the list is generated automatically every time parameters have been changed

tempCoordinates

NumpyVector

[]

(symbol: \(\cv_{temp} \in \Rcal^{n}\)) temporary vector containing coordinates

tempCoordinates_t

NumpyVector

[]

(symbol: \(\dot \cv_{temp} \in \Rcal^{n}\)) temporary vector containing velocity coordinates

tempCoordinates_tt

NumpyVector

[]

(symbol: \(\ddot \cv_{temp} \in \Rcal^{n}\)) temporary vector containing acceleration coordinates

visualization

VObjectGenericODE2

parameters for visualization of item

Visualization parameters

The parameters of VObjectGenericODE2, given as visualization:

name

type

size

default

description

show

Bool

True

set true, if item is shown in visualization and false if it is not shown

color

Float4

4

[-1.,-1.,-1.,-1.]

RGBA color for object; 4th value is alpha-transparency; R=-1.f means, that default color is used

triangleMesh

NumpyMatrixI

[]

a matrix of node numbers referring to the mesh nodes of the object, one triangle per row: 3 columns for flat triangles, or 6 for 6-node triangles drawn curved - the corners counterclockwise seen from outside, then the mid nodes of the edges 0-1, 1-2 and 2-0, as in GraphicsData triangles6; the mesh uses the nodes to visualize the underlying object; contour plot colors are still computed in the local frame!

showNodes

Bool

False

set true, nodes are drawn uniquely via the mesh, eventually using the floating reference frame, even in the visualization of the node is show=False; node numbers are shown with indicator ‘NF’

graphicsDataUserFunction

ObjectGenericODE2GraphicsDataUserFunction

0

A Python function which returns a bodyGraphicsData object, which is a list of graphics data in a dictionary computed by the user function; the graphics data is draw in global coordinates; it can be used to implement user element visualization, e.g., beam elements or simple mechanical systems; note that this user function may significantly slow down visualization

Drawing

Drawn as all super elements; its triangleMesh on the nodes, deformed with bodies.deformationScaleFactor, and with showNodes its nodes; or what its graphicsDataUserFunction returns.

Settings beyond those of all super elements: nodes.defaultSize, nodes.drawNodesAsPoint, nodes.show, nodes.showNumbers, nodes.tiling, openGL.advanced.initialMaxSceneSize.

Output variables

Available as OutputVariableType in sensors, Get...Output() and other functions:

output variable

symbol

description

CoordinatesTotal

all ODE2 displacement plus reference coordinates of object

Coordinates

all ODE2 (displacement) coordinates

Coordinates_t

all ODE2 velocity coordinates

Coordinates_tt

all ODE2 acceleration coordinates

Force

generalized forces for all coordinates (residual of all forces except mass*accleration; corresponds to ComputeODE2LHS)

KineticEnergy

\(T = \frac{1}{2} \dot\qv\tp \Mm\, \dot\qv\)

kinetic energy from the mass matrix of the current state and the velocities of the nodes; current configuration only; localPosition must be \([0,0,0]\)

PotentialEnergy

\(V = \frac{1}{2} \qv\tp \Km\, \qv - \fv\tp \qv\)

elastic energy of the stiffness matrix and the potential of the constant force vector; raises for a forceUserFunction; localPosition must be \([0,0,0]\)

Detailed description

Additional output variables for superelement node access

Functions like GetObjectOutputSuperElement(...), see MainSystem: Object, or SensorSuperElement, see MainSystem: Sensor, directly access special output variables (OutputVariableType) of the mesh nodes of the superelement. Additionally, the contour drawing of the object can make use the OutputVariableType of the meshnodes.

For this object, all nodes of ObjectGenericODE2 map their OutputVariableType to the meshnode \(\ra\) see at the according node for the list of OutputVariableType.

Equations of motion

An object with node numbers \([n_0,\,\ldots,\,n_n]\) and according numbers of nodal coordinates \([n_{c_0},\,\ldots,\,n_{c_n}]\), the total number of equations (=coordinates) of the object is

\[ n = \sum_{i} n_{c_i}, \]

which is used throughout the description of this object.

Equations of motion

The equations of motion read,

(56)\[ \Mm \ddot \qv + \Dm \dot \qv + \Km \qv = \fv + \fv_{user}(mbs, t, i_N,\qv,\dot \qv) \]

Note that the user function \(\fv_{user}(mbs, t, i_N,\qv,\dot \qv)\) may be empty (=0), and iN represents the itemNumber (=objectNumber).

In case that a user mass matrix is specified, (56) is replaced with

\[ \Mm_{user}(mbs, t, i_N, \qv,\dot \qv) \ddot \qv + \Dm \dot \qv + \Km \qv = \fv + \fv_{user}(mbs, t, i_N, \qv,\dot \qv) \]

The (internal) Jacobian \(\Jm\) of (56) (assuming \(\fv\) to be constant!) reads

\[ \Jm = f_{ODE2} \left(\Km - \frac{\partial \fv_{user}(mbs, t, i_N,\qv,\dot \qv)}{\partial \qv}\right) + f_{ODE2_t} \left(\Dm - \frac{\partial \fv_{user}(mbs, t, i_N,\qv,\dot \qv)}{\partial \dot \qv} \right) + \]

Chosing \(f_{ODE2} = 1\) and \(f_{ODE2_t}=0\) would immediately give the jacobian of position quantities.

If no jacobianUserFunction is specified, the jacobian is – as with many objects in Exudyn – computed by means of numerical differentiation. In case that a jacobianUserFunction is specified, it must represent the jacobian of the LHS of (56) without \(\Km\) and \(\Dm\) (these matrices are added internally),

(57)\[ \Jm_{user}(mbs, t, i_N, \qv, \dot \qv, f_{ODE2}, f_{ODE2_t}) = -f_{ODE2} \left(\frac{\partial \fv_{user}(mbs, t, i_N,\qv,\dot \qv)}{\partial \qv} \right) - f_{ODE2_t} \left(\frac{\partial \fv_{user}(mbs, t, i_N,\qv,\dot \qv)}{\partial \dot \qv} \right) \]

For clarification also see the example in TestModels/linearFEMgenericODE2.py.

CoordinateLoads are added for the respective ODE2 coordinate on the RHS of the latter equation.

Marker interfaces

The mesh nodes of the object are its nodes: mesh node \(i\) is node \(n_i\) of nodeNumbers, at the position of that node. MarkerSuperElementPosition and MarkerSuperElementRigid act on them, with the Jacobians of the nodes and the weights of the marker; a load or constraint on single coordinates uses MarkerObjectODE2Coordinates or the coordinate markers of the nodes. The general body markers - MarkerBodyPosition, MarkerBodyRigid, MarkerBodyMass - do not work on this object, whose body access functions are not available: Assemble() refuses them.

Userfunction: forceUserFunction(mbs, t, itemNumber, q, q_t) A user function, which computes a force vector depending on current time and states of object. Can be used to create any kind of mechanical system by using the object states. Note that itemNumber represents the index of the ObjectGenericODE2 object in mbs, which can be used to retrieve additional data from the object through mbs.GetObjectParameter(itemNumber, ...), see the according description of GetObjectParameter.

arguments / return

type or size

description

mbs

MainSystem

provides MainSystem mbs to which object belongs

t

Real

current time in mbs

itemNumber

Index

integer number \(i_N\) of the object in mbs, allowing easy access to all object data via mbs.GetObjectParameter(itemNumber, …)

q

Vector \(\in \Rcal^n\)

object coordinates (e.g., nodal displacement coordinates) in current configuration, without reference values

q_t

Vector \(\in \Rcal^n\)

object velocity coordinates (time derivative of q) in current configuration

return value

Vector \(\in \Rcal^{n}\)

returns force vector for object

Userfunction: massMatrixUserFunction(mbs, t, itemNumber, q, q_t) A user function, which computes a mass matrix depending on current time and states of object. Can be used to create any kind of mechanical system by using the object states.

arguments / return

type or size

description

mbs

MainSystem

provides MainSystem mbs to which object belongs to

t

Real

current time in mbs

itemNumber

Index

integer number \(i_N\) of the object in mbs, allowing easy access to all object data via mbs.GetObjectParameter(itemNumber, …)

q

Vector \(\in \Rcal^n\)

object coordinates (e.g., nodal displacement coordinates) in current configuration, without reference values

q_t

Vector \(\in \Rcal^n\)

object velocity coordinates (time derivative of q) in current configuration

return value

MatrixContainer \(\in \Rcal^{n \times n}\)

returns mass matrix for object, as exu.MatrixContainer, numpy array or list of lists; use MatrixContainer sparse format for larger matrices to speed up computations.

Userfunction: jacobianUserFunction(mbs, t, itemNumber, q, q_t, fODE2, fODE2_t) A user function, which computes the jacobian of the LHS of the equations of motion, depending on current time, states of object and two factors which are used to distinguish between position level and velocity level derivatives. Can be used to create any kind of mechanical system by using the object states.

arguments / return

type or size

description

mbs

MainSystem

provides MainSystem mbs to which object belongs to

t

Real

current time in mbs

itemNumber

Index

integer number \(i_N\) of the object in mbs, allowing easy access to all object data via mbs.GetObjectParameter(itemNumber, …)

q

Vector \(\in \Rcal^n\)

object coordinates (e.g., nodal displacement coordinates) in current configuration, without reference values

q_t

Vector \(\in \Rcal^n\)

object velocity coordinates (time derivative of q) in current configuration

fODE2

Real

factor to be multiplied with the position level jacobian, see (57)

fODE2_t

Real

factor to be multiplied with the velocity level jacobian, see (57)

return value

MatrixContainer \(\in \Rcal^{n \times n}\)

returns special jacobian for object, as exu.MatrixContainer, numpy array or list of lists; use MatrixContainer sparse format for larger matrices to speed up computations; NOTE that the format of returnValue must AGREE with (dense/sparse triplet) format of stiffnessMatrix and dampingMatrix; sparse triplets MAY NOT contain zero values!

Userfunction: graphicsDataUserFunction(mbs, itemNumber) A user function, which is called by the visualization thread in order to draw user-defined objects. The function can be used to generate any BodyGraphicsData, see Section GraphicsData. Use exudyn.graphics functions, see Section Module: graphics, to create more complicated objects. Note that graphicsDataUserFunction needs to copy lots of data and is therefore inefficient and only designed to enable simpler tests, but not large scale problems.

For an example for graphicsDataUserFunction see ObjectGround, ObjectGround.

arguments / return

type or size

description

mbs

MainSystem

provides reference to mbs, which can be used in user function to access all data of the object

itemNumber

Index

integer number of the object in mbs, allowing easy access

return value

BodyGraphicsData

list of GraphicsData dictionaries, see Section GraphicsData

Example:

#user function, using variables M, K, ... from mini example, replacing ObjectGenericODE2(...)
KD = numpy.diag([200,100])
#nonlinear force example; this force is added to right-hand-side ==> negative sign!
def UFforce(mbs, t, itemNumber, q, q_t):
    return -np.dot(KD, q_t*q) #add nonlinear term for q_t and q, q_t*q gives vector

#non-constant mass matrix:
def UFmass(mbs, t, itemNumber, q, q_t):
    return (q[0]+1)*M #uses mass matrix from mini example

#non-constant mass matrix:
def UFgraphics(mbs, itemNumber):
    t = mbs.systemData.GetTime(exu.ConfigurationType.Visualization) #get time if needed
    p = mbs.GetObjectOutputSuperElement(objectNumber=itemNumber, variableType = exu.OutputVariableType.Position,
                                        meshNodeNumber = 0, #get first node's position
                                        configuration = exu.ConfigurationType.Visualization)
    graphics1=graphics.Sphere(point=p,radius=0.1, color=graphics.color.red)
        graphics2 = {'type':'Line', 'data': list(p)+[0,0,0], 'color':graphics.color.blue}
    return [graphics1, graphics2]

#now add object instead of object in mini-example:
oGenericODE2 = mbs.AddObject(ObjectGenericODE2(nodeNumbers=[nMass0,nMass1],
                   massMatrix=M, stiffnessMatrix=K, dampingMatrix=D,
                   forceUserFunction=UFforce, massMatrixUserFunction=UFmass,
                   visualization=VObjectGenericODE2(graphicsDataUserFunction=UFgraphics)))

Mini example

#set up a mechanical system with two nodes; it has the structure: |~~M0~~M1
nMass0 = mbs.AddNode(NodePoint(referenceCoordinates=[0,0,0]))
nMass1 = mbs.AddNode(NodePoint(referenceCoordinates=[1,0,0]))

mass = 0.5 * np.eye(3)      #mass of nodes
stif = 5000 * np.eye(3)     #stiffness of nodes
damp = 50 * np.eye(3)      #damping of nodes
Z = 0. * np.eye(3)          #matrix with zeros
#build mass, stiffness and damping matrices (:
M = np.block([[mass,         0.*np.eye(3)],
              [0.*np.eye(3), mass        ] ])
K = np.block([[2*stif, -stif],
              [ -stif,  stif] ])
D = np.block([[2*damp, -damp],
              [ -damp,  damp] ])

oGenericODE2 = mbs.AddObject(ObjectGenericODE2(nodeNumbers=[nMass0,nMass1], 
                                               massMatrix=M, 
                                               stiffnessMatrix=K,
                                               dampingMatrix=D))

mNode1 = mbs.AddMarker(MarkerNodePosition(nodeNumber=nMass1))
mbs.AddLoad(Force(markerNumber = mNode1, loadVector = [10, 0, 0])) #static solution=10*(1/5000+1/5000)=0.0004

#assemble and solve system for default parameters
mbs.Assemble()

mbs.SolveDynamic(solverType = exu.DynamicSolverType.TrapezoidalIndex2)

#check result at default integration time
exu.sys['testResult'] = mbs.GetNodeOutput(nMass1, exu.OutputVariableType.Position)[0]

Relevant Examples (Ex) and TestModels (TM) with weblink to github: kinematicTreeAndMBS.py (Ex), nMassOscillator.py (Ex), nMassOscillatorInteractive.py (Ex), simulateInteractively.py (Ex), ACFtest.py (TM), coordinateVectorConstraintGenericODE2.py (TM), energiesTest.py (TM), genericODE2matrixFormatsTest.py (TM), genericODE2test.py (TM), linearFEMgenericODE2.py (TM), objectFFRFTest.py (TM), objectGenericODE2Test.py (TM), rigidBodyAsUserFunctionTest.py (TM), solverExplicitODE1ODE2test.py (TM)