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