Module: interactive
Utilities for interactive simulation and results monitoring; NOTE: does not work on MacOS!
Author: Johannes Gerstmayr
Date: 2021-01-17 (created)
Function: AnimateModes
AnimateModes(systemContainer
, mainSystem
, nodeNumber
, period = 0.04
, stepsPerPeriod = 30
, showTime = True
, renderWindowText = ''
, runOnStart = False
, runMode = 0
, scaleAmplitude = 1
, title = ''
, fontSize = 12
, checkRenderEngineStopFlag = True
, systemEigenVectors = None
)
- function description:animate modes of ObjectFFRFreducedOrder, of nodal coordinates (changes periodically one nodal coordinate) or of a list of system modes provided as list of lists; for creating snapshots, press ‘Static’ and ‘Record animation’ and press ‘Run’ to save one figure in the image subfolder; for creating animations for one mode, use the same procedure but use ‘One Cycle’. Modes may be inverted by pressing according ‘+’ and ‘-’ buttons next to Amplitude.
- input:
systemContainer
: system container (usually SC) of your model, containing visualization settingsmainSystem
: system (usually mbs) containing your modelnodeNumber
: node number of which the coordinates shall be animated. In case of ObjectFFRFreducedOrder, this is the generic node, e.g., ‘nGenericODE2’ in the dictionary returned by the function AddObjectFFRFreducedOrderWithUserFunctions(…); if nodeNumber=None, then the systemEigenVectors list is usedperiod
: delay for animation of every frame; the default of 0.04 results in approximately 25 frames per secondstepsPerPeriod
: number of steps into which the animation of one cycle of the mode is split intoshowTime
: show a virtual time running from 0 to 2*pi during one mode cyclerenderWindowText
: additional text written into renderwindow before ‘Mode X’ (use \(\backslash\)n to add line breaks)runOnStart
: immediately go into ‘Run’ moderunMode
: 0=continuous run, 1=static continuous, 2=one cycle, 3=static (use slider/mouse to vary time steps)scaleAmplitude
: additional scaling for amplitude if necessaryfontSize
: define font size for labels in InteractiveDialogtitle
: if empty, it uses default; otherwise define specific titlecheckRenderEngineStopFlag
: if True, stopping renderer (pressing Q or Escape) also causes stopping the interactive dialogsystemEigenVectors
: may be a list of lists of system eigenvectors for ODE2 (and possibly ODE1) coordinates or a eigenvector matrix containing mode vectors in columns; if nodeNumber=None, these eigenvectors are then used to be animated - output:opens interactive dialog with further settings
- notes:Uses class InteractiveDialog in the background, which can be used to adjust animation creation. If meshes are large, animation artifacts may appear, which are resolved by using a larger update period.Press ‘Run’ to start animation; Chose ‘Mode shape’, according component for contour plot; to record one cycle for animation, choose ‘One cycle’, run once to get the according range in the contour plot, press ‘Record animation’ and press ‘Run’, now images can be found in subfolder ‘images’ (for further info on animation creation see Section Generating animations); now deactivate ‘Record animation’ by pressing ‘Off’ and chose another mode
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
CMSexampleCourse.py (Ex), netgenSTLtest.py (Ex), NGsolveCMStutorial.py (Ex), NGsolveCraigBampton.py (Ex), NGsolvePistonEngine.py (Ex), objectFFRFreducedOrderShowModes.py (TM), runTestExamples.py (TM)
Function: SolutionViewer
SolutionViewer(mainSystem
, solution = None
, rowIncrement = 1
, timeout = 0.04
, runOnStart = True
, runMode = 2
, fontSize = 12
, title = ''
, checkRenderEngineStopFlag = True
)
- NOTE: this function is directly available in MainSystem (mbs); it should be directly called as mbs.SolutionViewer(…). For description of the interface, see the MainSystem Python extensions, Function: SolutionViewer
CLASS InteractiveDialog (in module interactive)
class description:
create an interactive dialog, which allows to interact with simulations the dialog has a ‘Run’ button, which initiates the simulation and a ‘Stop’ button which stops/pauses simulation; ‘Quit’ closes the simulation model for examples, see
simulateInteractively.py
andmassSpringFrictionInteractive.py
use __init__ method to setup this class with certain buttons, edit boxes and sliders
- example:
#the following example is only demonstrating the structure of dialogItems and plots
#dialogItems structure:
#general items:
# 'type' can be out of:
# 'label' (simple text),
# 'button' (button with callback function),
# 'radio' (a radio button with several alternative options),
# 'slider' (with an adjustable range to choose a value)
# 'grid': (row, col, colspan) specifies the row, column and (optionally) the span of columns the item is placed at;
# exception in 'radio', where grid is a list of (row, col) for every choice
# 'options': text options, where 'L' means flush left, 'R' means flush right
#suboptions of 'label':
# 'text': a text to be drawn
#suboptions of 'button':
# 'text': a text to be drawn on button
# 'callFunction': function which is called on button-press
#suboptions of 'radio':
# 'textValueList': [('text1',0),('text2',1)] a list of texts with according values
# 'value': default value (choice) of radio buttons
# 'variable': according variable in mbs.variables (or mbs.sys), which is set to current radio button value
#suboptions of 'slider':
# 'range': (min, max) a tuple containing minimum and maximum value of slider
# 'value': default value of slider
# 'steps': number of steps in slider
# 'variable': according variable in mbs.variables (or mbs.sys), which is set to current slider value
#example:
dialogItems = [{'type':'label', 'text':'Nonlinear oscillation simulator', 'grid':(0,0,2), 'options':['L']},
{'type':'button', 'text':'test button','callFunction':ButtonCall, 'grid':(1,0,2)},
{'type':'radio', 'textValueList':[('linear',0),('nonlinear',1)], 'value':0, 'variable':'mode', 'grid': [(2,0),(2,1)]},
{'type':'label', 'text':'excitation frequency (Hz):', 'grid':(5,0)},
{'type':'slider', 'range':(3*f1/800, 3*f1), 'value':omegaInit/(2*pi), 'steps':800, 'variable':'frequency', 'grid':(5,1)},
{'type':'label', 'text':'damping:', 'grid':(6,0)},
{'type':'slider', 'range': (0, 40), 'value':damper, 'steps':800, 'variable':'damping', 'grid':(6,1)},
{'type':'label', 'text':'stiffness:', 'grid':(7,0)},
{'type':'slider', 'range':(0, 10000), 'value':spring, 'steps':800, 'variable':'stiffness', 'grid':(7,1)}]
#plots structure:
plots={'nPoints':500, #number of stored points in subplots (higher means slower drawing)
'subplots':(2,1), #(rows, columns) arrangement of subplots (for every sensor)
#sensors defines per subplot (sensor, coordinate), xlabel and ylabel; if coordinate=0, time is used:
'sensors':[[(sensPos,0),(sensPos,1),'time','mass position'],
[(sensFreq,0),(sensFreq,1),'time','excitation frequency']],
'limitsX':[(0,2),(-5,5)], #x-range per subplot; if not provided, autoscale is applied
'limitsY':[(-5,5),(0,10),], #y-range per subplot; if not provided, autoscale is applied
'fontSize':16, #custom font size for figure
'subplots':False, #if not specified, subplots are created; if False, all plots go into one window
'lineStyles':['r-','b-'], #if not specified, uses default '-b', otherwise define list of line styles [string for matplotlib.pyplot.plot] per sensor
'sizeInches':(12,12)} #specific x and y size of figure in inches (using 100 dpi)
Class function: __init__
__init__(self
, mbs
, simulationSettings
, simulationFunction
, dialogItems
, plots = None
, period = 0.04
, realtimeFactor = 1
, userStartSimulation = None
, title = ''
, showTime = False
, fontSize = 12
, doTimeIntegration = True
, runOnStart = False
, addLabelStringVariables = False
, addSliderVariables = False
, checkRenderEngineStopFlag = True
, userOnChange = None
, useSysVariables = False
)
- classFunction:initialize an InteractiveDialog
- input:
mbs
: a multibody system to be simulatedsimulationSettings
: exudyn.SimulationSettings() according to user settingssimulationFunction
: a user function(mbs, self) which is called before a simulation for the short period is started (e.g, assign special values, etc.); the arguments are the MainSystem mbs and the InteractiveDialog (self)dialogItems
: a list of dictionaries, which describe the contents of the interactive items, where every dict has the structure {‘type’:[label, entry, button, slider, check] … according to tkinter widgets, ‘callFunction’: a function to be called, if item is changed/button pressed, ‘grid’: (row,col) of item to be placed, ‘rowSpan’: number of rows to be used, ‘columnSpan’: number of columns to be used; for special item options see notes}plots
: list of dictionaries to specify a sensor to be plotted live, see example; otherwise use default Noneperiod
: a simulation time span in seconds which is simulated with the simulationFunction in every iterationrealtimeFactor
: if 1, the simulation is nearly performed in realtime (except for computation time); if > 1, it runs faster than realtime, if < 1, than it is sloweruserStartSimulation
: a function F(flag) which is called every time after Run/Stop is pressed. The argument flag = False if button “Run” has been pressed, flag = True, if “Stop” has been pressedtitle
: title text for interactive dialogshowTime
: shows current time in dialogfontSize
: adjust font size for all dialog itemsdoTimeIntegration
: performs internal time integration with given parametersrunOnStart
: immediately activate ‘Run’ button on startaddLabelStringVariables
: True: adds a list labelStringVariables containing the (modifiable) list of string variables for label (text) widgetsaddSliderVariables
: True: adds a list sliderVariables containing the (modifiable) list of variables for slider (=tkinter scale) widgets; this is not necessarily needed for changing slider values, as they can also be modified with dialog.widgets[..].set(…) methodcheckRenderEngineStopFlag
: if True, stopping renderer (pressing Q or Escape) also causes stopping the interactive dialoguserOnChange
: a user function(mbs, self) which is called after period, if widget values are different from values stored in mbs.variables; this usually occurs if buttons are pressed or sliders are moved; the arguments are the MainSystem mbs and the InteractiveDialog (self)useSysVariables
: for internal visualization functions: in this case, variables are written to mbs.sys instead of mbs.variables - notes:detailed description of dialogItems and plots list/dictionary is given in commented the example below
Class function: OnQuit
OnQuit(self
, event = None
)
- classFunction:function called when pressing escape or closing dialog
Class function: StartSimulation
StartSimulation(self
, event = None
)
- classFunction:function called on button ‘Run’
Class function: ProcessWidgetStates
ProcessWidgetStates(self
)
- classFunction:assign current values of radio buttons and sliders to mbs.variables or mbs.sys
Class function: ContinuousRunFunction
ContinuousRunFunction(self
, event = None
)
- classFunction:function which is repeatedly called when button ‘Run’ is pressed
Class function: InitializePlots
InitializePlots(self
)
- classFunction:initialize figure and subplots for plots structure
Class function: UpdatePlots
UpdatePlots(self
)
- classFunction:update all subplots with current sensor values
Class function: InitializeSolver
InitializeSolver(self
)
- classFunction:function to initialize solver for repeated calls
Class function: FinalizeSolver
FinalizeSolver(self
)
- classFunction:stop solver (finalize correctly)
Class function: RunSimulationPeriod
RunSimulationPeriod(self
)
- classFunction:function which performs short simulation for given period
Relevant Examples (Ex) and TestModels (TM) with weblink to github: