(testmodels-connectoroutputvariablestest)= # connectorOutputVariablesTest.py You can view and download this file on Github: [connectorOutputVariablesTest.py](https://github.com/jgerstmayr/EXUDYN/tree/master/python/TestModels/connectorOutputVariablesTest.py) ```{code-block} python :linenos: #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # This is an EXUDYN example # # Details: Reading the output variables of connectors and joints (#2735), and what happens with one an # item does not declare: # (1) ObjectContactCoordinate: a 1D mass resting on a stop; Distance is the gap, negative in # contact, and the contact force holds the mass; with activeConnector=False the mass falls # through the stop; # (2) ObjectJointRevolute2D: the Displacement between the two joint points stays zero; # (3) ObjectJointPrismatic2D with the rotation constrained: Distance along the axis (the axis # need not be normalized) and Rotation, which stays zero; # (4) ObjectJointPrismatic2D with the rotation free: Rotation is the rotation of the body # relative to the ground; # (5) an output variable that an item does not declare raises an exception - Rotation of # ObjectJointRevolute2D, and ObjectContactCircleCable2D, which declares none. # # Author: Johannes Gerstmayr # Date: 2026-10-01 # # 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. # #+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import exudyn as exu from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities from exudyn.beams import GenerateBeamElementsAlongLine import numpy as np testIsActive = exu.sys.get('testIsActive', False) OV = exu.OutputVariableType simulationSettings = exu.SimulationSettings() simulationSettings.timeIntegration.newton.useModifiedNewton = False #Just for the test; modified Newton is usually faster testResult = 0 def ContactCoordinate(activeConnector): """a 1D mass at 0.1 above a stop, pushed down by 10 N; returns the system, the node and the contact""" SC = exu.SystemContainer() mbs = SC.AddSystem() nGround = mbs.AddNode(NodePointGround()) node = mbs.AddNode(Node1D(referenceCoordinates=[0], initialCoordinates=[0.1])) mbs.AddObject(ObjectMass1D(nodeNumber=node, mass=1)) mCoordinate = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber=node, coordinate=0)) mGround = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber=nGround, coordinate=0)) nData = mbs.AddNode(NodeGenericData(numberOfDataCoordinates=1, initialCoordinates=[0.1])) oContact = mbs.AddObject(ObjectContactCoordinate(markerNumbers=[mGround, mCoordinate], nodeNumber=nData, contactStiffness=1e4, contactDamping=100, activeConnector=activeConnector)) mbs.AddLoad(LoadCoordinate(markerNumber=mCoordinate, load=-10)) mbs.Assemble() mbs.SolveDynamic(simulationSettings) return (mbs, node, oContact) #(1) contact: at rest on the stop, the gap is the coordinate (stop at 0, no offset): -F/k = -1e-3 (mbs, node, oContact) = ContactCoordinate(True) q = mbs.GetNodeOutput(node, OV.Coordinates) #a float for a node with one coordinate gap = mbs.GetObjectOutput(oContact, OV.Distance) exu.Print('contact: coordinate', q, ', gap', gap, '(both -1e-3 at rest)') testResult += q + gap (mbs, node, oContact) = ContactCoordinate(False) q = mbs.GetNodeOutput(node, OV.Coordinates) #a float for a node with one coordinate exu.Print('inactive contact: coordinate', q, '(falls freely: 0.1 - F/(2m) t^2 = -4.9)') testResult += q def Planar(addJoint): """a planar rigid body joined to the ground by addJoint(mbs, mGround, mBody), pushed by a force and a torque""" SC = exu.SystemContainer() mbs = SC.AddSystem() oGround = mbs.AddObject(ObjectGround()) node = mbs.AddNode(NodeRigidBody2D(referenceCoordinates=[0, 0, 0])) body = mbs.AddObject(ObjectRigidBody2D(nodeNumber=node, mass=2, inertia=0.1)) mGround = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround)) mBody = mbs.AddMarker(MarkerBodyRigid(bodyNumber=body)) oJoint = addJoint(mbs, mGround, mBody) mbs.AddLoad(LoadForceVector(markerNumber=mBody, loadVector=[2, 1, 0])) mbs.AddLoad(LoadTorqueVector(markerNumber=mBody, loadVector=[0, 0, 0.1])) mbs.Assemble() mbs.SolveDynamic(simulationSettings) return (mbs, node, oJoint) #(2) revolute joint: the joint points stay together (mbs, node, oRevolute) = Planar(lambda mbs, m0, m1: mbs.AddObject(ObjectJointRevolute2D(markerNumbers=[m0, m1]))) displacement = mbs.GetObjectOutput(oRevolute, OV.Displacement) exu.Print('revolute joint: displacement', displacement) testResult += np.linalg.norm(displacement) #(3) prismatic joint along x with the rotation constrained: x = F_x/(2m) t^2 = 0.5 at t = 1 (mbs, node, oJoint) = Planar(lambda mbs, m0, m1: mbs.AddObject(ObjectJointPrismatic2D( markerNumbers=[m0, m1], axisMarker0=[2, 0, 0], normalMarker1=[0, 1, 0]))) distance = mbs.GetObjectOutput(oJoint, OV.Distance) rotation = mbs.GetObjectOutput(oJoint, OV.Rotation) exu.Print('prismatic joint, rotation constrained: distance', distance, '(0.5), rotation', rotation) testResult += distance + rotation #(4) prismatic joint with the rotation free: the output Rotation is the rotation of the body (mbs, node, oJoint) = Planar(lambda mbs, m0, m1: mbs.AddObject(ObjectJointPrismatic2D( markerNumbers=[m0, m1], constrainRotation=False))) q = mbs.GetNodeOutput(node, OV.Coordinates) rotation = mbs.GetObjectOutput(oJoint, OV.Rotation) exu.Print('prismatic joint, rotation free: rotation', rotation, '= body rotation', q[2]) testResult += rotation + mbs.GetObjectOutput(oJoint, OV.Distance) #(5) an output variable the item does not declare raises refused = 0 (mbs, node, oRevolute) = Planar(lambda mbs, m0, m1: mbs.AddObject(ObjectJointRevolute2D(markerNumbers=[m0, m1]))) try: mbs.GetObjectOutput(oRevolute, OV.Rotation) except Exception as error: exu.Print('refused:', str(error).split(' [Python file')[0]) refused += 1 SC = exu.SystemContainer() mbs = SC.AddSystem() oGround = mbs.AddObject(ObjectGround()) beamInfo = GenerateBeamElementsAlongLine(mbs, positionStart=[0, 0, 0], positionEnd=[1, 0, 0], numberOfElements=1, beamTemplate=ObjectANCFCable2D(massPerLength=1, bendingStiffness=1, axialStiffness=100), groundConstraintsStart=[1, 1, 1, 1]) nodes, elements, *_ = beamInfo['nodes'], beamInfo['elements'], beamInfo['loads'] mCircle = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oGround, localPosition=[0.5, -1, 0])) mShape = mbs.AddMarker(MarkerBodyCable2DShape(bodyNumber=elements[0], numberOfSegments=2)) nData = mbs.AddNode(NodeGenericData(numberOfDataCoordinates=2, initialCoordinates=[0.1, 0.1])) oContactCable = mbs.AddObject(ObjectContactCircleCable2D(markerNumbers=[mCircle, mShape], nodeNumber=nData, numberOfContactSegments=2, circleRadius=0.1, contactStiffness=1e3)) mbs.Assemble() try: mbs.GetObjectOutput(oContactCable, OV.Distance) except Exception as error: exu.Print('refused:', str(error).split(' [Python file')[0]) refused += 1 testResult += refused exu.Print('solution of connectorOutputVariablesTest=', testResult) exu.sys['testResult'] = testResult ```