NairnFEAMPM Icon

Using Internal NairnFEAMPM Script Control

Any text editing window for writing input commands (see NairnFEAMPM Commands) can alternatively be used to edit scripting commands to control and analyze calculations. The scripting commands use the same interpretive language commands used when creating input commands for calculations, but replaces the NairnFEAMPM commands for calculations with new commands for script control. The help topics for internal scripting control of NairnFEAMPM are:

Creating and Running a Script

To create a script to control NairnFEAMPM, you can use the menu command New→Blank File. Scripts are plain text documents with interpretive language commands and the first scripting command must always be a Script command. This command is how NairnFEAMPM distinguishes script control files from input command files used to set up FEA and MPM calculations.

Before a script can be run, the new document must be saved (with extension .fmcmd). To run a script, use the "Interpret Commands" menu command (in the "Analyze" menu) or click the "interpret" icon in the tool bar (plain hammer icon). The script will run. The script may write results to it's console as calculations proceed. When the script is done, the script window will return to the front and any written results will be visible.

Script Variables and Script Objects

Scripts allow standard numeric and string variables supported by the interpretive language. In addition to these standard "variables", scripts define "objects," that represent things like commands documents, results documents, and more. The properties and possible commands for all object types are given in the object dictionary. Objects are accessed in scripts through object names that must:

  1. Begin in a letter
  2. Contain any number of letters, numbers, and the underscore characters

Although script variables traditionally start in number sign (#), they are not required to do so. Some object commands, however, require a number sign to distinguish variables from object names. It is therefore recommend that internal scripts always start variables with a number sign such that names without a number sign are always object names.

Whenever an object name is needed for an existing object, such as when targeting a command or as arguments for commands, the object name can be dereferenced through a variable by using ^#name. The caret, ^, means to use the object whose name is equal to the value of the provided variable (here #name).

When writing internal scripts, object names are global. Subroutines should be careful not to overwrite objects in the main commands. When writing a subroutine whose result is to define an object, the main commands can access any objects using the name defined in the subroutine. Because subroutine arguments are only strings that are assigned to variables, passing an object to a subroutine must use one of the following two methods:

Sub UseObject,#obj
  GetObject obj,#obj
  obj.0.get "#listItem"
  
  ! ... or directly dereference the object name
  ^#obj.1.get passedObj
EndSub

CreateList mylist,"one string item",anObject
GoSub UseObject,"mylist"

The object name mylist is passed as a string that gets set to the subroutine variable #obj. The GetObject command evaluates that variable as an object name and then sets obj to that object. Alternatively, the object can be directly dereferenced with ^#obj.

A common task for internal scripts is to automate running calculations. When a script tells a commands document to interpret its commands or to interpret and run calculations, all variables defined in the script are transferred to the document. The typical script will define variables to control a calculation and then run one or more calculations.

Most FEA or MPM commands documents are written as stand-alone documents, which means they define all their own variables. To allow such documents to use script-defined variables when run from an internal script but their own variables when run on their own, a running script will also define a read only variable named _ScriptMode_. Thus, an FEA or MPM commands document can contain a section like:

ifNDef _ScriptMode_
  #myVar = 23
  (define variables to run as stand-alone file)
  ...
endif

When this FEA or MPM commands document is run in script control, the script will be expected to define all the variables defined in the above block and the commands document will use the script-defined variables instead of it's local variables. When that document is run by itself, however, it will execute the above section and define all variables needed to run as a stand-alone file.

A Sample Internal Script

The following sample internal script, opens the front Command document, runs one calculation, and reads and writes out the maximum stress in the y direction:

! First command must be "Script"
Script

! Find the front commands document
nfmapp.get cdoc,"frontCommandDocument"

! Set variables needed by calculations
#strain=2

! Interpret and run calculaitons
cdoc.run rdoc,"output.mpm"

! Get stress from a time plot
CreateDictionary settings
settings.setStringForKey "Stress","menutext"
settings.setStringForKey "1","tensorindex"
settings.setStringForKey "1","materialoption"
rdoc.timePlot data,settings

! data is a list with two lists, grab y data
! and seach for maximum value
data.1.get ydata
#smax=-1e6
Repeat "#k",1,@ydata.count-1
  #sval=@ydata.#k
  if #sval>#smax
    #smax = #sval
  endif
EndRepeat

! Write results to script console pabe
WriteLine "Maximum syy = "&#smax

The "Script" command marks these command as an internal scripts. All internal scripts have nfmapp defined as object name for the NairnFEAMPM application. That object is used to fetch the front Command document. Next variables needed by the script are set and the run command runs the calculation. The rest of this script plots average stress in the y direction (by entering plot settings into a created dictionary) and then loops over y values from the returned results (in lists) to find the maximum value. Finally, the maximum value is printed to the script's console pane.

Internal Scripting Commands

Besides the standard commands in the interpretive language, internal scripting adds some direct commands specific to internal scripting and many object commands that can be targeted to objects . The first "direct" command is:

All remaining "direct" commands are listed below while object commands are in the following section. Each command is documented with command name and arguments. Required arguments are listed with the command; optional arguments are enclosed in square brackets:

command (arg1),(arg2),[(arg3)],...
obj[.#i].command (arg1),(arg2),[(arg3)],...

The first is a "direct" command. The second is a command sent to a specific object. The optional .#i is an object extractor that can pick a object from a list by index starting at 0. The index can be a variable containing a number. All command arguments (e.g., (arg1), (arg2), ...) are evaluated first as an expression and the expression result is passed to the command. Two consequences of this process are:

  1. Many commands return a result in a variable that must be provided as a command argument. Such arguments are listed below as "#var". This quoted form is actually a string expression that evaluates to #var that is passed to the command. If needed, you could use an expression that evaluates to the name as well, such as:
    #ref = "#var"
    command #ref
    
    Finally, note that although the internal scripting language does not require variables to start with a # sign, variables names passed to scripting commands to retrieve results are required to being in a # sign (a good approach is just to use # sign for all variables in internal scripts).
  2. Other internal scripting commands return an object as their result. These commands expect the object name (denoted below by objName) to be passed as a string expression that evaluates to the object's name. Because object names cannot start in #, they typically act as expressions that just evaluate to their name even when not quoted. If there is ever a name conflict, put the object name in quotes. (Note: the requirement that "#var" passed to a command must start with a # sign is to guarantee that commands can distinguish between variables and objects).
  3. When an internal scripting command argument expects an object name parameter to refer to an existing object, it is listed as objName[.#i]. The optional .#i is an object locator that can pick an existing object from a list by index.

Direct Commands

This section has all the extra direct commands for internal scripts (in alphabetical order):

Scripting Commands for Objects

This section has all object commands (in alphabetical order). Note that a command to an invalid object (i.e., obj[.#i].(command) where obj[.#i] is not an existing object) or passing an invalid object to a command that expects an object (i.e., when obj[.#i] is in the list of command arguments) will, unless otherwise noted, cause an error and the script will end. Two important exceptions are the GetObject and get commands. When needed, you can use these commands to validate any object before targeting it with other commands or using it an "@" expression to read an object property.

obj[.#i].addList objName1[.#i],[objName2[.#i],...]
Adds individual elements of one or more lists to the target object. Any parameters that do not correspond to a valid list object will be skipped. Use addObject to add a list as a single object to another list.
    Supported By: lists
obj[.#i].addObject objName1[.#i],[objName2[.#i],...]
Adds one or more objects to the target list. Any parameters that do not correspond to a valid object will be skipped. Objects that are other lists are added as list objects (i.e., a list can contain other lists). Use addList to add elements of those lists to the target list.
    Supported By: lists
obj[.#i].addString (expr1),[(expr2),...]
Adds one or more strings to the target list. All parameters must valid expressions.
    Supported By: lists
obj[.#i].close
Closes the document and all its windows. If the document has been changed, any changes are lost.
    Supported By: Command documents, Results documents
obj[.#i].CrackClosure "objVar",(tipnode),<(normT)>,<(shearT)>
Calculate mode I and mode II energy release rates for the crack tip at the specified (tipnode). It will set object with name "objVar" to a dictionary with entries for "GI", "GII", and "Gtot" for the energy release rates. The returned dictionary will have other calculation details as well (similar to what appears in the crack closure window). If there is a error, the returned record will have single entry "ERROR" that describes the error. The tractions allow specification of constant crack-surface tractions to use in the calculations (they are zero if omitted)
    Supported By: Results documents
obj[.#i].export <(path)>
This command will save the contents of the console pane in the object document to the file specified by (path). The optional (path) can be a full path or a path relative to the script document. The folder to receive the output file must already exist. If (path) is omitted, the user is given a file-saving dialog box to select file name and save location.
    Supported by: Command documents
obj[.#i].FindNode "#var",(x),(y)
Finds the node in a 2D grid closest to the coordinates in the provided (x) and (y) parameters. The provided variable, quoted #var, is set equal to the node number or set to 0 if none found.
    Supported By: Results documents
obj[.#i].get ("#var" or objName),[(attr)]
The response of this command depends on the target object in obj[.#i]:
1. If obj[.#i] is a string or number, set #var to that value. The first parameter must be a valid variable name (starting in "#") and (attr) is ignored. Note that when obj is a List containing strings or numbers, this special case can also be done with an "@" expression instead:
#var=@obj.#i
2. If obj[.#i] is not a string, set objName (which must be a valid object name in the first parameter) to one of that object's "to-many" or "to-single" attributes defined by (attr). But, if optional (attr) is not provided, set objName to the object extracted by obj[.#i]
3. If obj[.#i] does not correspond to a valid object, this command will not cause an error. Instead, if the first parameter is "#var", that variable will be removed from the list of variables. If the first parameter is objName, the object name will set to None. Both these can be used to validate obj[.#i] with ifDef or ifNDef commands before using it in subsequent scripting that might cause an error.
    Supported By: all objects that that have attributes or properties and to get elements from lists
obj[.#i].insertObject objName[.#i],(index)
Inserts one object at index in the target list. The provided objName[.#i] must be a valid object name and list indices are zero based.
    Supported By: lists
obj[.#i].insertString (expr),(index)
Inserts one string at index in the target list. The provided (expr) must be a valid expression and list indices are zero based.
    Supported By: lists
obj[.#i].interpret
Interpret the commands in the object document. The resulting XML commands will appear in the console pane of that document. This command will wait until the interpretations are done before returning control to the script. One use of this command is to follow it with an object.export command to save the XML commands to a file.
    Supported by: Command documents
obj[.#i].join "#var",[(string)]
Joins all elements in the target object (which must be a list) separated by the optional (string) (if omitted joined by empty string). To work correctly, all elements in the target list must be strings. The provided variable, quoted #var, is set equal to the joined strings.
    Supported By: lists
obj[.#i].plottable (table)
This command will plot a table of data as a child window of the object document where (table) is a string argument of multiple lines. The first column has x data and all subsequent, tab-delimited columns have one or more y data sets. A column with no data for specific x can be left empty. The (table) can include a preamble of commands to set styles for the plot. These lines are at the beginning of the table, each begin with "#", and can use any commands documented in the PublishPlot application. A single plottable command can plot multiple tables if they are separated by blank lines within the (table) string argument. The use of multiple plottable commands will create multiple plot windows.
    Supported by: Results documents
obj[.#i].pop ("#var" or objName)
The command will get the last element of the target object in obj[.#i], which must be a List, and will remove that element from the list. If the element is a string, the variable #var will be set to that element. If it as object, the objName will be set to that element. If the list is empty, this command will not cause an error. Instead, if the first parameter is "#var", that variable will be removed from the list of variables. If the first parameter is objName, that object name will set to None.
    Supported By: Lists
obj[.#i].remove (index)
Remove item in a list at (index) (which can be any valid integer expression).
    Supported By: lists
obj[.#i].removeValueForKey (key)
Remove value in a dictionary corresponding to (key) (which can be any valid expression).
    Supported By: dictionaries
obj[.#i].run (resDoc),(path)
Interpret the commands in the object document, run the calculations (locally), save the result to the results document using the (path) argument, and finally set the object variable in (resDoc) (which must be a valid object name and not an expression) to the final results document. This command will wait until the calculations are done before returning control to the script. The (path) can be a full path or a path relative to the script document. The folder to receive the output file must already exist.
    Supported by: Command documents
obj[.#i].runremote
Java app only
obj[.#i].setObjectForKey objName1[.#i],(key)
obj[.#i].setStringForKey (expr),(key)
obj[.#i].setNumberForKey (expr),(key)
These three commands set a single key-value pair in a dictionary object (obj[.#i] must be a dictionary). Three commands are available to add three types of values using a (key), which can be any string or numeric expression. The first one adds any valid object to the dictionary. The other two add any valid expression (in (expr)) to the dictionary. The main use for setNumberForKey is in scripts that will later use the keysSortedByNumericValues relation of the dictionary.
    Supported By: dictionaries
obj[.#i].sort
Sorts the items in list by case insensitive comparisons. All items must be strings.
    Supported By: lists
obj[.#i].subList objName,start,[end]
The target object (in obj[.#i]) must be a list. This command creates a new list, which is stored in objName, containing elements from index start to index end-1 (note the first element in a list is at index 0). If optional end-1 is omitted, the sublist will be from start to the end of the list.
    Supported By: lists
obj[.#].timePlot objName,settings
Plots a selected MPM result as a function of time and returns the result in objName as a list with two lists at index 0 and 1 for time and values, respectively. The result to be plotted and options for the plot window are determined by the plot settings loaded into settings which must be a dictionary. See the xy plot command to get a 2D plot of a result through an FEA mesh or an MPM grid.
    Supported by: Results Documents
obj[.#i].valueForKey ("#var" or objName),(key)
Fetches the value from a dictionary (obj[.#i] must be a dictionary object) corresponding to (key), which is any valid expression. If the value is a string or a number, set #var (which must be a quoted variable name starting in "#") to that value. If the value is an object, set objName (which must be a valid object name) to that object. A mismatch between value type and the first parameter (e.g., using objName when value is a string or number or using "#var" when value is an object) will cause an error. If (key) is not in the dictionary, "#var" will be undefined or objName will set to None type. Both these can be checked as explained in the get command.
    Supported By: dictionaries
obj[.#i].XYPlot objName,settings
Plots a selected MPM or FEA result as a function of position in a mesh or grid and returns the result in objName as a list with two list at index 0 and 1 for distance and values, respectively. The result to be plotted and options for the plot window are determined by the plot settings. See the time plot command to plot an MPM result as a function of time.
    Supported by: Results Documents