Scripting environments like Matlab, Python and the OpenSim GUI shell allow users to interact with the classes of the OpenSim API (see The OpenSim API). There are many example scripts that are located in the OpenSim scripting folder, available with the distribution to help you get started. This page summarizes some of the common calls that you will make in the scripting environment of your choice.
These are inline commands that help you find the methods available for a class
|methodsview('Model') or methodsview(osimModel)||GUI and Matlab||Examine the methods available for a class (e.g. Model) or for an existing object that you've created (e.g. osimModel)|
|type(aObject)||GUI||Prints the full qualified type of aObject|
|Up/Down Arrows at the command prompt||GUI||Recalls past commands entered at the prompt|
|Tab completion||Matlab||Define an OpenSim model or object then use tab completion in Matlab to see the available methods|
Packages and libraries are collections of classes and methods (see Introduction to the OpenSim API for background) that have a well-defined interface and can be imported into your programming environment to utilize. These can be packages to browse files, read and write files, do mathematics operations, and run simulations. The commands below are common packages or libraries you will find useful.
|java.swing||GUI||Swing is the generic GUI kit for Java, allows for I/O and creating windows if needed. Examples of usage can be found here.|
|java.lang||GUI||Lang is the Java language core libraries e.g String, Math, etc. To use particular libraries (for example Math), do "from java.lang import Math"|
|java.io||GUI||IO is the package in Java that's used to perform input/output operations including file reading/writing.|
|org.opensim.modeling||GUI and Matlab||Modeling classes from the OpenSim API. This package is automatically imported in the GUI Shell. In Matlab, excute command import org.opensim.modeling.* to avoid having to type org.opensim.modeling.'Class'|
|org.opensim.utils||GUI||Provides some convenient file browsing options|
>>> import java.io as io # Import Read/Write package >>> trcFolder = io.File(trcDataFolder) # Use package to read TRC file
Creating New Objects
Creation of objects is performed by the constructor method of the Class. We can create an object and populate its properties, or pass the class a correctly formatted xml file.
Note: 'path' indicates your system path to the file (i.e., C:/Users/<username>/Documents/OpenSim/4.0/Models/...).
Note: Delete "modeling." from code for Matlab.
|Action||Class Information||Default construction (Scripting shell)||XML construction (Scripting shell)|
|Marker set object||newMarkerSet = modeling.MarkerSet()||newMarkerSet = modeling.MarkerSet([path 'markerSet.xml'])|
|Marker data object||markerData = modeling.MarkerData()||markerData = modeling.MarkerData([path 'walkingData.trc'])|
|Scaling tool object||scaleTool = modeling.ScaleTool()||scaleTool = modeling.ScaleTool([path 'scale_setup.xml'])|
|Inverse Dynamics analysis object||idTool = modeling.InverseDynamicsTool()||idTool = modeling.InverseDynamicsTool([path 'ID_setup.xml'])|
|Control Set||rawControls = modeling.ControlSet()||rawControls= modeling.ControlSet([path 'controls.mot'])|
>>> markerSetFile = "gait2354_MarkerSet.xml" # Define the full path to the Marker Set file >>> newMarkers = modeling.MarkerSet(markerSetFile) # Construct a MarkerSet Object >>> myModel.replaceMarkerSet(myState,newMarkers) # Replace the models existing MarkerSet with new MarkerSet >>> myState = myModel.initSystem() # Initialize the system and obtain the default state
>>> myModel = modeling.Model("gait2354.osim") # Create a Model Object >>> pelvisbody = myModel.getBodySet().get("pelvis") # Get a handle to the pelvis body >>> newMarkerSet = modeling.MarkerSet() # Create an empty MarkerSet Object >>> newMarkerSet.addMarkers("LASI", [1, 1, 1], pelvisbody) # Add a Marker to the MarkerSet called 'LASI', that is attached to the pelvis at [1,1,1] >>> myModel.replaceMarkerSet(myState,newMarkers) # Replace the models existing MarkerSet with new MarkerSet >>> myModel.initSystem() # re-initialize the system >>> myState =myModel.initSystem() # Define the new state
>> nBody = Body(); % Creates an body with default mass=1 >> massCenter = Vec3(-0.0707,0.0,0.0); % Create a Vec3 Object with Mass center information >> inertiaMat = Mat33(0.1028,0,0,0,0.0871,0,0,0,0.0579); % Create a Mat33 (3x3 Matrix) with inertial information >> nBody.setName('pelvis') % Set the name of the body using a string >> nBody.setMass(11) % Set the mass of the body using a double >> nBody.setMassCenter(massCenter) % Set the Mass Center >> nBody.setInertia(inertiaMat) % Set the Inertia %% Alternatively, a body can be created by sending all of these properties directly to the constructor >> massCenter = Vec3(-0.0707,0.0,0.0); % Create a Vec3 Object with Mass center information >> inertiaMat = Mat33(0.1028,0,0,0,0.0871,0,0,0,0.0579); % Create a Mat33 (3x3 Matrix) with inertial information >> bodyName = 'pelvis' % Set the name of the body using a string >> bodyMass = 11 % Set the mass of the body using a double >> nBody = Body(bodyName,bodyMass,massCenter,inertiaMat); % Creates an body from properties sent to constructor
>> pBody = Body('pelvis', bodyMass,massCenter,inertiaMat); % Either create or get a handle to the parent body >> cBody = Body('femur_r',bodyMass,massCenter,inertiaMat); % Either create or get a handle to the child body >> name = 'hip_r' % Assign the joint name >> locInParent = Vec3(-0.0707,-0.0661,0.0835); % A Vec3 location in the parent frame >> orienInParent = Vec3(0,0,0); % A Vec3 orientation in the parent frame >> locInChild = Vec3(0,0.0,0); % A Vec3 location in the child frame >> orienInChild= Vec3(0,0,0); % A Vec3 orientation in the child frame >> rrHip = BallJoint(name,nBody,locInParent,orienInParent,cBody,locInChild,orienInChild)
>> myModel = Model("gait2354.osim") # Create a Model Object >> femur_r = myModel.getBodySet().get('femur_r'); # Get a Handle to the Body A >> tibia_r = myModel.getBodySet().get('tibia_r'); # Get a Handle to the Body B >> zAxisTorque = Vec3(0,0,1); # A Vec3 of the z-axis >> torqueActuator = TorqueActuator(); # Create a Torque Actuator Object >> torqueActuator.setBodyA(femur_r); # Set Body A >> torqueActuator.setBodyB(tibia_r); # Set Body B >> torqueActuator.setAxis(zAxisTorque); # Set the axis about the torque to act >> torqueActuator.setOptimalForce(10); # Set the optimal force (gain) of the actuator
Loading models and dealing with model states is very common. Below are the methods for loading, copying and initializing a model
|Action||Environment||GUI Command||Matlab Command|
|Loads the specified model in the GUI (replace addModel in 3.0.1 and earlier)||GUI (3.1 and later)||loadModel(modelFileName)|
|Creates a handle to the current model in the GUI||GUI||myModel = getCurrentModel()|
|Load a model from file (Create Model Object)||GUI and Matlab||myModel = modeling.Model(modelFileName)||myModel = Model([path 'gait2354.osim'])|
|Creates a copy of myModel.||GUI and Matlab||myModelCopy = modeling.Model(myModel)||myModelCopy = myModel|
|Initialize the model.||GUI and Matlab||myModel.initSystem()||myModel.initSystem()|
|Get a handle to the current states||GUI and Matlab||myStates=myModel.initSystem()||myStates=myModel.initSystem()|
>>> modelFileName=modelFolder+"\gait2354_simbody.osim" # Define the full path to the model file >>> loadModel(modelFileName) # Load the model into the GUI >>> myModel=getCurrentModel() # Create a handle to the current model >>> myModel.initSystem() # Initialize the model >>> myState=myModel.initSystem() # Get a handle to the current states of the model
You can use the functionality of the OpenSim API to access the properties of a model and change their values. For examples, refer to the distributed scripts muscleScaler and alterTendonSlackLength. The OpenSim API Doxygen lists all of the available functions. For example, executing the following commands in the GUI scripting shell, sets and gets the name of the current model.
>>> myModel = getCurrentModel() >>> myModel.setName("My Model") >>> mymodel.getName() >>> "my Model"
You should generally avoid adding and removing objects from a model that is "live" in the OpenSim GUI. Instead you should make a copy of the model, make additions and deletions, then reload in the GUI.
The API also allows you to access and edit the components of an OpenSim model, like its bodies, muscles, and joints. Some properties have custom "get" and "set" functions - see the respective classes for details.
|Action||Class Information||Getting a Handle to a Set||Reference an Object by index||Get object from a name||Alternative 'long path'|
|Body Set||bodySet= myModel.getBodySet()||rightFemur = bodySet().get(1)||rightFemur = bodySet().get("femur_r")||rightFemur =myModel.getBodySet().get("femur_r")|
|Joint Set||jointSet = myModel.getJointSet()||rightHip = jointSet ().get(7)||rightHip = jointSet ().("hip_r")||rightHip = myModel.getJointSet().("hip_r")|
|Coordinate Set||cordSet= myModel.getCoordinateSet()||hip_coord = cordSet().get(4)||hip_coord = cordSet().get("hip_flexion_r")||hip_coord = cordSet().get("hip_flexion_r")|
|Muscle Set||muscleSet= myModel.getMuscles()||recFemR= muscleSet().get(3)||rec_fem_r= recFemRt().get("'recFem_r")||rec_fem_r= myModel.getMuscles().get("'recFem_r")|
|Path Point of a Muscle||pathPoints = myModel.getMuscles().get("'recFem_r").getGeometryPath().getPathPointSet()||recFemPathPoint1 = pathPoints.get(0)||recFemPathPoint1 = pathPoints.get("rect_fem_r-P1")||recFemPathPoint1 =myModel.getMuscles().get("'recFem_r").getGeometryPath().getPathPointSet()|
Once a Handle to the component has been created you can edit its properties and methods.
|Get the optimal fiber length||recFemFiberLength = RectusFemoris.getOptimalFiberLength()|
|Set the optimal fiber length||RectusFemoris.setOptimalFiberLength(0.23)|
|Set the tendon slack length||RectusFemoris.setTendonSlackLength(0.2105)|
|Get the muscle maximum isometric force||recFemMaxForce = RectusFemoris.getMaxIsometricForce()|
>>> ECRB = myModel.getMuscles().get("ECRB") # Get a handle to the ECRB >>> backupTendonSlackLength = ECRB.getTendonSlackLength() # Back up the original tendon slack length (just in case) >>> ECRB.setTendonSlackLength(0.2105) # Prescribe a new Tendon slack length >>> myModel.initSystem() # Re-initialize the states
You may need to downcast an object from an abstract class (e.g., Muscle) to a derived class (e.g., Thelen2003Muscle) in order to gain access to its properties and methods. Here is an example:
>> import org.opensim.modeling.* >> myModel = Model('arm26.osim'); >> mcl_TRIlong = Thelen2003Muscle.safeDownCast( myModel.getMuscles().get('TRIlong') ); >> mcl_TRIlong.setFmaxTendonStrain( 0.5*mcl_TRIlong.getFmaxTendonStrain() );
Tools contain a number of grouped Methods that allow you to run a study. For example, to scale a Model to match experimental data the ScaleTool groups GenericModelMaker(), ModelScaler() and MarkerPlacer() together. The AnalyzeTool() can group StaticOptimization() and MuscleAnalysis() together to output muscle states of a Static Optimization.
|Class||Doxygen Link||Default construction (Scripting shell)||XML construction (Scripting shell)|
|Scale||scaleTool = modeling.ScaleTool()||scaleTool = modeling.ScaleTool([path 'scale_Setup.xml'])|
|InverseKinematicsTool||ikTool = modeling.InverseKinematicsTool()||idTool = modeling.InverseKinematicsTool([path 'IK_Setup.xml'])|
|InverseDynamicsTool||idTool = modeling.InverseDynamicsTool()||idTool = modeling.InverseDynamicsTool([path 'ID_Setup.xml'])|
|RRATool||rraTool = modeling.RRATool()||rraTool = modeling.RRATool([path 'RRA_Setup.xml'])|
|CMCTool||cmcTool = modeling.CMCTool()||cmcTool = modeling.CMCTool([path 'CMC_Setup.xml'])|
|ForwardTool||cmcTool = modeling.ForwardTool()||cmcTool = modeling.ForwardTool([path 'forward_Setup.xml'])|
|AnalyzeTool||analyzeTool = modeling.AnalyzeTool()||analyzeTool = modeling.AnalyzeTool([path 'analyze_Setup.xml'])|
Below are examples of the OpenSim GUI shells native commands with files and file paths. Matlab and Python environments have their own methods for dealing with files and file paths.
|Command or Class||Platform||Action|
|getScriptsDir()||GUI||Returns the path of your scripts directory|
|java.io.File||GUI||A representation of file and directory pathnames that allows you to easily create files and directories, get all the files in a given directory, and more. Read more here: http://docs.oracle.com/javase/1.4.2/docs/api/java/io/File.html|
|getInstallDir()||GUI||Returns the path of your OpenSim Install directory|
|os.chdir(NewWorkingDirectoryName)||GUI||Changes the working directory of the scripting shell (default is your OpenSim installation directory) to the directory specified by NewWorkingDirectoryName (e.g. 'C:\OpenSim 3.1\Scripts'). You need to import the python os package before using it (i.e. import os).|
|execfile("ScriptFileName")||GUI||Executes a script. Can be used in shell or as part of script. File name can be absolute path to file or relative to the current directory.|
In the GUI scripting shell, we've provided a set of commands that allow you to easily perform some basic plotting functionality. This includes adding a plot window, adding curves, changing the legend, plotting from file, exporting the plot, etc.
These commands are exercised in the example "plotMuscleFiberLengthAgainstFile.py" and "plotMuscleMomentArmAgainstMotion.py".
There are additional advanced commands that you can call (the ones used by the GUI itself), though these commands have not been fully documented and tested with the scripting functionality, so please use with caution.
We encourage you to use Matlab's host of built in plotting capabilities. You can import OpenSim .sto and .mot files using Matlab's "Import Data" interface (see MATLAB's importdata function).
In OpenSim 3.1 and later we've exposed the most commonly used SimTK classes. In particular:
modeling.Vec3(double e0, double e1, double e2)
|All||Creates a Simtk Vec3 object (a vector of length 3). If passed only one argument (double e) all elements will be set to e.|
|modeling.Vector(int length, double e)||All||Creates a Simtk Vector with specified length. All elements are set to e.|
modeling.Mat33(double e0, ... , double e8)
|All||Creates a Simtk Mat33 object (a 3x3 matrix). If passed only one argument (double e), the diagonal elements will be set to e and other elements set to zero.|
See doxygen link at right for additional constructors
|All||Creates a Simtk Inertia object. All constructors are available except symmetric matrix constructors.|
|modeling.State()||All||Creates a Simtk State object. See the doxygen link for more information.|
Creates a Simtk Stage object, optionally realized to level l. See the doxygen link for more information.
Templates are advanced C++ constructs that are used extensively throughout the OpenSim API and Simbody API. C++ provides templates to allow for compiler generated classes from a common code base. This approach is useful primarily for containers (e.g. Array<double>, Array<int>, Array<string>) since it avoids code duplication making the code easier to maintain; however, these templates exist only in C++ and do not map easily to scripting languages. One way to work around that is to specialize templates into classes, give those classes unique names and then use them. The attached file lists template specializations used in OpenSim API (C++) & Doxygen and the corresponding named classes to be used in scripting (the list is current as of OpenSim 3.2):
In many cases the function you're trying to call takes an argument type different from the object you have already. This is true even moving data between Matlab and Java objects, and between objects in the SimTK namespace and those in the OpenSim namespace. The following set of convenience methods are "Adaptors" intended to help you pass data around between OpenSim objects and low level SimTK objects.
|modeling.ArrayDouble.createVec3([0.0,0.05,0.35])||GUI and Matlab||Creates a SimTK::Vec3|
|GUI and Matlab||returns SimTK::Vec3 populated from ArrayDouble of size 3.|
|modeling.ArrayDouble.getAsVector()||GUI and Matlab||return SimTK::Vector populated from ArrayDouble|
|modeling.ArrayDouble.populateFromVector(SimTK::Vector aVector)||GUI and Matlab||populate an ArrayDouble from the passed in SimTK Vector|
|modeling.ArrayDouble.getValuesFromVec3(SimTK::Vec3 vec3)||GUI and Matlab||returns an ArrayDouble populated from the passed in SimTK Vec3|
When referring to indexed elements remember that Matlab begins indexing at 1 while OpenSim data structures begin at 0.
Templates are advanced C++ constructs that are used extensively throughout the OpenSim API and Simbody API. If you see notation like Array<double> in the doxygen or C++ code that you are trying to replicate, this means you're working with a templatized class and will need to find its appropriate mapping in the scripting environment.
C++ templates allow the compiler to automatically generate classes from a common code base. This approach is useful primarily for containers (e.g. Array<double>, Array<int>, Array<string>) since it avoids code duplication making the code easier to maintain; however, these templates exist only in C++ and do not map easily to scripting languages.
One way to work around this is to specialize templates into classes, give those classes unique names, and then use them in scripting. The attached file lists template specializations used in OpenSim API (C++) & Doxygen and the corresponding named classes to be used in scripting (the list is current as of OpenSim 3.2):
Mapping of Templates to Class Names for Scripting
For more information regarding multibody system states, refer to the SimTK Simulation Concepts documentation in the Developer's Guide.
In order to obtain simulation position or velocity state information you must have a State object in hand.
>>> si = myModel.initSystem(); >>> myModel.equilibrateMuscles(si);
Now you can call the SimBodyEngine's getVelocity() (or getPosition()) method in order to fill a pre-allocated Vec3 object with velocity information.
>>> massCenter = Vec3(0.0,0.0,0.0); >>> velocity = Vec3(0.0,0.0,0.0); >>> bodySet = myModel.getBodySet() >>> bodySet.get('r_ulna_radius_hand').getMassCenter(massCenter); >>> simbodyEngine = myModel.getSimbodyEngine(); >>> simbodyEngine.getVelocity(si, osimModel.getBodySet().get('r_ulna_radius_hand'), massCenter, velocity);
You can use the visualizer from Simbody in Matlab and Python. To do so call the "setUseVisualizer" method and pass in the parameter "true", and when you run the simulation the Simbody Visualizer GUI will pop up. The example of usage is described in "TugOfWar_CompleteRunVisualizer.m"
osimModel = Model('tug_of_war_muscles_controller.osim'); osimModel.setUseVisualizer(true);
There are several examples in the Matlab scripts and GUI scripts that show how to perform batch processing by calling the OpenSim API (e.g. Analyze, IK). We encourage you to use this approach rather than using Matlab's xml parsing tools. To read more about why this is the case, please see the scripting FAQ:
Frequently Asked Questions
Next: Scripting in the GUI