# Writing Custom Elements for MotionSolve

The steps below describe how to write a custom element for a MotionSolve input deck. Appendix A contains an example of a custom element developed to implement a PID control.

## Create a Custom Mapping File

Copy and paste the following XML element into a file, for example, C:/test/my_custom_mapping.xml.
  <?xml version="1.0"?>
<!-- MotionSolve custom mapping definition file -->
<MSolve_Custom_Mapping>
<CustomElement
symbol             = "MyCustomElement">
<Attribute
id               = "integer"
name             = "attribute_name"
type             = "INTEGER | REAL | AUTO_ID"
default          = "default_value"
/>
<Attribute
...
/>
<Component
id               = "integer"
ctype            = "usrsub_name"
par_list         = "(comma separated list of integers)"
usrsub_dll_name  = "valid_path_name"
usrsub_fnc_name  = "valid_fnc_name"
/>
<Component
...
/>
</CustomElement>
</MSolve_Custom_Mapping>

The name defined by the parameter symbol will be used as the custom element name by MotionSolve. MotionSolve ensures that the internal interpretation of the name defined by the parameter symbol, (in this case, "MyCustomElement"), is equivalent to a list of components defined within the <CustomElement/> tag above. A custom element can contain multiple attributes and multiple components. For more information, refer to Appendix A below.

The attribute element(s) is/are what appears in the custom element as a parameter. The attribute element is written as:
<Attribute
id               = "integer"
name             = "attribute_name"
type             = "INTEGER | REAL | BOOL | AUTO_ID"
default          = "default_value"
/>
• The parameter id is an integer type and is used by the <Component> tags to reference the value of an attribute. This must be unique amongst all the attributes defined.
• The parameter name defines the string that appears in the Custom Element as a parameter that the user needs to specify.
• The parameter type can be either an integer, real, or Boolean. It can also take on the value of "AUTO_ID", in which case it is assigned an integer value automatically. If set to "AUTO_ID", the attribute id can be referenced by other components to set their ID values automatically.
• The parameter default sets the default value of the attribute if one is not specified in the custom element. Use this parameter only when type is not set to "AUTO_ID".
The component element(s) define the equivalent interpretation of the custom element. This is written as:
<Component
id               = "integer"
ctype            = "usrsub_name"
par_list         = "(comma separated list of integers)"
usrsub_dll_name  = "valid_path_name"
usrsub_fnc_name  = "valid_fnc_name"
[
/>
• The parameter id is an integer type. Its value refers to the ID of an existing <Attribute/> element. If the type of that attribute element is not set to "AUTO_ID", then the ID of the component takes on the value assigned to the parameter attribute_name in the custom element. If the type is set to "AUTO_ID", then the ID of the component is assigned an integer value automatically.
• The ctype parameter specifies the type of user subroutine to be used with this component. Depending on the user subroutine used, this component is transformed into a modeling element that uses that particular user subroutine.
• The par_list parameter specifies a comma separated list of attribute IDs (integers). Each entry in this list is expanded to the value represented by the attribute with that ID. This list is passed into the user subroutine.
• The parameters usrsub_dll_name and usrsub_fnc_name represent the path and name of the DLL that contains the user written subroutine with the name specified in usrsub_fnc_name.
Define and set the environment variable MS_CUSTOM_MAPPING_FILE.

After completing the steps above, you will be able to use the custom element <MyCustomElement/> like a regular MotionSolve element such as <Body_Rigid/>.

## Appendix A

This example develops a custom element that implements PID Control.

<!-- Custom Function Mapping section-->
<CustomElement
symbol             = "Control_PID">
<Attribute
id               = "1"
name             = "input_var_id"
type             = "INTEGER"
default          = "0"
/>
<Attribute
id               = "2"
name             = "output_var_id"
type             = "INTEGER"
default          = "0"
/>
<Attribute
id               = "3"
name             = "k"
type             = "REAL"
default          = "0.0"
/>
<Attribute
id               = "4"
name             = "c"
type             = "REAL"
default          = "0.0"
/>
<Attribute
id               = "8"
name             = "implicit"
type             = "BOOL"
default          = "TRUE"
/>
<Attribute
id               = "5"
name             = "dif_1_id"
type             = "AUTO_ID"
/>
<Attribute
id               = "6"
name             = "dif_2_id"
type             = "AUTO_ID"
/>
<Attribute
id               = "7"
name             = "dif_3_id"
type             = "AUTO_ID"
/>
<Component
id               = "2"
ctype            = "VARSUB"
par_list         = "(5,6,1,3)"
usrsub_dll_name  = "ms_csubdll"
usrsub_fnc_name  = "VAR_PID"
/>
<Component
id               = "5"
ctype            = "DIFSUB"
par_list         = "(1)"
usrsub_dll_name  = "ms_csubdll"
usrsub_fnc_name  = "DIF_PID1"
/>
<Component
id               = "6"
is_implicit      = "8"
ctype            = "DIFSUB"
par_list         = "(6,7)"
usrsub_dll_name  = "ms_csubdll"
usrsub_fnc_name  = "DIF_PID2"
/>
<Component
id               = "7"
is_implicit      = "8"
ctype            = "DIFSUB"
par_list         = "(1,7,4)"
usrsub_dll_name  = "ms_csubdll"
usrsub_fnc_name  = "DIF_PID3"
/>
</CustomElement>
1. The parameter symbol defines the name of the custom element, for example <Control_PID/>.
2. The attributes with IDs 1, 2, 3, 4, and 8 define the parameters that will appear in the custom element <Control_PID/>. For example:
<Control_PID
input_var_id        =   "INTEGER"
output_var_id       =   "INTEGER"
k                   =   "REAL"
c                   =   "REAL"
implict             =   "BOOLEAN"
/>
3. The attributes with ID 5, 6, and 7 define an AUTO_ID type, meaning that they will be assigned values automatically.
4. The components define the equivalent representation of the <Control_PID/> element.
• The id refers to an attribute with the same ID. If this attribute is not of type "AUTO_ID", then the ID for the component takes on the value represented by the attribute, or else it is assigned a value automatically.
• The ctype is a keyword that is used to identify the model element that the component should be converted to. For example, a DIFSUB component is converted to a <Control_Diff/>, a VARSUB to a <Reference_Variable/>, and so on.
• The par_list is an integer list of values that are passed into the user subroutine. These are essentially IDs of attribute elements and are expanded to their respective values (integer, real, or Boolean).
• The usrsub_fnc_name and usrsub_dll_name specify the function name and the name/path of the DLL in which the user subroutine is defined.
• Depending on the type of ctype used, there may be additional parameters used in the <Component/> element. For example, is_implicit and so on.

Finally, the custom element below:

<Control_PID
id                  = "1"
input_var_id        = "101"
output_var_id       = "200"
k                   = "0.1"
c                   = "0.02"
/>
is converted into the following equivalent interpretation by MotionSolve:
<Reference_Variable
id                  = "200"
type                = "USERSUB"
usrsub_param_string = "USER(1,2,101,0.1)"
usrsub_dll_name     = "ms_csubdll"
usrsub_fnc_name     = "VAR_PID"
/>
<Control_Diff
id                  = "1"
type                = "USERSUB"
usrsub_param_string = "USER(101)"
usrsub_dll_name     = "ms_csubdll"
usrsub_fnc_name     = "DIF_PID1"
/>
<Control_Diff
id                  = "2"
is_implicit         = "TRUE"
type                = "USERSUB"
usrsub_param_string = "USER(2,3)"
usrsub_dll_name     = "ms_csubdll"
usrsub_fnc_name     = "DIF_PID2"
/>
<Control_Diff
id                  = "3"
is_implicit         = "TRUE"
type                = "USERSUB"
usrsub_param_string = "USER(101,3,0.02)"
usrsub_dll_name     = "ms_csubdll"
usrsub_fnc_name     = "DIF_PID3"
/>