simulationSettingsRenamesTest.py
You can view and download this file on Github: simulationSettingsRenamesTest.py
1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2# This is an EXUDYN example
3#
4# Details: The simulation settings renamed and restructured in Exudyn 1.13 (#2813): every old name still works,
5# with a DeprecationWarning, and reaches its new place - written under the old name, read under the
6# new one, and the other way round; every use is counted in exu.sys['deprecationUse']; the old keys of
7# a dictionary given to SetDictionary reach their new place too. The list of
8# names is checked against the declarations by python/testing/test_checkDeprecations.py, so that it
9# cannot miss one.
10#
11# Author: Johannes Gerstmayr
12# Date: 2026-10-04
13#
14# 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.
15#
16#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
17
18import exudyn as exu
19import warnings
20
21testIsActive = exu.sys.get('testIsActive', False)
22
23#old name -> new name, both from simulationSettings
24renames = {
25 'solutionSettings.coordinatesSolutionFileName': 'solution.file.name',
26 'solutionSettings.writeSolutionToFile': 'solution.file.write',
27 'solutionSettings.writeFileHeader': 'solution.file.writeHeader',
28 'solutionSettings.writeFileFooter': 'solution.file.writeFooter',
29 'solutionSettings.writeInitialValues': 'solution.file.writeInitialValues',
30 'solutionSettings.solutionWritePeriod': 'solution.file.writePeriod',
31 'solutionSettings.binarySolutionFile': 'solution.file.binary',
32 'solutionSettings.appendToFile': 'solution.file.append',
33 'solutionSettings.flushFilesImmediately': 'solution.flushFilesImmediately',
34 'solutionSettings.flushFilesDOF': 'solution.file.flushAboveCoordinates',
35 'solutionSettings.exportAccelerations': 'solution.file.export.accelerations',
36 'solutionSettings.exportAlgebraicCoordinates': 'solution.file.export.algebraicCoordinates',
37 'solutionSettings.exportDataCoordinates': 'solution.file.export.dataCoordinates',
38 'solutionSettings.exportODE1Velocities': 'solution.file.export.ODE1Velocities',
39 'solutionSettings.exportVelocities': 'solution.file.export.velocities',
40 'solutionSettings.outputPrecision': 'solution.precision',
41 'solutionSettings.writeRestartFile': 'solution.restart.write',
42 'solutionSettings.restartFileName': 'solution.restart.name',
43 'solutionSettings.restartWritePeriod': 'solution.restart.writePeriod',
44 'solutionSettings.sensorsAppendToFile': 'solution.sensors.append',
45 'solutionSettings.sensorsWriteFileHeader': 'solution.sensors.writeHeader',
46 'solutionSettings.sensorsWriteFileFooter': 'solution.sensors.writeFooter',
47 'solutionSettings.sensorsWritePeriod': 'solution.sensors.writePeriod',
48 'solutionSettings.sensorsStoreAndWriteFiles': 'solution.sensors.active',
49 'solutionSettings.solutionInformation': 'solution.file.information',
50 'solutionSettings.solverInformationFileName': 'solution.solverInformationFileName',
51 'solutionSettings.recordImagesInterval': 'solution.recordImagesInterval',
52 'linearSolverSettings.pivotThreshold': 'linearSolver.pivotThreshold',
53 'linearSolverSettings.ignoreSingularJacobian': 'linearSolver.ignoreSingularJacobian',
54 'linearSolverSettings.reuseAnalyzedPattern': 'linearSolver.reuseAnalyzedPattern',
55 'linearSolverSettings.showCausingItems': 'linearSolver.showCausingItems',
56 'linearSolverType': 'linearSolver.solverType',
57 'displayComputationTime': 'show.computationTime',
58 'displayGlobalTimers': 'show.globalTimers',
59 'displayStatistics': 'show.statistics',
60 'outputPrecision': 'consolePrecision',
61 'timeIntegration.explicitIntegration.dynamicSolverType': 'timeIntegration.solverType',
62 'timeIntegration.explicitIntegration.eliminateConstraints': 'timeIntegration.explicit.eliminateConstraints',
63 'timeIntegration.explicitIntegration.useLieGroupIntegration': 'timeIntegration.explicit.useLieGroupIntegration',
64 'timeIntegration.explicitIntegration.computeEndOfStepAccelerations': 'timeIntegration.explicit.computeEndOfStepAccelerations',
65 'timeIntegration.explicitIntegration.computeMassMatrixInversePerBody': 'timeIntegration.explicit.computeMassMatrixInversePerBody',
66 'timeIntegration.simulateInRealtime': 'timeIntegration.realtime.active',
67 'timeIntegration.realtimeFactor': 'timeIntegration.realtime.factor',
68 'timeIntegration.realtimeWaitMicroseconds': 'timeIntegration.realtime.waitMicroseconds',
69 'timeIntegration.newton.newtonResidualMode': 'timeIntegration.newton.residualMode',
70 'timeIntegration.newton.useNewtonSolver': 'timeIntegration.newton.active',
71 'staticSolver.newton.newtonResidualMode': 'staticSolver.newton.residualMode',
72 'staticSolver.newton.useNewtonSolver': 'staticSolver.newton.active',
73 'timeIntegration.newton.numericalDifferentiation.forODE2connectors': 'timeIntegration.newton.numericalDifferentiation.forODE2Connectors',
74 'staticSolver.constrainODE1coordinates': 'staticSolver.constrainODE1Coordinates',
75 }
76
77def Get(settings, path):
78 for name in path.split('.'):
79 settings = getattr(settings, name)
80 return settings
81
82def Set(settings, path, value):
83 names = path.split('.')
84 for name in names[:-1]:
85 settings = getattr(settings, name)
86 setattr(settings, names[-1], value)
87
88def Other(value):
89 """a value different from the given one, of the same type"""
90 if isinstance(value, bool):
91 return not value
92 if isinstance(value, int):
93 return value + 1
94 if isinstance(value, float):
95 return value * 0.5 + 0.125
96 if isinstance(value, str):
97 return value + 'X'
98 if isinstance(value, exu.DynamicSolverType):
99 return exu.DynamicSolverType.RK44 if value != exu.DynamicSolverType.RK44 else exu.DynamicSolverType.DOPRI5
100 if isinstance(value, exu.LinearSolverType):
101 return exu.LinearSolverType.EigenSparse if value != exu.LinearSolverType.EigenSparse else exu.LinearSolverType.EXUdense
102 raise ValueError('no other value for ' + str(value))
103
104def Uses():
105 return sum(exu.sys.get('deprecationUse', {}).get('simulationSettings', {}).values())
106
107errors = 0
108used = Uses()
109for (old, new) in renames.items():
110 settings = exu.SimulationSettings()
111 with warnings.catch_warnings():
112 warnings.simplefilter('ignore', DeprecationWarning)
113 value = Other(Get(settings, new))
114 Set(settings, old, value) #written under the old name, read under the new one
115 if Get(settings, new) != value:
116 errors += 1
117 exu.Print('simulationSettingsRenamesTest: writing', old, 'does not reach', new)
118 value = Other(value)
119 Set(settings, new, value) #and the other way round
120 if Get(settings, old) != value:
121 errors += 1
122 exu.Print('simulationSettingsRenamesTest: reading', old, 'does not give', new)
123nUses = Uses() - used
124exu.Print('simulationSettingsRenamesTest:', len(renames), 'old names,', nUses, 'uses recorded, errors', errors)
125if nUses != 2 * len(renames):
126 errors += 1
127
128#a dictionary of an earlier Exudyn, given to SetDictionary: each old key reaches its new place, and the keys that are
129#not given keep their values (RG12.34.7)
130def NestedDictionary(path, value):
131 d = value
132 for name in reversed(path.split('.')):
133 d = {name: d}
134 return d
135
136for (old, new) in renames.items():
137 settings = exu.SimulationSettings()
138 settings.timeIntegration.endTime = 7.5 #not in the dictionary: stays
139 value = Other(Get(settings, new))
140 settings.SetDictionary(NestedDictionary(old, value))
141 if Get(settings, new) != value or settings.timeIntegration.endTime != 7.5:
142 errors += 1
143 exu.Print('simulationSettingsRenamesTest: the dictionary key', old, 'does not reach', new)
144
145#the same for the visualization settings, with three of their renamed keys
146SC = exu.SystemContainer()
147SC.visualizationSettings.SetDictionary({'window': {'renderWindowSize': [333, 222]}, 'general': {'drawWorldBasis': True},
148 'openGL': {'light0position': [1., 2., 3., 0.]}})
149visualizationSettings = SC.visualizationSettings
150if (list(visualizationSettings.view0.window.renderWindowSize) != [333, 222] or not visualizationSettings.view0.scene.drawWorldBasis
151 or list(visualizationSettings.openGL.light0.position) != [1., 2., 3., 0.]):
152 errors += 1
153 exu.Print('simulationSettingsRenamesTest: a renamed key of the visualization settings does not reach its new place')
154
155u = len(renames) + errors
156exu.Print('solution of simulationSettingsRenamesTest=', u)
157
158exu.sys['testResult'] = u