\hypertarget{pageScripting_secScriptingOverview}{}\subsection{Overview}\label{pageScripting_secScriptingOverview}
The {\itshape scripting} capabilities of the P\+I\+P\+E\+R application let the user insert custom operation in his workflow by \hyperlink{pageScripting_secScriptingScript}{Writing a script}. It is also possible to run complete workflows from scripts, this is the so called \hyperlink{pageScripting_secScriptingBatch}{Batch mode}. The scripts are written in \href{https://docs.python.org/2/}{\tt Python 2.\+7}, see \hyperlink{pageScripting_secScriptingReference}{P\+I\+P\+E\+R Python packages} for a reference of the P\+I\+P\+E\+R specific python A\+P\+I.\hypertarget{pageScripting_secScriptingRun}{}\subsection{Running a script}\label{pageScripting_secScriptingRun}
From the {\itshape Scripting} menu any python script can be run at any time. If the script expects parameters, they can be specified in a space separated list. A list of standard script is provided with the application (they are located in {\ttfamily share/python/scripting}). Additionnaly the user can set a custom script folder from which the python scripts are listed.


\begin{DoxyImage}
\includegraphics[width=0.3\textwidth]{scripting_01.png}
\caption{Running a python script with arguments}
\end{DoxyImage}
\hypertarget{pageScripting_secScriptingScript}{}\subsection{Writing a script}\label{pageScripting_secScriptingScript}
Using the provided {\ttfamily piper} python packages, the user can access and modify the current application {\itshape model}, {\itshape metadata} and {\itshape targets}. The following example are available in the {\ttfamily share/example/scripting} folder.\hypertarget{pageScripting_secScriptingScriptBasic}{}\subsubsection{Basic functionalities}\label{pageScripting_secScriptingScriptBasic}
The traditional {\itshape Hello world !} example (in {\ttfamily hello\+World.\+py})\+: 
\begin{DoxyCodeInclude}
1 \textcolor{comment}{# Simple hello-world script}
2 
3 \textcolor{comment}{# access PIPER application functions}
4 \textcolor{keyword}{import} piper.app
5 
6 piper.app.logInfo(\textcolor{stringliteral}{"Hello World !"})
\end{DoxyCodeInclude}


A script which manipulates its arguments (in {\ttfamily sum.\+py}) \+: 
\begin{DoxyCodeInclude}
1 \textcolor{comment}{# Compute the sum a + b}
2 \textcolor{comment}{#}
3 \textcolor{comment}{# arguments:}
4 \textcolor{comment}{#  a b}
5 
6 \textcolor{keyword}{import} sys
7 
8 \textcolor{comment}{# access PIPER application functions}
9 \textcolor{keyword}{import} piper.app
10 
11 \textcolor{keyword}{def }computeSum(a, b):
12     piper.app.logInfo(\textcolor{stringliteral}{"a+b = \{0\}"}.format(a+b))
13 
14 \textcolor{keywordflow}{if} (3 != len(sys.argv)):
15     \textcolor{keywordflow}{raise} RuntimeError(\textcolor{stringliteral}{"Invalid arguments"})
16 \textcolor{keywordflow}{else} :
17     computeSum(float(sys.argv[1]), float(sys.argv[2]))
18 
\end{DoxyCodeInclude}
\hypertarget{pageScripting_secScriptingScriptModel}{}\subsubsection{Accessing model metadata and geometry}\label{pageScripting_secScriptingScriptModel}
The following example shows how to access the current model and metadata, and also query the anatomy database. The script computes the vertebrae centroids and print the result in the application log (in {\ttfamily vertebrae\+Centroid.\+py}) \+: 
\begin{DoxyCodeInclude}
1 \textcolor{comment}{# Compute the centroid of each vertebra and print it in the application log}
2 
3 \textcolor{comment}{# numpy is a standard package for matrix manipulation}
4 \textcolor{keyword}{import} numpy
5 
6 \textcolor{comment}{# access PIPER human body model functionnalities}
7 \textcolor{keyword}{import} \hyperlink{namespacepiper_1_1hbm}{piper.hbm}
8 \textcolor{comment}{# access anatomy database functionnalities}
9 \textcolor{keyword}{import} piper.anatomyDB
10 \textcolor{comment}{# access PIPER application functions}
11 \textcolor{keyword}{import} piper.app
12 
13 model = piper.app.Context.instance().project().model()
14 
15 \textcolor{comment}{# if the model is empty, we can do nothing}
16 \textcolor{keywordflow}{if} (model.empty()):
17     piper.app.logWarning(\textcolor{stringliteral}{"Model is empty"})
18 \textcolor{keywordflow}{else}:
19     \textcolor{comment}{# get metadata and fem from the current project}
20     metadata = piper.app.Context.instance().project().model().metadata()
21     fem = piper.app.Context.instance().project().model().fem()
22     \textcolor{keywordflow}{for} (name,entity) \textcolor{keywordflow}{in} metadata.entities().iteritems() :
23         \textcolor{comment}{# check if this entity is a vertebrae}
24         \textcolor{keywordflow}{if} piper.anatomyDB.isEntityPartOf(name, \textcolor{stringliteral}{"Vertebral\_column"}, \textcolor{keyword}{True}):
25             piper.app.logInfo(\textcolor{stringliteral}{"\{0\}: \{1\}"}.format(name, computeCentroid(entity, fem)))
26 
27 \textcolor{comment}{# compute the centroid of an entity}
28 \textcolor{keyword}{def }computeCentroid(entity, fem):
29     c = numpy.zeros((3,1)) \textcolor{comment}{# initialize the centroid, notice the (3,1) shape for a vector}
30     envelopNodesId = entity.getEnvelopNodes(fem)
31     \textcolor{keywordflow}{for} id \textcolor{keywordflow}{in} envelopNodesId :
32          c += fem.getNode(id).get()
33     \textcolor{keywordflow}{return} (c / len(envelopNodesId)).flatten()
\end{DoxyCodeInclude}


The following example shows how to export the currently selected nodes and elements to an external {\ttfamily }.obj file (in {\ttfamily export\+Selected\+Geometry\+To\+Obj.\+py}). 
\begin{DoxyCodeInclude}
1 \textcolor{comment}{# This script exports the current selected geometry (nodes + triangles)}
2 \textcolor{comment}{# It also writes a json file which stores correspondances between obj vertices and piper nodes id}
3 \textcolor{comment}{# for further update with updateNodesFromObj.py script}
4 \textcolor{comment}{# }
5 \textcolor{comment}{# arguments:}
6 \textcolor{comment}{#  /path/to/mesh.obj}
7 
8 \textcolor{comment}{# author: Thomas Lemaire date: 2017}
9 
10 \textcolor{keyword}{import} sys
11 \textcolor{keyword}{import} json
12 
13 \textcolor{keyword}{import} \hyperlink{namespacepiper_1_1hbm}{piper.hbm}
14 \textcolor{keyword}{import} piper.app
15 
16 \textcolor{keyword}{def }writeObj(fem, nodeIds, elem2DIds, objFilePath):
17     \textcolor{comment}{# gather node ids from nodes and elements}
18     allNodeIds = set()
19     \textcolor{keywordflow}{for} id \textcolor{keywordflow}{in} nodeIds:
20         allNodeIds.add(id)
21     \textcolor{keywordflow}{for} elemId \textcolor{keywordflow}{in} elem2DIds:
22         elem = fem.getElement2D(elemId)
23         \textcolor{keywordflow}{if} \textcolor{keywordflow}{not} elem.getType() \textcolor{keywordflow}{in} \{piper.hbm.ELT\_TRI, piper.hbm.ELT\_QUAD\}:
24             piper.app.logWarning(\textcolor{stringliteral}{"Unsupported: elem: \{0\} type: \{1\}"}.format(elemId, elem.getType()))
25             \textcolor{keywordflow}{continue}
26         ids = elem.get()
27         \textcolor{keywordflow}{for} id \textcolor{keywordflow}{in} ids:
28             allNodeIds.add(id)
29     \textcolor{comment}{# in an obj file, vertices are referenced by their index, starting at 1, to describe faces}
30     nodeIdToObjIndex = dict()
31     objIndexToNodeId = dict()
32     with open(objFilePath, \textcolor{stringliteral}{'w'}) \textcolor{keyword}{as} objFile:
33         piper.app.logInfo(\textcolor{stringliteral}{"Writting obj file \{0\} ..."}.format(objFilePath))
34         objFile.write(\textcolor{stringliteral}{"# File generated by the PIPER application\(\backslash\)n"})
35         currentIndex = 1 \textcolor{comment}{# obj convention starts at 1}
36         \textcolor{keywordflow}{for} nodeId \textcolor{keywordflow}{in} allNodeIds:
37             nodeIdToObjIndex[nodeId] = currentIndex
38             objIndexToNodeId[currentIndex] = nodeId
39             coord = fem.getNode(nodeId).get().flatten()
40             objFile.write(\textcolor{stringliteral}{"v \{0\} \{1\} \{2\}\(\backslash\)n"}.format(coord[0], coord[1], coord[2]))
41             currentIndex+=1
42         \textcolor{keywordflow}{for} elemId \textcolor{keywordflow}{in} elem2DIds:
43             elem = fem.getElement2D(elemId)
44             ids = elem.get()
45             \textcolor{keywordflow}{if} elem.getType() == piper.hbm.ELT\_QUAD:
46                 idsQuad = elem.get()
47                 objFile.write(\textcolor{stringliteral}{"f \{0\} \{1\} \{2\}\(\backslash\)n"}.format(nodeIdToObjIndex[idsQuad[0]], nodeIdToObjIndex[
      idsQuad[1]], nodeIdToObjIndex[idsQuad[2]]))
48                 objFile.write(\textcolor{stringliteral}{"f \{0\} \{1\} \{2\}\(\backslash\)n"}.format(nodeIdToObjIndex[idsQuad[0]], nodeIdToObjIndex[
      idsQuad[2]], nodeIdToObjIndex[idsQuad[3]]))
49                 \textcolor{keywordflow}{continue}
50             \textcolor{keywordflow}{elif} elem.getType() == piper.hbm.ELT\_TRI:
51                 objFile.write(\textcolor{stringliteral}{"f \{0\} \{1\} \{2\}\(\backslash\)n"}.format(nodeIdToObjIndex[ids[0]], nodeIdToObjIndex[ids[1]], 
      nodeIdToObjIndex[ids[2]]))
52             \textcolor{keywordflow}{else}:
53                 \textcolor{keywordflow}{continue}
54     objIdFilePath = objFilePath+\textcolor{stringliteral}{".json"}
55     with open(objIdFilePath, \textcolor{stringliteral}{'w'}) \textcolor{keyword}{as} objIdFile:
56         piper.app.logInfo(\textcolor{stringliteral}{"Writting obj id file \{0\} ..."}.format(objIdFilePath))
57         json.dump(objIndexToNodeId, objIdFile)
58 
59 model = piper.app.Context.instance().project().model()
60 
61 \textcolor{comment}{# if the model is empty, we can do nothing}
62 \textcolor{keywordflow}{if} model.empty():
63     piper.app.logWarning(\textcolor{stringliteral}{"Model is empty"})
64 \textcolor{keywordflow}{elif} 2 != len(sys.argv) :
65     \textcolor{keywordflow}{raise} RuntimeError(\textcolor{stringliteral}{"Invalid arguments"})
66 \textcolor{keywordflow}{else} :
67     modelVTK = model.fem().getFEModelVTK()
68     nodeIds = modelVTK.getSelectedNodes()
69     elem2DIds = modelVTK.getSelectedElements(2)
70     piper.app.logInfo(\textcolor{stringliteral}{"nb selected nodes: \{0\}"}.format(len(nodeIds)))
71     piper.app.logInfo(\textcolor{stringliteral}{"nb selected elements: \{0\}"}.format(len(elem2DIds)))
72     writeObj(model.fem(), nodeIds, elem2DIds, sys.argv[1])
73     
74     
\end{DoxyCodeInclude}


The following example shows how to export entities nodes {\itshape id in F\+E code} and coordinate (in {\ttfamily export\+Entities\+Nodes\+Coordinates.\+py}) 
\begin{DoxyCodeInclude}
1 \textcolor{comment}{# Export nodes coordinates from a model in history}
2 \textcolor{comment}{# }
3 \textcolor{comment}{# arguments: }
4 \textcolor{comment}{#   /path/to/export/directory [history name]}
5 
6 \textcolor{keyword}{import} os
7 \textcolor{keyword}{import} os.path
8 \textcolor{keyword}{import} shutil
9 \textcolor{keyword}{import} exceptions
10 
11 \textcolor{keyword}{import} \hyperlink{namespacepiper_1_1hbm}{piper.hbm}
12 \textcolor{keyword}{import} piper.app
13 
14 model = piper.app.Context.instance().project().model()
15 
16 \textcolor{comment}{# if the model is empty, we can do nothing}
17 \textcolor{keywordflow}{if} model.empty():
18     piper.app.logWarning(\textcolor{stringliteral}{"Model is empty"})
19 \textcolor{keywordflow}{elif} \textcolor{keywordflow}{not} ( len(sys.argv) \textcolor{keywordflow}{in} \{2,3\} ) :
20     \textcolor{keywordflow}{raise} RuntimeError(\textcolor{stringliteral}{"Invalid arguments"})
21 \textcolor{keywordflow}{else} :
22     exportDirectory = sys.argv[1]
23     
24     \textcolor{comment}{# setup model in history}
25     originalHistory = \textcolor{keywordtype}{None}
26     \textcolor{keywordflow}{if} len(sys.argv) == 3:
27         originalHistory = model.history().getCurrent()
28         model.history().setCurrentModel(sys.argv[2])
29         
30     shutil.rmtree(exportDirectory, ignore\_errors=\textcolor{keyword}{True})
31     os.makedirs(exportDirectory)
32     metadata = model.metadata()
33     fem = model.fem()
34     piperIdToIdKey = fem.computePiperIdToIdKeyMapNode();
35     \textcolor{keywordflow}{for} (name,entity) \textcolor{keywordflow}{in} metadata.entities().iteritems() :
36         ids = entity.getEntityNodesIds(fem)
37         datFilePath = os.path.join(exportDirectory, name+\textcolor{stringliteral}{".dat"})
38         piper.app.logInfo(\textcolor{stringliteral}{"Export \{0\} nodes from entity \{1\} to \{2\}"}.format(len(ids), name, datFilePath))
39         with open(datFilePath, \textcolor{stringliteral}{'w'}) \textcolor{keyword}{as} datFile:
40             datFile.write(\textcolor{stringliteral}{"# Entity \{0\}\(\backslash\)n"}.format(name))
41             datFile.write(\textcolor{stringliteral}{"# Id x y z\(\backslash\)n"})
42             \textcolor{keywordflow}{for} nodeId \textcolor{keywordflow}{in} ids:
43                 coord = fem.getNode(nodeId).get().flatten()
44                 datFile.write(\textcolor{stringliteral}{"\{0\} \{1\} \{2\} \{3\}\(\backslash\)n"}.format(piperIdToIdKey[nodeId].id, coord[0], coord[1], 
      coord[2]))
45     
46     \textcolor{comment}{# restore model in history}
47     \textcolor{keywordflow}{if} \textcolor{keywordflow}{not} originalHistory \textcolor{keywordflow}{is} \textcolor{keywordtype}{None}:
48         model.history().setCurrentModel(originalHistory)
\end{DoxyCodeInclude}


T\+O\+D\+O\+: examples with target creation, T\+O\+D\+O\+: example with data preparation saved to (octave) file, running octave, reading output and preparing targets T\+O\+D\+O\+: doc for piper.\+app, \hyperlink{namespacepiper_1_1hbm}{piper.\+hbm} and piper.\+anatomydb python packages\hypertarget{pageScripting_secScriptingBatch}{}\subsection{Batch mode}\label{pageScripting_secScriptingBatch}
The {\itshape batch mode} enable the user to prepare {\itshape scripts} to run at once a sequence of operations. The functions available in batch mode includes Project read/write, import/export, target read/write and modification, module parameters modification and access to \hyperlink{pageModules}{P\+I\+P\+E\+R Modules Overview}.

The batch mode is started with\+: \begin{DoxyVerb}$ piper --batch my_script.py
\end{DoxyVerb}
 More options are available, refer to {\ttfamily \char`\"{}piper -\/-\/help\char`\"{}} output.\hypertarget{pageScripting_secScriptingBatchExample}{}\subsubsection{Examples}\label{pageScripting_secScriptingBatchExample}
\hypertarget{pageScripting_secBatchExample01}{}\paragraph{Target creation}\label{pageScripting_secBatchExample01}

\begin{DoxyCodeInclude}
1 \textcolor{keyword}{import} math
2 
3 \textcolor{keyword}{import} piper.app
4 \textcolor{keyword}{import} \hyperlink{namespacepiper_1_1hbm}{piper.hbm}
5 \textcolor{keyword}{import} piper.test
6 
7 target = \hyperlink{classpiper_1_1hbm_1_1TargetList}{piper.hbm.TargetList}()
8 
9 target.add(\hyperlink{classpiper_1_1hbm_1_1FixedBoneTarget}{piper.hbm.FixedBoneTarget}(\textcolor{stringliteral}{"Pelvic\_skeleton"}))
10 
11 leftASISTarget = \hyperlink{classpiper_1_1hbm_1_1LandmarkTarget}{piper.hbm.LandmarkTarget}()
12 leftASISTarget.setName(\textcolor{stringliteral}{"Pelvis\_position\_1"})
13 leftASISTarget.setUnit(piper.hbm.Length\_m)
14 leftASISTarget.landmark = \textcolor{stringliteral}{"Left\_ASIS"}
15 leftASISTarget.setValue(\{0:0.3, 1:1.2, 2:-0.25\})
16 target.add(leftASISTarget)
17 
18 piper.test.expect\_eq(piper.hbm.Length\_m, leftASISTarget.unit(), \textcolor{stringliteral}{"Error during target creation"})
19 
20 hipTarget = \hyperlink{classpiper_1_1hbm_1_1JointTarget}{piper.hbm.JointTarget}()
21 hipTarget.setName(\textcolor{stringliteral}{"Hip\_position"})
22 hipTarget.setUnit(piper.hbm.Length\_dm)
23 hipTarget.joint=\textcolor{stringliteral}{"Left\_hip\_joint"}
24 hipTarget.setValue(\{4:math.radians(45)\})
25 target.add(hipTarget)
26 
27 piper.test.expect\_eq(piper.hbm.Length\_dm, hipTarget.unit(), \textcolor{stringliteral}{"Error during target creation"})
28 
29 headTarget = \hyperlink{classpiper_1_1hbm_1_1FrameToFrameTarget}{piper.hbm.FrameToFrameTarget}()
30 headTarget.setName(\textcolor{stringliteral}{"Head\_position"})
31 headTarget.frameSource = \textcolor{stringliteral}{"W\_Origin"}
32 headTarget.frameTarget = \textcolor{stringliteral}{"B\_Skull"}
33 headTarget.setUnit(piper.hbm.Length\_mm)
34 headTarget.setValue(\{0:200\})
35 target.add(headTarget)
36 
37 piper.test.expect\_eq(4, target.size(), \textcolor{stringliteral}{"Error during target creation"})
\end{DoxyCodeInclude}
\hypertarget{pageScripting_secBatchExample02}{}\paragraph{Physics based positioning}\label{pageScripting_secBatchExample02}

\begin{DoxyCodeInclude}
1 \textcolor{keyword}{import} os.path
2 \textcolor{keyword}{import} math
3 
4 \textcolor{keyword}{import} piper.app
5 \textcolor{keyword}{import} \hyperlink{namespacepiper_1_1hbm}{piper.hbm}
6 
7 project = piper.app.Project()
8 
9 \textcolor{comment}{# save Child}
10 chilpProjectFile = os.path.join(piper.app.tempDirectoryPath(), \textcolor{stringliteral}{"child.ppj"})
11 \textcolor{comment}{#chilpProjectFile = os.path.join("/local2/build/piper-release/child.ppj")}
12 project.read(chilpProjectFile)
13 
14 project.moduleParameter().setInt(\textcolor{stringliteral}{"PhysPosi"},\textcolor{stringliteral}{"autoStopNbIterationMax"}, 100)
15 project.moduleParameter().setFloat(\textcolor{stringliteral}{"PhysPosi"}, \textcolor{stringliteral}{"autoStopVelocity"}, 1e-7)
16 project.moduleParameter().setFloat(\textcolor{stringliteral}{"PhysPosi"},\textcolor{stringliteral}{"voxelSize"}, 0.01)
17 
18 target = \hyperlink{classpiper_1_1hbm_1_1TargetList}{piper.hbm.TargetList}()
19 
20 target.add(\hyperlink{classpiper_1_1hbm_1_1FixedBoneTarget}{piper.hbm.FixedBoneTarget}(\textcolor{stringliteral}{"Pelvic\_skeleton"}))
21 
22 hipTarget = \hyperlink{classpiper_1_1hbm_1_1JointTarget}{piper.hbm.JointTarget}()
23 hipTarget.setName(\textcolor{stringliteral}{"Hip\_position"})
24 hipTarget.joint=\textcolor{stringliteral}{"Left\_hip\_joint"}
25 hipTarget.setValue(\{4:math.radians(45)\})
26 target.add(hipTarget)
27 
28 headTarget = \hyperlink{classpiper_1_1hbm_1_1FrameToFrameTarget}{piper.hbm.FrameToFrameTarget}()
29 headTarget.setName(\textcolor{stringliteral}{"Head\_position"})
30 headTarget.setUnit(piper.hbm.Length\_mm)
31 headTarget.frameSource = \textcolor{stringliteral}{"W\_Origin"}
32 headTarget.frameTarget = \textcolor{stringliteral}{"B\_Skull"}
33 headTarget.setValue(\{0:200\})
34 target.add(headTarget)
35 
36 piper.app.physPosiDeform(project, target)
\end{DoxyCodeInclude}
\hypertarget{pageScripting_secScriptingReference}{}\subsection{P\+I\+P\+E\+R Python packages}\label{pageScripting_secScriptingReference}
The P\+I\+P\+E\+R specific functions are made available in batch thanks to several Python packages \+:
\begin{DoxyItemize}
\item application Context, Project manipulation, logging functions and more\+: \hyperlink{group__piper__app}{Python package piper.\+app}
\item access H\+B\+M data, Metadata, Target and more\+: \hyperlink{group__piper__hbm}{Python package piper.\+hbm}
\item access anatomy database queries and anatomical frames computation\+: \hyperlink{group__piper__anatomydb}{Python package piper.\+anatomy\+D\+B} 
\end{DoxyItemize}