[38ba34]: / Body / AAUHuman / BodyModels / GenericBodyModel / Helper.ClassTemplates.any

Download this file

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