Automate your AnyBody simulations




Using AnyBody from Python

We will use a small open source library to help us. AnyPyTools

  • Handle all interaction with the console application

  • Create macros programatically

  • Run simualtions in parallel

How to get started


Requirements:

  • A Python installation
  • The AnyPyTools library

The easy way:

Install the Anaconda Python distribution.

  • continuum.io/downloads

Has all the important scientific python packages

More stuff can be installed using the build-in package-manager (conda)

c:\>conda config --add channels conda-forge
c:\>conda install anypytools

Running the console applicaiton from Python


A simple example



In [1]:
from anypytools import AnyPyProcess 
app = AnyPyProcess( )

In [2]:
macrolist = ['load "Knee.any"',
             'classoperation Main.MyParameter "Set Value" --value="10"',
             'operation Main.MyStudy.Kinematics',
             'run',
             'exit'] 

app.start_macro(macrolist);


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

Running multiple macros



In [3]:
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: 0.6 seconds

Better performance with parallelization


In [4]:
many_macros = [['load "Knee.any"',
                'classoperation Main.MyParameter "Set Value" --value="10"',
                'operation Main.MyStudy.Kinematics',
                'run',
                'exit']]*40

In [ ]:
many_macros

Better performance with parallelization

First sequentially


In [5]:
app = AnyPyProcess(num_processes = 1)
app.start_macro(many_macros);


[****************100%******************]  40 of 40 complete
Total time: 21.4 seconds

Then with parallelization


In [6]:
app = AnyPyProcess(num_processes = 10)
app.start_macro(many_macros);


[****************100%******************]  40 of 40 complete
Total time: 3.7 seconds

Getting data back from AnyBody


Usual approach: AnyOutputFile, Save all output data (HDF5 file)

  • :( Difficult to concatenate data across simulations.
  • :( Impractical if we only need a few variables.

There must be a better way.

...there is...

The console application has a class operation we can use

classoperation <AnyScript_variable_name> "Dump"

AnyPyTools will automatically grab any data or error from AnyBodyCon


In [7]:
from anypytools import AnyPyProcess 
app = AnyPyProcess( )

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

In [8]:
results = app.start_macro(macrolist)


[****************100%******************]  2 of 2 complete
Total time: 0.6 seconds

In [ ]:
results

Plotting the data


In [9]:
%matplotlib inline
from matplotlib.pyplot import plot

In [10]:
max_muscle_activity = results[0]['Main.MyStudy.Output.MaxMuscleActivity']
plot(max_muscle_activity);


Output behaves like default Python data types:

  • list and dictionary types.

But with extra convenience functionality:


In [11]:
results[0]['Main.MyStudy.Output.MaxMuscleActivity'].shape


Out[11]:
(100,)

In [12]:
results['Main.MyStudy.Output.MaxMuscleActivity'].shape


Out[12]:
(2, 100)

In [13]:
results['MaxMuscleActivity'].shape


Out[13]:
(2, 100)

Handling Errors


AnyPyTools will also catch Errors...

Here is a macro with misspelled operation:


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

In [15]:
from anypytools import AnyPyProcess 
app = AnyPyProcess( )

result = app.start_macro(macrolist);


[****************100%******************]  1 of 1 complete (1 Error)
Tasks with errors: 1
Failed 0.36227685484711003sec :webcast/live tutorial_0 n=0 : (_j0zjldan.log dir)
Total time: 0.4 seconds

In [16]:
result['ERROR']


Out[16]:
array([['Error : Main.MyStudy.Kinematic : Unresolved object.']], 
      dtype='<U51')

Creating macro programmatically


Why would we want to generate macro commands?

  • Individual macros can be really long and complex

  • Parameter and sensitivity studies may require thoudsands of different macros


In [17]:
%pycat "large_macro.anymcr"

In [2]:
from anypytools.macro_commands import Load, OperationRun, Dump, SetValue

In [19]:
Load("Knee.any")


Out[19]:
load "Knee.any"

In [20]:
SetValue('Main.Model.Parameter1', 100.3)


Out[20]:
classoperation Main.Model.Parameter1 "Set Value" --value="100.3"

In [21]:
macrolist = [ Load('Knee.any'),
              SetValue('Main.MyParameter', 10),
              OperationRun('Main.MyStudy.InverseDynamics'),
              Dump('Main.MyStudy.Output.MaxMuscleActivity')] 
macrolist


Out[21]:
[load "Knee.any",
 classoperation Main.MyParameter "Set Value" --value="10",
 operation Main.MyStudy.InverseDynamics
 run,
 classoperation Main.MyStudy.Output.MaxMuscleActivity "Dump"]

In [22]:
from anypytools import AnyPyProcess
app = AnyPyProcess()
app.start_macro(macrolist);


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

Creating many macros

We need an small helper class AnyMacro to wrap our macro list.


In [3]:
from anypytools import AnyMacro

macrolist = AnyMacro( [ SetValue('Main.MyModel.MyParameter',8)] )

macrolist.number_of_macros = 2
macrolist


Out[3]:
[['classoperation Main.MyModel.MyParameter "Set Value" --value="8"'],
 ['classoperation Main.MyModel.MyParameter "Set Value" --value="8"']]

In [4]:
parameter_list = [2.2, 2.5, 2.7, 2.9, 3.1]

macrolist = [ SetValue('Main.MyModel.MyParameter',parameter_list)] 

AnyMacro(macrolist, number_of_macros=5)


Out[4]:
[['classoperation Main.MyModel.MyParameter "Set Value" --value="2.2"'],
 ['classoperation Main.MyModel.MyParameter "Set Value" --value="2.5"'],
 ['classoperation Main.MyModel.MyParameter "Set Value" --value="2.7"'],
 ['classoperation Main.MyModel.MyParameter "Set Value" --value="2.9"'],
 ['classoperation Main.MyModel.MyParameter "Set Value" --value="3.1"']]

A simple parameter study


Combine everything in a parameter study

  • Vary patella tendon length in toy model (2 cm to 8 cm)

Observe the effect on maximum muscle activity.


In [25]:
patella_len = [0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08]

In [26]:
macro = [Load('Knee.any'),
         SetValue('Main.MyModel.PatellaLigament.DriverPos', patella_len ),
         OperationRun('Main.MyStudy.InverseDynamics'),
         Dump('Main.MyStudy.Output.Abscissa.t'), 
         Dump('Main.MyModel.PatellaLigament.DriverPos'),
         Dump('Main.MyStudy.Output.MaxMuscleActivity')]

parameter_study_macro = AnyMacro(macro, number_of_macros= 7 )

In [ ]:
parameter_study_macro

In [27]:
from anypytools import AnyPyProcess
app = AnyPyProcess()

output = app.start_macro(parameter_study_macro)


[****************100%******************]  7 of 7 complete
Total time: 1.7 seconds

In [28]:
%matplotlib inline
from matplotlib.pyplot import plot, title, xlabel, legend, ylabel

In [29]:
for data in output:
    maxact = data['Main.MyStudy.Output.MaxMuscleActivity']
    time = data['Main.MyStudy.Output.Abscissa.t']
    ligament_len = data['Main.MyModel.PatellaLigament.DriverPos'][0]
    plot(time, maxact, label = str(100* ligament_len)+' cm' )
    
title('Effect of changing patella tendon length')    
xlabel('Time steps')
ylabel('Max muscle activity')
legend(bbox_to_anchor=(1.05, 1), loc=2);


Batch processing


The approach depends on how the AnyBody model is structured.

  • Setup with a single main file:

    • Load -> Modify parameters -> run -> save results
    • Every macro is different
  • Setup with multiple main files:

    • Each main file defines its own parameters
    • All macros are the same. Main files in Diffent folders


In [30]:
from anypytools import AnyPyProcess
from anypytools.macro_commands import Load, OperationRun
app = AnyPyProcess(num_processes = 3)

macro = [Load("main.any"),
         OperationRun('Main.Study.InverseDynamics') ]
macro


Out[30]:
[load "main.any", operation Main.Study.InverseDynamics
 run]

In [31]:
app.start_macro(macro, search_subdirs= "model[1-9].*main.any" );


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

Other possiblities


  • Monte Carlo simulations

  • Latin hypercube sampling

  • Using external optimizers

Possible topics for a webcast in the fall.

For now... read the tutorial:

goo.gl/F6mCHC

from scipy.stats.distributions import norm

from anypytools import AnyPyProcess, AnyMacro from anypytools.macro_commands import Load, SetValue_random, OperationRun

app = AnyPyProcess( ) macro = AnyMacro( Load( "Knee.any"), SetValue_random('Main.MyModel.MyParameter', norm(0.1, 0.04)), OperationRun('Main.MyStudy.InverseDynamics') )

app.start_macro(macro.create_macros_MonteCarlo(1000));


In [ ]:
import seaborn as sns
sns.set_context('talk')
sns.set_style('whitegrid');
%matplotlib inline
from matplotlib.pyplot import plot, title, xlabel, legend, ylabel