Using AnyBody from Python


The package anypytools has utilities and tools to work with the AnyBody Modeling System (AMS). This will allow us to do the follwing directly from python:

  • Batch processing:
    Schedule the execution of many models in parallel.
  • Parameter studies:
    Running the same model multiple times with different input and observe the response of an output variable.
  • Perturbation studies:
    Finds the sensitivity of a set of output variables to small perturbations on a set of input variables. This is useful for calculating the Jacobian matrix in optimization studies.
Requirements: Python and and AnyPyTools

AnyPyTools is a python library for working with the AnyBody Modeling System. An easy way to get started is to download the Anaconda python distribution:

cmd
conda install -c public anypytools

This should install the newest version of AnyPyTools. Try launching the inteactive version of this tutorial (in the Anaconda start menu) and start working with anypytools.

Running macros


Let us see how to run a single model. In this tutorial we will use an example model Knee.any, which must be placed in the current working directory.

The first step is to import the appropriate class for working with the console application and create an instance of the class AnyPyProcess.


In [4]:
from anypytools.abcutils import AnyPyProcess 
app = AnyPyProcess()

Now we define an AnyScript macro which we want to run on the model. The macro is executed by starting the start_macro method of the AnyPyProcess class


In [5]:
macrolist = [['load "Knee.any"',
              'operation Main.MyStudy.Kinematics',
              'run',
              'exit']]

app.start_macro(macrolist);


[****************100%******************]  1 of 1 complete 
Total run time: 3 seconds

Running multiple macros

It is easy to run multiple macros by adding an extra set of macro commands to the macro list


In [8]:
macrolist = [['load "Knee.any"',
              'operation Main.MyStudy.Kinematics',
              'run',
              'exit'],
             ['load "Knee.any"',
              'operation Main.MyStudy.InverseDynamics',
              'run',
              'exit']]
app.start_macro(macrolist);


[****************100%******************]  2 of 2 complete (Total time: 4 seconds)

Notice, that AnyPyProcess will run the anyscript macros in parallel. Modern computers have multiple cores, but a single AnyBody instance can only utilize a single core, leaving us with a great potential for speeding things up through penalization.

To test this, let us create 10 macros in a for-loop.


In [12]:
macrolist = []
for i in range(15):
    macrolist.append(['load "Knee.any"',              
                      'operation Main.MyStudy.InverseDynamics',
                      'run',
                      'exit'] )

AnyPyProcess has a parameter 'num_processes' that controls the number parallel processes. Let us try a small example to see the difference in speed:


In [10]:
# First sequentially
app = AnyPyProcess(num_processes = 1)
app.start_macro(macrolist);


[****************100%******************]  15 of 15 complete (Total time: 60 seconds)

In [13]:
#Then with parallization
app = AnyPyProcess(num_processes = 4)
app.start_macro(macrolist);


[****************100%******************]  15 of 15 complete (Total time: 21 seconds)

Getting data from the AnyBody Model


If we are only interested in a few variables then In the following macro we have added a new classoperation to 'Dump' the result of the maximum muscle activity. The start_macro method will the return all the 'dump'ed variables:


In [7]:
macrolist = [['load "Knee.any"',
              'operation Main.MyStudy.InverseDynamics',
              'run',
              'classoperation Main.MyStudy.Output.MaxMuscleActivity "Dump"',
              'exit']] 

result = app.start_macro(macrolist)

max_muscle_act = result[0]['Main.MyStudy.Output.MaxMuscleActivity']


[****************100%******************]  1 of 1 complete 
Total run time: 3 seconds

In order to make the plot we import the matplotlib library, and enable inline figurs


In [10]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

plt.plot(max_muscle_act);


Getting output from many models

Running multiple models is only interesting if the models are different. In the following, the length of the patella ligament is varied from one to 10cm using the "Set Value" classoperation macro.


In [12]:
macrolist = []
patella_ligament_lengths = np.linspace(0.01, 0.1, 9)
for value in patella_ligament_lengths:
    macrolist.append( ['load "Knee.any"',   
                       'classoperation Main.MyModel.PatellaLigament.DriverPos "Set Value"\
                        --value={%f}'%(value),
                       'operation Main.MyStudy.InverseDynamics',
                       'run',
                       'classoperation Main.MyStudy.Output.MaxMuscleActivity "Dump"',
                       'exit'] )
output = app.start_macro(macrolist)


[****************100%******************]  9 of 9 complete 
Total run time: 11 seconds

We can now analyze the resulting maximum muscle activity by plotting the data in the output variable:


In [14]:
for i, result in enumerate( output ):
    maxact = result['Main.MyStudy.Output.MaxMuscleActivity']
    plt.plot(maxact, label='%d cm'%(100*patella_ligament_lengths[i]) )

plt.title('Effect of changing patella ligament length')    
plt.xlabel('time steps')
plt.ylabel('max muscle activity')
plt.legend(bbox_to_anchor=(1.05, 1), loc=2);


Saving and loading all data with HDF5 files

It can sometimes be convenient to save the entire model with all its data, although this can be several hundred megabytes. It is useful if we do not know which variables we are interested in before running the model. It can also be useful if we want to load the data in the GUI application and replay the result.

The macro language allows us to save the output of a study to the HDF5 file format. To do this we add a "Save data" classoperation to the macro and then re-run the model:


In [16]:
macrolist = [[
  'load "Knee.any"',
  'operation Main.MyStudy.Kinematics',
  'run',
  'classoperation Main.MyStudy.Output "Save data" --type="Deep" --file="output.anydata.h5"',
  'exit']] 
app.start_macro(macrolist);


[****************100%******************]  1 of 1 complete 
Total run time: 3 seconds

The data stored in the file output.anydata.h5 can be re-loaded in the AnyBody GUI application. To do this; load the model, then right click the Main.MyStudy.Output folder and select "Load data".

Moreover, since we set type="Deep" in the macro we can also load the data into external programs, e.g. Matlab or python. In python this is done using the h5py module


In [19]:
import h5py
h5file = h5py.File('output.anydata.h5')
data = np.array( h5file['/Output/MomentArm'] )
h5file.close()
print data


[ 0.05740825  0.05665018  0.05586448  0.05505892  0.05424032  0.05341468
  0.05258717  0.05176219  0.05094339  0.05013373  0.04933551  0.04855041
  0.04777948  0.04702321  0.04628154  0.04555385  0.04483899  0.0441353
  0.04344059  0.04275212  0.04206663  0.04138032  0.04068878  0.03998705
  0.03926952  0.03852994  0.03776138  0.03695617  0.03610588  0.03520129]

The data structure of the HDF5 files can unfortunately be very confusing. AnyBody does not save duplicate copies of the same data. If there are multiple references to the same folder, only one will be present in the HDF5 file. In our model Knee.any we have a reference to the Knee joint folder just before the Model folder in the study section. Thus, all variables inside the Knee folder cannot be accessed with the path '/Output/Model/Knee/...', but only through the path of the reference '/Output/kneeref/...'.

We can see the problem in the following code snippet:


In [14]:
with h5py.File('output.anydata.h5') as f:
    print '/Output/Model/Knee/Pos' in f
    print '/Output/kneeref/Pos' in f


False
True

This makes it difficult to find the correct path in large models with many references. AnyPyTools contains a wrapper for the h5py module, which automatically locates the right data, no matter what path is used. Using this module, we can easily locate the data.


In [2]:
import anypytools.h5py_wrapper as h5py2
with h5py2.File('output.anydata.h5') as f:
    print '/Output/Model/Knee/Pos' in f
    print '/Output/kneeref/Pos' in f


True
True

The h5py wrapper will also let us use the AnyScript variable names directly so we don't have to replace every . (dot) with a / (slash), and remove the stuff before the Output folder.


In [25]:
with h5py2.File('output.anydata.h5') as f:
    kneeangle = np.array(f['Main.MyStudy.Output.Model.Knee.Pos'] )
    momentarm = np.array(f['Output.MomentArm'] )
    
plt.plot(np.degrees(kneeangle),100*momentarm)
plt.xlabel('Knee flexion (deg)')
plt.ylabel('Moment arm (cm)');


Batch processing of many models


The approach to batch processing depends on the structure of the anybody model. The most commonly used strategy is a single anyscript main file which is loaded with different define statements to the trials, subjects or other parameters. This is the approach which is outlined on the anyscript.org wiki page, the first chapter of the tutorial explains how to handle this.

Another strategy is to have a separate main file for each trial. These indivudual main files hold all trial specific data and includes a base model which is common to all trials and subjects. This is makes it much easier to work with mocap models which have many subject or hundres of trials.

This example model illustrates the concept with the Arm2D demo from AnyBody. The main files are located in subfolders which load the base model "Demo.Arm2D.any" with different parameters.


In [26]:
%cd "BatchProcessExample"
!dir /B


C:\Users\Morten\Google Drive\IPython Notebooks\BatchProcessExample
batchprocess.py
Demo.Arm2D.any
model1
model2
model3
model4
model5
model6
model7
model8
model9
Output
RunExample.bat

In [28]:
from anypytools.abcutils import AnyPyProcess

app = AnyPyProcess(num_processes = 3)
macrolist = [['load "main.any"',
           'operation Main.Study.InverseDynamics',
		   'run',
		   'exit']]

app.start_macro(macrolist, search_subdirs= "[model[1-9].*main.any" );


[****************100%******************]  9 of 9 complete 
Total run time: 13 seconds

Running external optimizers with AnyBody


To come


In [ ]:


In [106]:
# This just formats the Notebook so it looks a bit nicer
from IPython.core.display import HTML
def css_styling():
    styles = open("custom.css", "r").read()
    return HTML(styles)
css_styling()


Out[106]:

In [ ]: