301 lines (228 with data), 11.4 kB
#ifndef HELPER_CLASSTEMPLATES_ANY
#define HELPER_CLASSTEMPLATES_ANY
// Utility macros to search for objects, Bool, Float, Int, String variables returning
// default value if they are not founds
#define GET_OBJ_DEFAULT(SEARCH_STR, DEFAULT) arrcat(ObjSearch(SEARCH_STR), & DEFAULT)[0]
#define GET_FLOAT_DEFAULT(SEARCH_STR, DEFAULT) arrcat(Obj2Num(ObjSearch(SEARCH_STR)),DEFAULT)[0]
#define GET_INT_DEFAULT(SEARCH_STR, DEFAULT) arrcat(round(Obj2Num(ObjSearch(SEARCH_STR))),round(DEFAULT))[0]
#define GET_STRING_DEFAULT(SEARCH_STR, DEFAULT) arrcat(Obj2Str(ObjSearch(SEARCH_STR)),DEFAULT)[0]
// Create a mesh grid for evaluating functions. This is similar to `[xx, yy, zz] = numpy.meshgrid(X,Y,Z)`
#define MESHGRID(X,Y,Z) { reshape(repmat(NumElemOf(Y), flatten(repmat(1, NumElemOf(Z), X))), {NumElemOf(Y), NumElemOf(X), NumElemOf(Z)}), \
reshape(flatten(repmat(1, NumElemOf(Z)*NumElemOf(X), Y)) , {NumElemOf(Y), NumElemOf(X), NumElemOf(Z)}), \
reshape(flatten(repmat(NumElemOf(X)* NumElemOf(Y), Z)), {NumElemOf(Y), NumElemOf(X), NumElemOf(Z)}) }
// Create a array of x,y,z triples for a 3D grid, defined by the vectors aa, bb,cc. This is similar to np.vstack([XX.ravel(), YY.ravel(), ZZ.ravel()].T where xx,yy,zz are outputs of meshgrid
#define MESHTRIPLES(X,Y,Z) reshape( MESHGRID(X,Y,Z), {3, NumElemOf(X)*NumElemOf(Y)*NumElemOf(Z) })'
#define REPLACE_ZEROS(x, replacement) ((x) + not(x)*(replacement))
// Create a difference matrix of of size (N,N-1)
// This can be used calcuate the difference between adjacent elements in a vector or matrix.
#define DIFFMAT(N) (arrcat(zeros(1,N-1), eye(N-1)')' - arrcat(eye(N-1)', zeros(1,N-1))')
// Pairwise distances between observations in n-dimensional space.
#define PDIST(X) sum(vnorm(DIFFMAT(SizesOf(X)[0])*(X)))
//Total length of a polyline defined by a set of points.
#define TOTAL_POLYLINE_LENGTH(P) sum(vnorm((arrcat(zeros(1,SizesOf(P)[0]-1), eye(SizesOf(P)[0]-1)')' - arrcat(eye(SizesOf(P)[0]-1)', zeros(1,SizesOf(P)[0]-1))')*P))
//An array with ones at and below the given diagonal and zeros elsewhere.
#define TRI(N) lteqfun(transpose(repmat(1,N ,iarr(1,N))), repmat(1,N,iarr(1,N)))
// Upper triangle of the array. Return a copy of an array with elements below the diagonal zeroed out
#define TRIU(IN) mult(IN, gteqfun(transpose(repmat(1,SizesOf(IN)[0] ,iarr(1,SizesOf(IN)[1]))), repmat(1,SizesOf(IN)[1],iarr(1,SizesOf(IN)[0]))))
// Lower triangle of the array. Return a copy of an array with elements above the diagonal zeroed out
#define TRIL(IN) mult(IN, lteqfun(transpose(repmat(1,SizesOf(IN)[0] ,iarr(1,SizesOf(IN)[1]))), repmat(1,SizesOf(IN)[1],iarr(1,SizesOf(IN)[0]))))
// Projection of P onto the line BA
#define VECTOR_PROJECTION(P, A, B) (A) + ( ((P)-(A))*((B)-(A))' / ( ((B)-(A))*((B)-(A))') )*((B)-(A))
// Normal vector for the non-coliniar points A,B,C
#define NORMAL_VECTOR(A,B,C) cross((B)-(A), (C)-(B)) / vnorm( cross((B)-(A), (C)-(B)) )
// Projection of the point P on the plane defined by A,B,C
#define PLANE_PROJECTION(P,A,B,C) (P) - (((P)-(A))*(NORMAL_VECTOR(A,B,C))')*NORMAL_VECTOR(A,B,C)
// Remove artificial muscles' contribution to the total Pmet calculation
// Is defined in all relevant AnyMuscles and some AnyMusclesViaPoint
#define EXCLUDE_MUSCLE_METABOLISM AnyMetabModelSimple ZeroMetabolicMdl = {EtaCon = 2e22; EtaEcc = 2e22;}; MetabModel = &ZeroMetabolicMdl;
// Extract non unique elements from an array
// one version for pointers and one for values
// we sort the array and take two indexes shifted by one element
// by comparing the two adjecant elements we identify duplicates
#define NON_UNIQUE_VALUES(A) take( \
ObjSort(A), \
take( \
unique( \
mult( \
iarr(1, NumElemOf(ObjSort(A)) -1), \
eqfun( \
take(ObjSort(A), iarr(1, NumElemOf(ObjSort(A)) - 1)), \
take(ObjSort(A), iarr(0, NumElemOf(ObjSort(A)) - 2)) \
) \
) \
), \
iarr(1, NumElemOf( \
unique( \
mult( \
iarr(1, NumElemOf(ObjSort(A)) -1), \
eqfun( \
take(ObjSort(A), iarr(1, NumElemOf(ObjSort(A)) - 1)), \
take(ObjSort(A), iarr(0, NumElemOf(ObjSort(A)) - 2)) \
) \
) \
) \
) -1) \
) \
)
// Same as NON_UNIQUE_VALUES but for pointers and returning a pointer array
#define NON_UNIQUE_POINTERS(A) ObjSearch( \
take( \
ObjSort(CompleteNameOf(A)), \
take( \
unique( \
mult( \
iarr(1, NumElemOf(ObjSort(CompleteNameOf(A))) -1), \
eqfun( \
take(ObjSort(CompleteNameOf(A)), iarr(1, NumElemOf(ObjSort(CompleteNameOf(A))) - 1)), \
take(ObjSort(CompleteNameOf(A)), iarr(0, NumElemOf(ObjSort(CompleteNameOf(A))) - 2)) \
) \
) \
), \
iarr(1, NumElemOf( \
unique( \
mult( \
iarr(1, NumElemOf(ObjSort(CompleteNameOf(A))) -1), \
eqfun( \
take(ObjSort(CompleteNameOf(A)), iarr(1, NumElemOf(ObjSort(CompleteNameOf(A))) - 1)), \
take(ObjSort(CompleteNameOf(A)), iarr(0, NumElemOf(ObjSort(CompleteNameOf(A))) - 2)) \
) \
) \
) \
) -1) \
) \
) \
)
#define SET_DEFAULT_ACTUATOR_VOLUME Volume = 1e-6
// Add backwards compatible macro to set the operation display priority for the
// for the dropdown operations menu. PRIORITY can be
// PriorityLow: The operation will never show in the dropdown menu.
// PriorityNormal: Default rules apply to when operations are shown.
// PriorityHigh: Opeartion will always appear in the dropdown menu.
#if (ANYBODY_V1 > 7)|(ANYBODY_V1 == 7 & ANYBODY_V2 > 1)
#define OPERATION_DISPLAY_PRIORITY(PRIORITY) Settings.DisplayPriority = PRIORITY
#define OPERATION_SELECT_ON_LOAD Settings.SelectOnLoad = On
#else
#define OPERATION_DISPLAY_PRIORITY(PRIORITY) Settings = {}
#define OPERATION_SELECT_ON_LOAD Settings = {}
#endif
/* this piece of code ensures backcompatibility of AMMR using AnyComponentDefinition
with versions of AMS below 7.2.x */
#if (ANYBODY_V1 > 7)|(ANYBODY_V1 == 7 & ANYBODY_V2 > 1)
#else
#class_template AnyComponentDefinition
{
#var AnyStringVar NameCast = "";
#var AnyStringVar SubGroupRegexSearch = "";
#var AnyStringVar SubGroupRegexReplace = "";
#var AnyIntVar Hidden = 0;
#var AnySwitchVar IsBranch = Off;
};
#endif
/* Creates a Folder with and AnyFunConst member. This is useful for creating
weight function with weight that can later be overridden by the user.
*/
#class_template Template_AnyFunConst (NUMBER_OF_ELEMENTS=1, WEIGHT=0.01, _NAME=Fun) {
AnyFunConst _NAME={
#var Value=repmat(NUMBER_OF_ELEMENTS, WEIGHT);
};
};
#class_template Template_OperationSaveValues(__CLASS__= AnyOperationSequence, _REDEFINE_INPUTS=Off) {
#if _REDEFINE_INPUTS == Off
#var AnyObjectPtrArray ObjectsMarkedAsModified = ObjSearch("");
#var AnyObjectPtrVar Folder = &Main;
#var AnyFileVar FileName;
#endif
AnyOperationSetValue MarkAsModified = {
Source = .ObjectsMarkedAsModified;
Target = .ObjectsMarkedAsModified;
};
AnyOperationMacro SaveValuesToFile = {
MacroStr = {
("classoperation "
+ CompleteNameOf(.Folder)
+ strquote("Save Values")
+ " --file="
+ strquote(FilePathCompleteOf(.FileName))
)
};
};
};
#class_template Template_OperationUpdateValues(__CLASS__= AnyOperationMacro) {
MacroStr = {"classoperation Main " + strquote("Update Values") };
};
#class_template Template_OperationLoadValues(__CLASS__= AnyOperationSequence, _REDEFINE_INPUTS=Off) {
#if _REDEFINE_INPUTS == Off
#var AnyFileVar FileName;
#endif
AnyOperationMacro LoadValuesFromFile = {
MacroStr = {"classoperation Main " + strquote("Load Values") + " --file=" + strquote(FilePathCompleteOf(.FileName) };
};
};
/*
Create a sorted string array of {Name, value} pairs.
Arrays in AMS must all have only one type (no dictionary objects). So this functions
creates a string represenation of the values.
E.g.:
{"Main.HumanModel.BodyModel.Right.Leg.Mus.VastusIntermedius6.Activity", "0.10421"},
{"Main.HumanModel.BodyModel.Right.Leg.Mus.VastusIntermedius5.Activity", "0.03122"},
{"Main.HumanModel.BodyModel.Right.Leg.Mus.VastusIntermedius4.Activity", "0.01232"},
This template is useful for attaching names to values which are searched out using functions
such as ObjectSearch or ObjectSearch recursive.
Arguments:
NAME_OF_FUN = CompleteNameOf
The funciton use to generate the names in the map.
Default is the complete name of the objects.
ORDER = "Desending"
The order which the values are sorted. Default is desending.
Anything else will give Assending order
FORMAT="%.4f"
The format specifier used when generating a string represenation of the values
default is 4 digits.
STUDY_T = .t
A link to a t (time) value. In either a study or mechanical object. This is a necesssary
hack to make sure the values are evaluated at every time step.
This has a default value which allows the class_template to be used in studies or
in mechanical objects without modifing the default value.
Members:
ValuePtrs: AnyObjectPtr (Required)
- An array of pointers to AnyValues objects which will be used to generate
the <Name, Value> map
NamePtr : AnyObjectPtr (Optional)
- An array of pointers to AnyObjects which will be used when generating the names
in the <name, values> map. This default to the `ValuePtrs` array, but can be different
if needed.
Output member:
Output: AnyString
A string array of sorted <name, value> pairs
Examples:
NameValueMap RightLegActivity() = {
ValuePtrs = ObjSearchRecursive("Main.HumanModel.BodyModel.Right.Leg.Mus", "Activity", "AnyVar");
};
NameValueMap AllMuscleActivity(
NAMEOF_FUN=NameOf
) = {
ValuePtrs = ObjSearchRecursive(NamePtrs, "Activity", "AnyVar", 1);
NamePtrs = ObjSearchRecursive("Main", "*", "AnyMuscle");
};
*/
#class_template NameValueMap(
NAMEOF_FUN = CompleteNameOf,
ORDER = "Desending",
FORMAT="%.4f",
STUDY_T = .MaxMuscleActivity,
AGGEGRATION=max,
){
#var AnyObjectPtr ValuePtrs;
#var AnyObjectPtr NamePtrs = ValuePtrs;
AnyInt ValueSizes = arrcat(SizesOf(Obj2Num(ValuePtrs)), {1,1,1,1,1,1,1});
AnyInt FirstDim = ValueSizes[0];
AnyInt SecondDim = prod(take(ValueSizes, iarr(1,NumElemOf(ValueSizes)-1) ));
AnyFloat Values = AGGEGRATION(reshape(Obj2Num(ValuePtrs), {FirstDim,SecondDim})) + 0*STUDY_T;
AnyString Names = NAMEOF_FUN(NamePtrs);
#if ORDER == "Desending"
AnyString Output = flip(transpose( {ObjSort(Names, &Values), strval(ObjSort(Values), FORMAT) }),0);
#else
AnyString Output = transpose( {ObjSort(Names, &Values), strval( ObjSort(Values), FORMAT) });
#endif
};
#endif