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