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(…)

Function: ClearWorkspace

ClearWorkspace()

  • 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:

  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 (Ex), ACFtest.py (TM)

Function: SmartRound2String

SmartRound2String(x, prec = 3)

  • 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

Function: Normalize

Normalize(v)

  • 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 (Ex), NGsolveCMStutorial.py (Ex), NGsolveGeometry.py (Ex), NGsolvePistonEngine.py (Ex), ObjectFFRFconvergenceTestHinge.py (Ex)

Function: GaussIntegrate

GaussIntegrate(functionOfX, integrationOrder, a, b)

  • 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

Function: LobattoIntegrate

LobattoIntegrate(functionOfX, integrationOrder, a, b)

  • 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

Function: GetOtherMarker

GetOtherMarker(mbs, bodyNumber, existingMarker, show = True)

  • 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:

  #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 (Ex)

Function: GetJointArgs

GetJointArgs(mbs, markerNumber0 = None, markerNumber1 = None, rotationMarker0 = None, rotationMarker1 = None, bodyNumber0 = None, bodyNumber1 = None)

  • 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:

  #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 (TM), rotationMarkerDeprecationTest.py (TM)

Function: ShowOnlyObjects

ShowOnlyObjects(mbs, objectNumbers = [], showOthers = False)

  • 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

Function: HighlightItem

HighlightItem(SC, mbs, itemNumber, itemType = exudyn.ItemType.Object, showNumbers = True)

  • 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

Function: UFsensorRecord

UFsensorRecord(mbs, t, sensorNumbers, factors, configuration)

  • 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)

Function: AddSensorRecorder

AddSensorRecorder(mbs, sensorNumber, endTime, sensorsWritePeriod, sensorOutputSize = 3)

  • 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 (Ex)

Function: UIWindowSuppressed

UIWindowSuppressed(kind, callerInfo = '')

  • 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:

  if UIWindowSuppressed('Plots', 'PlotSensor'): return plt

Function: OutputFilePath

OutputFilePath(fileName, callerInfo = '')

  • 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:

  exudyn.config.outputDirectory = 'run17'
  OutputFilePath('solution/sensor.txt') #'run17/solution/sensor.txt'

Relevant Examples (Ex) and TestModels (TM) with weblink to github: ANCFALEtest.py (Ex), beltDriveALE.py (Ex), beltDriveReevingSystem.py (Ex), beltDrivesComparison.py (Ex), bicycleIftommBenchmark.py (Ex), abaqusImportTest.py (TM), binarySolutionFileTest.py (TM), compareFullModifiedNewton.py (TM), …

Function: CreateDirectoryForFile

CreateDirectoryForFile(fileName)

  • 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).

Function: LoadSolutionFile

LoadSolutionFile(fileName, safeMode = False, maxRows = -1, verbose = True, hasHeader = True)

  • 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 (Ex), beltDriveReevingSystem.py (Ex), beltDrivesComparison.py (Ex), fourBarMechanism3D.py (Ex), kinematicTreeAndMBS.py (Ex), ACFtest.py (TM), ANCFbeltDrive.py (TM), ANCFgeneralContactCircle.py (TM), …

Function: NumpyInt8ArrayToString

NumpyInt8ArrayToString(npArray)

  • function description: simple conversion of int8 arrays into strings (not highly efficient, so use only for short strings)

Function: BinaryReadIndex

BinaryReadIndex(file, intType)

  • function description: read single Index from current file position in binary solution file

Function: BinaryReadReal

BinaryReadReal(file, realType)

  • function description: read single Real from current file position in binary solution file

Function: BinaryReadString

BinaryReadString(file, intType)

  • function description: read string from current file position in binary solution file

Function: BinaryReadArrayIndex

BinaryReadArrayIndex(file, intType)

  • function description: read Index array from current file position in binary solution file

Function: BinaryReadRealVector

BinaryReadRealVector(file, intType, realType)

  • 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

Function: LoadBinarySolutionFile

LoadBinarySolutionFile(fileName, maxRows = -1, verbose = True)

  • 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

Function: RecoverSolutionFile

RecoverSolutionFile(fileName, newFileName, verbose = 0)

  • 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

Function: SetSolutionState

SetSolutionState(mbs, solution, row, configuration = exudyn.ConfigurationType.Current, sendRedrawSignal = True)

  • 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

Function: AnimateSolution

AnimateSolution(mbs, solution, rowIncrement = 1, timeout = 0.04, createImages = False, runLoop = False)

  • 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 (Ex), SliderCrank.py (Ex), slidercrankWithMassSpring.py (Ex), sliderCrankFloatingTest.py (TM)