rotationMarkerDeprecationTest.py

You can view and download this file on Github: rotationMarkerDeprecationTest.py

  1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2# This is an EXUDYN example
  3#
  4# Details:  The rotation of a joint or connector frame is given to its markers, as localHT (#2745):
  5#           a body on a GenericJoint and a body on a RigidBodySpringDamper, each turned once by
  6#           rotationMarker0/1 and once by the localHT of the markers, move the same; the
  7#           RigidBodySpringDamper applies rotationMarker0 on the same side as all joints (#2801).
  8#           rotationMarker0/1 are deprecated: setting one other than the unit matrix warns where it is
  9#           added, once per session and name - every time with exu.special.deprecations.warnOnce = False -
 10#           and every use is counted in exu.sys['deprecationUse']['items'] (#2804, #2806). GetJointArgs
 11#           with a rotation for an existing marker uses no deprecated parameter.
 12#
 13# Author:   Johannes Gerstmayr
 14# Date:     2026-10-03
 15#
 16# Copyright:This file is part of Exudyn. Exudyn is free software. You can redistribute it and/or modify it under the terms of the Exudyn license. See 'LICENSE.txt' for more details.
 17#
 18#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 19
 20import exudyn as exu
 21from exudyn.utilities import *
 22import numpy as np
 23import warnings
 24import os
 25
 26testIsActive = exu.sys.get('testIsActive', False)
 27
 28A0 = RotationMatrixX(0.3) @ RotationMatrixY(0.5) #the joint frame on the ground
 29A1 = RotationMatrixZ(-0.4) @ RotationMatrixX(0.2) #the joint frame on the body
 30Ab = A0 @ A1.T #the body, turned so that both joint frames agree in the reference configuration
 31pb = -Ab @ np.array([-0.2, 0, 0]) #and its marker at the origin
 32
 33def ItemUses():
 34    """all recorded uses of deprecated item parameters"""
 35    return sum(exu.sys.get('deprecationUse', {}).get('items', {}).values())
 36
 37def Model(mbs):
 38    oGround = mbs.AddObject(ObjectGround())
 39    inertia = InertiaCuboid(density=1000, sideLengths=[0.4, 0.1, 0.1])
 40    node = mbs.AddNode(NodeRigidBodyEP(referenceCoordinates=list(pb) + list(RotationMatrix2EulerParameters(Ab)),
 41                                       initialVelocities=[0]*7))
 42    body = mbs.AddObject(ObjectRigidBody(nodeNumber=node, mass=inertia.Mass(), inertia=inertia.GetInertia6D()))
 43    return (oGround, node, body)
 44
 45def Simulate(useLocalHT, connector):
 46    SC = exu.SystemContainer()
 47    mbs = SC.AddSystem()
 48    (oGround, node, body) = Model(mbs)
 49    if useLocalHT:
 50        m0 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround, localHT=exu.HT(rotation=A0)))
 51        m1 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=body, localHT=exu.HT(rotation=A1, translation=[-0.2, 0, 0])))
 52        rotations = {}
 53    else:
 54        m0 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround, localPosition=[0, 0, 0]))
 55        m1 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=body, localPosition=[-0.2, 0, 0]))
 56        rotations = {'rotationMarker0': A0, 'rotationMarker1': A1}
 57    with warnings.catch_warnings():
 58        warnings.simplefilter('ignore', DeprecationWarning)
 59        if connector:
 60            k = 2000.
 61            mbs.AddObject(RigidBodySpringDamper(markerNumbers=[m0, m1], stiffness=np.diag([k, 2*k, 3*k, 0.1*k, 0.2*k, 0.3*k]),
 62                                                damping=np.diag([1, 1, 1, 0.1, 0.1, 0.1]), **rotations))
 63        else:
 64            mbs.AddObject(GenericJoint(markerNumbers=[m0, m1], constrainedAxes=[1, 1, 1, 1, 1, 0], **rotations))
 65    mbs.AddLoad(LoadForceVector(markerNumber=mbs.AddMarker(MarkerBodyPosition(bodyNumber=body, localPosition=[0.2, 0, 0])),
 66                                loadVector=[0, -10, 5]))
 67    mbs.Assemble()
 68
 69    simulationSettings = exu.SimulationSettings()
 70    simulationSettings.timeIntegration.newton.useModifiedNewton = False #Just for the test; modified Newton is usually faster
 71    simulationSettings.timeIntegration.numberOfSteps = 200
 72    simulationSettings.timeIntegration.endTime = 0.2
 73    simulationSettings.timeIntegration.verboseMode = 0
 74    simulationSettings.solution.file.write = False
 75    mbs.SolveDynamic(simulationSettings)
 76    return np.array(mbs.GetNodeOutput(node, exu.OutputVariableType.Coordinates))
 77
 78errors = 0
 79u = 0.
 80#the same motion with the rotation in the markers and in the deprecated parameters; only the latter is recorded
 81for connector in [False, True]:
 82    used = ItemUses()
 83    qLocalHT = Simulate(True, connector)
 84    if ItemUses() != used:
 85        errors += 1
 86    qRotationMarker = Simulate(False, connector)
 87    if ItemUses() != used + 2: #rotationMarker0 and rotationMarker1
 88        errors += 1
 89    exu.Print('connector' if connector else 'joint', ': difference localHT - rotationMarker =', np.linalg.norm(qLocalHT - qRotationMarker))
 90    if np.linalg.norm(qLocalHT - qRotationMarker) > 1e-10:
 91        errors += 1
 92    u += np.sum(qLocalHT)
 93
 94#the warning: at the line that adds the item, once per session and name, or on every use
 95deprecations = exu.special.deprecations
 96warnOnceStored = deprecations.warnOnce
 97SC = exu.SystemContainer()
 98mbs = SC.AddSystem()
 99(oGround, node, body) = Model(mbs)
100m0 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround))
101m1 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=body, localPosition=[-0.2, 0, 0]))
102nWarnings = []
103for warnOnce in [True, False]:
104    deprecations.warnOnce = warnOnce
105    deprecations.Reset() #as if the session had just started
106    with warnings.catch_warnings(record=True) as caught:
107        warnings.simplefilter('always')
108        for i in range(3):
109            mbs.AddObject(GenericJoint(markerNumbers=[m0, m1], constrainedAxes=[0]*6, rotationMarker0=A0))
110    found = [entry for entry in caught if issubclass(entry.category, DeprecationWarning)]
111    nWarnings.append(len(found))
112    if any('ObjectJointGeneric: the parameter rotationMarker0' not in str(entry.message)
113           or os.sep + 'exudyn' + os.sep in entry.filename for entry in found):
114        errors += 1 #the message names item and parameter, the warning points at this script, not into Exudyn
115deprecations.warnOnce = warnOnceStored
116exu.Print('warnings, once per session and on every use:', nWarnings)
117if nWarnings != [1, 3]:
118    errors += 1
119
120#GetJointArgs turns a copy of the existing marker instead of passing rotationMarker0 on
121used = ItemUses()
122args = GetJointArgs(mbs, markerNumber0=m0, rotationMarker0=A0, bodyNumber1=body)
123mbs.AddObject(RevoluteJointZ(**args))
124if ItemUses() != used or 'rotationMarker0' in args:
125    errors += 1
126
127exu.Print('rotationMarkerDeprecationTest: errors', errors)
128u += errors
129exu.Print('solution of rotationMarkerDeprecationTest=', u)
130
131exu.sys['testResult'] = u