A
A
N
N
SA
SA
version 13.x
Scripting Language
Table of Contents
1. DESCRIPTION OF THE SCRIPTING LANGUAGE...5
1.1 General...5
1.2 Data Types...5
1.2.1 User Defined Data Types (structures)...6
1.3 Variables...6
1.3.1 Naming of Variables and Restrictions...6
1.3.2 Declaration of variables...7
1.3.3 The const keyword...7
1.3.4 Checking the variables’ spelling...7
1.4 Operators and Basic Calculation...8
1.4.1 Expressions and assignments for numeric data types...8
1.4.2 Operator precedence...9
1.4.3 Important Notes on Operators...9
1.4.4 Numeric intrinsic functions...10
1.4.5 Expressions and assignments for string data types...10
1.4.6 Expressions and assignments for user defined data types (structures)...11
1.5 Sets of data: Matrices and maps...12
1.5.1 Matrices...12
1.5.2 Maps...14
1.6 Conditional Statements and Branching...15
1.6.1 The "if-else" blocks and the logical operators...15
1.6.2 The switch statement...17
1.6.3 The goto statement...17
1.7 Loop statements...18
1.7.1 The foreach statement...18
1.7.2 The for statement...18
1.7.3 The while statement...19
1.7.4 The do while construct...19
1.7.5 The continue and break statements...19
1.8 User functions and comments...20
1.8.1 Definition...20
1.8.2 Argument list and function call...20
1.8.3 Declaring functions as variables...21
1.8.4 Returning data from functions (return, byref call)...21
1.8.5 Scope and lifetime of variables...22
1.8.6 public and private functions...24
1.8.7 Including files...24
1.8.8 Including project files...25
1.8.9 Compilation control (Pre processor)...25
1.8.10 Recursive structures...26
1.8.11 Initialization and un-initialization of matrices and variables in main and global code...27
1.8.12 Use of help text and comments in functions...28
1.9 Session commands for use in Scripting Language...29
2. INTERACTING WITH ANSA...30
2.1 General...30
2.2 Handling Data...30
2.2.1 Data of element type...30
2.2.2 ANSA cards and entity types...30
2.3 Collecting entities...32
2.3.1 General...32
2.3.2 Collecting entities massively from the whole database...33
2.3.3 Collecting entities massively from other entities...33
2.3.4 Collecting massively visible entities...35
2.3.5 Collecting available entity types of specific deck...35
2.3.7 Collecting part and groups from their ids...36
2.3.8 Collecting entities according to their name...37
2.3.9 Collecting all new created/imported entities...37
2.3.10 Collecting files and directories...38
2.3.11 Select files or directories through File Manager...38
2.4 Edit, Create and Delete Entities...39
2.4.1 General...39
2.4.2 Getting values from an entity using its Edit card...39
2.4.3 Modifying the card's values...40
2.4.4 Creating new entities...41
2.4.5 Creating parts and groups...41
2.4.6 Creating connection entities...41
2.4.7 Editing the characteristics of a connection entity...42
2.4.8 Realizing connections...43
2.4.9 Getting the entities of connections...45
2.4.10 Deleting entities...46
3. CUSTOMIZE GUI...47
3.1 General...47
3.2 Creation of user buttons ...47
3.3 Creation of custom GUI ...47
3.3.1 Setting Cancel and Ok buttons...48
3.3.2 Opening and Destroying Windows...48
3.3.3 Callback functions...49
3.4 Setting of controls...49
3.4.1 Setting edit fields and check buttons...49
3.4.2 Creating and setting up menus and radio buttons...50
3.4.3 Creating and setting up List Boxes...52
3.4.4 Hiding and Showing controls...55
4. HANDLING ASCII, XML AND BINARY FILES...56
4.1 General...56
4.2 ASCII files...56
4.2.1 Opening and closing files ...56
4.2.2 Reading files...56
4.2.3 Writing files...58
4.3 XML files...59
4.3.1 Opening xml files...60
4.3.2 Getting nodes and sub-nodes...60
4.3.3 Getting the name of the node...60
4.3.4 Getting attributes and node data...61
4.3.5 Writing XML files and setting the base node...61
4.3.6 Creating nodes...61
4.3.7 Setting attributes and node data...62
4.4 BINARY files...63
4.4.1 Opening binary files...63
4.4.2 Reading and Writing binary files...63
5. SPECIALIZED FUNCTIONS...64
5.1 General...64
5.2 Description of Specialized functions...64
5.2.1 Creating Connectors and GEBs with scripting...64
5.2.2 Executing specialized script functions from Connection Manager...66
6. HANDLING SCRIPTS FROM GUI...70
6.1 General...70
6.2 Using the Command Line window...70
6.2.2 Description of auxiliary built in functions...70
6.2.3 Loading scripts...71
6.2.4 Running scripts...72
6.3 Using script menu...73
6.3.1 Script menu interface...73
6.3.2 File>Script options...73
7. AUTOMATION THROUGH THE ANSA_TRANSL FILE...76
7.1 Location of ANSA_TRANSL file...76
7.1.1 How does ANSA interacts with ANSA_TRANSL...76
7.1.2 Form of ANSA_TRANSL...76
7.1.3 Registers used for translation...77
7.1.4 Importing CAD files...78
7.1.5 Executing functions without any user interaction (autoexec)...84
8. EXTRACTING INFORMATION FROM CATIA...85
8.1 General...85
8.2 Script commands related with Catia...85
8.2.1 Orientation check...85
8.2.2 Extracting thickness from catia entities...86
8.2.3 Checking geometry existence...86
8.3 Reading Header/Comment Section of Catia file...86
8.4 Creating connections from points and curves of Catia...88
8.5 Handling of properties...89
8.6 Writing in the Catia log file...89
8.7 The "Extra Options" field of Catia Translator...90
9. SCRIPT EDITOR...91
9.1 Script Editor Layout...91
9.2 Opening scripts...92
9.3 Running scripts...92
9.4 Making use of the immediate tab...92
9.5 Help area...92
9.6 Compiled scripts...93
9.7 Making and importing snippets...93
9.8 Creating projects...94
9.8.1 Starting a new project...94
9.8.2 Adding existed files to a project...95
9.8.3 Adding new files to a project...97
9.8.4 Creating the ‘main’ script...98
9.8.5 Handling projects...98
9.9 Debugging scripts...98
APPENDIX...101
1. Description of the Scripting Language
1.1 GeneralA general description of the scripting language is given below. The description is organized in the following main sections:
- Datatypes - Variables - Operators - Conditional Statements - Loop Statements - User Functions 1.2 Data Types
The data type determines the kind of data that a variable or a function can hold. Data types include integer or floating point numbers, strings, matrices etc. as well as user defined types. The following paragraphs describe the available data types for writing an ANSA script. Note however that variables used in ANSA scripts, are considered typeless.
Integers
The integer data type is used by variables that can only have whole numbers as values. Such variables are represented in memory by 32 or 64 bits depending on the machine architecture.
my_var = 10;
Floating Point
Values that are not integral are stored as floating point numbers. A floating point variable can be expressed as a decimal number such as 112.5, or with an exponent such as 1.125E2. In the latter case the decimal part is multiplied by the power of 10 after the E symbol.
A floating point must contain a decimal point, or an exponent or both. If you write neither, then you have an integer. Floating point numbers are represented in memory by 32 or 64 bits depending on the machine architecture.
my_var = 112.5;
Strings
As string, we declare a series of printable text characters representing human readable stuff. A string value is enclosed in quotes (e.g. "this is a string") and can be assigned to any variable for storage and easy access. String variables are internally represented as arrays of characters.
s = "a string";
Elements
This is ANSA - specific data type, representing entities used within the model, for example a shell element or a property or a set. The keyword used to declare such entities is element.
1.2.1 User Defined Data Types (structures)
In many cases, user scripts can be more elegantly and concisely expressed if they can be written in terms of aggregate structures. Such structures can be considered as user defined data types that represent a collection of one or more variables, possibly of different types, grouped together under a single name for convenient handling. The keyword used to declare such collections is called struct and the individual variables within the collection are called its members.
1.3 Variables
A variable is a named memory location that contains data and can be modified during script execution. For every variable we distinguish its data type and its value:
- The data type describes what particular kind of data is stored in a variable, such as an integer number, a string etc. As we saw earlier, variables are typeless, meaning that their type is defined by the way the variables are used.
- The value of the data that a variable contains at any point, is determined by the instructions of our code and, of course, this value will usually change many times during program execution.
1.3.1 Naming of Variables and Restrictions
The name of a variable is called an identifier, or more conveniently, a variable name. Variable names can include the letters A-Z (in upper or lower case), the numbers 0-9 and the underscore character. All other characters including the blank space are illegal. A variable name is case sensitive and must begin with a letter or an underscore. Names usually indicate the kind of information that is stored in the variable and must be chosen in a manner that will not confuse the user. The following table lists some valid / invalid variable names:
# Variable Name Validity Reason
1. surface_area Valid
--2. surface-area Invalid Is considered an operation 3. surface area Invalid Contains blank space 4. SurfaceArea Valid
--5. _surface_area Valid
--6. surface@area Invalid Contains reserved characters 7. _1-Surface Valid
--8. Surface"1" Invalid Contains reserved characters 9. Surface_1 Valid
--10. Surface/1/ Invalid Contains reserved characters 11. 1Surface Invalid Begins with a number
Although the number of characters in a variable name can be unlimited, it is usually a good programming practice to keep it short. Furthermore, the language reserves some "names" as "keywords". These names are used to represent internal functions and are not allowed to be used as variable or function names. The reserved characters and reserved words for writing an ANSA script are listed below:
reserved characters:
=^*/+-%&'"\!(){}[]:;<>,.
reserved words:
include, void, int, def, float, char, string, matrix, map pointer, element, struct, byref, if, else, for, do, while, foreach, in, const, switch, break, continue, goto, case, default, return, static, global, projectfile, defbutton, script, stricton, strictoff, public, private
reserved variables:
FILENAME, FILEPATH, FLANCH_PROPERTY_ID,
PART_COORD_SYS_DX1, PART_COORD_SYS_DX2, PART_COORD_SYS_DX3, PART_COORD_SYS_DY1, PART_COORD_SYS_DY2, PART_COORD_SYS_DY3, PART_COORD_SYS_DZ1, PART_COORD_SYS_DZ2, PART_COORD_SYS_DZ3, PART_COORD_SYS_X, PART_COORD_SYS_Y, PART_COORD_SYS_Z,
PART_MODEL_NAME, PART_NAME, PART_VERSION, PART_VSC,
PART_PROPERTY_ID, PART_PROPERTY_NAME, PART_PROPERTY_THICKNESS, POST_TRANSL_SCRIPT, POST_TRANSL_SCRIPT_ARGS,
TRANSLATIONS, SEPARATORS, MAT_REG,
SYMMETRY_PART_ID, SYMMETRY_PART_PID_OFFSET
reserved constants:
NASTRAN LSDYNA PAMCRASH ABAQUS RADIOSS ANSYS CFD MORPH
1.3.2 Declaration of variables
When writing ANSA scripts, it is not necessary to explicitly define the data type of variables. This is because all variables used in ANSA scripts are considered by default typeless and automatically acquire the proper data type depending on their use at the time. For example, in a statement like:
my_var = 13;
the variable my_var is treated as being of integer type. But, if later on, the same variable is found in another statement like:
my_var = "my string";
it will switch from integer to string type
The use of typeless variables reduces the total number of variables used in a script, since the same variable can be used in different ways. However, typeless variables can be proven dangerous when they must be passed as arguments to a function, since the function should be aware as to how to treat these variables. Thus, in such cases, the data type of all variables that are communicated to a function
must be explicitly declared in the functions' arguments. For example, if var1, var2 and var3
represent integer, float and string variables respectively, they should be declared as:
def my_function (int var1, float var2, string var3) 1.3.3 The const keyword
A variable can get a unique and unchangeable value if defined as constant. Once it is defined, it keeps its original value even if later on is given a different value. This kind of variables can be declared in global or function code, using the keyword const followed by the type of variable. The type is auxiliary and is used only for the definition.
const float pi = 3.14; def main()
{
pi = 3;
Print(pi);//The 3.14 will be printed }
1.3.4 Checking the variables’ spelling
A very frequent problem for all programmers is the variables’ spelling. Especially in lengthy codes where there is a significant number of variables, an error like that can cause erroneous results and a serious waste of time for debugging. This can be totally avoided if using the statement #stricton written in global section of the script. Doing this, the parser issues a warning when it comes across an undeclared variable. The declaration of variables is given explicitly either in the global section or within a function and must follow always a specific data type. The script stops this check by invoking the statement #strictoff. Thus, any code located between the two statements is examined also for variables’ spelling errors.
#stricton int a; float b; float param; def main() { a = 1; b = 1.2; value = a*b; params = a/b; } #strictoff
In the next example, the parser will recognize the two undeclared variables (‘value’ and ‘params’) and will return the following warning message:
---Important Note 2: There is no restriction to the number of times the #stricton and #strictoff can be
invoked inside a script.
Important Note 3: #strictoff is the default state. 1.4 Operators and Basic Calculation
Various data types can be combined, by the appropriate operators, to form expressions. These expressions are evaluated when the script is executed. The results of a calculation can be stored for future use by assigning a value to a variable. This is done by an assignment statement whose general form is:
<variable name> = <expression>;
where <variable name> is the name of the variable, while <expression> is an expression formed by the combination of variable names using operators.
The sets of operators and the rules of how expressions may be written and evaluated are determined by the types of the operands involved. Therefore, the data type is a very critical attribute of any data value.
1.4.1 Expressions and assignments for numeric data types
An expression is formed by the combination of variables, constants and operators. Operators are used in order to compute new values out of old ones, and can be of two types:
1. arithmetic operators
2. assignment operators
There are five different arithmetic operators that can occur in numeric expressions. These are:
# Operator Operation 1. + Addition 2. - Subtraction 3. * Multiplication 4. / Division 5. ** Exponentiation
Some examples of arithmetic expressions are:
surface_area = width_x * width_y;
interior_vol = exterior_vol-width_x * width_y * width_z; hypot2 = a**2 + b**2;
However, the meaning of the 2nd and 3rd examples might not be clear. For instance, the 2nd example might
be interpreted as
interior_vol = (exterior_vol-width_x) * width_y * width_z;
or
The meaning of such expressions is resolved by defining an order of precedence for operators. This precedence will determine the order in which the expression is to be evaluated.
The assignment operators are the ones that actually assign a value to a variable. The well known “=“ sign is an assignment operator. For example
x = 1;
sets x to 1, and
a = b;
sets a to whatever b's value is. The expression
i = i + 1;
is a standard programming idiom for increasing a variable's value by 1, while
i = i - 1; i = i * 2; i = i / 2;
will decrease a variable’s value by 1, multiply and divide it by 2 respectively.
1.4.2 Operator precedence
The order of precedence is very much alike what is known from algebra. Thus, exponentiations are
carried out first, then multiplications and divisions and finally additions and subtractions.
Multiplication and division have equal precedence. When a number of multiplications and divisions are found in sequence, the expression is evaluated from left to right. The same applies for addition and subtraction. Thus, the expression
x / y * z ;
is understood to be
(x / y) * z
and not
x /(y * z)
It should be noted here that the use of parentheses can force the order of evaluation of certain expressions. Thus, the expression:
x /(y * z);
will be evaluated exactly as written.
1.4.3 Important Notes on Operators
Note 1: Combination of assignment with arithmetic operators
The pattern:
v = v op value;
where v is a variable, op is any of the addition, subtraction, multiplication and division operators +,-,*,/ and
value is a constant arithmetic value, can be shortly expressed as:
v op = value;
where v does not have to be mentioned twice. For example, the expressions
i = i - 1; i = i * 2; i = i / 2;
can be equivalently written as:
i += 1; i -= 1; i *= 2; i /= 2;
Note 2: Increment and decrement operators
For the most common cases where we add or subtract the constant value 1 from a variable, ANSA scripting language allows the use of auto-increment or auto-decrement operators. In their simpler form, they look like this:
i++; i--;
These expressions correspond to the slightly longer:
i += 1; i -= 1;
and to the fully expanded:
i = i + 1; i = i - 1;
1.4.4 Numeric intrinsic functions
It is often necessary to evaluate special mathematical functions, such as the square root of a number, the sine or cosine of an angle. ANSA scripting language incorporates several such intrinsic functions, to enable such functions to be evaluated easily. Some of the most important arithmetic functions are given in the table below.
# intrinsic function Description comment
1. Sqrt(x) calculates the square root of x
--2. Cos(x) calculates the cosine of x x is given in radians 3. Sin(x) calculates the sine of x x is given in radians 4. Tan(x) calculates the tangent of x x is given in radians 5. Exp(x) calculates e raised to the power or x
--6. Log(x) calculates the natural algorithm of x --7. Asin(x) calculates the arcsine of x --8. Acos(x) calculates the arccosine of x
--9. Atan(x) calculates the arctangent of x result between –pi/2 and +pi/2 10. Abs(x) calculates the absolute value of x
--1.4.5 Expressions and assignments for string data types
Characters may be assigned to string variables, using statements similar to those of numeric types:
property = "PSHELL"; mat_name = "steel_105";
The operators that can be used to form expressions between string data types are:
# operator operation
1. + string catenation
2. % string catenation
property = "PSHELL";
can be concatenated with the string variable
id = "with id 1";
as
property_id = property + id;
or with the equivalent
property_id = property % id;
and assign to the property_id variable the value
"PSHELL with id 1"
1.4.6 Expressions and assignments for user defined data types (structures)
A typical example of a user defined data type can be the point collection: Each point occupies a position in space as dictated by its coordinates and also have a unique ID to distinguish it from other points. The point coordinates are real numbers and the ID is an integer. These point data can be grouped under the same structure in the following way:
struct {int point_id; float x; float y; float z;} point;
The above line defines a structure called point whose members are an integer called point_id and three floats for the coordinates x, y, z.
Once the structure is defined, it can be used as a regular data type for the declaration of other variables. For example, if we need to declare a point PA in space, we just need to type:
point PA;
Now, the PA variable can automatically reference the members of the point structure, in other words PA
can reference its id and its x, y, z coordinates. The syntax for this reference is struct.member and in this case takes the form:
PA.point_id …the id of point PA
PA.x …x-coordinate of PA
PA.y …y-coordinate of PA
PA.z …z-coordinate of PA
For example, to assign number 13 as the id of point PA type:
PA.point_id = 13;
and to assign the coordinates of PA type:
PA.x = 123.45; PA.y = 321.00; PA.z = 456.78;
As an extension to declaring a single point PA that belongs to the structure point, we can declare an array (matrix) of points. For example, to declare an array called pts of 10 points in space using the structure point type:
point pts[10];
The reference to the individual variables of the pts array follows the same rules as before. For example, to assign 13 as the id of the 5th point of the pts array, type:
pts[5].point_id = 13;
pts[5].x = 123.45; pts[5].y = 321.00; pts[5].z = 456.78;
1.5 Sets of data: Matrices and maps
Most problems that occur in practice require more than simple variables for their definition and solution. Thus, it is often necessary to handle data as sets of similar or different kind objects. Towards this direction comes the definition of matrices and maps.
1.5.1 Matrices
A matrix data type provides a way to collect entities under the same storage. As a good programming practice, matrices should be declared so that the program will reserve enough space to store the data. The corresponding keyword for this declaration is matrix.
Since matrix members are actually variables, they can hold any type of variable, so a matrix like:
m={1, 1.23, "some string", "a", 2, 99.23};
is perfectly valid.
Matrix members are accessed with index operators, i.e. m[0] is the first element in a matrix. Indices run from 0 to allocated space -1, i.e. for matrix m[10] they run from 0 to 9.
The function MatLen returns the length of matrix m.
len = MatLen(m);
Set some data in a matrix:
To set some data to a specific position in a matrix type:
m[3] = 10;
To specify all the matrix members at once:
m = {10,7,9};
Matrix members can even be other matrices. Thus, a matrix like:
m = {{10,7,9}, {5,2,17} {6,12,25}};
would form a 3x3 2 dimension matrix.
Retrieve a matrix member value:
To retrieve a value of a specific member of a matrix, the user must provide the corresponding index operator:
i = m[0];
For the 3x3 2 dimension matrix given above:
i = m [1][0];
will assign to i the value of 5.
Handling strings
A string has a length equal to the number of characters that comprise it and each one character holds an index. The first character has index 1 and the last one has index equal to the string length. This characteristic is essential for isolating specific parts of a string variable.
str = "Bumber_Front";
We can get any part of the string by using the indices of the characters. Here are some examples:
str = str(1:6); //This will get the "Bumber" str = str(8:12);//This will get the "Front" str = str(8:8); //This will get the character "F" str = str(7:7); //This will get the character "_" str = str(3:8); //This will get the "mber_F" str = str(5:); //This will ge the "er_Front" str = str(:7); //This will get the "Bumber_"
Important Note: The string length can be found using the function Strlen. Matrix expressions:
All algebraic operations between matrices and constant values are interpreted as operations between each member of the matrix and the constant value. For example the expression:
B = 10*A;
will result to a matrix B whose members are 10x the corresponding members of A.
Addition, subtraction, division and exponentiation operations between matrices should take place only between conformable matrices (i.e. matrices having the same shape). On the other hand, the multiplication operation can take place both between conformable and unconformable matrices. In the former case, the multiplication takes place between each member of the matrices while in the latter case a matrix multiplication takes place. Having two conformable matrices A and B 2x3:
A = {{10,7,9}, {5,2,17}}; B = {{2,1,1}, {1,2,1}}; an addition operation: C = A+B;
will lead to a matrix C:
C = {{12,8,10}, {6,4,18}};
Having two non-conformable matrices A, 2x3 and B 3x1:
A = {{10,7,9}, {5,2,17}}; B = {{1}, {2}, {1}}; a multiplication operation: C = A * B;
will lead to a matrix C 2x1:
C = {{10*1+7*2+9*1}, {5*1+2*2+17*1}};
The following table summarizes some intrinsic functions available for the management of matrices:
# Function Description
1. MatLen(m); returns the length of the matrix m
2. Min(m,no_of_values); returns the min value of the matrix m for the first no_of_values 3. Max(m,no_of_values); returns the max value of the matrix m for the first no_of_values 4. CrossProduct(vec1, vec2); returns the CrossProduct of vector 1 and vector 2 5. DotProduct(vec1, vec2); finds the dot product of vector 1 and vector 2 6. NormalVec(vec) computes a unit normal vector of input vector 'vec' 7. Normalize(vec); normalizes a vector
8. TransposeMatrix(m) transposes m
9. MaxIndex(m,no_of_values); finds the index of the maximum of an array of no_of_values 10. MinIndex(m,no_of_values); finds the index of the minimum of an array of no_of_values 1.5.2 Maps
A map data type can be seen as an expansion of the matrix, since the indexing is done with arbitrary values. The keyword that specifies this data type is map.
A map is characterized by a name and is like a user defined tree-structure, where each node holds a specific value and is referenced by a specific key:
(map_name, key, value)
Note that to use a map, you need to initialize it first using the command CreateMap:
m = CreateMap(); Set some data in a map:
When a map is created and initialized, it is originally blank. To set some data to a specific node of a map, use the SetMapNode:
SetMapNode(m, key, value);
For example, the command SetMapNode(m, 1140, 1) will assign the value 1 to the node holding the key 1140. An equivalent expression would be:
m[1140] = 1;
The values and keys of a map can be of any type. Nodes within the same map are sorted according to their key and the corresponding precedence order is:
number > map > string
For example, node (m,"1140",1) comes after node (m,1140,2), since the former node uses a string-type key and the latter node uses a numeric key. Note that when maps are used as keys, they are sorted according to the number of nodes they have, with larger maps taking precedence over smaller maps.
Retrieve a node value:
To retrieve a value of a specific node, the user must provide the corresponding nodal key using the
GetMapNode function:
i = GetMapNode(m, key);
For example, for the node (m,"1140",1), the command
i = GetMapNode(m,"1140");
will assign to i the value of 1. An equivalent expression would be:
Delete a node:
Deletion of a node within a map is achieved using the EraseMapNode command:
EraseMapNode(m, key);
Iteration through the data in a map:
In order to search through the data of a map, the user must first identify the first or the last node of the map using the GetFirstNode or the GetLastNode commands respectively:
i = GetFirstNode(m, key, value); i = GetLastNode(m, key, value);
Both functions return 1 on success and 0 upon failure (e.g. when the map is not defined or is empty). Looping through the map is achieved using the GetNextNode and GetPreviousNode commands:
i = GetNextNode(m, key, value); i = GetPreviousNode(m, key, value);
for(ret=GetFirstNode(m, key, value);ret;ret= GetNextNode(m, key, value)) {
Print("For key "+key+" the value is "+value); }
Destroy the map and release memory:
To delete a map, use the DestroyMap:
DestroyMap(m);
Identify the number of nodes in a map:
To identify how many nodes a map contains, use the GetMapEntries:
i = GetMapEntries(m);
The following table summarizes the intrinsic functions available for the management of maps:
# Function Description
1 m = CreateMap(); initialize map m
2 SetMapNode(m,key,value); assign a value to the node referenced by key 3 GetMapNode(m,key); retrieve the data of the node referenced by key 4 EraseMapNode(m,key); erase the data of the node referenced by key 5 GetFirstNode(m,key,value); return the first node of the map
6 GetNextNode(m,key,value); forward advance to the next node of the map 7 GetLastNode(m,key,value); return the last node of the map
8 GetPreviousNode(m,key,value); backward advance to the next node of the map 9 DestroyMap(m); delete map and release memory
10 GetMapEntries(m); identify how many nodes the map contains 1.6 Conditional Statements and Branching
1.6.1 The "if-else" blocks and the logical operators
The if statement is the basic decision statement of a script. Its operation is based on the evaluation of a condition that will yield a result that is either true or false. If the condition is true (i.e. not equal to 0), then the if-block of statements is executed. If the condition is false, then the else-block of statements is executed. The if statement general form is:
if (condition) statement;
The alternative line of execution is created with else:
statement; else statement;
Since the condition is interpreted as a logical operator, the operators used for its expression are the logical relational operators. Such operators are summarized in the table below:
# Operator Meaning
1. < less than
2. <= less than or equal to
3. > greater than
4. >= greater than or equal to
5. == equal to
6. != not equal to
7 || Logical OR
8 && Logical AND
9 ^ Logical XOR
Some examples of the use of the if-else blocks follow:
if (a>5) {
b = 0; c = 0; }
In this case the logical expression a>5 will be evaluated. If it is proved true, then b and c will be assigned zero values. Otherwise, this block of statements will be ignored.
if (a>5) { b = 0; c = 0; } else { b = 1; c = 1; }
In this case the logical expression a>5 will be evaluated. If it is proved true, then b and c will be assigned zero values. Otherwise, they will be assigned unit values as dictated by the else group of statements.
if (a>5 ^ c==1)
b = 0; In this case b will be assigned zero value, only if one of the two expressions is true. It is similar to : if((a>5 && c!=1) || (c==1 && a<=5))
if (a>5) { b = 0; c = 0; } else if (a<3) { b = 1; c = 1; }
In this case the logical expression a>5 will be evaluated. If it is proved true, then b and c will be assigned zero values. Otherwise, the logical expression a<3 will be evaluated. If it is proved true, then b and c will be assigned unit values. If none of the conditions is fulfilled, the whole block of statements will be ignored.
if(a>5 || b==1)
c = 1; In this case a unit value will be assigned to c if one of the two expressions is true. if(a>5) && b==1)
1.6.2 The switch statement
The switch statement is an alternative form of a conditional statement, which allows the definition of multiple possible execution paths. The general form of the statement is:
switch (expression) { case constant1: statement; .... break; case constant2: statement; /* fall through */ case constant3: statement; .... break; .... default: statement; break; }
The switch statement evaluates the value of an expression and branches to one of the case labels. The expression can evaluate an integer or a string. The case labels can be in any order and must be constants or strings. The default label can be placed anywhere within the switch. Note that two case labels cannot have the same value. When ANSA reads a switch statement, it evaluates the expression and then looks for a matching case label. If none is found, the default label is used. If no default is found, the statement does nothing, i.e.:
a = 2; switch (a) { case 0: Print("a is zero"); break; case 1: Print("a is one"); break; case 2: Print("a is two"); break;
/* will fall through default as well */ default:
Print("a is not zero"); break;
}
The result is: a is two 1.6.3 The goto statement
The goto statement is a powerful branching statement. It can be used to create jumps and redirect the execution order of a program. Its general form is:
goto < label >
where < label > is the label of an executable statement. i.e.
some_label: ...
if (a>5)
1.7 Loop statements
A loop comprises of a block of statements that are executed repetitively. When the end of the loop is reached, the block is repeated from the start of the loop.
1.7.1 The foreach statement
The foreach statement allows the iteration over the elements of an array. foreach loops do not maintain any explicit counter. The general form of the statement is:
foreach <item> in <array> {
do something to <item> }
An example of the statement use is given below:
all_properties = {"PSHELL","PCOMP","PBAR","PBEAM","PELAS"}; foreach property in all_properties
Print (property); the result is PSHELL PCOMP PBAR PBEAM PELAS
1.7.2 The for statement
The for statement introduces an indexed loop, where the number of repetitions is known before the loop is started. The general form of the for statement is:
for (initial-statement; condition; iteration-statement) body-statement;
The initial-statement initializes the explicit counter, the condition specifies the number of repetitions and the iteration-statement dictates the increment or decrement value of the explicit counter during the loop.
for (a=0; a<5; a++) Print (a); the result is 0 1 2 3 4
Important Note: When a foreach or for loop statement affects only one line then it is not necessary to
enclose this line in brackets:
One line is affected for (a=0; a<5; a++)
Print (a);
More lines are affected for (a=0; a<5; a++)
{
Print(a); Print(a+1); }
1.7.3 The while statement
The while statement introduces a conditional exit loop. The program executes the specified statements repetitively for as long as the given condition remains true (i.e. not equal to 0). Its general form is:
while (condition) body-statement;
If operators are to be used for the expression of the condition, these must be of logical relational type (see Section 1.6.1). a = 0; while (a<3) { Print(a); a++; }
the above result will be something like:
0 1 2
1.7.4 The do while construct
While the for and while statements check the condition before entering the loop, the do while construct makes the check after every pass of the loop and thus guarantees that at least one pass will take place. Its general form is:
do
body-statement; while (condition);
In the example below:
a = 1; do { Print (a); a++; } while (a>5);
the result is: 1
1.7.5 The continue and break statements
The continue and break statements can be used to redirect and stop the execution order of a loop. The
break statement allows the termination of a loop regardless of the loop control condition. In other words it
can lead to an unconditional branching. A typical example is given below:
a = 0; while (a<5) { Print(a); a++; if ( a == 3) break; }
In this case the result would be:
0 1 2
The continue statement jumps back to the beginning of the loop’s block to begin the next iteration. Thus, it omits a certain block of statements. A typical example is given below:
a = 0; while (a<5) { a++; if ( a == 3) continue; Print(a); }
In this case the result would be:
1 2 4
1.8 User functions and comments
User functions allow to group a set of operations into a compact unit that can be easily and repeatedly accessed. The repetitive use of functions saves much time while reduces the chances of error. Each user function is given a name, optionally uses some input parameters (arguments) and returns the results as output parameters.
From now on, the term main will be used to denote the function which is called by the user to execute the script.
1.8.1 Definition
User functions are defined using the def statement. This statement is followed by the function name. The rest of the code must be enclosed in brackets. A typical function has the form:
def main(list of arguments if exist) {
... Statement ... }
1.8.2 Argument list and function call
Each user-defined function accepts a number of input arguments (<=40). These arguments are passed from the main function as parameters and are used as initial values inside the function that is called. During the declaration of a sub-function it is necessary to define explicitly the type of the input arguments (int, float, string, element etc)
Important Note 1: A sub-function can be called from a main function or from another sub-function. Important Note 2: Variable number of input arguments is not valid.
def main() { mass = 1.1; id = 10; name = "right_door"; search_type = "GRID"; nodes = CollectEntities(NASTRAN,0,search_type,0); fun_to_call1(mass, name, nodes);
fun_to_call2(id); }
def fun_to_call1(float mass, string name, matrix nodes) {
...
counter = 100;
... }
def fun_to_call2(int id) {
... }
def fun_to_call3(int counter) {
... }
1.8.3 Declaring functions as variables
A new functionality introduced in v13.0 enables the definition of functions’ names as variables, giving the capability to control all actions inside a code parametrically. A useful implementation could be the following: Imagine that it is needed to call different functions with same data sequentially. Instead of using an if structure which makes the code difficult to maintain, a parametric call would be more handy (See
Section 1.8.2): def main() { s = {1,3,"title"}; functs = {"test1","test2"}; for(i=0;i<2;i++) { functs[i](s); } }
def test1(matrix data) {
... }
def test2(matrix data) {
... }
1.8.4 Returning data from functions (return, byref call)
Since the target of each sub - function is to perform a certain task, there must be a way to ’notify’ the function that called it for the result of the procedure it performed.
The communication between the functions can be achieved through the return command. This command can be used anywhere in the code and is followed by any data. A function that calls another function can store the returned value in an output argument or even can ignore it. Functions that don’t return anything are executed normally and may not use the return command. Equivalent, they can return a dummy value. Return value def main() { a = 100; b = 50; result= substr(a, b); Print(result); }
def substr(int a, int b) { res = a-b; return res; } No return def main() { a = 100; b = 50; result = substr(a, b); Print(result); }
def substr(int a, int b) {
res = a-b; }
Return dummy value def main() { a = 100; b = 50; result = substr(a, b); Print(result); }
def substr(int a, int b) {
res = a-b; return 1; }
Only the data that are passing through the return command are valid for the main function.
Important Note: If the return command is used in the main function, then the execution of the script is
terminated.
Another way of exchanging data is through the byref statement. This is very useful in cases where it is important for the user to know the new modified values of any variables that had been passed to a sub-function. def main() { w = 10; h = 1; rect_area(w, h); Print(w);//The value of w is 20 }
def rect_area(byref int w, int h) {
a = w*h; w = a+10; }
Important Note: The matrices, elements and maps are considered byref by default. 1.8.5 Scope and lifetime of variables
A variable's scope is determined by where you declare it. When a variable is declared within a function, then only the code within this function can access or change its value. It is then said that this variable is local to this function. As a result, there is no conflict to have two or more variables of local character sharing the same name in different functions.
In contrast to local variables, global variables are valid throughout the program, so they can be accessed and changed by any individual function of the program. g lobal variables must be declared prior to the definition of any function (global section), and are defined either using the global keyword or by declaring their type followed by their name. The type is auxiliary and helps the language to distinguish a local from a global variable. As said before, the variables still remain typeless.
global c;//Here is used the global keyword for variable c int a;//a is now global for all functions
float b;//b is now global for all functions def main()
{
a = 10; b = 5; c = 1;
Print("initial value of c is:"+c); fun();
Print("final value of c is:"+c); Print("final value of a is:"+a); } def fun() { c = a+b; a++; }
However, a variable can be declared as local and global simultaneously in the same script. In this case it can be treated as being two different variables if using the scope operator ‘::’
int a; def main() {
a = 3;//This value is assigned in local 'a' ::a = 5;// This value is assigned in global 'a' i = a+1;
Print(i); k = ::a+1; Print(k); }
There is also a third type of variable called static. A static variable can be either global or local and its major difference from the other two is that it can keep its value even if the execution of the function has come to an end. An internal static variable can be defined in a user function and it is valid only for this function while holds its information regardless of the number of times the function will be called. Similar to this, an external static variable is valid throughout the script where it is defined. Consequently, external
static variables help us to ‘hide’ the function names and thus avoid possible conflicts. Example of internal static variable (1)
def main() { static s; if(!IsInitialized(s)) { //Iniatializing s s = 0; } else s = s+1;
Print("s value from main:"+s); subfun();
}
def subfun() {
Print("s value from subfun:"+s); }
Example of external static variable (2) static s; def main() { if(!IsInitialized(s)) { s = 1; } else s = s+1;
Print("s value from main:"+s); subfun();
}
def subfun() {
Print("s value from subfun:"+s); }
In the first example the value of the variable after each execution will be: Execution 1 ---> s from main = 1, s from subfun = <empty>
Execution 2 ---> s from main = 2, s from subfun = <empty> Execution 3 ---> s from main = 3, s from subfun = <empty> etc....
while in the second example:
Execution 1 ---> s from main = 3, s from subfun = 3 Execution 2 ---> s from main = 2, s from subfun = 2 Execution 3 ---> s from main = 1, s from subfun = 1 etc....
Suppose that we have loaded two scripts that both use a function called ‘subfun’. In order to avoid a conflict we define each of the common functions as static.
SCRIPT 1 def main1()
{
subfun(); }
static def subfun() { Print("value of script 1: 10"); } SCRIPT 2 def main2() { subfun(); }
static def subfun() {
Print("value of script 2: 20"); }
After the execution of main1 the result is 'value of script 1: 10'
After the execution of main2 the result is 'value of script 1: 20' 1.8.6 public and private functions
A function can be hided even it is not a static one. This is very useful especially in cases where you decide that a function must not be seen, accessed or invoked from other users. This function although is loaded normally, it is not visible and thus it considered private. In ANSA scripting language all functions are by default public. The private: statement is used to create such functions while the public: turns the code in the default status.
def main() { test1(); test2(); test3(); }
static def test1() {
Print("test1"); }
//The function test2 will be hidden private: def test2() { Print("test2"); } public: def test3() { Print("test3"); } 1.8.7 Including files
Scripting language enables the collection of several existing functions into a file. This declaration is made with the #include statement. Each line like the one below:
#include "fullpath to the name of file"
is substituted from the contents of the included file (the quotes are necessary). The include statement must be declared in the global section of the script and its usage has 2 major advantages:
i) The files remain short.
ii) Assures that no mistake will be made since no cutting and pasting actions are performed.
#include "/home/work/CreatePoint_struct.bs" def CreatePoint()
{
set_P point;//The set_p structure is placed in "CreatePoint_struct.bs" //The x,y,z members were defined in "CreatePoint_struct.bs"
point.x = 11; point.y = 10; point.z = 3; }
Important Note 1: In v13.0, the include statement works different than v12.1.x
Important Note 2: Include files should not be used to define functions because if you include the same
file more than once, you will end up with multiple definitions of those functions. Include files should be used only for type definitions (structs, global variables, etc).
1.8.8 Including project files
External files can be treated also as project files. This declaration is made in the global section with the
#projectfile statement. Each line like the one below:
#projectfile "fullpath to the name of file"
is NOT substituted from the contents of the project file (the quotes are necessary) but only enables the usage of file contents. Static variables sharing the same name but located in different project files are loaded normally.
Important Note: #projectfile works exactly the same as the #include statement of versions 12.1.x.
Therefore, It is mandatory to make the replacement if v13.0 or later version is used.
1.8.9 Compilation control (Pre processor)
ANSA scripts can be compiled only through Script Editor (See Section 9.6 for details). The compiled script is treated as any other script - regarding loading and executing - but it cannot be edited since the code inside is not human readable anymore.
Sometimes, a code must be partially compiled either for security reasons or for keeping as small as possible the size of a file. This job is controlled through the internal script preprocessor which searches for specific statements/keywords. A part of a code is defined in the preprocessor via the #define keyword followed by an identifier which can be anything:
#define status
The existence of an identifier is checked through the #ifdef, #if, defined and #ifndef keywords. All definitions can be optionally combined with an #else statement but definitely must end with an #endif. The code between the above statements is ignored during compilation.
Suppose that a script must be compiled and specific users need to have different level of access to included functions. In this case, it would be very annoying and time consuming to maintain two or more versions of the script. Thus, the best solution would be to assign the relevant functions in the pre processor: #define user1 //#define user2 #ifdef user1 def fun_for_user_1 { ... } #endif #ifdef user2 def fun_for_user_2 { ... } #endif
The compiled version of next script is appealed to ‘user1’ and will not contain the function ‘fun_for_user2’. If the user that is going to use the script is ‘user2’, then just comment out the first line: ‘#define user1’ and uncomment the second one: ‘#define user2’. In this case the ‘fun_for_user1’ will be ignored. In the same way different compilations schemes can be done according to user needs.
Important Note: The logical operators !, ||, && are allowed. #define FOO
#define GOO #define ZOO
#if defined FOO && (!defined GOO || defined ZOO) def main()
{
... }
#endif
Another use of pre processor is to protect the user from loading a part of a code more than once. A concrete example can be the case where a file includes some scripts and additionally one of them
includes again at least one of the previous included scripts. If the double defined script contain only user functions this wouldn’t be a problem because the last read will be kept. But, if the script contains global code like a struct definition this can cause problems. In order to avoid this, it is recommended to add within all included scripts a series of pre processor statements that will ensure no multiple definitions. Let’s say that Script1 is used as include and contains only a structure defined in the global section. Script2 includes Script1 and Script3 which in turn includes Script1.
Script1 Struct{ float x; float y; float z; } Script2 #include Script1 #include Script3 def fun1() { } Script3 #include Script1 def fun3() { }
Such an improper definition leads to a syntax error and no loading takes place. If instead, the structure had been defined as part of the pre processor, the corresponding code would be loaded only once and any other time the Script1 was invoked, it would be ignored. Thus the correct approach could be the following: Script1 #ifndef structure #define structure Struct{ float x; float y; float z; } endif Script2 #include Script1 #include Script3 def fun1() { } Script3 #include Script1 def fun3() { } 1.8.10 Recursive structures
Recursive structures are supported in scripting language. This means that a function can call itself as many times as needed. Recursive structures in ANSA have been proved very helpful when trying to search into entities that have a hierarchical structure. A common example is the extraction of all ansa files that exist under a directory tree.
def main() { filenames = 0; path = "/home/demo/model"; type = "ansa"; parse_tree(filenames,path,type); }
def parse_tree(matrix filenames, string path, string type) { i = 0; f = FileList(path+"/*"+type); no_of_files = MatLen(f); if(f!=0){ foreach file in f{ filenames[i++] = file; Print(file); } } m = DirList(path); if(m!=0) { foreach d in m{ new_path = path+"/"+d;
parse_tree(filenames,new_path,type); }
} }
1.8.11 Initialization and un-initialization of matrices and variables in main and global code
A well-structured algorithm implies that any variables or matrices that change their values during the execution of a script must be first initialized. The initialization is very crucial especially when a variable is used as counter for filling the indices of a matrix. A variable or a matrix are initialized by assigning to them an initial value (zero value is preferred in most of the cases).
To release the memory occupied by matrices, the ReleaseVar function can be used to reset them to ‘un-initialized’ state. This function comes handy in cases an existing matrix must be refilled with new data.
def main() { //Initialize counter i i = 0; //Initialize matrix m m = 0;
//Define matrix data1 data1 ={10,20,30,40}; len = MatLen(data1); for(k=0;k<len;k++) { m[i++] = data[k]; } ... statements ... data2 ={1,2,3,4}; ReleaseVar(m); len = MatLen(data2); for(k=0;k<len;k++) { m[i++] = data[k]; } .... statements .... }
Initialization of variables can also be done in global section but only if they are preceded by their type. For example all the following declarations made in global section are valid.
int a = 10; float b = 2.5; string s = "alpha"; def main() { c = a+b+100; Print(c); }
Keep in mind that the type is not binding since it is only used for syntax checking. Thus, it can be changed anytime.
Finally, a variable can get an initial value from a function call not only within the function code but in global section too. This is the way of invoking a function before the "main" or other user defined function. Again, it is essential to assign a certain type to the variable.
//Global code int a = InitVal(); def main() { .... } def InitVal() { no_of_props = MatLen(CollectEntities(NASTRAN,0,"PSHELL")); return no_of_props; }
1.8.12 Use of help text and comments in functions
The common practice has proven that even the most experienced programmer needs to keep some comments in order the code to be more readable and understandable. In ANSA scripting language there are two ways to add comments. The first is to use the symbol // which is practical in cases where a single-line comment is needed. For commenting-out a number of subsequent single-lines use the bounds of a /* comment */.
def my_fun() {
//Collect the parts
search_type[0] = "ANSAPART";
parts = CollectEntities(NASTRAN,0,search_type,1); /*Use each part as a container in
order to collect its faces*/ search_type[0] = "FACE"; k = 0;
foreach part in parts {
container[0] = part;//The container must be in a matrix form faces[k++] = CollectEntities(NASTRAN,container,search_type,0); }
}
A comment line denoted by // symbol can be incorporated in a comment block (/* comment */).
A script function can also have its own help description. This description is a text that must be enclosed between the symbols ## and must be written always prior to the function which describes.
##
Name: NcogToSet
Description: Function that adds the Ncog nodes of PAMCRASH rbodies to a set ##
def NcogToSet() {
statement }
The user script help can be accessed in ANSA through the built in command script_help which is invoked from the command line and through the File>Script>Run function of the SCRIPT menu. Further information and guidelines regarding loading and running scripts will be discussed in Section 6.
1.9 Session commands for use in Scripting Language
All session commands can be used within the scripting language as well, following this convention regarding the command syntax:
- blank spaces and the ">" symbol in session file commands are substituted by an underscore "_" in ANSA Scripting Language.
- the ":" at the end of a session file command is substituted by a parenthesis "( )". All numerical arguments (if any) following the ":" symbol should be included into the parenthesis separated by commas. Non-numerical arguments should also appear within quotes.
Examples:
SESSION FILE Syntax SCRIPTING LANGUAGE Syntax
TOPO>FACEs>ORIENT: TOPO_FACES_ORIENT(); SAVE AS: filename SAVE_AS("filename");
NEW:DISCARD NEW("discard");
2. Interacting with ANSA
2.1 GeneralThe basic idea behind the scripting language is to automate many repetitive and tedious procedures with the minimum user interaction or even to perform specific tasks that are not covered by the standard ANSA GUI commands. Some of the tasks that can be performed with scripting language are the following:
1. Reading and writing ASCII files.
2. Extracting any type of information from an already defined model. 3. Selections that take into account any criteria.
4. Assignment of attributes to parts, materials, properties etc. 5. Use of system commands.
6. Building and executing batch mesh sessions. 7. Creating a model hierarchy.
8. Creating user defined windows and buttons.
9. Co-operating with the MORPH tool for controlling an optimization loop. 10.Use of session commands
11. Running automatically (after launching ANSA) a series of functions.
12. Can be called anytime without reopening a file and as many times as the user wants. 13. Communication with the interface (File Manager functions, Pick functions).
All these tasks that can affect the model definition, are controlled through a series of functions that interact with the ANSA interface. Before proceeding to the explanation of individual functions, it is important to emphasize in two basic topics: the treatment of ANSA elements and the meaning of ANSA entities and cards.
2.2 Handling Data 2.2.1 Data of element type
As mentioned in section 1, one of the data types that is used within scripting language is the element (The user must not confuse it with the elements of ANSA DECKS). Since the scripting language is C-like, we can say that the meaning of this type is similar to the pointer of the C language. An element (or pointer) either includes all the data held by an entity, which most of the times is the information that is included inside an entity card, or the entity itself. Using this element (pointer), we can access the contents of cards or we can even affect an entity (like translating a part or making a property visible).
Some entities that do not have cards in GUI like batch mesh sessions, can be also referenced by elements (pointers).
2.2.2 ANSA cards and entity types
Most of the entities in ANSA GUI have a card that includes all necessary information regarding them. The type of each entity is displayed on the card window header, enclosed in brackets. This entity name is of major importance since this is the keyword that must be used in order to collect the entity itself and to have access in its contents. For example, each NASTRAN "shell" has a card with name SHELL and this is the keyword that must be used for dealing with this type of entity. Exceptions to this rule are the ANSA part and ANSA group, which use different keywords. The labels of card fields are also important since they must be used in order to get their values.
The keywords of the entities that either don't have entity cards or the rule described before doesn’t cover them are the following:
# Entity type Description
1 Ansa part ANSAPART
2 Ansa group ANSAGROUP
3 Batch mesh group BATCH_MESH_SESSION_GROUP
4 Layer scenario BATCH_MESH_LAYERS_SCENARIO
5 Volume scenario BATCH_MESH_VOLUME_SCENARIO
6 Batch mesh session BATCH_MESH_SESSION
7 Layer session BATCH_MESH_LAYERS_SESSION
8 Volume session BATCH_MESH_VOLUME_SESSION
9 Solid facets SOLIDFACET
10 Continuum shell facets TSHELLFACET
Important Note: Keep in mind that although connection entities have cards, they cannot be accessed
through Connection Manager but through the Database Browser. Finally, the deck curves use a variety of keywords that can be found under the help text of the built in function CreateLoadCurve.
2.3 Collecting entities 2.3.1 General
The most significant functions for collecting entities are those that displayed in the following table: Common characteristic of these functions is that they return the elements (pointers) of the entities.
The types of entities that can be collected using these functions are: ELEMENTs (SHELLs, SOLIDs, BEAMs, etc)
COORDINATE SYSTEMs CONSTRAINTs
LOADs
CONDITIONs (intial or boundary) BOXes SETs GRIDs ANSAPARTs ANSAGROUPs CONNECTIONs
GEOMETRIC ENTITIES (Curves, Points, Cons, Faces etc) PROPERTIEs
MATERIALs INCLUDEs CONNECTORs GEBs
Important Note: The GetEntity function cannot collect ANSAPARTS and ANSAGROUPS of PART
MANAGER
# Function Description
1 CollectEntities Collect entities massively
2 GetEntity Get a single entity
3 GetFirstEntity Get the first entity according to its id 4 GetNextEntity Get the next entity according to its id
5 GetPartFromModuleId Get PARTs or GROUPs
6 Name2Ents Get entities from their name
7 CollectNewModelEntitiesStart Start collection monitor for new
entities created or imported to the model.
8 ReportNewModelEntities Report entities gathered since the previous matching call to the
CollectNewModelEntitiesStart function
9 CollectNewModelEntitiesEnd End collection monitor for new entities created or imported to the model
In any of these functions where the "type" of an entity is required, the first argument is an integer that refers to the DECK for which we require the entity type. These integers are given internally to ANSA and the user needs only to type the corresponding DECK name:
NASTRAN LSDYNA PAMCRASH ABAQUS RADIOSS ANSYS CFD
Important Note 1: If zero value is given instead of the deck name, then the current deck will be taken into
account.
Important Note 2: The MORPH statement must be used for handling entities coming from morph menu. 2.3.2 Collecting entities massively from the whole database
For collecting massively a type of entity (e.g. SHELL) the appropriate function is the CollectEntities. One of the advantages of this function is that it can be used for finding entities that are used by other entities while it is the only function that can collect any visible entities. Its syntax is very flexible and can accept either matrices or single elements (pointers). A variable number of input arguments can be specified as well. Let's see the capabilities of the CollectEntities function with some examples.
def main() {
/*Define into a matrix the keywords of entities that you want to collect. These keywords are taken from the title of their cards*/
search_type[0] = "PSHELL"; search_type[1] = "PSOLID";
ents = CollectEntities(NASTRAN,0,search_type,0); }
In this approach the input arguments are matrices. The second argument indicates the search domain and in case the user needs to collect entities from the whole database it must be zero. The output argument is a matrix that contains the elements (pointers) of PSHELLs and PSOLIDs of the database. The definition of the deck must be compatible with the entities that are going to be collected. An approach like the following is not accepted:
search_type[0] = "PSHELL"; search_type[1] = "PSOLID";
ents = CollectEntities(PAMCRASH,0,search_type,0);
In this case the equivalent keywords for PAMCRASH deck are PART_SHELL and PART_SOLID.
2.3.3 Collecting entities massively from other entities
In this case we would like to collect the GRIDs that are used from SHELLs. In scripting language terminology, the matrix of shells is considered as a container and must be given as a second argument in order to prompt the function to search only into the collected shells. A container can be either a matrix of elements (pointers) or a single element (pointer).
def main() {
//Collect first the shells of the whole database search_type[0] = "SHELL";
shells = CollectEntities(NASTRAN,0,search_type,0); //Collect the grids of the shells
search_grid[0] = "GRID";
grids = CollectEntities(NASTRAN,shells,search_grid,0); }
def main() {
//Collect first the shells of the whole database shells = CollectEntities(NASTRAN,0,"SHELL",0); //Collect the grids of the shells
grids = CollectEntities(NASTRAN,shells,"GRID",0); }
The third argument that defines the types of entities that we are looking for, can be also set to zero. This setting can be used for gathering all the entities that are included into a superior entity. This makes sense in SETs, PARTs and INCLUDEs.
def main() {
//Collect the sets of the database sets = CollectEntities(NASTRAN,0,"SET");
//Collect all the entities that belong to these sets ents = CollectEntities(NASTRAN,sets,0);
}
Attention must be given in the meaning of containers. Many entities in ANSA are considered as containers since they include other entities inside them e.g SHELLs include GRIDs. These containers are classified according to their level. For instance, SHELLs are of higher level than GRIDs while PSHELLs are of higher level than SHELLs and GRIDs. So, if we want to search for entities inside a container we can instruct the CollectEntities to search recursively until the lower level. This is very clear in the following examples. def main() { pshells = CollectEntities(NASTRAN,0,"PSHELL",0); shells = CollectEntities(NASTRAN,pshells,"SHELL",0); Print(MatLen(shells)); }
The last argument of CollectEntities is zero since SHELLs is only one level under PSHELLs. Another equivalent syntax could be:
shells = CollectEntities(NASTRAN,pshells,"SHELL","recursive","no");
For finding directly the GRIDs that are used by PSHELLs, we have to invoke the function to search recursively until the lowest level. In this case the last argument takes the value 1.
def main() { pshells = CollectEntities(NASTRAN,0,"PSHELL",0); grids = CollectEntities(NASTRAN,pshells,"GRID",1); Print(MatLen(grids)); }
Similarly we could have written:
grids = CollectEntities(NASTRAN,pshells,"GRID","recursive","yes");
A matrix that contains entities of specific type cannot be used as container for collecting entities of the same type. This is more clear with the following example: Suppose that we have a matrix that contains elements (pointers) of SHELLs and SOLIDs. In this case the CollectEntities will not work if we define as search type either SHELLs or SOLIDs. It will work only if we search for GRIDs.
2.3.4 Collecting massively visible entities
CollectEntities is the only script function capable of collecting visible entities.
def main() {
grids = CollectEntities(NASTRAN,0,"SHELL","filter_visible","yes"); Print(MatLen(grids));
}
Important Note: Visible entities like Properties, Materials, ANSAPARTs, ANSAGROUPs, Sets or
Includes cannot be collected.
2.3.5 Collecting available entity types of specific deck
As we saw in paragraphs 2.3.2, 2.3.3, and 2.3.4, the CollectEntities function needs to know, in most cases, what types of entities to search for. In simple cases where specific types are needed, the user just have to open the respective card and see what string to use as keyword. For more complicated cases where the entities that we search for are not well known or they are too many to open their cards one by