typeInformationTest.py

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

  1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2# This is an EXUDYN example
  3#
  4# Details:  Test of exudyn.types: the generated type information agrees
  5#           with the C++ module (enum values, item parameters), and the query functions agree with
  6#           mbs.Assemble() for marker/object and connector/marker combinations that are built here.
  7#           The result is the number of disagreements (0).
  8#
  9# Author:   Johannes Gerstmayr, Claude-JG
 10# Date:     2026-09-15
 11#
 12# 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.
 13#
 14#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 15
 16import exudyn as exu
 17import exudyn.itemInterface as itemInterface
 18import exudyn.types as types
 19import contextlib
 20import inspect
 21import io
 22
 23testIsActive = exu.sys.get('testIsActive', False)
 24
 25errors = 0
 26def Check(condition, text):
 27    global errors
 28    if not condition:
 29        errors += 1
 30        exu.Print('typeInformationTest: ' + text)
 31
 32#++++++++++++++++++++++++++++++++++++++++++++++++++
 33#data agrees with the C++ module and itemInterface.py
 34enumNames = {'Node': set(exu.NodeType.__members__), 'Marker': set(exu.MarkerType.__members__)}
 35for name in types.ItemNames():
 36    info = types.ItemInfo(name)
 37    if info['kind'] in enumNames:
 38        Check(set(info['types']) <= enumNames[info['kind']], name + ': unknown type bits ' + str(info['types']))
 39    for key in ('requestedNodeTypes', 'requestedMarkerTypes'):
 40        kind = 'Node' if key == 'requestedNodeTypes' else 'Marker'
 41        Check(set(info.get(key, [])) <= enumNames[kind], name + ': unknown ' + key)
 42    Check(set(info.get('accessFunctionTypes', [])) <= set(exu.AccessFunctionType.__members__),
 43          name + ': unknown access function types')
 44    signature = inspect.signature(getattr(itemInterface, name)).parameters
 45    #the class also takes the old names of renamed parameters, as its last keywords (#2589)
 46    Check(set(types.Parameters(name)) == set(signature) - {'visualization'} - set(info.get('deprecatedParameters', {})),
 47          name + ': parameters differ from itemInterface.py')
 48    Check(set(info['visualization']) == set(signature['visualization'].default),
 49          name + ': visualization parameters differ from itemInterface.py')
 50
 51#++++++++++++++++++++++++++++++++++++++++++++++++++
 52#queries agree with mbs.Assemble(): markers on bodies, connectors on markers
 53def AssembleWorks(Build):
 54    SC = exu.SystemContainer()
 55    mbs = SC.AddSystem()
 56    printToConsole = exu.config.printToConsole
 57    exu.config.printToConsole = False
 58    try:
 59        with contextlib.redirect_stdout(io.StringIO()):
 60            Build(mbs)
 61            mbs.Assemble()
 62        return True
 63    except Exception:
 64        return False
 65    finally:
 66        exu.config.printToConsole = printToConsole
 67
 68def AddBody(mbs, objectName):
 69    if objectName == 'ObjectMassPoint':
 70        n = mbs.AddNode(itemInterface.NodePoint())
 71        return mbs.AddObject(itemInterface.ObjectMassPoint(mass=1, nodeNumber=n))
 72    if objectName == 'ObjectRigidBody':
 73        n = mbs.AddNode(itemInterface.NodeRigidBodyEP(referenceCoordinates=[0,0,0, 1,0,0,0]))
 74        return mbs.AddObject(itemInterface.ObjectRigidBody(mass=1, inertia=[1,1,1,0,0,0], nodeNumber=n))
 75    return mbs.AddObject(itemInterface.ObjectGround())
 76
 77markerBuilders = {'MarkerBodyPosition': lambda b: itemInterface.MarkerBodyPosition(bodyNumber=b),
 78                  'MarkerBodyRigid': lambda b: itemInterface.MarkerBodyRigid(bodyNumber=b),
 79                  'MarkerBodyMass': lambda b: itemInterface.MarkerBodyMass(bodyNumber=b)}
 80
 81for objectName in ['ObjectMassPoint', 'ObjectRigidBody', 'ObjectGround']:
 82    for markerName, MarkerBuilder in markerBuilders.items():
 83        expected = markerName in types.MarkersForObject(objectName)
 84        works = AssembleWorks(lambda mbs: mbs.AddMarker(MarkerBuilder(AddBody(mbs, objectName))))
 85        Check(expected == works, markerName + ' on ' + objectName + ': query ' + str(expected) + ', Assemble ' + str(works))
 86        Check((objectName in types.ObjectsForMarker(markerName)) == expected, markerName + ': ObjectsForMarker inconsistent')
 87
 88connectorBuilders = {'ObjectConnectorSpringDamper': lambda m: itemInterface.ObjectConnectorSpringDamper(markerNumbers=m, stiffness=1),
 89                     'ObjectConnectorRigidBodySpringDamper': lambda m: itemInterface.ObjectConnectorRigidBodySpringDamper(markerNumbers=m),
 90                     'ObjectJointSpherical': lambda m: itemInterface.ObjectJointSpherical(markerNumbers=m)}
 91for markerName in ['MarkerBodyPosition', 'MarkerBodyRigid']:
 92    for connectorName, ConnectorBuilder in connectorBuilders.items():
 93        expected = connectorName in types.ConnectorsForMarkers(markerName)
 94        def Build(mbs):
 95            m0 = mbs.AddMarker(markerBuilders[markerName](AddBody(mbs, 'ObjectGround')))
 96            m1 = mbs.AddMarker(markerBuilders[markerName](AddBody(mbs, 'ObjectRigidBody')))
 97            mbs.AddObject(ConnectorBuilder([m0, m1]))
 98        works = AssembleWorks(Build)
 99        Check(expected == works, connectorName + ' on two ' + markerName + ': query ' + str(expected) + ', Assemble ' + str(works))
100
101Check('NodeRigidBodyEP' in types.NodesForObject('ObjectRigidBody') and
102      'NodePoint' not in types.NodesForObject('ObjectRigidBody'), 'NodesForObject(ObjectRigidBody)')
103Check('LoadForceVector' in types.LoadsForMarker('MarkerBodyPosition') and
104      'LoadTorqueVector' not in types.LoadsForMarker('MarkerBodyPosition'), 'LoadsForMarker(MarkerBodyPosition)')
105
106exu.Print('typeInformationTest: ' + str(len(types.ItemNames())) + ' items, ' + str(errors) + ' disagreements')
107exu.sys['testResult'] = errors