## Basic Tcl/Tk

The message window in Ansys ICEMCFD is a Tcl/Tk shell with an extended library consisting of ICEMCFD commands. Most of these commands begin with "ic_" to indicate an ICEMCFD command. One place where documentation can be obtained for Tcl/Tk procedures is at http://www.scriptics.com. Many books have also been written on the subject.

Tcl, which stands for "Tool Command Language," is a string-based programming language. This means that, except for inside the expr command, we need not discern between variable types, such as integers, doubles, or strings. Everything is treated as a string. There is also no need to set aside memory (dimension) for variables, and they can be reset to values of any length without redimensioning.

Tk stands for "Toolkit" and contains the add-on Tcl commands that allow graphical interfaces, or windows, of an application to be made.

Command syntax

The basic syntax for a Tcl command is:

command arg1 arg2 arg3 ...

Commands are terminated by either a newline character (not usually displayed) or a semicolon, ";".
Spaces are key characters which separate arguments.
Commands can only be continued to the next line with a "\" at the end of the line, or with the beginning of an argument grouping using "{" or ".

Argument grouping

If a space is to occur inside an argument, then the argument must be grouped as one so that it is not interpreted as separate arguments. For example, the syntax for "puts" is:

puts ?-nonewline? ?channelId? string

The text between question marks, "?...?" are optional arguments or switches which may or may not be present. Consider the following commands and their return values:

% puts {Hello world}
Hello world
% puts Hello world
can not find channel named "Hello"

In the first example, you'll see that the grouping brackets, "{...}", were stripped out by the interpreter, but it was treated as a single argument.
In the second example, the arguments, "Hello" and "world" are treated as separate arguments where "Hello" is the channelId. At this point, no channel named "Hello" exists.

There are 3 types of grouping:

- {...} - Groups without allowing substitution inside
- "..." - Groups while allowing substitution inside.
- [...] - Interrupts the current command to do the command contained inside the brackets. The next word following "[" must be a command. This creates a nested Tcl command structure. Some Tcl documentations don't consider this a grouping structure.

Note: puts will not output text to the ICEMCFD message window. To do this, use mess or ic_mess. This command automatically does the -nonewline switch. You must use "\n" inside the message string to insert a new line.

Substitution

There are 3 types of substitution:

- Command - This is done whenever there are square brackets, "[...]". The command is executed and the return value is substituted before continuing with the original command.
- Variable - Variable substitutions are done by using a dollar sign, "$", in front of the variable.
- Backslash - When a backslash, "\" is encountered, the next character is treated special. For example, "\n" means to substitute a new line character.

The following commands can be used to set a value to a variable and then substitute that value for the variable later:

% set x 5
5
% mess "x is: $x\n"
x is: 5
% mess {x is: $x\n}
x is: $x\n

Here, the "\n" is used to ensure that the next text printed to the message window will appear on the next line. Without it, the text will continue on the same line. Also notice that the set command will also return the value as well as set the variable to the value.
In the third example, you'll see that no substitution, variable or backslash, was done inside the brackets, "{...}".

Note: Argument grouping is ALWAYS done before substitution, so the number of arguments input into a command is always determined before any variable or command substitutions that may result in multiple return values.

Creating a simple script

Lets say you want to load multiple geometry files of varying names and save them all as one new geometry file, and you want to do it without ever seeing the ICEMCFD window (GUI) displayed (GUI stands for Graphical User Interface).
First go to File, Replay Scripts, Replay Control, then load 1 tetin. After that, save the tetin to a different name. You should see the following commands printed:

1. ic_load_tetin support/test/tetin1.tin
2. ic_geo_get_body_matlpnt LIVE.0
3. ic_boco_solver
4. ic_boco_clear_icons
5. ic_boco_natran_csystem reset
6. ic_uns_set_modified 0
7. ic_geo_set_modified 0
8. ic_undo_start
9. ic_save_tetin support/test/new_tetin.tin 0 0

We can discard all but the first and last commands since we are not interested in any GUI updates, boco settings, or the undo log. So we'll end up with this:

1. ic_load_tetin support/test/tetin1.tin
9. ic_save_tetin support/test/new_tetin.tin 0 0

The file name paths will start from either the working directory as in this case or from the toplevel drive. Since the tetin names can be changed, as well as the working directory, we must use variables. It is safe to specify all names from the toplevel, so set a variable that is the path of the working directory:

set wdir D:/user/support/test
set tetin tetin1.tin
ic_load_tetin $wdir/$tetin
ic_save_tetin $wdir/new_$tetin.tin 0 0

Note that we use "/" on Windows operating systems as well as Unix. The "\" is an escape character which interprets the next character differently. There are situations, however, where this could potentially cause problems, so it is good practice to use the file join command. With the file join command inserted inside bracket expressions, it looks like this:

set wdir D:/user/support/test
set tetin tetin1.tin
ic_load_tetin [file join $wdir $tetin]
ic_save_tetin [file join $wdir new_$tetin.tin] 0 0

Now we can use a foreach loop to cycle through multiple tetin files. The simplest syntax for the foreach command is:

foreach varname list body

The foreach loop will step through a list of values assigning each next item in the string to the "varname", and evaluating "body" each time. The "list" can be a proper Tcl list made with the list command, or by simply grouping text within "..." or {...}. List elements must be separated by spaces. With a foreach loop, the script becomes this:

set wdir D:/user/support/test
foreach tetin [list tetin1.tin tetin2.tin tetin3.tin] {

ic_load_tetin [file join $wdir $tetin]

}
ic_save_tetin [file join $wdir new_$tetin.tin] 0 0

The previous example illustrates another important property of grouping arguments with {...} or "..." (but not [...]).
The grouping quotes or curly brackets (the "body" argument here) allow an argument to span multiple lines so that the current command is not terminated by the first newline character (which are usually not displayed in the text editor).

So now we can save this script as "script.tcl" inside "D:/user."

Running your script

There are 4 ways we can run the script:

- Replay control window - By using "do one" or "do all"
- File, Replay Scripts, Run from script file
- source - Tcl command to execute Tcl commands in a file.
- icemcfd -script - specify a script to run when you start up Ansys ICEMCFD

All 4 methods can be used with the GUI displayed, but only the last two can be done in batch mode.
source D:/user/script.tcl can be typed in the message window, or Ansys ICEMCFD can be started in batch mode by adding the "-batch" argument to the ICEMCFD startup command (icemcfd -batch). Then you can source the script from the shell.
Using both the -batch and -script arguments (icemcfd -batch -script D:/user/script.tcl) will start ICEMCFD in batch mode and immediately run the script.

Note: The source command can be used inside a script to execute Tcl commands from a separate script.
You can have ICEMCFD close immediately after your script is finished if you add the exit command to the end of your script.

Arrays and environment variables

Environment variables are accessed through a reserved global array variable named "env".
An array is a variable name followed by another name within parantheses. This is a variable which contains sub-variables, each of which can have a value assigned. The following are array variables of the same array:

geom(point)
geom(curve)
geom(surface)

We can use the env variable to make our script portable between different installations of ICEM by using it in the path for any scripting commands that run another executable inside ICEMCFD.
For example, the following line was printed in the Replay Control window when a mesh was written to CFX5 format:

ic_exec {C:/Program Files/Ansys Inc/v90/icemcfd/5.1-win/icemcfd/output-interfaces/cfx5} -dom D:/user/support/test/tetra_mesh.uns -b D:/user/support/test/family_boco.fbc -ascii -internal_faces D:/user/support/test/cfx5_input

"cfx5" is the executable being run.
The ICEM_ACN environment variable points to the top ICEMCFD folder, 5.1-win. So we can substitute the environment variable for the path leading up to 5.1-win. We will also set a working directory variable as before and substitute that where appropriate using the file join command:

set wdir D:/user/support/test
ic_exec [file join $env(ICEM_ACN) icemcfd output-interfaces cfx5] -dom [file join $wdir tetra_mesh.uns] -b [file join $wdir family_boco.fbc] -ascii -internal_faces [file join $wdir cfx5_input]

Since argument grouping is always done before substitution, we don't need to put quotes, "...", around $env(ICEM_ACN). It is seen as one argument into the file join command even though it's value contains spaces:

$env(ICEM_ACN) = "C:/Program Files/Ansys Inc/v90/icemcfd/5.1-win"

Notice also that we got rid of the curly brackets, {...}, in the original command because we needed to do variable substitution within, and the square brackets, [...], will do the grouping for us.

Creating your own procedures (functions)

By using the proc command, we can put the earlier script in a procedure and use the file names as the arguments, so different file names can easliy be typed in without re-sourcing the file or restarting ICEMCFD. The syntax for the proc command is:

proc name args body

An example procedure using the earlier script might look like this:

set wdir D:/user/support/test
proc merge_tetins {infiles outfile} {

global wdir
foreach tetin $infiles {

ic_load_tetin [file join $wdir $tetin]

}
ic_save_tetin [file join $wdir $outfile] 0 0

}

Notice the global command inside the procedure. Any variables defined outside of a procedure are global variables. Any variable set or used inside a procedure, including the arguments, are local variables, and will be unset when the procedure is finished executing. wdir is a global variable since it was defined outside a procedure. To access it inside a procedure, it must be declared inside the procedure as global.
After reading the script into ICEMCFD with any of the above 4 methods, the procedure will only be defined. It will not be executed. To execute the procedure, type this in the ICEM message window or in the shell (in batch mode):

merge_tetins {tetin1.tin tetin2.tin tetin3.tin} new_tetin.tin

You can re-type this at any time with different argument inputs to re-execute the procedure. If you would like to execute the procedure when the script is read, you can add the call of the procedure to the end of your script.
A script can have any number of procedures, and any of the procedures can be called from inside the script.

Mathematical expressions

Mathematical expressions cannot be evaluated in Tcl simply be typing them. They must be contained within the expr command.
Example:

% expr {5+2/7}
5
% expr {5+2/7.0}
5.28571428571

The expr command does its own substitution, so if we use "..." or no grouping at all instead of {...}, it will substitute once before the command is executed, and then once again when it is executed. It won't hurt the result, but it will be quicker executing if we only allow one substitution by using the curly brackets.
The order of evaluation is the same as conventional mathematics. 2/7 is done before 5 is added. The resulting type (floating, integer, etc...) will be integer if all of the operands are integer. If any one operand is a floating point, then the result will be a floating point.

Note: The expr command is done on the test conditions for the if, while, and for commands, so you can use mathematical expressions inside without using the expr command.