(sec-module-basicutilities)= # Module: basicUtilities Basic utility functions and constants; they depend on numpy only, not on exudyn. - **Author**: Johannes Gerstmayr - **Date**: 2020-03-10 (created) - **Notes**: Additional constants are defined: pi = 3.1415926535897932 sqrt2 = 2**0.5 g=9.81 Two variables 'gaussIntegrationPoints' and 'gaussIntegrationWeights' define integration points and weights for function GaussIntegrate(...) (sec-basicutilities-clearworkspace)= ## Function: ClearWorkspace [`ClearWorkspace()`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L44) - **function description**: clear all workspace variables except for system variables with '_' at beginning, 'func' or 'module' in name; it also deletes all items in exudyn.sys and exudyn.variables, EXCEPT from exudyn.sys['renderState'] for pertaining the previous view of the renderer - **notes**: Use this function with CARE! In Spyder, it is certainly safer to add the preference Run$\ra$'remove all variables before execution'. It is recommended to call ClearWorkspace() at the very beginning of your models, to avoid that variables still exist from previous computations which may destroy repeatability of results *example*: ```python import exudyn as exu import exudyn.utilities #clear workspace at the very beginning, before loading other modules and potentially destroying unwanted things ... ClearWorkspace() #cleanup #now continue with other code from exudyn.itemInterface import * SC = exu.SystemContainer() mbs = SC.AddSystem() ... ``` Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`springDamperUserFunctionNumbaJIT.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/springDamperUserFunctionNumbaJIT.py) (Ex), [`ACFtest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/ACFtest.py) (TM) (sec-basicutilities-smartround2string)= ## Function: SmartRound2String [`SmartRound2String(x, prec = 3)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L94) - **function description**: round to max number of digits; may give more digits if this is shorter; using in general the format() with '.g' option, but keeping decimal point and using exponent where necessary (sec-basicutilities-normalize)= ## Function: Normalize [`Normalize(v)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L106) - **function description**: take a vector and return it normalized to L2-norm 1; a zero vector is returned as zero vector - **input**: vector v as list or in numpy format - **output**: list: v multiplied with a scalar such that its L2-norm is 1, or the zero vector; a list, as callers append the result to lists of normals Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`contactCurveWithLongCurve.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/contactCurveWithLongCurve.py) (Ex), [`NGsolveCMStutorial.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/NGsolveCMStutorial.py) (Ex), [`NGsolveGeometry.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/NGsolveGeometry.py) (Ex), [`NGsolvePistonEngine.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/NGsolvePistonEngine.py) (Ex), [`ObjectFFRFconvergenceTestHinge.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/ObjectFFRFconvergenceTestHinge.py) (Ex) (sec-basicutilities-gaussintegrate)= ## Function: GaussIntegrate [`GaussIntegrate(functionOfX, integrationOrder, a, b)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L138) - **function description**: compute numerical integration of functionOfX in interval [a,b] using Gaussian integration - **input**: - `functionOfX`: scalar, vector or matrix-valued function with scalar argument (X or other variable) - `integrationOrder`: odd number in {1,3,5,7,9}; currently maximum order is 9 - `a`: integration range start - `b`: integration range end - **output**: (scalar or vectorized) integral value (sec-basicutilities-lobattointegrate)= ## Function: LobattoIntegrate [`LobattoIntegrate(functionOfX, integrationOrder, a, b)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L178) - **function description**: compute numerical integration of functionOfX in interval [a,b] using Lobatto integration - **input**: - `functionOfX`: scalar, vector or matrix-valued function with scalar argument (X or other variable) - `integrationOrder`: odd number in {1,3,5}; currently maximum order is 5 - `a`: integration range start - `b`: integration range end - **output**: (scalar or vectorized) integral value (sec-basicutilities-getothermarker)= ## Function: GetOtherMarker [`GetOtherMarker(mbs, bodyNumber, existingMarker, show = True)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L211) - **function description**: creates a new marker for body with bodyNumber using another marker existingMarker, such that the new marker has the same reference position as the existing marker, working for MarkerBodyPosition (no rotations included); this alleviates creation of markers and calculation of localPosition - **input**: - `mbs`: multibody system where new marker is added to - `bodyNumber`: body where new marker shall be attached to - `existingMarker`: marker number which serves as a reference - `show`: if True, marker is shown - **output**: returns marker number of new marker *example*: ```python #oBody0 = mbs.CreateRigidBody(...) #oBody1 = mbs.CreateRigidBody(...) marker0 = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oBody0,localPosition=[1,0,0])) #create joint from one marker (with rotation) and other body mbs.AddObject(SphericalJoint(markerNumbers=[marker0, GetOtherMarker(mbs, oBody1, marker0)])) ``` Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`NGsolveFFRF.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/NGsolveFFRF.py) (Ex) (sec-basicutilities-getjointargs)= ## Function: GetJointArgs [`GetJointArgs(mbs, markerNumber0 = None, markerNumber1 = None, rotationMarker0 = None, rotationMarker1 = None, bodyNumber0 = None, bodyNumber1 = None)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L248) - **function description**: creates input args for joints, based on an exiting marker (markerNumber, may be rigid or flex body), with optional existing rotationMarker and uses another rigid body (given as bodyNumber) to create a new MarkerBodyRigid and rotationMarker; this alleviates creation of joint args, see the example; inputs are either markerNumber0 [, rotationMarker0], bodyNumber1 OR markerNumber1 [, rotationMarker1], bodyNumber0 - **input**: - `mbs`: multibody system where new marker is added to - `markerNumber0`: markerNumber of existing rigid body marker - `markerNumber1`: markerNumber of existing rigid body marker - `rotationMarker0`: rotation of the joint frame relative to the frame of markerNumber0; the joint then takes a copy of the marker turned by it - `rotationMarker1`: the same for markerNumber1 - `bodyNumber0`: existing body used to create new marker - `bodyNumber1`: existing body used to create new marker - **output**: returns dict with the 'markerNumbers' list, ready to be used as args; the new marker carries the joint's rotation as its localHT; for a rotationMarker0/1 given, the existing marker is replaced by a copy turned by it *example*: ```python #oBody0 = mbs.CreateRigidBody(...) #oBody1 = mbs.CreateRigidBody(...) marker0 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oBody0, localHT=exu.HT(rotation=RotationMatrixX(0.5*pi), translation=[1,0,0]))) #create joint from one marker (with rotation) and other body mbs.AddObject(RevoluteJointZ(**GetJointArgs(mbs, markerNumber0=marker0, bodyNumber1=oBody1) ``` Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`jointArgsTest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/jointArgsTest.py) (TM), [`rotationMarkerDeprecationTest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/rotationMarkerDeprecationTest.py) (TM) (sec-basicutilities-showonlyobjects)= ## Function: ShowOnlyObjects [`ShowOnlyObjects(mbs, objectNumbers = [], showOthers = False)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L321) - **function description**: function to hide all objects in mbs except for those listed in objectNumbers - **input**: - `mbs`: mbs containing object - `objectNumbers`: integer object number or list of object numbers to be shown; if empty list [], then all objects are shown - `showOthers`: if True, then all other objects are shown again - **output**: changes all colors in mbs, which is NOT reversible (sec-basicutilities-highlightitem)= ## Function: HighlightItem [`HighlightItem(SC, mbs, itemNumber, itemType = exudyn.ItemType.Object, showNumbers = True)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L349) - **function description**: highlight a certain item with number itemNumber; set itemNumber to -1 to show again all objects - **input**: - `mbs`: mbs containing object - `itemNumbers`: integer object/node/etc number to be highlighted - `itemType`: type of items to be highlighted - `showNumbers`: if True, then the numbers of these items are shown (sec-basicutilities-ufsensorrecord)= ## Function: UFsensorRecord [`UFsensorRecord(mbs, t, sensorNumbers, factors, configuration)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L392) - **function description**: Internal SensorUserFunction of the deprecated function AddSensorRecorder - **notes**: Warning: this method is DEPRECATED, use storeInternal in Sensors, which is much more performant; Note, that a sensor usually just passes through values of an existing sensor, while recording the values to a numpy array row-wise (time in first column, data in remaining columns) (sec-basicutilities-addsensorrecorder)= ## Function: AddSensorRecorder [`AddSensorRecorder(mbs, sensorNumber, endTime, sensorsWritePeriod, sensorOutputSize = 3)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L411) - **function description**: DEPRECATED: Add a SensorUserFunction object in order to record sensor output internally; this avoids creation of files for sensors, which can speedup and simplify evaluation in ParameterVariation and GeneticOptimization; values are stored internally in mbs.variables['sensorRecord'+str(sensorNumber)] where sensorNumber is the mbs sensor number - **input**: - `mbs`: mbs containing object - `sensorNumber`: integer sensor number to be recorded - `endTime`: end time of simulation, as given in simulationSettings.timeIntegration.endTime - `sensorsWritePeriod`: as given in simulationSettings.solution.sensors.writePeriod - `sensorOutputSize`: size of sensor data: 3 for Displacement, Position, etc. sensors; may be larger for RotationMatrix or Coordinates sensors; check this size by calling mbs.GetSensorValues(sensorNumber) - **output**: adds an according SensorUserFunction sensor to mbs; returns new sensor number; during initialization a new numpy array is allocated in mbs.variables['sensorRecord'+str(sensorNumber)] and the information is written row-wise: [time, sensorValue1, sensorValue2, ...] - **notes**: Warning: this method is DEPRECATED, use storeInternal in Sensors, which is much more performant; Note, that a sensor usually just passes through values of an existing sensor, while recording the values to a numpy array row-wise (time in first column, data in remaining columns) Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`ComputeSensitivitiesExample.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/ComputeSensitivitiesExample.py) (Ex) (sec-basicutilities-uiwindowsuppressed)= ## Function: UIWindowSuppressed [`UIWindowSuppressed(kind, callerInfo = '')`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L441) - **function description**: ask exudyn.special.userInterface whether this kind of window must not open (#2477) - **input**: - `kind`: one of 'Renderer', 'SolutionViewer', 'Plots', 'Dialogs'; the name of the flag without the 'suppress' prefix - `callerInfo`: name of the calling function, shown in the notice - **output**: True if the window must not be opened - **notes**: The flags are set for automated runs - test runners, CI, AI-assisted development - where a window that waits for a human stops everything. A suppressed call is a silent no-op, except that the FIRST suppression of each kind prints one line, so that a window-less session is never a mystery. *example*: ```python if UIWindowSuppressed('Plots', 'PlotSensor'): return plt ``` (sec-basicutilities-outputfilepath)= ## Function: OutputFilePath [`OutputFilePath(fileName, callerInfo = '')`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L469) - **function description**: merge a local file name with the global exudyn.config.outputDirectory, exactly as the solver does when it writes solution, sensor, image and print files (#2454) - **input**: - `fileName`: file name as given by the user or stored in a sensor or in the simulation settings - `callerInfo`: name of the calling function, used in the error message - **output**: fileName unchanged if exudyn.config.outputDirectory is empty, otherwise the merged path - **notes**: The rule in Exudyn is: everything WRITTEN as output of a run follows exudyn.config.outputDirectory, and a file is READ from there only if its name comes from Exudyn itself - the simulation settings (SolutionViewer) or a sensor definition (PlotSensor). A file name that you pass to a function such as LoadSolutionFile is read exactly as given; wrap it in OutputFilePath(...) yourself if you want the output directory. Model data (mesh import, FEMinterface/ObjectFFRFreducedOrderInterface SaveToFile and LoadFromFile, SaveDictToHDF5/LoadDictFromHDF5) is never redirected. *example*: ```python exudyn.config.outputDirectory = 'run17' OutputFilePath('solution/sensor.txt') #'run17/solution/sensor.txt' ``` Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`ANCFALEtest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/ANCFALEtest.py) (Ex), [`beltDriveALE.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/beltDriveALE.py) (Ex), [`beltDriveReevingSystem.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/beltDriveReevingSystem.py) (Ex), [`beltDrivesComparison.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/beltDrivesComparison.py) (Ex), [`bicycleIftommBenchmark.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/bicycleIftommBenchmark.py) (Ex), [`abaqusImportTest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/abaqusImportTest.py) (TM), [`binarySolutionFileTest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/binarySolutionFileTest.py) (TM), [`compareFullModifiedNewton.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/compareFullModifiedNewton.py) (TM), ... (sec-basicutilities-createdirectoryforfile)= ## Function: CreateDirectoryForFile [`CreateDirectoryForFile(fileName)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L511) - **function description**: create the directory a file is going to be written into, if it does not exist yet - **input**: - `fileName`: file name including its path; a name without any path is left alone - **output**: fileName unchanged, so that the call can wrap the file name at the point of use - **notes**: Every Exudyn function that writes a file calls this first, so that a path such as 'solution/sensor.txt' - or anything under exudyn.config.outputDirectory - works without the caller having to create the directory. Failure is deliberately ignored: creating a directory can fail for reasons that do not stop the write (a read-only parent on a network share, a race with another process that just created it), and the write itself reports the real problem with a better message (#2493). (sec-basicutilities-loadsolutionfile)= ## Function: LoadSolutionFile [`LoadSolutionFile(fileName, safeMode = False, maxRows = -1, verbose = True, hasHeader = True)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L538) - **function description**: read coordinates solution file (exported during static or dynamic simulation with option exu.SimulationSettings().solution.file.name='...') into dictionary: - **input**: - `fileName`: string containing directory and filename of stored coordinatesSolutionFile - `saveMode`: if True, it loads lines directly to load inconsistent lines as well; use this for huge files (>2GB); is slower but needs less memory! - `verbose`: if True, some information is written when importing file (use for huge files to track progress) - `maxRows`: maximum number of data rows loaded, if saveMode=True; use this for huge files to reduce loading time; set -1 to load all rows - `hasHeader`: set to False, if file is expected to have no header; if False, then some error checks related to file header are not performed - **output**: dictionary with 'data': the matrix of stored solution vectors, 'columnsExported': a list with integer values showing the exported sizes [nODE2, nVel2, nAcc2, nODE1, nVel1, nAlgebraic, nData], 'nColumns': the number of data columns and 'nRows': the number of data rows Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`beltDriveALE.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/beltDriveALE.py) (Ex), [`beltDriveReevingSystem.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/beltDriveReevingSystem.py) (Ex), [`beltDrivesComparison.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/beltDrivesComparison.py) (Ex), [`fourBarMechanism3D.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/fourBarMechanism3D.py) (Ex), [`kinematicTreeAndMBS.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/kinematicTreeAndMBS.py) (Ex), [`ACFtest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/ACFtest.py) (TM), [`ANCFbeltDrive.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/ANCFbeltDrive.py) (TM), [`ANCFgeneralContactCircle.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/ANCFgeneralContactCircle.py) (TM), ... (sec-basicutilities-numpyint8arraytostring)= ## Function: NumpyInt8ArrayToString [`NumpyInt8ArrayToString(npArray)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L676) - **function description**: simple conversion of int8 arrays into strings (not highly efficient, so use only for short strings) (sec-basicutilities-binaryreadindex)= ## Function: BinaryReadIndex [`BinaryReadIndex(file, intType)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L685) - **function description**: read single Index from current file position in binary solution file (sec-basicutilities-binaryreadreal)= ## Function: BinaryReadReal [`BinaryReadReal(file, realType)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L693) - **function description**: read single Real from current file position in binary solution file (sec-basicutilities-binaryreadstring)= ## Function: BinaryReadString [`BinaryReadString(file, intType)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L701) - **function description**: read string from current file position in binary solution file (sec-basicutilities-binaryreadarrayindex)= ## Function: BinaryReadArrayIndex [`BinaryReadArrayIndex(file, intType)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L709) - **function description**: read Index array from current file position in binary solution file (sec-basicutilities-binaryreadrealvector)= ## Function: BinaryReadRealVector [`BinaryReadRealVector(file, intType, realType)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L717) - **function description**: read Real vector from current file position in binary solution file - **output**: return data as numpy array, or False if no data read (sec-basicutilities-loadbinarysolutionfile)= ## Function: LoadBinarySolutionFile [`LoadBinarySolutionFile(fileName, maxRows = -1, verbose = True)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L731) - **function description**: read BINARY coordinates solution file (exported during static or dynamic simulation with option exu.SimulationSettings().solution.file.name='...') into dictionary - **input**: - `fileName`: string containing directory and filename of stored coordinatesSolutionFile - `verbose`: if True, some information is written when importing file (use for huge files to track progress) - `maxRows`: maximum number of data rows loaded, if saveMode=True; use this for huge files to reduce loading time; set -1 to load all rows - **output**: dictionary with 'data': the matrix of stored solution vectors, 'columnsExported': a list with integer values showing the exported sizes [nODE2, nVel2, nAcc2, nODE1, nVel1, nAlgebraic, nData], 'nColumns': the number of data columns and 'nRows': the number of data rows (sec-basicutilities-recoversolutionfile)= ## Function: RecoverSolutionFile [`RecoverSolutionFile(fileName, newFileName, verbose = 0)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L916) - **function description**: recover solution file with last row not completely written (e.g., if crashed, interrupted or no flush file option set) - **input**: - `fileName`: string containing directory and filename of stored coordinatesSolutionFile - `newFileName`: string containing directory and filename of new coordinatesSolutionFile - `verbose`: 0=no information, 1=basic information, 2=information per row - **output**: writes only consistent rows of file to file with name newFileName (sec-basicutilities-setsolutionstate)= ## Function: SetSolutionState [`SetSolutionState(mbs, solution, row, configuration = exudyn.ConfigurationType.Current, sendRedrawSignal = True)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L975) - **function description**: load selected row of solution dictionary (previously loaded with LoadSolutionFile) into specific state; flag sendRedrawSignal is only used if configuration = exudyn.ConfigurationType.Visualization (sec-basicutilities-animatesolution)= ## Function: AnimateSolution [`AnimateSolution(mbs, solution, rowIncrement = 1, timeout = 0.04, createImages = False, runLoop = False)`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/exudyn/basicUtilities.py#L1001) - **function description**: This function is not further maintaned and should only be used if you do not have tkinter (like on some MacOS versions); use exudyn.interactive.SolutionViewer() instead! AnimateSolution consecutively load the rows of a solution file and visualize the result - **input**: - `mbs`: the system used for animation - `solution`: solution dictionary previously loaded with LoadSolutionFile; will be played from first to last row - `rowIncrement`: can be set larger than 1 in order to skip solution frames: e.g. rowIncrement=10 visualizes every 10th row (frame) - `timeout`: in seconds is used between frames in order to limit the speed of animation; e.g. use timeout=0.04 to achieve approximately 25 frames per second - `createImages`: creates consecutively images from the animation, which can be converted into an animation - `runLoop`: if True, the animation is played in a loop until 'q' is pressed in render window - **output**: renders the scene in mbs and changes the visualization state in mbs continuously Relevant Examples (Ex) and TestModels (TM) with weblink to github: [`NGsolvePistonEngine.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/NGsolvePistonEngine.py) (Ex), [`SliderCrank.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/SliderCrank.py) (Ex), [`slidercrankWithMassSpring.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/Examples/slidercrankWithMassSpring.py) (Ex), [`sliderCrankFloatingTest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/sliderCrankFloatingTest.py) (TM)