Creating AnyScript Macros#

AnyPyTools can help write the AnyScript macros automatically. Doing so make it easier to create complex macros and do things like parameter studies, Monte Carlo simulation, etc.

Most AnyBody class operations and macros have a correspoding helper class in AnyPyTools.

from anypytools.macro_commands import (
MacroCommand, 
Load,
Dump,
SetValue,
SetValue_random,
SaveDesign,
LoadDesign, 
SaveValues,
LoadValues,
UpdateValues,
RunOperation,
Export,
ExtendOutput,
)

A quick example#

The following shows how the to generate a simple macro.

macrolist = [
    Load('Knee.any', defs={'SUBJECT':'"S02"', 'TRIAL':'"T04"'}),
    RunOperation('Main.MyStudy.InverseDynamics'),
    Export('Main.MyStudy.Output.MaxMuscleActivity'),
] 
macrolist 
[load "Knee.any" -def SUBJECT=---"\"S02\"" -def TRIAL=---"\"T04\"",
 operation Main.MyStudy.InverseDynamics
 run,
 print Main.MyStudy.Output.MaxMuscleActivity]

Each macro object will generate one or more macro commands with the correct syntax. The macro can be launched using the start_macro() method of the AnyPyProcess object.

from anypytools import AnyPyProcess
app = AnyPyProcess()
app.start_macro(macrolist);
Completed: 1


Overview of macro commands#

The macro_commands module have classes for generating many of the standard AnyScipt macro commands.

  • Load(mainfile, defines, paths): Loads a model file in AnyBody

  • RunOperation(var): Runs an operation

  • Export(var, name): Exports a variable from AnyBody with a optionally different name.

  • ExtendOutput(var, value): Add an arbitrary var=value to the output.

  • LoadDesign(var, filename): classoperation “Load design”

  • SaveDesign(var, filename): classoperation “Save design”

  • LoadValues(filename): classoperation Main “Load Values”

  • SaveValues(filename): classoperation Main “Save Values”

  • UpdateValues(): classoperation “Update Values”

  • SetValue(var,value): classoperation “Set Value”

  • MacroCommand(macro_string): Add abitrary macro string

Creating many macros#

The macro in the previous example would have been easy to write manually. However, in some cases we want to create many macros. Then it is a big advantage to generate them programmatically.

This is easily done in Python with a for loop.

macrolist = []
for i in range(3):
    macro = [
        Load('Knee.any' ),
        RunOperation('Main.MyStudy.InverseDynamics'),
    ]
    macrolist.append(macro)
    
macrolist
[[load "Knee.any",
  operation Main.MyStudy.InverseDynamics
  run],
 [load "Knee.any",
  operation Main.MyStudy.InverseDynamics
  run],
 [load "Knee.any",
  operation Main.MyStudy.InverseDynamics
  run]]

Running many macros is only really useful if the macros are different. So let us try to create a macro which sets different values in each run.

Imagine a list of 5 parameters. We want to create five macros that use these values:

parameter_list = [2.2, 2.5, 2.7, 2.9, 3.1]

macrolist = []
for val in parameter_list:
    macro = [
        Load('Knee.any' ),
        SetValue('Main.MyParameter', val),
        RunOperation('Main.MyStudy.InverseDynamics'),
    ]
    macrolist.append(macro)
    
macrolist
[[load "Knee.any",
  classoperation Main.MyParameter "Set Value" --value="2.2",
  operation Main.MyStudy.InverseDynamics
  run],
 [load "Knee.any",
  classoperation Main.MyParameter "Set Value" --value="2.5",
  operation Main.MyStudy.InverseDynamics
  run],
 [load "Knee.any",
  classoperation Main.MyParameter "Set Value" --value="2.7",
  operation Main.MyStudy.InverseDynamics
  run],
 [load "Knee.any",
  classoperation Main.MyParameter "Set Value" --value="2.9",
  operation Main.MyStudy.InverseDynamics
  run],
 [load "Knee.any",
  classoperation Main.MyParameter "Set Value" --value="3.1",
  operation Main.MyStudy.InverseDynamics
  run]]

A simple parameter study#

Let us combine the previous to create a parameter study. We will continue with the simplified knee model where we left off in the previous tutorial. The parameter study will vary the patella tendon length from 2.0cm to 8.0cm, and observe the effect on maximum muscle activity.

First we create a list of patella length parameters.

patella_tendon_lengths = [
    0.02 + i*0.01 
    for i in range(7)
]
print(patella_tendon_lengths)
[0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08]

This list of values is added to the macros with the SetValue class.

parameter_study_macro = []

for patella_length in patella_tendon_lengths:
    macro = [
        Load('Knee.any'),
        SetValue('Main.MyModel.PatellaLigament.DriverPos', patella_length),
        RunOperation('Main.MyStudy.InverseDynamics'),
        Export('Main.MyStudy.Output.Abscissa.t', "Time steps"),
        Export('Main.MyStudy.Output.MaxMuscleActivity', "Max muscle activity"),
        ExtendOutput("PatellaLength", patella_length),
    ]
    parameter_study_macro.append(macro)

Note, that here we have used two special helper classes Export(var, name), and ExtendOutput(name, value). The Export class allows us to rename the output variables, so we don’t need to refer to the long AnyBody names in the output. The second ExtendOutput is mostly a convinance, as it adds a PatellaLength variable to the output, so we don’t need to keep track of which length corresponds to different ouptuts.

parameter_study_macro[0:2]
[[load "Knee.any",
  classoperation Main.MyModel.PatellaLigament.DriverPos "Set Value" --value="0.02",
  operation Main.MyStudy.InverseDynamics
  run,
  print "#### ANYPYTOOLS RENAME OUTPUT: Time steps"
  print Main.MyStudy.Output.Abscissa.t,
  print "#### ANYPYTOOLS RENAME OUTPUT: Max muscle activity"
  print Main.MyStudy.Output.MaxMuscleActivity,
  print "PatellaLength = 0.02;"],
 [load "Knee.any",
  classoperation Main.MyModel.PatellaLigament.DriverPos "Set Value" --value="0.03",
  operation Main.MyStudy.InverseDynamics
  run,
  print "#### ANYPYTOOLS RENAME OUTPUT: Time steps"
  print Main.MyStudy.Output.Abscissa.t,
  print "#### ANYPYTOOLS RENAME OUTPUT: Max muscle activity"
  print Main.MyStudy.Output.MaxMuscleActivity,
  print "PatellaLength = 0.03;"]]

It means that the macro now starts to look a bit messy. But luckly we don’t have think about that.

We just pass the parameter_study_macro to the start_macro() function which gives us back a results variable:

results = app.start_macro(parameter_study_macro)
Completed: 7

%matplotlib inline
import matplotlib.pyplot as plt

for data in results:
    plt.plot(
        data['Time steps'],
        data['Max muscle activity'],
        label='{:.1f} cm'.format(100* data['PatellaLength'])
    )

plt.title('Effect of changing patella tendon length')    
plt.xlabel('Time steps')
plt.ylabel('Max muscle activity')
plt.legend(bbox_to_anchor=(1.05, 1), loc=2);
../_images/a781676d21451c5c45542e45b810ab52bc331e652c9bc66c2c4ebe50644db33b.png