• CFD, Fluid Flow, FEA, Heat/Mass Transfer
Scripting Languages

Table of Contents: SCHEME Summary | FLUENT TUI | Examples of UDF | Macros in STAR-CCM+ | Field Functions in STAR-CCM+ | Batch Scripts | Windows PowerShell | Shell Scripts | AWK Programming | Scripting in ANSA


Scripts, Journals, UDF, Field Functions

A collection of scripts, journals and macros in CFD simulations to automate some tasks as well as enhance simulation capabilities. One may need such functions to apply special boundary conditions such as inlet velocity which is function of both time and space. Scripts or macros can be used to repeat the same simulation with changed boundary conditions or can be used to create a checking log where the summary of boundary conditions, solver setting, material properties and interface/periodicity information can be written out in a log file for self and peer review. For a practical demonstration of scripting, refer to the manual "Scripted CFD simulations and postprocessing in Fluent and ParaVIEW" by Lukas Muttenthaler from JOHANNES KEPLER UNIVERSITY LINZ.

For flow and thermal simulation jobs, consultancy, training, automation and longer duration projects, reach me at fb@cfdyna.com. Our bill rate is INR 1,200/hour (INR 9,600/day) with minimum billing of 1 day. All simulations shall be carried out using Open-source Tools including documentations.


Definitions and concepts

  • A STAR-CCM+ macro is a Java program that is compiled and executed within the STAR-CCM+ workspace. A FLUENT UDF is a C program that is compiled and executed within the FLUENT workspace.
  • CFX uses a high level programming called CCL or CFX command language. Unlike UDF or JAVA macros, it does not need to be interpreted or compiled. However, for special post processing, commands in PERL and accessing solver program in FORTRAN is required.
  • Note that specific heat capacity Cp cannot be accessed or changed via UDF in FLUENT.

Program and Scripting/Macro Language

ICEM CFDSTAR-CCM+FLUENT*CFXOpenFOAMParaViewANSAHyperMesh
Tck/TkJava SCHEME, CCCL, PERL, FORTRANC++PythonPythonTcl/Tk
* ANSYS SpaceClaim (rebranded as ANSYS Discovery in 2024) used IronPython for scripting.

A sophisticated automation approach requires developement of a consistent naming convention for the geometry, surface, boundaries and volumetric regions (domains). This include CAD package, the pre-processor, solve and post-processor. Even the structure of CAD program (such as model tree) to represent an assembly need to be simple and consistent with CFD pre-processor. It may be an uphill task if the CAD program, the pre-processors and solvers uses different programming and scripting languages. For example, ANSYS SpaceClaim uses Python, FLUENT is based on SCHEME and the syntax in CFD-Post is CEL/PERL. In such cases, end-to-end automation may not yield desired advantages and a separate automation should be worked out at each step. FLUENT GUI is based on Qt Toolkit and graphical attributes can be modified using Qt stylesheets such as cxdisplay.css for FLUENT. This file needs to be placed in home directory (location where FLUENT executables are placed during installation). This article "Scripted CFD simulations and postprocessing in Fluent and ParaVIEW" by Lukas Muttenthaler et al at Johannes Kepler University Linz provides a detailed automation method which can be improvised further.

  • A guide describing syntax used in SCHEME language can be found here (Scheme programming).
  • Another book: gustavus.edu/mcs/max/concrete-abstractions-pdfs/ConcreteAbstractions.pdf --- Concrete Abstractions - An Introduction to Computer Science Using Scheme by Hailperin et al. Some example from this book is provided towards end of this page.
  • A summary of few basic yet key features of the programming languages mentioned above is tabulated below.
  • SCHEME is a dialect of LISP (having fully parenthesised syntax) and is the second-oldest high-level programming language after FORTRAN. The command and variable names are case-insensitive (though should only contain small letters in ANSYS FLUENT).
  • Note: if in future ANSYS decides to re-write FLUENT GUI and TUI in some other programmins langauge say C++ or Python, the scripts described on this page may get obsolete.
  • ANSYS has a feature ACT to facilitate automation an customization of simulation workflows.
Feature Tcl/Tk FORTRAN CJAVA
Case-sensitiveY N YY
Comment# C, !/* ... */ //
End of Statement;Newline character;;
Line Continuation\Any character\Not required
Variable Definition set x = 1;real x = 1real x = 1; real x = 1;
If Loopif { x == y } {
 x = x + 1;
}
if (x .EQ. y) then
 x = x + 1
endif
if (x = y) {
 x = x + 1;
}
if (x = y) {
 x = x + 1;
}
For Loop for {set j 1} {$j <= $n} {incr j} {
  ...
}
DO Loopfor (i=0; i<= 10, i++) {
 ...
}
for (i=0; i<= 10, i++)
{
 ...
}
Arrays$x(5); x(5) x[5];x[5];
File Embeddingsource "common.dat"; include "common.dat" #include "common.h";import common.class;
Note:

Java doesn't need a "line continuation character" since the end of the line has no significance so long a semi-colon is added at the end of a statement. It acts just as any other whitespace character. In other words, one can end the line immediately after an x = and continue on the assignment (say 10 in x = 10) on next line without any problems. For Tck/Tk used in ICEM CFD, the end of statement is also a newline character. However, if more than one statements are to be put on a line, they can be separated by a semi-colon. In SCHEME, a string literal is continued from one line to another, the string will contain the newline character (#\newline) at the line break. Like most of the programming languages: string is written as a sequence of characters enclosed within double quotes " ". To include a double quote inside a string, precede the double quote with a backslash \ (escape it).


CFX uses PERL for automation such as for-loop and lists. It does not accept underscore or hyphen in names, though spaces are allowed.


Examples: In FLUENT, the in-built macros used to access components of the velocity are
  • C_U(c,t): x-component of velocity
  • C_V(c,t): y-component of velocity
  • C_W(c,t): z-component of velocity
In STAR-CCM, it is achieved as:
  • Magnitude: mag($$Velocity)
  • X-component: $$Velocity[1]
  • Y-Component: $$Velocity[1]...
  • The directions X,Y,Z are represented by [0],[1],[2] respectively.

An example of a journal script which can be used in FLUENT to set-up a solver is as follows. This journal just needs to be edited for user's need. Note that there should be no empty line till the end of file. An empty line is assumed to be end of input. Use the remark character ; instead. The journal can be further parametrized by defining parameter using syntax (define X 0.7). Similarly, mathematical operation can be performed e.g. a = a + 0.1 can be written as (define a (+ a 0.1)).

Script and Macros

(ti-menu-load-string) is used to invoke a TUI command in SCHEME journal i.e. to convert a journal command to Scheme command. e.g. (ti-menu-load-string "solve set time-step 0.01"). Return value: #t if successful, #f if error occurs or cancelled by pressing Ctrl-C. Note all the SCHEME commands should be inside parentheses ( ... ).


Example scripts to make batch runs: SINGLE PHASE

Steady StateCold FlowSIMPLEGravity OFFEnergy OFF
Steady StateCold FlowCoupled Psuedo-TransientGravity OFFEnergy OFF
Steady StateCold FlowCoupledGravity OFFEnergy OFF
Steady StateConjugate Heat TransferSIMPLEGravity OFF Energy ON
Steady StateConjugate Heat TransferCoupled Psuedo-TransientGravity OFF Energy ON

One of the major drawbacks of the SCHEME TUI in ANSYS FLUENT is that these commands are sequential one should not miss anything in between. In other words, only a specific value of a boundary conditions cannot be changed. Additionally, full TUI commands changes from case to case depending upon which models are enabled. For example, the TUI command for RANS-based model with flow and energy OFF would be different for energy ON condition. Dedicated Scheme commands do not exist for each function. However, some commands can be embedded in journal commands a scheme wrapper such as (ti-menu-load-string "..."). Not all TUI commands are documented as the sequence vary based on which models are active. For example, the initialise command will ask only for inputs based on models so the command is different if k-ε or k-ω turbulence is on. (cx-gui-do ...) commands come from recording a transcript for macros from the GUI which are often unreliable as they depend on whether the GUI panel was open or not before and after running the journal. They rre also difficult to read and comprehend. Also when a TUI command fails it triggers all sorts of errors through the remainder of the journal though there are cases where solution may still progress. You cannot read a journal while writing a journal. For example, you cannot necessarily run a read-journal command inside a journal.

Terminate or Save and Terminate a FLUENT job running in batch-mode on remote server (cluster): GUI based method is to use "Remote Visualization Client". Another option is to create checkpoints in the script: e.g. (set! checkpoint/exit-filename "/FOLDER/exit-fluent-FILENAME") where 'FOLDER' is location to store the case and data files. FILENAME is same which needs to be created whenever you want to save the data: touch /FOLDER/exit-fluent-FILENAME

Some basic pre-processing can be done faster on a HPC cluster: file read-case oldCase.cas.h5, file write-setting setUp.bc, file replace-mesh newMesh.msh.h5, file read-setting setUp.bc, mesh scale 0.001 0.001 0.001, file write-case newCase.cas.h5 - These 6 statements in a journal file can be used to read a case file, replace mesh and create a new case file.

Note that the HPC server needs a trigger from the solver to stop or exit the job when there is any error while iterating. As per FLUENT user guide: "Batch option settings are not saved with case files. They are meant to apply for the duration of the current ANSYS FLUENT session only. As batch options are not saved with case files, journal files developed for use in batch mode should begin by enabling the desired batch option settings". The TUI command that should be added to the journal file before iterate statement is /file/set-batch-options n y y n where n, y, y and n stands for answer to "Confirm Overwrite?", "Exit on Error", "Hide Questions" and "Redisplay the Questions" respectively.

Any TUI can be reached in two ways. Either by typing out the full path to the command such as "/solve/initialize/initialize-flow" or by use of shortcuts which are any unique set of characters that represent the sequence of commands and sub-command. For example, the initialize-flow command above can be shortened to just "so in in" or "s i i" or s in ini.


  (define rf 0.7)
  ;Prefix of the files saved as back-up
  (define backupCasePrefix "backUp_")
  ;Suffix to be added to file after completion of runs
  (define backupCaseSufix "_end")
  file/read-case fluent.msh
  ;Change solid-domains into fluid type
  define/boundary-conditions/modify-zones/zone-type 4 fluid
  mesh/repair-improve/allow-repair-at-boundaries y
  mesh/repair-improve/repair
  ;Check and reorder the mesh to reduce the bandwidth of matrix
  mesh/check
  mesh/mesh-info 0
  mesh/reorder/reorder-domain
  mesh/reorder/reorder-domain
  /file/set-batch-options no yes yes no
  (set! *cx-exit-on-error* #t)
  define/models/solver/pressure-based yes
  define/models/viscous/ke-standard yes ke-realizable yes
  define/models/viscous/near-wall-treatment enhanced-wall-treatment yes
  ;-----------CONSTANT DENSITY ---------
  define/materials/change-create air air y constant 1.187 n n y constant 0.0000182 n n n
  ;-----------IDEAL-GAS ----------------
  define/materials/change-create air air yes ideal-gas yes polynomial 
    3 1033.33 -0.196044 3.93365e-4 yes polynomial 3 6.24978e-6 9.73517e-5 -3.31177e-8 
    yes sutherland two-coefficient-method two-coefficient-method 
    1.458e-6 110.4 yes 28.966 no no no no no
  ;-----------As on older version-------
  define/boundary-conditions/zone-type inlet pressure-inlet
  define/boundary-conditions/pressure-inlet inlet no 0 no 0 no 300 no yes no yes 5 0.1
  define/boundary-conditions/zone-type outlet pressure-outlet
  define/boundary-conditions/pressure-outlet outlet no 0 no 0 no 300 no yes no yes 5 0.1 
  ;-----------As on version 19.X--------
  define b-c zone-type z-right mass-flow-outlet
  define b-c zone-type z-right mass-flow-inlet 
  define b-c zone-type z-right pressure-outlet 
  define b-c zone-type z-right mass-flow-inlet 
  define b-c set vel-inlet z-right z-left () vmag no 1.25
  define b-c set vel-inlet z-right () vel-spec turb-intensity 2 () turb-visc-ratio 5 ()
  def b-c set m-f-i z-right () dir-spec no yes 
  def b-c set m-f-i z-right () mass-flow no 1.50 ()
  def b-c set m-f-i z-right () t-i 5 ()
  def b-c set m-f-i z-right () t-v-r 10 ()    
  ;Setup periodic flow
  /mesh/modify-zones/make-periodic p_z11 p_z12 n y y
  /mesh/modify-zones/make-periodic p_z21 p_z22 n y y
  /define/periodic-conditions massflow 10 , , , , , ,

  define/operating-conditions operating-pressure 101325
  define/operating-conditions reference-pressure-location 0 0 0
  define/operating-conditions gravity no
  ;Define Discretization Scheme
  ;0=1st UDS, 1=2nd UDS, 2=Power Law, 4=QUICK, 6=3rd Order MUSCL
  solve/set/discretization-scheme density 1
  solve/set/discretization-scheme mom 1
  solve/set/discretization-scheme k 1
  solve/set/discretization-scheme epsilon 1
  solve/set/discretization-scheme temperature 1
  ;
  ;Pressure: 10=Std, 11=Linear, 12=2nd Order, 13=Body Force Weighted, 14=PRESTO!
  solve/set/discretization-scheme pressure 12
  ;Flow: 20=SIMPLE, 21=SIMPLEC, 22=PISO
  solve/set/p-v-coupling 21
  ;Define Under-Relaxation Factors: method varies based on PV-coupling
  ;SIMPLE/SIMPLEC
  solve/set/under-relaxation body-force 0.8
  solve/set/under-relaxation k 0.8
  solve/set/under-relaxation epsilon 0.8
  solve/set/under-relaxation density 0.8
  solve/set/under-relaxation mom 0.4
  ;Switch ON/OFF equations: mp = multiphase (volume fraction)
  /solve/set/equations/temperature no
  /solve/set/equations/mp no
  /solve/set/equations/ke yes
  ;
  ;COUPLED with Psuedo-Transient
  solve/set/psuedo-under-relaxation mom 0.4
  solve/set/under-relaxation pressure rf
  solve/set/under-relaxation turb-viscosity 0.8
  solve/set/under-relaxation temperature 1.0
  solve/set/limits 50000 150000 250 400 1e-14 1e-20 40000
  ;
  solve/monitors/residual convergence-criteria 1.0e-6 1.0e-6 1.0e-6 1.0e-6 1.0e-6 1.0e-6
  solve/monitors/residual plot y
  solve/monitors/residual print y
  ;
  ; Initialize the solution and set auto-save data frequency: 3 options
  /solve/initialize/hybrid-initialization
  /solve/initialize/compute-defaults all-zones
  /solve/initialize/set-defaults/k 0.01
  /solve/initialize/set-defaults/e 0.01
  /solve/initialize/set-defaults/pressure 10
  /solve/initialize/set-defaults/temperature 300
  /solve/initialize/set-defaults/x-velocity 0.1
  /solve/initialize/set-defaults/y-velocity 0.1
  /solve/initialize/set-defaults/z-velocity 0.1
  ; Set volume fraction for second phase or patch after initialization
  /solve/initialize/set-defaults/phase-2 mu 0.2
  /solve/patch phase-2 () air-vol () mp 0.2
   ;
  /file/auto-save/data-frequency 200
  /file/auto-save/case-frequency if-case-is-modified
  /file/auto-save/retain-most-recent-files yes
  ;In case auto-save file name to be saved as differently
  /file/auto-save/root-name ./new-file-name
  ;Field Functions
  /define/custom-field-functions/define "vort1" dz_velocity_dy-dy_velocity_dz
  /mesh/modify-zones/slit-interior-between-different-solids
  ;-----------Steady State Runs---------
  ; Record the start time in a txt file
  !date >> solution_time.txt
  ;Reporting and Profile Update Intervals to 10 and 5 iterations
  /solve/iterate 2000 10 5
  ;-----------Transient Runs------------
  solve/set/data-sampling y 1 y y
  solve/set/time-step 0.00001
  solve/set/adaptive-time-stepping y n 0.01 1.50 0.000001 0.001 0.5 2 5
  solve/dual-time-iterate 10000 20
  ;-----------Post-Processing-----------
  surface/line-surface L1 0.0 1.0 5.0 1.0
  surface/point-surface P1 5.0 0.5 0.0
  surface/plane-surface pNameXY xy-plane z0
  surface/plane-surface pNameYZ yz-plane x0
  surface/plane-surface pNameZX zx-plane y0
  surface/plane-surface pName3P three-points x1 y1 z1 x2 y2 z2 x3 y3 z3
  surface/plane-surf-aligned newsurf refsurf 0.0 0.25 0.0
  solve/monitors/surface/set-monitor P1 "Area-Weighted Average" 
    pressure P1 () n n y P1.txt 1 y flow-time
  ;
  ;Save pressure xy plots of lines
  plot/plot y PL1.txt n n n pressure y 1 0 L1 ()
  plot/file PL1
  display/save-picture PL1.png
  plot/plot y PL1.txt n n n x-velocity y 1 0 L1 ()
  plot/file XVL1
  display/save-picture XVL1.png
  ;
  parallel/timer/usage
  report/system/proc-stats
  report/system/sys-stats
  report/system/time-stats
  ;
  file/confirm-overwrite no
  ; Report global balance of mass and energy: good practice to check accuracy
  report fluxes mass-flow no zone-1 zone-2 () no
  report surface-integrals mass-weighted-avg inlet_zone outlet_zone () pressure no
  report surface-integrals area-weighted-avg outlet_face () pressure no
  !date >> solution_time.txt
  exit yes

As an exception, file names are not evaluated in the text prompt that is inside a journal. Hence, /file/read-case (rpgetvar 'case_name) shall not work. Instead, (ti-menu-load-string (format #f "/file/read-case ~s") case_name) should be used with case_name supplied with double quotes such "case1.cas.gz". (ti-menu-load-string (format #f "/file/read-case ~a") case_name) can be used where case name is specified without quotes that is just case1.cas.gz

Global Definitions: As explained in a post on cfd-online.com - using (define (fmt . args) (apply format (append (list #f) args) ) ) and (define (tui . args) (ti-menu-load-string (apply fmt args) ) ), the statement (ti-menu-load-string (format #f "/file/read-case ~s") case_name) can be simplified to (tui "/file/read-case ~s" case_name).

Define new materials: define material copy solid aluminum cstl csteel - this line of code copies aluminum to a new material 'cstl' (a short form of cast-steel) and 'csteel' as the new material formula. Note that aluminum (and not aluminium) is the default material when a new ANSYS FLUENT session is created. Some line of codes to create different types of solids are:

  • define material change-create aluminum insulation y constant 1500 y constant 450 y constant 0.20 n
  • define material change-create aluminum bulk y constant 1750 y constant 500 y constant 15.0 n
  • define material change-create aluminum pcb y constant 2000 y constant 750 y orthotropic 1 0 0 0 1 0 constant 0.4 constant 50 constant 50 n

Scheme command to turn on exit on error is: (set! *cx-exit-on-error* #t). To write the data file only, execute the following Scheme command before iterating: (rpsetvar 'checkpoint/write-case? #f). Some other TUI commands for post-processing are:

  • report volume-integrals volume-avg [zoneName or zoneID] () temperature no () - temperature can be substituted with any other field variables, 'no' here is response to the prompt: "Write to File?". report fluxes heat-transfer yes no: yes - all boundary/interior zones, no - "Write to File?"
  • display set lights lights-on yes, display set lights headlight-on? yes, display set contours n-contours 10, display set contours global-range? yes, display set contours auto-range? yes
  • display set contour coloring yes 10: yes - banded coloring, 10 - number of color band. display set color-map bgr
  • display objects create contour contourName field temperature suface-list zoneID or zoneName () coloring banded q color-map size 10 q q
  • display objects display contour-t: contour-t is the name of the contour, display objects display scene-1, display save-picture t-contour.png
  • views restore-view [front / back / left / right / top / bottom] where front = +x+y, back = -x+y, left = +z+y, right = -z+y, top = -x+z, bottom = -x-z where + direction is towards right and up

SCHEME Script to generate volume mesh in batch mode say on HPC clusters

;Read the surface mesh
/file/read-mesh surfaceMesh.msh
;
;Optionally, compute volume regions - better do in GUI mode
;/objects/volume-regions compute objectName useMaterialPoint?
;/objects/volume-regions compute simRegion yes
;
;Set auto-mesh paramters as per syntax below
;/mesh/auto-mesh objectName keepSolidZones? quadTetTransion volumeFill mergeCellZones?
;/mesh/auto-mesh fluid yes pyramids tet yes
;/mesh/auto-mesh simGeom yes pyramids poly yes
;/mesh/auto-mesh fluid yes pyramids hexcore yes
;
;Save raw volume mesh with quality as generated
/file/write-mesh volumeMeshRaw.msh
;
;Clean-up mesh zone names
/mesh/zone-names-clean-up yes
;
;Improve mesh quality: skewness
/report/quality-method/skewness angle
/mesh/modify/auto-node-move (*) (*) 0.99 50 120 yes 5
/mesh/modify/auto-node-move (*) (*) 0.98 50 120 yes 5
/mesh/modify/auto-node-move (*) (*) 0.97 50 120 yes 5
/mesh/modify/auto-node-move (*) (*) 0.96 50 120 yes 5
/mesh/modify/auto-node-move (*) (*) 0.95 50 120 yes 5
/mesh/modify/auto-node-move (*) (*) 0.90 50 120 yes 5
;
/file/write-mesh volumeMeshFinal.msh yes
/exit yes

Create a probe point: display surface point-surface pName x y z where x, y and z are respective coordinates.

Conditional Stopping Criteria: Report Definitions are used only for defining a report and not for computing it. Though in GUI there is an option by doing a right-click on Report-Definitions and selecting Compute. In TUI, you need to define an output-parameter which is equal to report-definition. Set stopping criteria based on some computed value.

(if((>= (string->number 
  (pick "/solve/report-definitions/compute air_temp_outlet")) 90.0))
  (set! mstop #t)
) 
/solve/report-definitions/add avg_t surface-areaavg field temperature surface-names wall_htx () report-type surface-areaavg

/define/parameter/output-parameters create report-definition “avg_t"

(if 
  (>=
    (string->number (pick "report surface-integrals area-weighted-avg wall_htx () temperature no"))
     40.0
  )
  set! mstop? #t
)
(if
  (>=
    (pick-a-real "define parameters output-parameters print-to-console avg_t-op" 3)
     40
  )
  (set! mstop? #t)
)

Note that output parameter name is defined as report name such as 'avg_t' and suffix '-op' thus 'avg_t-op'. define parameters output-parameters print-to-console report-def-0-op - it will return number but other strings as well. That is what pick-a-real is supposed to do. Since the whole output is a list of strings (Scheme language is a subset of List Processing Language), user needs to specify which member of the list is required. Index starts from bottom. So, usually, for dimensional return values, 3 is the index to be used and for non-dimensional ones, 2 is to be used. You need to pick up only the value using pick-robust or pick-a-real. (pick-a-real "TUI command" indices), where TUI command is fully defineed parameter command all the way up to selection of the output parameter and indices are used to idenity the value you want to pick-up. One can try with just one index, say, 3 or 4 and check if the value returned is what was expected. In FLUENT one can incorporate report definition as "Convergence Monitor" to avoid writing Scheme/UDF for that.

The command (pic "/report/projected-surface-area 1 () 0.1 0 1 0") or identically same (pic "/report/projected-surface-area (1) 0.1 0 1 0") returns a single string that can be converted to a bumber using (string->number ...). The string is the last token of the output of the TUI commmand. The command (pic "/report/projected-surface-area 1 () 0.1 0 1 0" 8) does the same, but the returned string is the last-but-8 element of the list. The command (pick "/report/projected-surface-area 1 () 0.1 0 1 0" 6 8 10) returns a 'list' of three strings containing the last-but-9th, last-but-7th, and last-but-5th element. Note that the 'last' element is addressed by the index '1'). (display-pick-list) displays the list and numbering of tokens from the last 'pick' command. The command (display-pick-list "TUI command") displays the list and numbering of tokens from the output of "TUI command". Finally, (pick-a-real "TUI Command") or (pick-a-real "TUI Command" 5) shall do what any analogous 'pick' command produces, but the return value will be a number generated from the string obtained. Please note that "(pick-a-real ...)" may not support any other syntax that “(pick ...)" might support. In some cases, "(pick ...)" may fail to capture any output from the TUI command. In such cases, try: (pick-robust ...).


The list of all the SCHEME codes impemented in FLUENT is summarized in attached file. It is being categorized into appropriate steps of simulation activites. The sample codes for scripts in ANSYS Discovery / SpaceClaim is in this text file.


SCHEME Summary

Not all the built-in functions available in standard SCHEME are incorporated into FLUENT. For example, string-trim, string-prefix, string-suffix, string-replace... do not work in FLUENT TUI.

  • Statements are always included in small brackets such as (...). Scheme: A space is required between operand and operator.
  • Semi-colon ; is used at the beginning of a line to comment it, Comma , is used to accept default value in a command, () are used to define a list of selection. For instance (d1 d2 d3) or d1 d2 d3 () would both choose the three named zones and end the list.
  • Tilde (~) immediately followed by a newline ignores the newline and any following non-newline whitespace characters. With an @, the newline is left in place, but any following whitespace is ignored. This directive is typically used when control-string is too long to fit nicely into one line of the program.
  • Boolean: #t = true, #f = false. (define x_exists #t): variable x_exists = True, Along with format statement, #f is used to return the output as a string. #t: destination port is the current-output-port. Refer to "Common Lisp" documentation for additional information.
  • #f: this may also get printed while using loops such as a 'do' loop. This is the return value if the loop is not provided a return expression. In other words, if no return value/expression is provided, 'do' loop will return either '#f' (meaning false) or '()' (meaning nothing).
  • Port: Ports represent input and output devices. To Scheme, an input port is a Scheme object that can deliver characters upon command, while an output port is a Scheme object that can accept characters.
  • "string" is a string, 'string is a symbol. No distinction between variable types (Integer, Real, String, ...). Like most of the programming languages: string is written as a sequence of characters enclosed within double quotes " ". To include a double quote inside a string, precede the double quote with a backslash \ (escape it).
  • Example of strings: (define fn "backStep") (ti-menu-load-string (string-append "file read-case-data " fn ".cas")). Note the space after 'read-case-data'.
  • (symbol-bound? 'symbol (the-environment) ) - check if a symbol is defined (bound)
  • (symbol-assigned 'symbol (the-environment)) - check if a symbol is assigned a value
  • (define x 3): x = 3, (define vel #\A) = define 'vel' as uppercase 'A', let defines variables as local: ( let (( x 3) ( y 5) ) (* x y ) )
  • LISP and hence SCHEME uses prefix notation where operators are written before their operands. Thus: a * ( b + c ) / d is expressed as (/ (* a (+ b c) ) d)
  • LISP programs have 3 basic building blocks − atom, list and string
  • (+ 2 4 5) = 11, (/ 6 3) = 2, (/ 2) = (/ 1 2) = 0.5
  • Function f(x) is called as (f x) such as (abs x), (sqrt x), (expt xy) = xy, (exp x) = ex, (log x) = ln(x), (sin x), (cos x), (atan x), (atan y x) = arctan(x/y)...
  • (remainder 45 6) = 3, (modulo 5 2) = 1, (truncate x), (round x), (ceiling x), (floor x), (max x y ...), (min x y ...) e.g. from a list search for maximum: (apply max (1 5 8 3 4)) = 8
  • (define y '(+ x 2)) = y is a 'list' with elements +, x, 2 and hence it is not evaluated. Tick mark ' is called quote and is a short-hand for (quote ...) call. It does not create a list, it is used to return something without evaluation.
  • (eval y (the-environment)) = 5, 'list' y interpreted as a SCHEME command. E.g. (define c (list ’+ b 5)): Define a list with + , b and 5, (eval c (the-environment)): Evaluate (+ b 5) = b + 5
  • Use quote when you pass some static data (variable or list). For example, '(z) will be passed to cx-gui-do as is, variable 'z' will not be substituted and will stay as a symbol z
  • Equality of numbers: (= a b), equality of objects: (eq? a b) or (equal? a b), same value objects: (eqv? a b)
  • Relations: (positive? x), (negative? x) (< a b) (> a b) (<= a b) (>= a b)
  • Boolean functions: (not a), (and a b c ...), (or a b c ...)
  • List: By definition, all lists have finite length and are terminated by the empty list. (Define zNames '(w-bot w-top vi-front po-rear symmetry)). (list object ...) - returns a list of its arguments. e.g. (list 'a (+ 3 4) 'c) = (a 7 c). (length lst_name): Returns the length, (list-ref lst_name 3): returns the third element of the list. Terminate a list with ().
    • First item of a list: (car zNames) = w-bot
    • Rest of a list (i.e. list without first element): (cdr zNames) = (w-top vi-front po-rear symmetry)
    • Number of list elements: (length zNames) = 5
    • (list-ref xlst i): get ith item from list named 'xlst', similarly get head and tail items of a list: (list-head xlst n) / (list-tail xlst n)
    • Nested (car cdr) is 'cadr': (cadr x) = (car (cdr x)). (cadr '(a 5 b 8) ) = 5
    • (list-union list-1 list-2 list-3), (list-intersection list-1 list-2 list-3), (list-subtract list-1 list-2)
    • cons pushes item into a list that already exists
    • null? object: returns #t if object is the empty list otherwise returns #f
    • (string->list "xyz-123") = (x y z - 1 2 3) - note the output is within parentheses as it is a list. (list->string ((string->list "xyz-123")) = xyz-123
  • Type (pick-docu) in the console and read the details - this command will shows documentation for pick. Essentially, to extract the outcome of a TUI command and save it as a scheme variable, you need to pick the outcome.
  • Similar to the %-character in C the tilde (~) controls a pattern.
  • Format commands: The format command is similar to printf in C. Instead the % sign used in C, the tilde character ˜ introduces a format directive and the next character specifies the kind of format.
    • ~a: placeholder for a variable in general format (string without "")
    • ~d: integer number
    • ~04d: integer with zeros on the front is always 4 digits fill ( 5 is about 0005). e.g. this is important for file names.
    • ~f: floating-point number
    • ~4.2f: floating point number, a total of 4 characters long, 2 digits after the decimal: 1.2 will be 1.20
    • ~s: string with "" included: from (format #f "string: ~s!" "text") = "text"!
  • \n: newline character line feed, \" = " i.e. the double quotes are escaped by backslash.
  • (display expression) - write a printable representation of 'expression' to the default output port. (newline) - writes a newline character to the default output port.
  • (format #f "~6.4f" avgPr) - format AvgPr with 4 digits after decimal place
  • Vector or Array operations
    • (vector expr1 expr2 . . .) - creates a new vector containing the values of the given expressions. Vector elements are 0-indexed.
    • (make-vector n [expression]) - creates a new vector of 'n' elements each initialized to the value of the given 'expression' when provided. [...] indicates this is optional.
    • (vector-ref v n) - returns the element at position 'n' of vector v, where 0 is the index of the first element of the vector. Error will be reported if n < 0 or n is > the last element in the vector.
    • (vector-set! v n expression) - sets the value at position 'n' of vector v to the value of the 'expression'.
  • (zone-id->name zid) returns (displays in TUI console) the name of zone having id 'zid' Equivalent commands in FLUENT Pre-Post are (thread-name->id "solid01") and (thread-id->name 123). (get-thread-by-name) is not defined but (%get-thread-by-name) works.
  • RP-variables are model related variables: (%rpgetvar 'nut-kappa) = nut-kappa (Karman constant), (rpsetvar 'nut-kappa 0.06)
  • Define a variable to store ID of a zone: (rp-var-define 'iz 1 'integer #f). '/' is allowed character in variable names which is meant to categorise the variables as per the need. (rp-var-define 'relax 0.25 'real #f)
  • Set the value of zone ID to the variable: (rpsetvar 'iz (zone-name-> 'front))
  • Use the value of zone ID: (rpgetvar 'iz)
  • Wildcard character * on its own will only chose all entities, (*) will chose all entities and close the list
  • Obtain a list of all face zones: (define all-face-zones (get-face-zones-of-filter '*)) where (display all-face-zones) is needed to print values stored in 'all-face-zones', (get-face-zones-of-filter '*): get list of all zone names (note wildcard character *), Works in FLUENT Mesher (Tgrid) only. Refer to Query and Utility Functions section of User's Guide.
  • Obtain a list of all cell zones: (define all-cell-zones (get-cell-zones-of-filter '*)), (get-cell-zones-of-filter '*): get list of all 'cell' zone names (note wildcard character *), Works in FLUENT Mesher (Tgrid) only.
  • (inquire-thread-names) in Pre-Post prints names of all the zones including of type 'Interior' and it does not accept wildcard characters.
  • Get number of facets of a face zone: (tg-get-thread-count zID) where zID is the zone ID
  • RP in (rpgetvar) refers to user-specifiable model macros. Similarly, CX in (cxgetvar) refers to environmental Fluent-related variable (Cortex): (cxgetvar 'CMAP-list) = colourmap value, (cxsetvar 'def CMAP "rgb") = set colourmap to RGB
  • Evaluate a list as a Scheme command in the TUI: (define y '(1 2 3)) (eval y (the-environment))
  • (system "command"): Run command in the system shell
  • (gui-show-partition) prints statistics of grid partitions, (gui-memory-usage) gives information related to memory used by the solver
  • Most (not all) Schemes have built-in support for regular expression (regex or regexp) matching using the same regular expression syntax found in languages such as Perl and Javascript.
  • Conditionals in Scheme: cond works by searching through its arguments in order. It the first argument returns #t then returns the second element of the this argument. It the first argument returns #f then goes on to evaluate second argument and if it returns #t then returns the second element of the second argument. It the second argument also returns #f the it returns the third and last element. (cond [(equal? 'one 'won) '1] [(equal? 'two 'too) '2] [else 'spelling-error]): this returns "spelling-error" as the first two arguments will return #f.
  • Predicates are functions (like + or *) which return Boolean values (#t or #f). Predicates are usually given a '? as the last character of their name as a mnemonic device, for example odd? is a predicate for odd numbers.
  • Binding constructs: let, let* and letrec give Scheme a block structure where the syntax of the three constructs is identical, but they differ in the regions they establish for their variable bindings. In a let expression, the initial values are computed before any of the variables become bound. In the let* expression, the bindings and evaluations are performed sequentially and in letrec expression, all the bindings are in effect while their initial values are being computed, thus allowing mutually recursive definitions.
  • File Operations in SCHEME: (define file_name "in.txt") (define input_txt (open-input-file file_name)) - read text from a file
  • (read-line input_txt): read first line, (read-line input_txt 2): read third line

Loops in Scheme: do, map and for-each --- map command stores every return value of all calls, for-each function loops do not store the return values of each call. ( map ( lambda ( x ) (* x 3) ) ’(1 2 3 4 5 ) ): output is (3 6 9 12 15), ( for - each ( lambda ( x ) ( display (* x 3) ) ) ’(1 2 3 4 5) ): output is (1*3)(2*3)(3*3)(4*3)(5*3) = 3691215.


SCHEME: (system "dir .") - lists all files, (system "dir /W /B ."): prints only file names, (system "dir \"*.pdf\" /W /B"): prints only the PDF files.

(if(not(rp-var-object 'hflx-id))
  (rp-var-define 'hflx-id 10 'integer #f) ()
)
(rpgetvar 'hflx-id) -> This will print 10 in console.
(if (zone-name->id 'wall_hflx)
  (rpsetvar 'hflx-id (zone-name->id 'wall_hflx))
  (rpsetvar 'hflx-id 10)
)

TUI commands that take single or multiple zone names support the use of wildcards. For example, to copy boundary conditions (copy-bc) to all zones of a certain type, use a * in the name of the zone to which you want to copy the conditions. Example: report surface-integrals facet-avg w-htc* , temperature no

Similarly, following script can be used to change all walls having names ending in 'shadow' to type coupled: define b-c wall *shadow () 0 n 0 y steel y coupled n n 1

(list-bc "settings.bc") prints a list of type (zone name : zone type) where the input file "settings.bc" were created by TUI operation "file write-settings settings.bc".

Set Wall Rotation for zone having id ZID about X-axis passing through [XC YC ZC] and speed RPM: /define/b-c/wall ZID y n n n y n n 0 n 0 n RPM XC YC ZC 1 0 0

ZIDZone ID or name of the zone
yChange current value?
nChange shear-bc-noslip?
nChange rough-bc-standard?
nWall motion relative to cell zone?
yApply rotation velocity?
nDefine wall velocity components?
nUse profile for wall-roughness height?
0Wall roughness height
n
0
n
RPMWall rotation speed in RPM
XCX-coordinate of a point on axis of rotation
YCY-coordinate of a point on axis of rotation
ZCZ-coordinate of a point on axis of rotation
1Direction cosine of X-axis
0Direction cosine of Y-axis
0Direction cosine of Z-axis

Set volumetric heat source for a zone with id ZID and material MATNAME: /define/b-c/solid ZID y MATNAME y 1 y 1250 n no n 0 n 0 n 0 n 0 n 0 n 0 n no no

Note that some version of FLUENT shall print names of all the solid zones in the console after every execution of this script.

ZIDZone ID or name of the zone
yChange current value?
MATNAMEName of the material defined
y Specify source terms?
1 Number of energy sources
y Use constant or expression for Energy 1
1250Heat density in [W/m3]
nSpecify fixed value?
noFrame motion?
nUse profile for reference frame X-origin of rotation axis?
0X-coordinate of the origin
nUse profile for reference frame Y-origin of rotation axis?
0 Y-coordinate of the origin
n Use profile for reference frame Z-origin of rotation axis?
0 Z-coordinate of the origin
nUse profile for reference frame X-component of rotation axis?
0 X-component of the axis
n Use profile for reference frame Y-component of rotation axis?
0 Y-component of the axis
n Use profile for reference frame Z-component of rotation axis?
0 Z-component of the axis
n Mesh motion?
no Solid motion (enter 'no' and not 'n')
n Solid motion (enter 'no' and not 'n')

Set Mass Flow Inlet boundary conditions: /define/b-c/mass-flow-inlet zNAME y y n 0.75 n 50.0 n 10000 n y n n y 2 5

zNAMEName of the zone
y Reference Frame: Absolute?
y Mass Flow Specification Method: Mass Flow Rate?
n Use Profile for Mass Flow Rate?
0.75Mass Flow Rate in [kg/s]
nUse Profile for Total Temperature?
50Total Temperature [in unit selected i.e. K or °C]
nUse profile for Supersonic / Initial Gauge Pressure?
10000Supersonic Initial Gauge Pressure (in [Pa])
nDirection Specification Method: Direction Vector?
yDirection Specification Method: Normal to Boundary?
n Turbulence Specification Method: K and Epsilon?
nTurbulence Specification Method: Intensity and Length Scale?
n Turbulence Specification Method: Intensity and Viscosity Ratio?
y Use profile for reference frame Z-component of rotation axis?
2 Turbulent Intensity [%]
5 Turbulent Viscosity Ratio

Create Named Expressions:

/define/named-expressions add exprName definition "1.25 [m/s]" q: the last entry 'q' is needed to bring the TUI to root position.

In case of field values: /define/named-expressions add exprName definition "MassFlowAve(StaticPressure, ['outlet-1', 'outlet-1']" q - here 'outlet-1' and 'outlet-2' are names of the zone of type outlet.

The boundary conditions can be defined in terms of named expressions: define/b-c/set velocity-inlet inlet () vmag "namedExpr" q where "namedExpr" is the name of the Named Expression with double quotes. vmag is a built-in variable which tells that velocity magnitude is being set or updated. As summarized in the sample journal file above: a zone type can be changed by "define b-c zone-type zName mass-flow-inlet" where zName is the name of the zone. Only the new type of zone (Mass Flow Inlet here) is needed irrespective of the original type of that zone. Once a boundary is set as type m-f-i, use following lines to make additional changes: "define b-c set m-f-i zName () direction-spec n y q" where 'n' is response to "Direction Specification Method: Direction Vector?" and 'y' is response to "Direction Specification Method: Normal to Boundary?".


Some of the actions which one may need during automation activities are:

  1. Find all wall of type 'coupled'.
  2. How to access all the zones of type 'interface'?
  3. How to check if a 'wall' zone is attached to 'solid' or 'fluid'?
  4. How to access all wall zones without those created as 'shadow' walls?
  5. List walls with specified type of boundary conditions such as 'Temperature'.
  6. How to access all zones except of some types such as 'interface', 'inlet' and 'outlet'?

FLUENT Scheme Error Debugging

(display get-thread-list): output is #[compound-procedure]

(display (get-thread-list)): it results in error with following message:

  Error: eval: unbound variable

  Error Object: name --- this indicates the argument is missing for get-thread-list

Similarly, (display (get-thread-list '*shadow)) shall print all zones with names ending in shadow. (display (get-thread-list 'solid*)) will print all the zones whose names start with 'solid'. When the error message is only Error: eval: unbound variable, it implies that the code is not defined in FLUENT Scheme.

Scheme codes which try to access mesh elements shall make the program crash. For example, (get-all-thread) or (display get-all-thread) shall make FLUENT session crash. However, (map thread-id (get-all-threads)) shall print the ID of all threads (zones) in the set-up (case) file. Similarly (get-threads-of-type 'interior) or (get-threads-of-type 'velocity-inlet) make the cortex crash, (map thread-id (get-threads-of-type 'wall)) prints the IDs of all zone of type wall

As explained in later sections: "Think of a ‘zone’ as being the same as a ‘thread’ data structure when programming UDFs. Thus: node thread = grouping of nodes, face thread = grouping of faces, cell thread = grouping of cells. A domain is a data structure in ANSYS FLUENT that is used to store information about a collection of node, face threads, and cell threads in a mesh." There would be only 1 domain in single phase flow simulations including conjugate heat transfer with only 1 flow medium.

In FLUENT, a 'surface' is defined as any plane created for post-processing purposes and not the one used in computation. Hence, Scheme codes working on surface shall not accept boundary face zone as input. e.g. (define tp (surface-area-average (list (surface-name->id "plane-10")) "temperature")) works but (define tp (surface-area-average (list (surface-name->id "w-htc-x")) "temperature")) does not work where w-htc-x is a face zone with specified HTC boundary conditions. (list (surface-name->id) "plane-10") shall print (10) as output. However (surface-area-average) will give following error:
  Error: eval: unbound variable
  Error object: s


Access each member of a list
The functions 'car' and 'cdr' can be used in combination to explore a list.
(define (print-list items)
  (for-each 
    (lambda (ii)
      (display ii)  (display " ") (newline)
    )
    items
  )
  (newline)
) (print-list '(a b c))

This function named 'print-list' prints each member of the list on separate lines. The following code creates 'sum' function to add each member of the list. Note 'list' is a reserved word in SCHEME to define built-in variable. Hence, do not use the word 'list' as an argument to a function.

(define (sum items)
  (if (null? items) 0
    (+  (car items)  (sum (cdr items)  )
    )
  )
)
(sum '(5 10 15)) = 30. Now an 'avg' function can be defined to find 'average' of the numbers in a list.
(define (avg ist)
  (/ (sum ist) (length ist) )
)
(avg '(5.0 10.0 15.0) ): gives output 10.0.

Thus following function can be used in FLUENT mesher to rename solid (cell) or/and boundary (face) zones or add a prefix / suffix to face and/or cell zones. The code to rename only cell zones are defined below. Note that strings (such as zone names) with hyphen '-' needs to be converted into string using format ~s option.

(define (rename-cell-zones items)
  (for-each 
    (lambda (zid)
      (define zold (zone-id->name zid) )
      (define zolx (format #f "~s" zold) )
      (define znew (string-append zolx "_mat") )
      (ti-menu-load-string (string-append "mesh manage name " zolx " " znew) )
    )
    items
  )
  (newline)
) (rename-cell-zones (get-cell-zones-of-filter '*))

Split String: Splits a string into a list of strings separated by the delimiter character such as comma, space, colon... Few important procedures related to string manipulations are: string-ref string idx - (which returns character string[idx], using 0-origin indexing), substring string start end - returns a string containing the characters of string beginning with index 'start' (inclusive) and ending with index 'end' (exclusive). string-take str nc - returns a string containing the first 'nc' charactoers of string 'str', string-drop str nc - returns a string containing all but the first 'nc' character of string 'str', string-take-right str nc - returns a string containing the last 'nc' characters of string 'str', string-drop-right str nc - returns a string containing all but the last 'nc' characters of string 'str'. Out of these functions, only string-ref and substring works in FLUENT Mesher.

(define (str-split str ch)
  (let 
    (
      (len (string-length str))
    )
    (letrec
       (
         (split 
           (lambda (a b)
             (cond
               (
                 (>= b len) (if (= a b) '() (cons (substring str a b) '()))
               )
               (
                 (char=? ch (string-ref str b)) (if (= a b)
                 (split (+ 1 a) (+ 1 b))
                   (
                     cons (substring str a b) (split b b))
                   )
               )
               (else (split a (+ 1 b)))
             )
           )
         )
       )
       (split 0 0)
    )
  )
) 

(str-split "abc:def:pqr" #\:) - output = (abc def pqr). (str-split (format #f "~s" "abc:def:pqr") #\:) - output = ("abc def pqr"). Similarly, (list-ref (str-split "abc:def:pqr" #\:) 1) = def.

Join list of strings with delimiter

(define (string-join lst delimiter)
  (if (null? lst) ""
    (let loop ((result (car lst)) (lst (cdr lst)))
       (if (null? lst) result
          (loop (string-append result delimiter (car lst))
             (cdr lst)
          )
       )
    )
  )
) 
(string-join '("abc" "123" "xyz") "-") = abc-123-xyz

IF-Loop

Automation Icon

(if cond true-value false-value) - 'cond' is a boolean expression that is either #t (true) or #f (false). ((if #f + *) 3 4) = (* 3 4) = 12, ((if #t + *) 2 5) = (+ 2 5) = 7. (if (> 1 0) 'yes 'no) = yes, if (> 2 3) 'yes 'no) = no
(if (cond 
 (begin  
   (if ... True-value ) 
 )
 (begin 
   (else ... False-value)
 )   
)

Conditionals - similar to IF-Loop

(cond
  (test1 value1) 
  (test2 value2) 
  ... 
  (else value)
)
(define x 5)
(cond 
  ((> x 3) 'pass)
  ((< x 3) 'fail)
  (else 'retry)
)
e.g. Check if a boundary zone, plane... exists or not
(if 
 (equal? (surface-name-> id 'planeXY)  
  #f
 )
)

(surface-name/id? 'planeXY) produces #t if a surface named 'front' exists. Similarly, (display (zone-name-> id 'water)) shall display/print the ID of zone named 'water'.

Define a boundary condition if a zone-name exists. The syntax uses 'member' as in (member x LIST) which return the first item or sub-list of 'LIST' whose 'car' (the first element) is 'x' or returns '#f' if 'x' does not occur in the list. Equal? can be used for comparison. The script also uses 'map' which is a higher order procedure: (map fn list-1 list-2 . . .): Apply 'fn' to each element of all the input lists and collect the return values into a list which is returned from 'map'. map command stores every return value of all calls, for-each function loops do not store the return values of each call.

(if 
 (member 'bc-inlet 
  (map thread-name (get-face-thread)
  )
 )
 (begin
  (ti-menu-load-string "define b-c vel-in n n y y n 5.0 n 0 n n y 5 10")
 )
)

Wildcard character '*' can be used to specify zone names. E.g. (fluid*) refers to all the zones starting with 'fluid'. Since this method of refering multiple zones creates a list, it has to be included in (...) i.e. (fluid*) and not fluid*. e.g. "report volume volume-average (fluid*) temperature no". (inquire-cell-threads) and (inquire-grid-threads) print the thread or zone ID and zone type as pair such as (121 . 1). The zone type defined in ANSYS FLUENT are: 1 - Solid, 2 - Interior, 3 - Wall, 4 - Inlet (pressure-inlet, inlet-vent...), 5 - Outlets (pressure-outlet, exhaust-fan...), 10 - velocity-inlet, 20 - mass-flow-inlet or mass-flow-outlet, 24 - Interface, 37 - Axis.


Change boundary condition using UDF and Scheme: Adapted from post on cfd-online.com

(define (change_bc)
 (cond
  ((and (>= (rpgetvar 'flow-time) 0.10) (<= (rpgetvar 'flow-time) 0.20))
   (ti-menu-load-string "define/boundary-conditions/zone-type 10 wall"))
  (else
   (ti-menu-load-string "define/boundary-conditions/zone-type 10 mass-flow-inlet")
   (ti-menu-load-string ti-menu-load-string "define/b-c m-f-i 10 yes yes yes yes \"udf\" \"mdot::libudf\" no 0 no yes")
  )
 )
)

DO-Loop

(do 
 (
   (x start-x (+ x delta-x))  ((> x x-end))
   ... loop body ...
)
Merge free and non-free odes with increasing value of tolerance:
(do 
 ( (i 10 (+ i 10)) (> i 50) )
  (ti-menu-load-string (format #f "boundary/merge-nodes (*) (*) no yes ~a" i) )
 )
)
Create multiple planes every 0.2 [m]: do(x = 0, x = x + 0.2,  x < 3.0)
(do 
 ( (x 0 (+ x 0.2)) (>= x 3.0) )
  (ti-menu-load-string (format #f "surface iso-surface x-coordinate x-3.1f ~a () 3.1f ~a ()" x x)) 
)
Output: Creates the following text interface commands: 
surface iso-surface x-coordinate x-0.0 () 0.0 () 
surface iso-surface x-coordinate x-0.2 () 0.2 () 
surface iso-surface x-coordinate x-0.4 () 0.4 () 
... 
surface iso-surface x-coordinate x-3.0 () 3.0 ()

To add a '+' symbol for positive numbers:
(if (> x = 0)
  "+" "") x x)

Reference: www.eureka.im/1087.html - To write the solution residuals to a text file, create a SCHEME file named say init.scm:

(define port) 
(set! port (open-output-file "residuals.txt"))
(format port "~a ~2t" 'Iterations )
(do (
  (i 0 (+ i 1))
 ) 
 (
  (= i (length (solver-residuals)))
 ) 
 (
   format port "~a ~2t" (car (list-ref (solver-residuals) i))
 )
) 
(newline port)

After reading case/data files, read the Scheme file (init.scm) and then set the following execute command at every iteration using solve/execute: "file read-journal residual.jou" where the content of the journal file (residual.jou) should be as follows:

(format port "~a ~2t" (%iterations 0) )
(do (
  (i 0 (+ i 1))
 ) 
 (
  (= i (length (solver-residuals)))
 ) 
 (
  format port "~a ~2t" (cdr (list-ref (solver-residuals) i))
 ) 
) (newline port)

Another script from ansysofkemin.blogspot.com/2018/05/tui-fluent.html

(display "Save the residual in a file") (newline)
(let (
 (writefile 
  (lambda (p)
    (define np (length (residual-history "iteration")))
   (let loop ((i 0))
    (if (not (= i np))
     (begin (define j (+ i 1))
      (display (list-ref (residual-history "iteration") (- np j)) p) (display " " p)
      (display (list-ref (residual-history "continuity") (- np j)) p) (display " " p)
      (display (list-ref (residual-history "x-velocity") (- np j)) p) (display " " p)
      (display (list-ref (residual-history "y-velocity") (- np j)) p) (display " " p)
      (display (list-ref (residual-history "z-velocity") (- np j)) p) (display " " p)
      (display (list-ref (residual-history "k") (- np j)) p) (display " " p)
      (display (list-ref (residual-history "omega") (- np j)) p)
      (newline p)
      (loop (+ i 1))
     )
    )
   )
  ) 
 )
 (output-port (open-output-file "residual.txt"))
 )
 (writefile output-port)
 (close-output-port output-port)
)

Rename all monitor report files to case_name.report_name.out i.e. instead of mass_flow.out, use Case_xyz.mass_flow.out

(define (rename_files)
  (define case_name (strip-directory (in-package cl-file-package rc-filename)))
  (do ((x 1 (+ x 1))) ((> x 10)) 
    (define list_item (pick "solve report-files list " x))
    (if (equal? list_item "list") 
      (begin
        (define x 100)
      )
      (begin
        (format "Changing filename of report file ~s\n" list_item) 
        (define new_filename (format #f "./~a.~a.out" case_name list_item))
        (ti-menu-load-string (format #f "solve report-files edit ~a filename ~s" list_item new_filename))
        (format "...Success\n")
      )
    )
  )
)

Save intermediate results: For some models, it may be needed to request multiple jobs in order to finish the convergence process and the [fixed interval] auto-save settings will not save state immediately prior to the job being terminated either manually or by the scheduler thus losing information. To address this there is an complimentary method which will save before your job finishes. Place the following commands in the journal file:
(set! checkpoint/check-filename "./check-fluent")
(set! checkpoint/exit-filename "./exit-fluent").
This instructs solver to check for files called check-fluent and exit-fluent in the current working directory fof the running job. The presence of check-fluent file will instruct Fluent to conduct a save and then resume computation. The presence of exit-fluent file will instruct Fluent to conduct a save and then exit. The exit-fluent command also automatically generates a #restart.inp file (a journal) which can be used to restart the job from where it was stopped.


Read multiple data files (usually created during transient runs) and save images of a pre-defined contour plot in PNG format

(define datfile "Run-1-A-")
(define suffix ".000.dat.gz")
(define m 10)
(define n 50)
(define s 5
(do 
 (
  (i  m (+ i  s) )
 )
 (
  (> i  n)
 )
 (ti-menu-load-string (string-append "file read-data " datfile (number->string i) suffix))
 (ti-menu-load-string "display objects display contour-vel")
 (define pic (string-append datfile (number->string i) ".png"))
 (ti-menu-load-string (string-append "display save-picture " pic))
)

Author: William Wangard, Ph.D. Fluent, Inc. 2003:
(define (pad-zeros name pad-length)
  ; Function to pad a string with zeros to pad-length
  (if (< (string-length name) pad-length)
    (begin (pad-zeros (string-append "0" name) pad-length)) name
  )
)
(auto-animate "Uniform-" 1 100 "uniform_contours.jou"): This command will sequentially load "Uniform-0001.dat.gz" to Uniform-0100.dat.gz and for each of these journal file "uniform_contours.jou" shall be processed.
define (auto-animate base first last journal-file-name)
  ; first and last are integers, base is a string and journal-file-name
  ; is a journal file to be processed on each data file
  (if (<= first last)
    (begin

    ; Create index (string) padded with zeros with total 4 fields
    (define padded-index (pad-zeros (number->string first) 4))

    ; Create data file string name
    (define name (string-append (string-append (string-append base) padded-index) ".dat.gz"))

    ; Read data file
    (read-data name)

    ; Read animation journal file
    (ti-read-journal journal-file-name)

    ; Recursively call function...
    (auto-animate base (+ first 1) last journal-file-name)
    )
    (begin
      (display "Auto-animate is done.")
    )
  )
)

Local Function: lambda - a lambda expression evaluates to a procedure. The result of the last expression in the body will be returned as the result of the procedure call.

e.g.(lambda (x) (+ x x)): the function or procedure || ((lambda (x) (* x x)) 5) = 25 - the value is returned by procedure

(lambda (arg1 arg2 ...) 
  ... 
  function value
)

FOR EACH-Loop

Set temperature and wall velocity for several BC wall zones:
(for-each 
 (lambda (zone) 
  (ti-menu-load-string 
   (format #f "def b-c wall ~a 0 y steel y temperature n 300 n n n n 0 no 0.5 no 1" zone) 
  ) 
 (newline) (display "") 
 )
)

Create a function:

(map 
 (lambda(x)
   (+ (* x x) 5.0)
 )
 '(1 2 3)
) 
Output: (6, 9, 14)

CASE-Loop: discrete values of a variable - If x in one of the lists found (eg in (x11 x12 x13 ...)), then the corresponding value is returned (value1).

(case x 
 ((x11 x12 x13 ...) 
    value1
 ) 
 ((x21 x22 x23 ...) 
    value2
 ) 
 ... 
 (else value)
) 

Boundary condition for specified heat flux: def b-c wall top 0 n 0 y steel n n 2000 n n n n 0 no 0.5 no 1. The default setting in FLUENT is aluminum as material, heat flux as boundary conditions and no-slip stationary walls.


Monitor Points

Define velocity inlet b.c. by components: def b-c v-i bc_inlet n y y n 0 y n 1.0 n 2.0 n 3.0 n n y 5 10
Define velocity inlet b.c. by magnitude and direction: def b-c v-i bc_inlet y y n 5.0 n 0 y n 0.707 n 0 n 0.707 n n y 5 10
solve report-definitions add mf-inlet flux-mass-massFlow zone-names mf-inlet ()
solve report-files add mf-inlet report-definitions mf-inlet () file-name mf-inlet.out print yes ()
solve report-definitions add p-inlet surface-areaavg field pressure surface-names srf-1 srf-2 ()
Field (flow) variables in FLUENT: pressure, entropy, x-surface-area, pressure-coefficient, total-energy, y-surface-area, dynamic-pressure, internal-energy, z-surface-area, rel-total-temperature, x-coordinate, dp-dx, wall-temp-out-surf, y-coordinate, dp-dy, wall-temp-in-surf, z-coordinate, dz-dp...

Define zone name as variable and use it in post-processing:

(define zName '(vi_inlet))
(display zName)
(define avgPr 
  (pick-a-real
    (format #f "/report/s-i/a-w-a ~a pressure no ()" zName)
  )
)
(display avgPr)
Note: (display (format "~6.4f" avgPr)) will produce 0.0247*the-non-printing-object*. The statement (display (format #f "~6.4f" avgPr)) will give the desired output 0.0247.

Display a message if certain criteria is met: e.g. if temperature is less than or equal to 373 [K], report 'pass' or 'fail'.

(if 
 (<= 373
  (pick-a-real 
   (format #f "report/surf-integral/a-w-a w-cht-hx temperature no)
  )
 )
 (display "pass") (display "fail")
)

Export fluent zone names: this is applicable to FLUENT pre-post and not FLUENT Mesher. Once this journal is copy-pasted in TUI or read through a journal file, one need to type commmand (export-bc-names) in the TUI - including the parentheses.

(define (export-bc-names) 
  (for-each 
    (lambda (name) 
      (display 
        (format #f " {~a, \"~a\", \"~a\"}, \n" 
          (zone-name->id name) name (zone-type (get-zone name)) 
        )
      )
    )
    (inquire-zone-names)  
  ) 
) (export-bc-names)
(inquire-zone-names)-- this provides list of zone names to the 'for-each' loop. Fluent output:
(export-bc-names) 
{26, "w-top", "wall"}, 
{2, "fluid", "fluid"}, 
{29, "w-bot", "wall"}, 
{15, "w-side", "wall"}, 
{17, "inlet", "vi-inlet"}, 
{25, "default-interior", "interior"}

Rename Shadow Walls

Scheme script to rename shadow wall pairs. This code was downloaded from the public domain and variable names have been shortened a bit and text indented.

; Scheme function to identify which interior zones are "immersed" in a certain
; fluid zone. To use it, load the Scheme function through
; File>Read>Scheme ... or through  (load "immersed.scm") and then use the TUI 
; command (for example): (imme-info 'fluidX)
; It will print 1 or several interior zones that are completely immersed into 
; the fluid zone specified. One of them is for sure the Default-Interior type
; associated with that fluid zone named fluidX
(define (imme-info fzn)
  (let 
    (
      (id-fz (thread-name->id fzn)
      )
       (int-list (map thread-id (get-threads-of-type 'interior))
       )
    )
    (for-each 
      (lambda (id)
        (let 
        (
          (zz (inquire-adjacent-threads id))
          (id1)(id2))
          (set! id1 (car zz))
          (set! id2 (cadr zz))
          (if (eqv? id1 id2) 
            (if (eqv? id1 id-fz)
              (format "\n Interior zone "~a" is immersed in "~a" \n" (thread-id->name id) fzn)
            )
          )
        )
      ) int-list
    )
  )
)

Change Boundary Condition at Flow Times

A Scheme code referenced from ANSYS Learning Forum is described below.

(cond
  ((and 
    (> (rpgetvar 'flow-time) 0.1) (< (rpgetvar 'flow-time) 0.2)
   )
     (ti-menu-load-string "define/b-c/z-t 6 wall")
     (ti-menu-load-string "define/b-c/z-t 7 pressure-outlet"))
  ((and 
    (> (rpgetvar 'flow-time) 0.5) (< (rpgetvar 'flow-time) 0.6)
   )
     (ti-menu-load-string "define/b-c/z-t 6 wall")
     (ti-menu-load-string "define/b-c/z-t 7 pressure-outlet"))

(else
  (ti-menu-load-string "define/b-c/z-t 7 wall")
  (ti-menu-load-string "define/b-c wall 7 no no no no 0 no 0.5")
  (ti-menu-load-string "define/b-c/z-t 6 pressure-inlet")
  (ti-menu-load-string "define/b-c pressure-inlet 6 yes no 0 no 0 no yes no no yes 2 5"))
)

Create cell registers: /solve/cell-registers add clipVolume type cylinder inside? yes radius 0.05 axis-begin 0.1 0.0 0.0 axis-end 0.2 0.0 0.0 q q. Ensure that units are set as [m] as all inputs from TUI are interpreted to be in SI. One can use /define/units/length m before using previous SCHEME command.


Creating animation: Create animation from the data files of a transient simulation, single frames will be created for an animation. The names of the data files are numbered with initial, final value with a step size. Errors encountered during the execution of a Fluent command, or a termination by Ctrl-C will also cause the Scheme program to quit.

File names are twophase-0010.dat, twophase-0020.dat... and images generated are image-01.png, image-02.png... Note that 'hardcopy' has been replaced by 'picture' in version 2020-R1 though there is backward compatibiity.

(define datfile "twophase") 
(define f-index 10) 
(define l-index 100) 
(define delta 10) 
(define imgfile "image")
(define (time) (rpgetvar 'flow-time)) 
(define t0 0)
;Function to create frames for the film 
(define (pp) 
 (let ((break #f)) 
  (ti-menu-load-string "display set hardcopy driver png")
  (ti-menu-load-string "display set hardcopy color-mode color")
  (do ((j f-index (j + delta)) (i 1 (+ i 1))) ((or (> j l-index) break))
   (set! break 
    (not
      (and
       (ti-menu-load-string (format #f "file r-d ~a ~04d.dat" datfile j))
       (begin (if (= i 1) (set! t0 (time))) #t)
       (ti-menu-load-string "display hardcopy ~a ~02d.png" imgfile i) 
      )
    )
   ) 
  ) 
  (if break 
   (begin (newline) (newline) 
    (display "Scheme interrupted!") 
    (newline)
   )
  )
 )
)

Simple example (disp)-function for contour-plot:
(define (disp) 
 (ti-menu-load-string "display contour temperature 300 500")
)
Example (disp) function: overlay contours and velocity-vectors. To call the (disp) function for testing: (disp), call the function to generate the images: (pp).
(define (disp) 
 (and 
  (ti-menu-load-string (format #f "display lang set title \" Time 5.1fs = ~ \ "" (- (time) t0)))
  (ti-menu-load-string "display set overlays no") 
  (ti-menu-load-string "display temperature contour 300 500") 
  (ti-menu-load-string "display set yes overlays") 
  (ti-menu-load-string "display lang velocity vectors, velocity-magnitude 0.0 1.0 5 0") 
 ) 
)

GUI Components in FLUENT and SCHEME Script


Few examples from posts on cfd-online.com: This piece of code prints centroid of boundaries defined at type "velocity-inlet".

(display
 (map 
  (lambda (zone) 
   (format #f "~a: (~a,~a,~a)\n" zone 
    (pick-a-real
     (format #f "/report/surface-int/a-w-a ~a () x-coordinate no" zone)
    )
    (pick-a-real
     (format #f "/report/surface-int/a-w-a ~a () y-coordinate no" zone)
    )
    (pick-a-real
     (format #f "/report/surface-int/a-w-a ~a () z-coordinate no" zone)
    )
   )
  )
  (filter
   (lambda (zn) (eq? (zone-type (get-zone zn)) 'velocity-inlet)) (inquire-zone-names)
  )
 )
)

Check whether a cell thread is adjacent to a face thread or not

(define (check_adjacency fluid_id face_id)
  (let 
    ( 
      (fluid_chk (inquire-adjacent-threads face_id)) (aa)
    )
    (set! aa (car fluid_chk))
    (if(eqv? aa fluid_id)
      (display "Face and Fluid adjacent.")
      (display "Face and Fluid not adjacent.")
    )
  )
)

ANSYS FLUENT Mesher Commands: Once you compute "Volumetric Regions", use TUI /objects/volumetric-regions list objectName * () to print a tabulated information of all volumes printed under headings "name | type | volume | material-point | face-zones"


Mesh Adaption

(ti-menu-load-string (format #f "/mesh/adapt/list-adaption-cells \n"))

ANSYS FLUENT start-up customization: This can be complementary to options available under Preferences in latest versions (V2021...)

(let (old-rc client-read-case)
 (set! client-read-case
  (lambda args
    (apply old-rc args)
    (if (cx-gui?)
     (begin
      (rpsetvar 'residuals/plot? #t)
      ;Turning off convergence check
      (rpsetvar 'residuals/settings '(
        (continuity #t 0 #f 0.0001)
        (x-velocity #t 0 #f 0.0001)
        (y-velocity #t 0 #f 0.0001)
        (z-velocity #t 0 #f 0.0001)
        (energy #t 0 #f 1e-08)
        (k #t 0 #f 0.0001)
        (epsilon #t 0 #f 0.0001)
        )
      )
      (rpsetvar 'mom/relax 0.4)
      (rpsetvar 'pressure/relax 0.5)
      (rpsetvar 'realizable-epsilon? #t)
      (cxsetvar 'vector/style "arrow")
     )
    )
  )
 )
)

Read a custom color map or write an existing one. The procedure consists of: Loading the Scheme file >> (load "rw-colormap.scm") >> Reading a new color map: /file/read-colormap >> Writing an existing color map: /file/write-colormap. Reference: Fluent Tips & Tricks - UGM 2004 by Sutikno Wirogo and Samir Rid.

(define (write-cmap fn)
  (let (
    (port (open-output-file (cx-expand-filename fn)))
    (cmap (cxgetvar 'def-cmap))
    )
    (write (cons cmap (cx-get-cmap cmap)) port)
    (newline port)
    (close-output-port port)
  )
)
(define (read-cmap fn)
  (if (file-exists? fn)
    (let ((cmap (read (open-input-file (cx-expandfilename fn)))))
      (cx-add-cmap (car cmap) 
        (cons (length (cdr cmap)) 
         (cdr cmap)
        )
	  )
      (cxsetvar 'def-cmap (car cmap))
    )
    (cx-error-dialog
      (format #f "Macro file ~s not found." fn)
    )
  )
)
(define (ti-write-cmap)
  (let ((fn (read-filename "colormap filename" "cmap.scm")))
    (if (ok-to-overwrite? fn)
      (write-cmap fn)
    )
  )
)
(define (ti-read-cmap)
  (read-cmap (read-filename "colormap filename" "cmap.scm"))
)
(ti-menu-insert-item! file-menu
  (make-menu-item "read-colormap" #t ti-read-cmap "Read colormap from file")
)
(ti-menu-insert-item! file-menu
  (make-menu-item "write-colormap" #t ti-writecmap "Write colormap to file")
)

Replace all occurrenece of characters in a string. Reference: stackoverflow.com/.../flexible-replace-substring-scheme. Note that this code require (prefix?) to work as it is not implemented in all Scheme environments.

(define (rplc-all input trgt src)    
  (let 
    (
      (input (string->list input))
      (trgt (string->list trgt))
      (src (string->list src))
      (trgt-len (string-length trgt))
    )
    (let loop ((input input) (acc '()))
      (cond ((null? input) (list->string (reverse acc)) )
          ((prefix? input trgt)
            (loop (list-tail input trgt-len)
              (reverse-append src acc)
            )
          )
           (else
             (loop (cdr input) (cons (car input) acc))
           )
      )
    )
  )
)
(rplc-all "w-htc_2" "-" "_)

(let um (cx-add-menu "usrMenu" #\M)): it adds a menu named usrMenu in the top main menu bar with M underlined to indicate keyboard shortcut. The ID of the newly created menu is printed in console which can also be access by code (cx-get-menu-id "usrMenu"). To add items to this menau: (cx-add-item um "CFD Steps" #\O #f and (lambda () (system "chrome.exe https://cfdyna.com &")))

FLUENT SCHEME Command Error Message
In general the error message from Scheme commands in FLUENT is a bit cryptic, some gives an idea of missing arguments or inputs. Following sections describes the error messages and hints about missing arguments.

(scale-grid): This will give following errors:

(scale-grid) (scale-grid 0.01)
Error eval: unbound variable Error eval: unbound variable
Error Object: fx Error Object: fy
The code is expecting (unknown number of) arguments. The first one is denoted as fx The code is expecting (unknown number of) arguments. The second one is denoted as fy
As you can guess, scaling of mesh required three scaling factors. Hence, the correct synstax is (scale-grid 0.1 0.1 0.1)
Another example:
(color-list)
Error eval: invalid function
Error Object: ("foreground" "red" "blue" .... "salmon")
As you can guess, the output of code is a list which could not be processed. (display color-list) prints the list of colours ("foreground" "red" "blue" .... "salmon")
More examples:
(thread-domain-id) (thread-id), (domain-id)
Error eval: unbound variableError eval: unbound variable
Error Object: thread Error Object: thread
As you can guess, the code is expecting a list of threads. However, (get-all-domains) makes the cortex crash but (map domain-id (get-all-domains)) shall print (1) for single-phase flow cases.

(inquire-grid) shall print summary of mesh such as (0 874 2056 342 2) where the numbers correspond to cells, faces and node. (map domain-type (get-all-domains)) prints (mixture). (map domain-type (get-all-domains)) prints (geom-domain). (fluent-exec-name) prints the path of executables (*.exe) files. (list-database-materials) prints the names of all materials defined inside ANSYS FLUENT. (get-database-material 'air) prints all the properties currently defined for material air. Note the single quote before the name for material.

More examples:
(thread-surface) (thread-surface 21)
Error eval: too few arguments(0)Error eval: too few arguments(1)
Error Object: #[primitive-procedure %zone-surface] Error Object: #[primitive-procedure %zone-surface]
The code is expecting (unknown number of) arguments. However, #[primitive-procedure %zone-surface] is a bit cryptic and difficult to guess.

(volume-integrals) results in error with message "Error eval: unbound variable". (%volume-integrals) also results in error with differnt message:
Error: eval: too few arguments(0)
Error Object: #[primitive procedure %volume-integrals]


Customization vs. Extensibility
CustomizationExtensibility
In-product operationOut of product feature expansion
Modify existng functionality, Create new featureEnhance a software package with minimum development

EXAMPLES OF UDF

Only velocities in Cartesian coordinates (Ux,Uy,Uz) are accessible through the UDF macros. Radial, tangential & axial velocities (Ur, Ut, Ua) within a fluid zone will need to be computed using the UDF itself. The UDF below can be used to define inlet velocity as a function of radius and time. It is assumed that the centre of inlet face is at origin.

  Note that in order to access UDF parameters in post-processing, UDM (User Defined Memory) needs to be initialized using GUI path: Parameters & Customization → User Defined Memory → Number of User-Defined Memory Location where the UDM numbering starts from 0. In your UDF, assign your variable to a specific UDM. E.g. F_UDMI(face, thread, 0) = U_txyz; C_UDMI(cell, threat, 0) = vol_heat_source; '0' here refers to the UDM number.

Note that the DEFINE_XX macros implement general solver functions that are independent of the model(s) being used in ANSYS Fluent. For example, DEFINE_ADJUST is a general-purpose macro that can be used to adjust or modify variables that are not passed as arguments. For example, modify flow variables (velocities, pressure...) and compute integrals of a scalar quantity over a domain which can be used to adjust a boundary condition based on the result. A function that is defined using DEFINE_ADJUST executes at every iteration and is called at the beginning of every iteration before transport equations are solved.

#include "udf.h"
DEFINE_PROFILE(U_txyz, thread, position) {
  /*position: Index of variable say 'U' to be set                 */
  real x[ND_ND];             /* Position vector of nodes          */
  real xi, yi, zi, r;
  face_t f;
  real R = 0.050;            /* Radius in [m]                     */
  real t = CURRENT_TIME;     /* Current time of simulation        */
  begin_f_loop(f, b)         /* Loops over all faces in thread 'b'*/
  {
    /* C_CENTROID(x,c,t): returns centroid in real x[ND_ND]       */

    F_CENTROID(x, f, b);    /* Gets centroid of face f            */
    
    /* x[ND_ND]: Position vector of nodes                         */
    xi = x[0]; yi = x[1]; zi = x[2];
    r = sqrt(xi*xi + yi*yi + zi*zi);
    F_PROFILE(f, b, position) = 2.0 + 0.5*sin(t/5)*sin(0.31416*r/R);
  } 
  end_f_loop(f, thread)
} 

Note: The constant ND_ND is defined as 2 for RP_2D (2D domain) and 3 for RP_3D (3D domain). It can be used when it is require to build a 2x2 matrix in 2D and a 3x3 matrix in 3D. Instead if ND_ND is used, the UDF will work for both 2D and 3D cases, without requiring any modifications.


Another example of UDF which can be used to define a linear translation and angular displacement to a cylinder of plate with dynamic mesh motion setting is described below.
/* Rigid body motion of a cylinder: translation and rotations,
can be used for a flapping plate if translation is set 0.    */

#include "udf.h"
/* -----  Define frequency of rotation / flapping in Hz.     */
  #define f 5.0  
/* -----  Define angular velocity in [rad/s].                */
  #define omega 2.0*M_PI*f
/* -----  Define maximum angular deflection in [rad]         */
  #define thetaMax M_PI/180
/* -----  Define linear translation in [m]                   */
  #define xMax 0.01;
  
DEFINE_CG_MOTION(TransRot, dt, cg_vel, cg_omega, time, dtime) {
  real angVel, linVel;
  
  linVel = xMax * omega * cos(omega*time);
  cg_vel[0] = linVel;
  cg_vel[1] = 0.0;
  cg_vel[2] = 0.0;
  
  /*cg_omega[0] -> wx, cg_omega[1] -> wy, cg_omega[2] - wz   */
  /*Axis of rotation is about origin and should be ensured.  */
  angVel = ThetaMax * omega * sin(omega*time);
  cg_omega[1] = angVel;
  cg_omega[2] = 0.0;
  cg_omega[3] = 0.0;
}

Summary of UDF commands

Exerpts from user manual: Think of a ‘zone’ as being the same as a ‘thread’ data structure when programming UDFs. Thus: node thread = grouping of nodes, face thread = grouping of faces, cell thread = grouping of cells. A domain is a data structure in ANSYS FLUENT that is used to store information about a collection of node, face threads, and cell threads in a mesh.

UDF thread domain hierarchy

  • Data Types: Node is a structure data type that stores data associated with a mesh point, face_t is an integer data type that identifies a particular face within a face thread, cell_t is an integer data type that identifies a particular cell within a cell thread, Thread is a structure data type that stores data that is common to the group of cells or faces that it represents.
  • NODE_X(node) = X-coordinate of node
  • NODE_Y(node) = Y-coordinate of node
  • NODE_Z(node) = Z-coordinate of node
  • F_NNODES(f, t) = number of nodes in a face
  • C_CENTROID(x, c, t) / F_CENTROID(x, f, t): = returns centroid in a 1x3 array real x[ND_ND]
  • F_AREA(a, f, t): returns face area (normal) vector in real a[ND_ND]
  • C_VOLUME(c, t) = volume of cell
  • C_NNODES(c, t) = number of nodes
  • C_NFACES(c, t) = number of faces
  • C_FACE(c, t, i) = global face index, corresponding to local face index i
  • C_R(c, t) / F_R(f, t) = Access cell / boundary face flow variable density
  • C_P(c, t) / F_P(f, t) = Access cell / boundary and interior face flow variable pressure
  • C_U(c, t) / F_U(f, t) = Access cell / boundary face flow variable x-velocity
  • C_V(c, t) / F_V(f, t) = Access cell / boundary face flow variable y-velocity
  • C_W(c, t) / F_W(f, t) = Access cell / boundary face flow variable z-velocity
  • C_T(c, t) / F_T(f, t) = Access cell / boundary face flow variable temperature
  • C_H(c, t) / F_H(f, t) = Access cell / boundary face flow variable enthalpy
  • C_K_L(c, t) = Access cell material property "thermal conductivity". 'L', 'T' and 'EFF' suffix is used for 'Laminar', 'Turbulent' and 'Effective' properties. For example, C_MU_L, C_MU_T and C_MU_EFF refers to 'Laminar', 'Turbulent' and 'Effective' viscosities respectively.
  • Similarly, K, NUT, D, O and YI can be added to C_ to access TKE, turbulent viscosity of Spalart-Allmaras model, TED (ε), specific dissipation rate (ω) and mass fraction respectively. Note that the UDF will result in fatal error if the TKE or TDR is accessed in a solid domain (thread).
  • F_FLUX(f, t) = Access face flow variable mass flux
  • d = Get_Domain(1) = Get domain using FLUENT utility. Here, domain_id = 1 is an integer for the mixture or fluid domain, but the values for the phase domains can be any integer greater than 1. E.g. porousDomain = Get_Domain(2);
  • Derivative macro: C_UDSI(c, t, VORTICITY_Z) = C_DVDX(c,t) - C_DUDY(c,t) = define z-component of vorticity
  • C_R_G(c, t), C_P_G(c, t), C_U_G(c, t) ... can be used to get gradient vector: {dp/dx dp/dy dp/dz)
  • The M1 suffix can be applied to some of the cell variable macros to access value of the variable at the previous time step (t - Δt). These data may be useful in unsteady simulations. For example, C_T_M1(cell, thread); returns the value of the cell temperature at the previous time step
  • Similarly, M2 suffix can be applied to some of the cell variable macros to access value of the variable at second previous time step (t -2Δt). These data may be useful in unsteady simulations. For example, C_T_M2(cell, thread); returns the value of the cell temperature at the previous to previous time step
  • PRINCIPAL_FACE_P(f,t) = test if the face is the principle face - not required for serial operation, applicable to compiled UDFs only
  • C_VOLUME = get the cell volume and accumulates it. The end result is total volume of each cell of respective mesh.
  • C_UDMI(c, t,0) = store result in user-defined memory, location index 0. The user-defined memory field gets saved to the data file and can be used to generate contours and any other post-processing activity.
  • The NV_ macros have the same purpose as ND macros, but they operate on vectors (that is, arrays of length ND_ND) instead of separate components.
    • NV_V: The utility NV_V performs an operation on two vectors. NV_V(a, =, x) will result in a[0] = x[0], a[1] = x[1] and a[2] = x[2]
    • Use of '+ =' instead of '=' in the above equation results in summation. NV_V(a, +=, x) will result in a[0] = a[0] + x[0], a[1] = a[1] + x[1] and a[2] = a[2] + x[2]
    • NV_VV performs operations on vector elements. The operation that is performed on the elements depends upon what symbol (-, /, *) is used as an argument. NV_VV(a, =, x, +, y) will yield a[0] = x[0] + y[0], a[1] = x[1] + y[1] and a[2] = x[2] + y[2]
    • NV_V_VS utility operates (+, -, *, /) a vector to another vector which is multiplied or divided by a scalar. NV_V_VS(a, =, x, +, y, *, 0.5) will result in 2D: a[0] = x[0] + y[0] * 0.5, a[1] = x[1] + y[1] * 0.5
    • NV_VS_VS utility operates (+, -, *, /) a vector to another vector where both are multiplied or divided by a scalar. NV_VS_VS(a, /, 2.0, x, +, y, *, 5.0) will result in a[0] = x[0] / 2.0 + y[0] * 5.0, a[1] = x[1] / 2.0 + y[1] * 5.0, a[3] = x[3] / 2.0 + y[3] * 5.0
  • Other NV_ operations:
    • NV_VEC(A) - declare vector A
    • NV_D(psi, =, F_U(f,t), F_V(f,t), F_W(f,t)) - define psi in terms of velocity field, NV_D(axis, =, 0.0, 1.0, 0.0), NV_D(origin, =, 0.0, 0.0, 5.0)
    • NV_VV(rvec, =, NODE_COORD(v), -, origin)
    • NV_S(q, =, 0.0), NV_S(psi, *=, F_R(f,t)) - multiplying density to get psi vector
    • NV_DOT(A, B) - dot product of the two vectors, NV_CROSS(A, B) - crosss product of the two vectors
  • boolean FLUID_THREAD_P(thread): Check if 'thread' is of type FLUID
  • Some macros are defined in 'mem.h' and not in 'udf.h'. Example includes: C_FACE_THREAD(c, t, i), C_FACE(c, t, i), C_R(c,t), C_P(c,t), C_U(c,t), C_V(c,t)... F_PROFILE.

DEFINE_ON_DEMAND is a general-purpose macro that can be used to specify a UDF that is executed as needed in ANSYS FLUENT, rather than having ANSYS FLUENT call it automatically during the calculation. UDF will be executed immediately, after it is activated, but it is not accessible while the solver is iterating. Note that the domain pointer d is not explicitly passed as an argument to DEFINE_ON_DEMAND. Therefore, if you want to use the domain variable in your on-demand function, you will need to first retrieve it using the Get_Domain utility.

Excerpt from UDF Manual: The following UDF, named on demand calc, computes and prints the minimum, maximum, and average temperatures for the current data field. It then computes a temperature function f(T) = [T − TMIN]/[TMAX − TMIN] and stores it in user-defined memory location 0. After the on-demand UDF is hooked, the field values for f(T) will be available in drop-down lists in postprocessing dialog boxes in ANSYS FLUENT. This field can be accessed by choosing User Memory 0 in the User-Defined Memory... category.Note that this is for demontration purpose only as the features to find out maximum, minimum and volume-weighted average are avaialbe as standard post-processing operatons.

#include "udf.h"
DEFINE_ON_DEMAND(Tavg) {
/* declare domain pointer: it isn't passed as an argument to the DEFINE macro */
  Domain *d; 
  real tavg = 0.0;
  real tmax = 0.0;
  real tmin = 0.0;
  real tp, volm, vtot;
  Thread *t;
  cell_t c;
  /* Get the domain using ANSYS FLUENT utility */
  d = Get_Domain(1); 
  /* Loop over all cell threads in the domain */
  thread_loop_c(t,d) {
    /* Compute max, min, volume-averaged temperature */
    /* Loop over all cells */
     begin_c_loop(c,t) {
       volm = C_VOLUME(c,t); /* get cell volume */
       tp = C_T(c,t);   /* get cell temperature */
       if (tp < tmin || tmin == 0.0) tmin = tp;
       if (tp > tmax || tmax == 0.0) tmax = tp;
       vtot = vtot + volm;
       tavg = tavg + tp*volm;
    } end_c_loop(c,t)
    tavg /= vtot;
    printf("\n Tmin = %g Tmax = %g Tavg = %g\n",tmin,tmax,tavg);
    /* Compute temperature function and store in UDM*/
    /*(location index 0) */
    begin_c_loop(c,t) {
      tp = C_T(c,t);
      C_UDMI(c,t,0) = (tp-tmin)/(tmax-tmin);
    } end_c_loop(c,t)
  }
}

This UDF will print the volume of cells with temperature withing specified [in K] range.

DEFINE_ON_DEMAND(isoVolume) {
/* declare domain pointer: it isn't passed as an argument to the DEFINE macro */
  Domain *d; 
  real tmax = 300.0;   /* This value should in [K] */
  real tmin = 320.0;   /* This value should in [K] */
  real temp, volm, vtot;
  Thread *t;
  integer zid;
  cell_t c;
  /* Get the domain using ANSYS FLUENT utility */
  d = Get_Domain(1); 
  /* Loop over all cell threads in the domain */
  thread_loop_c(t, d) {
     vtot = 0.0;
    /* Loop over all cells */
     begin_c_loop(c,t) {
       tp = C_T(c,t); /* get cell temperature */
       if (tp <= tmax && tp >= tmax) {
         /*Get cell volume and add to total volume */
         volm = C_VOLUME(c,t); 
         vtot = vtot + volm;
       }
    } end_c_loop(c,t)
    zid = THREAD_ID(t);
    printf("\n Zone - %d -- Volume in specified range = %g \n", zid, vtot);
  }
}

UDF in Parallel Computing on Clusters

Serial solver contains Cortex and only a single ANSYS Fluent process.

The parallel solver contains 3 types of executable: Cortex, host, and compute node (or simply 'node' for short). When ANSYS Fluent runs in parallel, an instance of Cortex starts, followed by one host and n compute nodes, thereby giving a total of (n + 2) running processes. For this reason, UDF for parallel run will need to be developed such that the function will successfully execute as a host and a node process.

Example of operations that require parallelization of serial source code include the following:
  • Reading and Writing Files
  • Global Reductions, Global Logicals
  • Global Sums, Global Minimums and Maximums
  • Certain Loops over Cells and Faces
  • Displaying Messages on a Console, Printing to a Host or Node Process
List of parallel compiler directives:
/*--------------------------------------------------------------------*/
/* Compiler Directives                                                */
/*--------------------------------------------------------------------*/
#if RP_HOST       /* only host process is involved                    */
#if !RP_HOST      /*either serial or compute node process is involved */
  ...
#endif

#if RP_NODE       /* only compute nodes are involved                  */
#if !RP_NODE      /* either serial or host process is involved        */
  ...
#endif

#if PARALLEL     /* both host and compute nodes are involved, but not */
                 /* serial equivalent to #if RP_HOST || RP_NODE       */
#if !PARALLEL    /* only serial process is involved                   */
  ...
#endif

Depending upon a UDF, the UDF written in C language needs to be compiled before it can be used in FLUENT. Best a UDF should be compiled on a system with the same operating system (OS) and processor architecture as the compute cluster. Typically the compute nodes are diskless nodes with bare minimum boot image, it lacks a C or CPP programming environment (compiler, linker, libraries). Hence, it is not possible to compile a UDF in batch mode on a compute node of the Linux clusters.


More examples of FLUENT UDF
UDF for Temperature Dependent Viscosity
DEFINE_PROPERTY(visc_T, c, Tp)		{
  real mu; real a = C_T(c,t);  
  mu = 2.414e-05 * pow(10, 247.8/(Tp - 140));
  return mu;						
}

Compute area of a face zone:

 #include "udf.h" 
 real Ar1 = 0.0; 
 begin_f_loop(f, t) 
 if PRINCIPAL_FACE_P(f, t) {  
  /* compute area of each face */  
  F_AREA(area, f, t);   
  /*compute total face area by summing areas of each face*/  
  Ar1 = Ar1 + NV_MAG(area);   
 }  
 end_f_loop(f,t)  
 Ar1 = PRF_GRSUM1(Ar1);  
 Message("Area = %12.4e \n", Ar1); 

Compute volume of a cell zone:

 #include "udf.h" 
 real Vm1 = 0.0; 
 begin_C_loop(c, t) 
  /*compute total volume by summing volumes of each cell*/  
  Vm1 = Vm1 + C_VOLUME(c, t);   
 }  
 end_f_loop(c, t)  
 Vm1 = PRF_GRSUM1(Vm1);  
 Message("Volume = %12.4e \n", Vm1);

UDF: change time step value in Transient Simulation

This example, UDF needs to operate on a particular thread in a domain (instead of looping over all threads) and the DEFINE macro DEFINE_DELTAT used in UDF does not have the thread pointer passed to it from the solver. Hence, Lookup_Thread is required in the UDF to get the desired thread pointer.

 #include "udf.h"
 DEFINE_DELTAT(timeStep, d) { 
 real newTime = CURRENT_TIME; real oldT; real minT = 0.0; real maxT = 0.0;
 Thread *t; cell_t c; d = Get_Domain(1); 
 int zID = 1; Thread *t = Lookup_Thread(d, zID); 
 begin_f_loop(f, t) { /* Loop over all face elements*/
   oldT = F_T_M1(f, t); /* Get face temperature at previous time-step */
   if (oldT < minT || minT == 0.0) minT = oldT;
   if (oldT > maxT || maxT == 0.0) maxT = oldT;
 }
 end_f_loop(f, t)

 if(maxT < 100.0) 
  timeStep = 0.5; 
 else 
  timeStep = 0.1; 
 
 return timeStep; 
 }

Density as function of temperature:

#include "udf.h"
DEFINE_PROPERTY(rho_T, c, Tp) {
  real rho;
  /* Get temperature of the cell in K and convert into C */
  real Tp = C_T(c,t) - 273.11; 
  real a0 =  999.8396;
  real a1 =  18.22494;
  real a2 = -7.92221e-03;
  real a3 = -5.54485e-05;
  real a4 =  1.49756e-07;
  real a5 = -3.93295e-10;
  real b =   1.81597e-02;

  rho = a0 + a1*Tp + a2*Tp*Tp + a3*pow(Tp, 3) + a4*pow(Tp, 4) + a5*pow(Tp, 5);
  rho = rho / (1 + b*Tp);
  return rho;						
}

Sample UDF for 6DOF case. DEFINE_SDOF_PROPERTIES (name, properties, dt, time, dtime) specifies custom properties of moving objects for the six degrees of freedom (SDOF) solver which includes mass, moment and products of inertia, external forces and external moments. real *properties - pointer to the array that stores the SDOF properties. The properties of an object which can consist of multiple zones can change in time, if desired. External load forces and moments can either be specified as global coordinates or body coordinates. In addition, you can specify custom transformation matrices using DEFINE_SDOF_PROPERTIES. The boolean properties[SDOF_LOAD_LOCAL] can be used to determine whether the forces and moments are expressed in terms of global coordinates (FALSE) or body coordinates (TRUE). The default value for properties[SDOF_LOAD_LOCAL] is FALSE.

#include "udf.h"
#include "math.h"
DEFINE_SDOF_PROPERTIES(valve_6dof, prop, dt, time, dtime) {
prop[SDOF_MASS] = 0.10; /*Mass of the valve in [kg] */
prop[SDOF_IZZ] = 1.5e-3;/*Mass moment of inertia about Z axis [kg/m^2] */
/* Translational motion setting, use TRUE and FALSE as applicable */
prop[SDOF_ZERO_TRANS_X] = TRUE; /*Translation allowed in X-Direction? */
prop[SDOF_ZERO_TRANS_Y] = TRUE; /*Translation allowed in Y-Direction? */
prop[SDOF_ZERO_TRANS_Z] = TRUE; /*Translation allowed in Z-Direction? */
/* Rotational motion setting, use TRUE and FALSE as applicable*/
prop[SDOF_ZERO_ROT_X] = TRUE; /*Rotation allowed about X-Axis? */
prop[SDOF_ZERO_ROT_Y] = TRUE; /*Rotation allowed about Y-Axis? */
prop[SDOF_ZERO_ROT_Z] = FALSE;/*Rotation allowed about Z-Axis? */
/* Gravitational, External Forces/Moments: SDOF_LOAD_F_X, SDOF_LOAD_F_Y ... SDOF_LOAD_M_Z */
M = prop[SDOF_MASS]; Larm = 0.10 */
prop[SDOF_LOAD_M_Z] = -9.81 * M * Larm * sin(DT_THETA(dt)[2];
Message("\n 2D: updated 6DOF properties DT_THETA_Z: %e, Mz: %e, Mass: %e \n",
DT_THETA(dt)[2], prop[SDOF_LOAD_M_Z], prop[SDOF_MASS]);
}

Tips and Tricks on UDF / UFF
  • To write output to a file from UDF operation / loop: open a file using statement: FILE *fileName; fileName = fopen("udfOutput.txt", "a");
  • fprintf(fileName,"%g %g\n", x[0], source); fclose(fileName); However, all the fopen / fprintf / fclose commands are incompatible with parallel operation.
  • To send output to the console: Message("x = %g source = %g\n", x[0], source);)
  • In STAR-CCM+ du/dy = grad($Velocity[0]/grad($Centroid[1]), in FLUENT UDF: C_DUDY(cell, thread). Similarly, C_DVDX(cell, thread) can be defined.
  • Similarly in FLUENT, C_T_G(cell, thread)[0] returns the x-component of the cell temperature gradient vector.

Scheme examples from web such as cookbook.scheme.org, schemers.org....

Find first occurrence of an element in a list

(define (list-index fn list)
  (let iter ((list list) (index 0))
    (if (null? list) -1
      (let ((item (car list)))
        (if (fn item)
          index
          (iter (cdr list) (+ index 1))
        )
      )
    )
  )
)

Remove duplicate (repeat) entries from a list which are adjacent to each other

(define (delete-adjacent-duplicates xs)
  (let loop ((prev-pair #f) (xs xs) (new-list '()))
    (if (null? xs) (reverse new-list)
       (loop xs
          (cdr xs)
          (let ((x (car xs)))
            (if (and prev-pair (equal? x (car prev-pair)))
               new-list
               (cons x new-list)
            )
          )
       )
    )
  )
) 
(delete-adjacent-duplicates '(1 2 3 1 1 4 5 5)) = (1 2 3 1 4 5)

Find substring in string: this will work only is (char?) is defined.

(define (string-find haystack needle . rest)
  (let ((start (if (null? rest) 0 (car rest))))
    (let* ((haystack-len (string-length haystack))
           (needle-len (string-length needle))
           (start 0))
      (let loop ((h-index start)
                 (n-index 0))
        (let ((h-char (string-ref haystack h-index))
              (n-char (string-ref needle n-index)))
          (if (char=? h-char n-char)
            (if (= (+ n-index 1) needle-len)
               (+ (- h-index needle-len) 1)
               (loop (+ h-index 1) (+ n-index 1))
            )
            (if (= (+ h-index 1) haystack-len) #f
               (loop (+ h-index 1) 0)
            )
          )
        )
      )
    )
  )
)
(string-find input search)
(define (list? x)
  (if (equal? (length x) 0) #f)
  (if (> (length x) 0) #t)
) 
(list? '2) - error, (list? '(2 3)0 = #t, (list? '()) = #f.

Examples from stackoverflow.com/ ... /searching-and-replacing-n-element-on-list-scheme: the keyword list has been replaced with xlst.

(define (find-replace a b xlst)
  (cond
    ;Start with a list. If it's empty, leave it
    ((null? xlst) '())
    ;If the first element is a list, call function recursively. If the first 
    ;element is equal to what your searching for, cons the replacement onto a 
    ;recursive call of your function on the rest of the list...keep searching
    ((list? (car xlst)) 
       (cons (find-replace a b (car xlst)) (find-replace a b (cdr xlst)))
    )
    ((eq? (car xlst) a) (cons b (find-replace a b (cdr xlst))))
    ;If none of the earlier conditions are true, cons the first element on to
    ;a recursive call of your function for the rest of the list
    (else
      (cons (car xlst) (find-replace a b (cdr xlst)))
    )
  )
)
Reference: The Little Schemer
(define atom?
  (lambda (x)
    (and (not (pair? x)) (not (null? x)))
  )
)

Substitute every occurrence of old with an occurrence of new. Note that this code will work only if (atom?) is defined which is not the case in all Scheme implementations.

(define subst-lst
  (lambda (new old l)
    (cond
       ((null? l) (quote ()))
       ((atom? (car l))
         (cond
           ((eq? (car l) old) (cons new
             (subst new old (cdr l)))
           )
           (else (cons (car l)
             (subst new old (cdr l)))
           ) 
         )
      )
      (else (cons (subst new old (car l))
        (subst new old (cdr l)))
      )
    )
  )
)
Some Examples from GitHub
(define (delete-n list n)
  (if (= n 0)
    (cdr list)
    (cons (car list) (delete-n (cdr list) (- n 1)))
  )
)

(define (insert-n list item n)
  (if (= n 0)
    (cons item list)
    (cons (car list) (insert-n (cdr list) item (- n 1)))
  )
)

(define (list-nth list n)
  (if (= n 0)
    (car list)
    (list-nth (cdr list) (- n 1))
  )
)

(define (replace-nth list n item)
  (if (= n 0)
    (cons item (cdr list))
    (cons (car list) (replace-nth (cdr list) (- n 1) item))
  )
)

(define (swap-item list m n)
  (let
    ( (a (list-nth list m)) (b (list-nth list n)) )
    ( replace-nth (replace-nth list m b) n a )
  )
)

Examples:
(swap-item (list 1 2 3 6) 2 3)
(replace-nth (list 3 2 9 2) 2 8)
(delete-n (list 1 2 3 4 5) 2)
(insert-n (list 1 2 3 4 5) 8 2)
(list-nth (list 1 2 3 4 5) 3)

From the Book: Concrete Abstractions - An Introduction to Computer Science Using Scheme

Procedure that counts the number of elements in a list:
(define length
  (lambda (lst)
    (if (null? lst) 0
      (+ 1 (length (cdr lst)))
    )
  )
)

Procedure that selects those elements of a given list that satisfy a given predicate:

(define filter
  (lambda (ok? lst)
    (cond ((null? lst) '())
      ((ok? (car lst))
        (cons (car lst) (filter ok? (cdr lst)))
      )
      (else
        (filter ok? (cdr lst)))
    )
  )
)
Example: (filter odd? (integers-from-to 1 15)) = (1 3 5 7 9 11 13 15)
Errors and Troubleshooting in FLUENT UDF

[Error message] line xx: structure reference not implemented ---There can be multiple reasons such as the UDF interpreter could not find required libraries (for example Visual Studio). Another reason can be that the C preprocessor is trying to interpret code that contains elements of C that the interpreter does not accommodate ((which is not supported).

If an UDF is interpreted which resulted in error, a fresh FLUENT session is needed to compile the UDF.


Accessing FLUENT from Python

pyAnsys: This is the module which can be used to access FLUENT commands from Python code.

Python Code to create Summary of a FLUENT Case File

Most of the programs such as ANSYS FLUENT and STAR-CCM+ have a well-defined structure to report summary of the set-up file. This Python code can be used to summary the lines containing specific keyword. The code has been tested on this sample text file.

Another version of Python codes containing the functions to summarize various types of boundary conditions are in this code. You can check how many shadow zones are not coupled, how many walls have Convective boundary conditions...

Similarly, the classes and functions defined in all Python script files stored in a folder and its subfolders can be summarized using this code.


Python Library for Fluid Mechanics: A library is available at github.com/CalebBell/fluids. The installation method is explained in the Readme file. An alternate method to use all the functions available in 'fluids' library is described below. Once source code is downloaded, this folder needs to be copied in your working directory.

import sys
sys.path.append('fluids')
import fluids
nRe = 5000
RRH = 0.002
fricFac = fluids.friction.Colebrook(nRe, RRH)
print("\n Friction factor - Colebrook formula: {0:8.3f}".format(fricFac),'\n') 

ICEM CFD: Tck/Tk Examples
For loop to copy a point entity:
for {set i 1} {$i <= $NS} {incr i}  {  
  ic_geo_duplicate_set_fam_and_data point ps$j ps[expr {$j+2}] {} _0  
  ic_move_geometry point names ps[expr {$j+2}] translate "0 $L 0"  
  ic_geo_duplicate_set_fam_and_data point ps[expr {$j+1}] ps[expr {$j+3}] {} _0  
  ic_move_geometry point names ps[expr {$j+3}] translate "0 $L 0"  
  set j [expr {$i*10+1}]  
} 

Macros in STAR-CCM+

The STAR-CCM+ user guide describes automation features available in STAR-CCM+ with many examples. There are some sample codes available online such as github.com/nitronayak/StarCCMAutomation

The first step in writing a JAVA macro for STAR CCM+ is to import the relevant packages. For example:

package macro;  - similar to #include "udf.h"
import java.util.*;  - similar to header files in C
import star.turbulence.*; - import turbulence model data
import star.common.*;   import star.material.*;
import star.base.neo.*; import star.vis.*;
import star.flow.*;     import star.energy.*;
import star.coupledflow.*;

// defineSim is the name of macro and the file name should be defineSim.java.
public class defineSim extends StarMacro {
  public void execute() {
    execute0();
  }
  //Get active simulation data
  Simulation getSim = getActiveSimulation();
  //Get domain named as FLUID and store it as 'cfd' - similar to Get_Domain in FLUENT UDF
  Region cfd = getSim.getRegionManager().getRegion("FLUID");
  //Set viscous model
  PhysicsContinuum pC0 = ((PhysicsContinuum) cfd.getContinuumManager().getContinuum("Physics 1"));
    pC0.enable(SteadyModel.class);
    pC0.enable(SingleComponentGasModel.class);
    pC0.enable(CoupledFlowModel.class);
    pC0.enable(IdealGasModel.class);
    pC0.enable(CoupledEnergyModel.class);
    pC0.enable(TurbulentModel.class);
    pC0.enable(RansTurbulenceModel.class);
    pC0.enable(KEpsilonTurbulence.class);
    pC0.enable(RkeTwoLayerTurbModel.class);
    pC0.enable(KeTwoLayerAllYplusWallTreatment.class);

  //Get boundary named INLET and velocity specification CLASS
  Boundary b1 = cfd.getBoundaryManager().getBoundary("INLET");
  VelocityProfile vP1 = b1.getValues().get(VelocityProfile.class);
  
    //Specify velocity normal to boundary with specified "MAGNITUDE and DIRECTION"
    //Note the word scalar in ConstantScalarProfileMethod.class
    b1.getConditions().get(InletVelocityOption.class).setSelected(InletVelocityOption.MAGNITUDE_DIRECTION);
    vP1.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(5.0);
	
    //Inlet velocity by its COMPONENTS, note 'vector' in ConstantVectorProfileMethod.class
    //b1.getConditions().get(InletVelocityOption.class).setSelected(InletVelocityOption.COMPONENTS);
    //vP1.getMethod(ConstantVectorProfileMethod.class).getQuantity().setComponents(5.0, 0.0, 0.0);
  
    //Set turbulence parameters - TURBULENT INTENSITY and VISCOSITY RATIO at INLET boundary
    TurbulenceIntensityProfile TI = b1.getValues().get(TurbulenceIntensityProfile.class);
    TI.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.02);

    TurbulentViscosityRatioProfile TVR = b1.getValues().get(TurbulentViscosityRatioProfile.class);
    TVR.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(5.0);
	
    //Specify fluid temperature in [K] at INLET
    StaticTemperatureProfile Tin = b1.getValues().get(StaticTemperatureProfile.class);
    Tin.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(323.0);
	
  //Get boundary named OUTLET and pressure boundary CLASS
  Boundary b2 = cfd.getBoundaryManager().getBoundary("OUTLET");
  StaticPressureProfile sP0 = b2.getValues().get(StaticPressureProfile.class);
    
    //Specify static pressure at OUTLET boundary
    b2.setBoundaryType(PressureBoundary.class);
    sP0.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.0);
  
    //Specify back flow turbulence parameters at OUTLET boundary
    TurbulenceIntensityProfile TI2 = b2.getValues().get(TurbulenceIntensityProfile.class);
    TI2.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(0.01);

    TurbulentViscosityRatioProfile TVR2 = b2.getValues().get(TurbulentViscosityRatioProfile.class);
    TVR2.getMethod(ConstantScalarProfileMethod.class).getQuantity().setValue(2.0);
	
    //Other options for reverse flow specifications
    b2.getConditions().get(BackflowDirectionOption.class).setSelected(BackflowDirectionOption.EXTRAPOLATED);
    b2.getConditions().get(BackflowDirectionOption.class).setSelected(BackflowDirectionOption.BOUNDARY_NORMAL);
    b2.getConditions().get(ReversedFlowPressureOption.class).setSelected(ReversedFlowPressureOption.ENVIRONMENTAL);
    b2.getConditions().get(ReversedFlowPressureOption.class).setSelected(ReversedFlowPressureOption.STATIC);
    b2.getConditions().get(ReferenceFrameOption.class).setSelected(ReferenceFrameOption.LOCAL_FRAME);
    b2.getConditions().get(ReferenceFrameOption.class).setSelected(ReferenceFrameOption.LAB_FRAME);
    b2.getConditions().get(KeTurbSpecOption.class).setSelected(KeTurbSpecOption.INTENSITY_LENGTH_SCALE);
    b2.getConditions().get(KeTurbSpecOption.class).setSelected(KeTurbSpecOption.INTENSITY_VISCOSITY_RATIO);
	
  //Save SIM file by specifying full path - note double backslashes
  getSim.saveState(resolvePath("C:\\STAR_CCM\\PipeFlow.sim"));
  
  //Close the simulation scene
  getSim.close(true);
}

Another macro recorded in STAR-CCM+ V14.x:
// STAR-CCM+ macro: Macro.java, Written by STAR-CCM+ 14.02.012
package macro; import java.util.*;
import star.common.*; import star.base.neo.*; import star.segregatedflow.*;
import star.material.*; import star.turbulence.*; import star.rsturb.*;
import star.vis.*; import star.flow.*; import star.kwturb.*;

public class Macro extends StarMacro {
 public void execute() { 
   execute0(); 
 }
 private void execute0() {
  Simulation sim_0 = getActiveSimulation();
  ImportManager IM_0 = sim_0.getImportManager();

  IM_0.importMeshFiles(new StringVector(new String[] {resolvePath("D:venturi.ccm")}), 
    NeoProperty.fromString("{\'FileOptions\': [{\'Sequence\': 42}]}"));

  FvRepresentation fvRep0 = ((FvRepresentation) 
    sim_0.getRepresentationManager().getObject("Volume Mesh"));

  Region region_0 = sim_0.getRegionManager().getRegion("fluid");
  fvRep0.generateCompactMeshReport(new NeoObjectVector(new Object[] {region_0}));

  sim_0.getSceneManager().createGeometryScene("Geometry Scene", "Outline", "Geometry", 1);
  Scene scene_0 = sim_0.getSceneManager().getScene("Geometry Scene 1");
  scene_0.initializeAndWait();

  PartDisplayer PD_0 = ((PartDisplayer) scene_0.getDisplayerManager().getDisplayer("Outline 1"));
  PD_0.initialize();

  PartDisplayer PD_1 = ((PartDisplayer) scene_0.getDisplayerManager().getDisplayer("Geometry 1"));
  PD_1.initialize();

  SceneUpdate sceneUpdate_0 = scene_0.getSceneUpdate();
  HardcopyProperties hardcopyProperties_0 = sceneUpdate_0.getHardcopyProperties();
  hardcopyProperties_0.setCurrentResolutionWidth(1506);
  hardcopyProperties_0.setCurrentResolutionHeight(618);
  scene_0.resetCamera();

  sim_0.saveState("D:\\STAR\\Venturi.sim");
 }

 private void execute1() {
  Simulation sim_0 = getActiveSimulation();

  MeshManager MM_0 = sim_0.getMeshManager();
  Region region_0 = sim_0.getRegionManager().getRegion("fluid");
  MM_0.convertTo2d(1.0E-18, new NeoObjectVector(new Object[] {region_0}), true);

  Scene scene_0 = sim_0.getSceneManager().getScene("Geometry Scene 1");
  CurrentView currentView_0 = scene_0.getCurrentView();
  currentView_0.setInput(new DoubleVector(new double[] {0.0, 0.0, 0.0}), 
    new DoubleVector(new double[] {0.0, 0.0, 1.0}), 
    new DoubleVector(new double[] {0.0, 1.0, 0.0}), 1.143640, 0, 30.0);
  scene_0.resetCamera();

  Region region_1 = sim_0.getRegionManager().getRegion("fluid 2D");
  region_1.setPresentationName("FLUID");

  Boundary BN_0 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region");
  Boundary BN_1 = region_1.getBoundaryManager().getBoundary("cyclic 2");
  MM_0.combineBoundaries(new NeoObjectVector(new Object[] {BN_0, BN_1}));
  MM_0.splitBoundariesByAngle(89.0, new NeoObjectVector(new Object[] {BN_0}));
  BN_0.setPresentationName("Axis");

  Boundary BN_2 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region 2");
  BN_2.setPresentationName("Outlet");

  Boundary BN_3 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region 3");
  BN_3.setPresentationName("Inlet");

  Boundary BN_4 = region_1.getBoundaryManager().getBoundary("Default_Boundary_Region 4");
  BN_4.setPresentationName("Wall");

  PhysicsContinuum Cm_0 = ((PhysicsContinuum) sim_0.getContinuumManager().getContinuum("Physics 1"));

  sim_0.getContinuumManager().remove(Cm_0);

  PhysicsContinuum Cm_1 = ((PhysicsContinuum) sim_0.getContinuumManager().getContinuum("Physics 1 2D"));

  Cm_1.setPresentationName("Physics 1");

  Cm_1.enable(SteadyModel.class);
  Cm_1.enable(SingleComponentLiquidModel.class);
  Cm_1.enable(SegregatedFlowModel.class);  
  Cm_1.enable(ConstantDensityModel.class);
  
  Cm_1.enable(TurbulentModel.class);
  Cm_1.enable(RansTurbulenceModel.class);
  Cm_1.enable(ReynoldsStressTurbulence.class);
  ReynoldsStressTurbulence RSM_0 = Cm_1.getModelManager().getModel(ReynoldsStressTurbulence.class);
  Cm_1.disableModel(RSM_0);

  Cm_1.enable(KOmegaTurbulence.class);
  Cm_1.enable(SstKwTurbModel.class);
  Cm_1.enable(KwAllYplusWallTreatment.class);
  
  sim_0.saveState("D:\\STAR\\Venturi.sim");
 }
}

Field Functions in STAR-CCM+

Field functions are mathematical expressions to define boundary conditions, material properties and booleans. Few basic rules that applies to creating Field Functions in STAR are described below.
  1. The name of field functions can contain few special characters: For example 'Split@X=0.50[m]' is a valid name.
  2. If the name contains any non-alphanumeric characters other than underscore '_', enclose the field function name in curly braces, '{...}' such as ${Split@X=0.50[m]} or ${test-Temperature}.
  3. Creating Field Function Expressions: color code to guide the editing process
    • Green indicates a syntactically correct reference to an existing field function
    • Parentheses appear in yellow to indicate the matching parenthesis
    • Red indicates an incorrect entry
    • If a field function reference has red text (but no black text or red background) the color represents a syntactically correct reference to a field function that does not yet exist
    • Field function definitions are always done in SI units, independent of the units that you use for input or display.
  4. Scalars are defined with single $ such as $Pressure or $Time and vectors with $$ such as $$Position and $$Velocity
  5. Field function names are case-sensitive. Thus, $Time and $time or $Radius and $radius are not same. Since the names are case-sensitive, they must be entered in the field function definition exactly as they are shown in the function name.
  6. Field functions access data on specific parts that are defined in the simulation
  7. Field functions used to define expressions cannot be a function of space that is (x, y, z). They must evaluate to a single number as the expressions are constants in space. Variables such as $Time, $TimeStep, and $Iteration are valid where as variables such as $Temperature or $Pressure are not valid as they have different values at every point in space and hence cannot be used in expressions.
  8. Literal constants can have a unit specification in a different system and are parsed at run time. The syntax for the units is <number units>. For example: <0.001 kg/m/s>, <10 psi>, <0.05 lb/ft^3> The character hyphen "-" binds tighter than "/", so kg/m-s^2 equals (kg)/(m-s^2) not (kg/m)*(s^2).
  9. When defining an expression or a field function that reference other field functions within it, prefixed that Field Function with $, such as $vol_flow_rate.
  10. Components of vectors are retrieved by adding additional $ such $$Velocity[0], $$Velocity[1] and $$Velocity[2] refer to X-, Y- and Z-components of the velocity vector. Subscript operator [] is appended to access components of the vector with indices of [0], [1], or [2].
  11. $$Position(@CoordinateSystem("CylCS"))[0] - The components of a local cylindrical coordinate system is defined by @CoordinateSystem(<Name of Coordinate System>) where <Name of Coordiante System> = "CylCS" in this example. Note that $$Position[0], $$Position[1] and $$Position[2] refer to r, θ and z axes respectively.
  12. When field functions are accessed on boundary parts, following rules by default: 1) If the data is stored on the boundary, the boundary data are accessed. For example "wall velocity" values stored in wall boundaries. 2)If the data is not stored on the boundary, the cell data from the cells in the region adjacent to selecte boundary are accessed. For example, wall-adjacent fluid velocity are stored in the cells.
  13. When Ignore Boundary Values option is switched ON, the field function is evaluated from the data stored for cell next to the boundary.
  14. To define a vector, array or position field function in terms of its components, specify the 3 components inside square brackets separated by commas: [($$Centroid[0] <= 1.0) ? 2.5 : 0.0, 0.0, 5.0]
  15. Initialize a particular volume: $${Position}[0] >= 0.50 && $${Position}[1] <= 1.00 && $${Position}[0] <= 2.50 && $${Position}[1] >= 0.25 ? 300 : 323 - this sets temperature in a cuboid to 323 [K]. To initialize a field variable in spherical volume: $$Position( @CoordinateSystem( "Laboratory.spheric" ) ) <= 0.50 ? 323 : 300. This is equivalent to: if($$Position( @CoordinateSystem( "Laboratory.spheric" ) ) <= 0.50, 323, 300).
  16. Set transient boundary condition where temperature ramps up linearly from 300K to a value of 500 [K] at a time of 5 [s]. ($Time >= 5.0) ? 500 : 300 + (500 - 300)/5.0*$Time. This is short form of conditional IF-ELSE statement. Ternary operator "? :" defines a condition operation similar to the C language.
  17. Divergence of velocity ∇.v = div($$Velocity), Divergence of density, velocity ∇.ρv is specified as: div($Density * $$Velocity), Gradient of pressure ∇p is specified as: grad($Pressure), Curl of velocity ∇×v is specified as: curl($$Velocity).
  18. Pressure ratio to get pressure in atmosphere [atm] unit: ${AbsolutePressure}/101325.0. Note that the default pressure option in Star CCM+ is given as absolute pressure rather than the relative presure.
  19. User field functions can be previewed by without actually running the simulation. The output values for the dependent variable is calculated by substituting the values of each of the independent variables and sweeping through the specified range.
  20. The dot product can be used to find components of a vector where unit($$Area))*unit($$Area) is used to define unit vector for area. For example, normal component of wall shear stress: sN = dot($$WallShearStress, unit($$Area)) * unit($$Area). Since, $WallShearStress is a vector sum of normal and tangential shear stresses, sT = $$WallShearStress - $$sT
  21. Multiple if conditions - Split a region (Split Regions by Function dialog) into 3 parts: ($$)Position[1] <= 2.5) ? 1 : (($$Position[1] >= 0.5) ? 2 : 0). In this case, after the split: The cells where 0.5 < y < 2.5 belong to Region 1, as the field function does not affect them. The cells where y ≤ 0.5 belong to Region 1 2, as it is the created region with the least cells. The cells where y ≥ 2.5 belong to Region 1 3, as it is the created region with the most cells.
  22. stepFun = ($$Centroid[2] <= 50) ? 0 : 1 - this creates a step function at the global z-coordinate of centroids of cell ≤ 50
  23. Field function for temperature dependent thermal conductivity: thCondAir = 1.52e-11 * pow($Temperature,3) - 4.86e-8 * pow($Temperature,2) + 1.02e-4 * $Temperature - 3.93e-4 where T is in [K]. As per the formulat, thCondAir = 0.0262 [W/m-K] at T = 300 [K].

public class CreateUserFieldFunctions extends StarMacro {
  public void execute() {
    execute0();
  }
  private void execute0() {
    Simulation sim_0 = getActiveSimulation();

  UserFieldFunction uFF_0 = simulation_0.getFieldFunctionManager().createFieldFunction();
  uFF_0.getTypeOption().setSelected(FieldFunctionTypeOption.SCALAR);
  uFF_0.setPresentationName("R1");
  uFF_0.setFunctionName("R1");
  uFF_0.setDefinition("0.50");
	
  UserFieldFunction uFF_1 = sim_0.getFieldFunctionManager().createFieldFunction();
  uFF_1.getTypeOption().setSelected(FieldFunctionTypeOption.SCALAR);
  uFF_1.setPresentationName("Radius");
  uFF_1.setFunctionName("Radius");
  x = $$Position[0]
  y = $$Position[1]
  uFF_1.setDefinition("sqrt(x*x + y*y)");
  }
}

Scripting in ANSA

ANSA uses Python as scripting and automation capabilities.
import os
import ansa
#from ansa import *
from ansa import base
def openFile():
	base.Open("C:/Users/myFile.ansa")
#Collect sets for different areas
deck = ansa.constants.LSDYNA
set1 = ansa.base.PickEntities(deck,("SET",))
parts = base.PickEntities(deck, ("SECTION_SHELL","SECTION_SOLID",))
set2 = base.CreateEntity(deck, "SET", {'Name' : "SetName", })
set3 = base.CollectEntities(deck, None, "__PROPERTIES__", )
def printPIDname():
	deck = constants.OpenFOAM  #NASTRAN, FLUENT, STAR, LSDYNA
	pid_list = base.collecEntities(deck, none, "PSHELL", False, True)
	#pid_list = base.collecEntities(deck, none, "__PROPERTIES__", False, True)
	for pid in pid_list:
		print(pid._name)
		oldPID = pid._name
		if "grille" in oldPID:
			newPID = "po_"+oldPID
			base.ReplaceProperty(oldPID, newPID)
		#subifm($,'oldPID','newPID')
def openMultipleFiles():
    #Select multiple files
	files = utils.SelectOpenFileIn('C:/Users/XYZ', 1)
	i = 1
	for f in files:
		print("File Number {1} is {2}:", i, f)
		#Opening the file
		ansa.base.Open(f) 
		i = i + 1
#Print all PID and their names
import ansa
from ansa import *

idList = []
nameList = []
def main():
	deck = constants.LSDYNA
	pName = base.CollectEntities(deck, None, "__PROPERTIES__", False, True)
	for i in part_name:
		idList.append(i._id)
		nameList.append(i._name)
        pass
main()
mergeList = list(zip(idList, nameList))
for i in mergeList:      
    print(i)
	if __name__ == '__main__':
		main()

Scripting in CFX and CFD-Post

A CCL or CFX Command Language file required for scripting and automation in CFX is as follows. This file can also be used to set orthotropic thermal conductivity which is otherwise not possible through GUI. PERL statements can be directly embedded in CCL syntax. CCL syntax starting with '>' is execution statement. The PERL statements start with '!'. \ is the line continuation character and lists are separated by comma. CFD-Post session file have extension .cse (CFX SEssion) and .cst (CFX STate). Nested loop in CEL: if(var1=val1, val2, if(var2=val3, val4, if(var3=val5, val6, val6))). Condition statement with Boolean: if (0.005[m] <= x && x <= 0.025[m], 2.50, 7.50). Variables and expressions are case sensitive, for example t vs T. Units can be mixed so long they are dimensionally consistent for addition and subtraction operations (example: 1.0 [mm] + 0.45 [inch] is valid expression.

Conditional If Statement: example to set inlet temperature to 300 [K] for the first 50 iterations then increase it to 325 [K] after 50 iterations: inleTemp = 300 [K] + if(aitern >= 50, 25 [K], 0 [K]). Here aitern = Accumulated Iteration Number. The inside() function returns 1 when inside the specified location and 0 when outside - this is useful to limit the scope of a function to a subdomain or boundary. The step() function return 1 when the argument is positive and 0 when the argument is negative. This is useful as an on-off switch and alternatively if() function can also be used as a switch. sqrt(X^2 + Z^2) defines distance from the Y-axis and sqrt(X^2 + Y^2 + Z^2) defines a sphere. sqrt(X^2 + Y^2 + (Z - 0.5[m])^2) moves the sphere by a distance of 0.5 m in the positive Z direction.

Basics of PERL

Perl statements are terminated by a semicolon (;), Whitespace and indentation do not matter except for making the code readable, Everything is case sensitive, Comments are preceded by a pound sign (#) and there are no multi-line comments (e.g. /* [..] */ in C++). Variable type is implied, not declared. Leading character determines return type *Scalars: $… Denotes a ‘single’ value and can be a number, character string, pointer, array element. Linear Arrays: @… where elements are referenced by position, elements may be any type (scalar, array, hash). Example: @evens=(2,4,6,8); Access a array elements using $listName[indices]; such as $four = $evens[1]; ($six,$eight) = $evens[2,3]; Hash (associative array): % where elements are referenced by lookup (associative), elements may be any type and useful for nested data.

Strings are a quoted group of characters: double-quoted (") and single-quoted (') strings are handled slightly differently. Double quoted strings act a lot like strings in C which can include "backslash escapes" to represent special characters. String operators: concatenation (. or .=) "hello" . "world", string repetition (x): "Name" x 3 = "NameNameName". The chomp($a) function removes the last character from a string if it is a newline (\n).

Arrays (lists): To determine the size of an array, use ‘scalar(@listName)’. Useful array functions are: push, pop: To add/remove elements from the high end of a list such as push(@list,$newValue) or push(@list,@moreElements), $oldValue=pop(@list). shift, unshift: To add/remove elements from the low end of a list. reverse: reverses the order of the elements in a new list such as @backwardList=reverse(@forwardList). sort: sorts the elements in ASCII order into a new list e.g. ordered=sort(@unordered).

Logical Operators: ‘!’ will negate any logical expression (i.e. 'not'), && is a logical 'and' || is a logical 'or'.

Examples of Expressions
dP = massFlowAve(Pressure)@inlet - massFlowAve(Pressure)@outlet
Pv = 0.5 * areaAve(Density)@Inlet * areaAve(Velocity)@Inlet^2
areaAve(p)@Inlet - area-weighted average of 'pressure' on the boundary named 'Inlet'
area()@REGION:Inlet - area of a 2D mesh region named 'Inlet' belonging to domain REGION. area_x()@Inlet is area projected in direction 'X'.
massFlow()@Inlet: mass flow rate through 'Inlet'. Add multiple zones separated by space. e.g. massFlow()@Out1 Out2 Out3
>calculate area, Inlet, - calculates the area of the locator 'Inlet'. Note that adding the comma after 'Inlet' removes the axis specification
@Xlocs = (0.05, 0.10, 0.15, 0.20) - define a list in PERL, $Xlocs[$i] - accesss a member in the list
volumeInt(Density)@Tank - calculate mass of fluid in volume named 'Tank'

Print mass flow rate, area and area-average velocity on single line: here 'front' is the name of the boundary. !print("front: Mass Flow Rate [kg/s] = 10%5f, Area [m^2] = %10.6f, Area-Avg-Velocity [m/s] = %10.2f", massFlow("front"), area("front"), areaAve("Velocity", "front"), "\n");


Booleans in CEL: Let's write an expression as dx = (x ≥ 0.05 [m] && x ≤ 0.25 [m]). The value of dx for 3 different values of x are as follows:

  • x = 0.0, dx = 0
  • x = 0.2, dx = 1
  • x = 0.5, dx = 0

Note that this expression can be used to define a finite cylinder of radius 0.1 [m] on x-axis between x = 0.05 [m] and x = 0.25 [m]. fincyl = (y*y + z*z ≤ 0.1*0.1 && x ≥ 0.05 [m] && x ≤ 0.25 [m])


Example PERL script - use it in command editor, the output would be printed in CFD-Post terminal.

! ($MFinlet, $MFunit) = evaluate("massFlow()\@Inlet");
! printf (Mass Flow at Inlet "%10.5f [$MFunit] \n", $MF01);

! for ($i = 1; $i <= 8; $i++) {
!  if ($i < 10) { 
!   $i = '0'.$i; 
!  }
!
!  ($ARi, $ARunit) = area()@OUTLET_.$i;
!  ($MFi, $MFunit) = massFlow("OUTLET_.$i");
!  printf("OUTLET_.$i = %10.5f [$ARunit], MF = %10.5f [$MFunit] \n", $ARi, $MFi);
! }

Write output or results of function calculators to a FILE.

! $AvQ=areaAve("Wall Heat Flux", "WALL_CYL");
! open(RESULT, ">Output.dat");
! print RESULT "$AvQ\n";
! close(RESULT);

Create a PLANE in CFD-Post


Create a pressure contour on PlaneYZ created earlier.


Set Camera Views, Show/Hide Contours and save hardcopies

# Sending visibility action from ViewUtilities
>show /CONTOUR:ContourPlaneYZ, view=/VIEW:View 1
# Sending visibility action from ViewUtilities
>hide /PLANE:PlaneYZ, view=/VIEW:View 1
>setcamera viewport=1, camera=-X
HARDCOPY:
  Antialiasing = On
  Hardcopy Filename = Orifice_Walled_Duct_HighTI_001.png
  Hardcopy Format = png
  Hardcopy Tolerance = 0.0001
  Image Height = 600
  Image Scale = 100
  Image Width = 600
  JPEG Image Quality = 80
  Screen Capture = Off
  Use Screen Size = On
  White Background = On
END
>print 

CCL and PERL are case sensitive.

COMMAND FILE:
  CFX Pre Version = 12.1
END
# Define variables in a PERL file and include with 'require' statement
! require "VarCFX_Pre.pl";
>load mode=new
>update

>gtmImport filename=$FCFX5, type= Generic, genOpt= -n, units=mm, \
nameStrategy=$Name
>update
>writeCaseFile filename=$CASE
>update

LIBRARY:
 CEL:
  EXPRESSIONS:
   CpAir=1005.6 [J kg^-1 K^-1] + 5.6E-3 [J kg^-1 K^-2] * T
  END
 END
END
>update
LIBRARY:
 CEL:
  EXPRESSIONS:
   kAir = -3.9333E-4[W m^-1 K^-1] + 1.0184E-4 [W m^-1 K^-2]*T \
    -4.8574E-8 [W m^-1 K^-3]*T*T + 1.5207E-11 [W m^-1 K^-4]*T^3
  END
 END
END
>update
LIBRARY:
 CEL:
  EXPRESSIONS:
   MuAir=1.72E-5 [kg m^-1 s^-1] *(T / 293 [K])^0.742
  END
 END
END
>update
LIBRARY:
 CEL:
  EXPRESSIONS:
   AvHeatFlux=areaAve(Wall Heat Flux )@REGION:$WallName
  END
 END
END
>update

Set Boundary Conditions and Solver Parameters

FLOW: Flow Analysis 1
  &replace   OUTPUT CONTROL:
    MONITOR OBJECTS:
      MONITOR BALANCES:
        Option = Full
      END # MONITOR BALANCES:
      MONITOR FORCES:
        Option = Full
      END # MONITOR FORCES:
      MONITOR PARTICLES:
        Option = Full
      END # MONITOR PARTICLES:
      MONITOR POINT: Mon1
        Expression Value = VF
        Option = Expression
      END # MONITOR POINT:Mon1
      MONITOR RESIDUALS:
        Option = Full
      END # MONITOR RESIDUALS:
      MONITOR TOTALS:
        Option = Full
      END # MONITOR TOTALS:
    END # MONITOR OBJECTS:
    RESULTS:
      File Compression Level = Default
      Option = Standard
    END # RESULTS:
  END # OUTPUT CONTROL:
END # FLOW:Flow Analysis 1
> update
> writeCaseFile
> update
> writeCaseFile filename=$DEF, operation=start solver interactive
# operation="write def file" or "start solver batch"

Post-processing statements in PERL


File Search in Windows 10

From Command Line - search files bigger than 10 MB --- forfiles /P F:\DataFiles\XYZ /M * /S /C "cmd /c if @fsize GEQ 10485760 echo @path > bigFiles.log" --- note that it creates files bigFiles.log in each sub-directory of parent directoty [F:\DataFiles\XYZ in this case]

Here GEQ = ≥, 1kB = 1,024 bytes -- 1 MB = 10,48,576 byts -- 1 GB = 1,07,37,41,824 bytes. forfiles takes following arguments: /P "pathname" - Specifies the path from which to start the search. By default, searching starts in the current working directory. /M "searchmask" - Searches files according to the specified search mask. The default searchmask is *. /S - Instructs the forfiles command to search in subdirectories recursively. /C "command" - Runs the specified command [should be wrapped in double quotes] on each file. Default command is "cmd /c echo @file".

File Search by Size in Windows

The options and range of file size which is seached is summarized as follows:
  1. small: 16kB ~ 1 MB
  2. medium: 1 ~ 128 MB
  3. large: 128 MB ~ 1 GB
  4. huge: 1 ~ 4 GB
  5. gigantic: > 4 GB
  6. size: > 100MB can be used to each for files having size > 100 MB. Similarly, size: > 50MB < 80MB can be used to find the files having size in a specified range.

DOS Scripts: Batch Scripting for Windows

'DOS' (the Disk Operating System) is used to describe cmd (ther command terminal). In Windows OS, DOS commands are stored in a text file with extension *.bat (BATch) files. These files can be used to run program in batch (non-GUI) mode and automated repeated tasks. By default, a batch file will display its command as it runs. Command "echo off" turns off the display for the whole script, except command itself. Sign '@' in front makes the command apply to itself as well. echo. prints an empty (blank) lines.

Colour of Fonts and Terminal Window: "colour bg_colur fg_colour" is used to set the font (foreground) and terminal window (background) colours. Colours are hexadecimal numbers as per the table below:

NumberColourNumberColourNumberColourNumberColour
0Black4Red8Gray CLight Red
1Blue5Purple9Light BlueDLight Purple
2Green6YellowALight GreenELight Yellow
3Aqua7WhiteBLight AquaF Bright White

Command: "colour 70" (without double quotes) shall change the appearance of terminal to white background and black fonts.

  • The redirect operator > directs the output to specfied location (terminal, file...). >> is used to append the output to an existing content
  • The command line arguments can be called through the variables %1, %2, %3 and so on - Inside batch files, the variables are referred by %%x as compared to %x on command line
  • Variables: set /A X=10, echo %X%, SET /A c = %a% + %b% - variable is assigned using 'set' command and value is accessed using %...% operator
  • %homepath% ≡ %userprofile% where both refers to home directory of the users typically C:\Users\UserName
Batch scripts support the concept of command line arguments which can be accessed from the batch files through the variables %1, %2, %3... up to 9 parameters passed in this way. And %* refers to 'all' arguments passed to the command.

Get User Input while Running a Batch Script: set /p "choice= Choose Option (1: ANSYS, 2: STAR, 3: Both -- ". Note that the space after = is important and %choice% can be used as a parameter to another command or conditional operator say IF-block.


Run multiple commands one after another in DOS Terminal- Conditional Execution: Linux and Powershell use semi-colon ; to concatenate commands (similar but not exactly same as & described below). Use of semi-colon executes all commands in the chain irrespective of success or failure in each command. && and || works in Powershell as described below.

  • command1 & command2: runs the first command, and then the second command
  • command1 && command2: run the command following && only if the command preceding the symbol is successful
  • command1 || command2: run the command following || only if the command preceding || fails
  • (command1 & command2): Use to group or nest multiple commands. Linux use curlay braces { command-list; } to group commands - note the semi-colon at the end of command list.
  • ; or ,: command1 parameter1;parameter2 - Use to separate command parameters.

Examples:

  1. The conditional execution & starts next task after execution of previous task has (whether with error or with success) finished: e.g. ocrmypdf --output-type pdf --skip-text -l hin+eng In-1.pdf Out-1.pdf & ocrmypdf --output-type pdf --skip-text -l hin+eng In-2.pdf Out-2.pdf
  2. The conditional execution & starts next task after execution of previous task has successfully finished: e.g. ocrmypdf --output-type pdf --skip-text -l hin+eng In-1.pdf Out-1.pdf && ocrmypdf --output-type pdf --skip-text -l hin+eng In-2.pdf Out-2.pdf
  3. Additionally, the double pipe || symbols start the next command if the previous command fails
  4. Alternatively, add all the commands line by line in a batch file, and save the file as say batchRuns.bat. Execute that batch file which would run all the commands sequentially in the order they are stored in the file. A batch file executes a command and waits until the command is finished, then runs the next command. Use start to start the batch file: e.g. start "" batchRuns.bat - The empty pair of double-quote marks is for the "Title" that will be shown in the title bar of the command window that start command will open.

Global and Local Scope of Variables: By default, variables are global for entire batch script. SET LOCAL ... END LOCAL block can be used to make variables local in scope.

  • % is used to refer to a variable: e.g. %f IN (in*.f) where %f refers to file names matching 'in*.f'
  • REM (REMark) or :: is used for comments. DOS commands are not case-sensitive
  • Line continuation: You may break up long lines of code with the caret ^. Put it at the end of a line, next line must have space at the begining
  • pause will display: Press any key to continue . . .
  • dir /T:W >> list.txt: write files of the current folder into file list.txt
  • dir /T:W C:\commands.docx: Get the last modified time for the file 'C:\commands.docx'
  • dir /T:W -> Get modified date/time for all files and folders in the current directory
  • dir /T:W /A:-D -> Get modified date/time only for files in the current directory (exclude folders)
  • Using forfiles command we can get modified date/time for all files in a directory: forfiles /C "cmd /c echo @file @fdate @ftime"
  • Restrict the command only to certain files using * command. E.g. get modified time/date only for pdf files: forfiles /M *.pdf /C "cmd /c echo @file @fdate @ftime"
  • List the content of folder and its sub-folders: dir C:\XYZ /ad /b /s > List.log
  • rmdir /q /s "%%I" -> it will delete directories quietly and removes all files, sub-folders and the directory itself
  • Calls another batch file and returns control to the first when done: CALL C:\NEW.bat
  • To echo or escape a special character, precede them with a caret: ECHO ^<
  • Spliting strings: "tokens=1-5 delims=/ " - How many tokens the incoming data (in this case the date) will be broken into. 1-5 is five different tokens. The 'delims' argument is short for delimiters and is what is used to break up the date, in this example the / (forward slash) and a space (space before the quote)
  • for /f "tokens=1-5 delims=/ " %%d in ("%date%") do rename "hope.txt" %%e-%%f-%%g.txt, use the date command within the for command to extract the current date and use that data to rename the file. Note tokesn=1-5 makes %%d expand into 5 variables %%d, %%e, %%f, %%g, %%h. for /F always skips the empty lines.
  • %d is explicitly declared in the for statement, %e, %f, %g and %h are implicitly declared by using tokens=. You can use tokens= to specify up to 26 tokens, provided that it does not cause an attempt to declare a variable higher than the letter z or Z
  • FINDSTR: searches for string in a file and returns the entire line that contains the that string. Lines staring with semi-colon ; shall be skipped as default option for END-OF-LINE (EOL) is semi-colon.
  • str = %str:=% - removes all spaces in the string. Similarly str = %str:=chr% shall remove all occurrences of 'chr' from the string.

File parsing consists of reading the output, string, or file content, and then breaking it into individual lines of text and parsing each line into zero or more tokens.

Escape Character:

To display an exclamation mark (!) in batch scripts, wrap the word or phrase in double quotes followed by a caret before the exclamation mark ("Hello World^!"). Alternatively, a double caret (^^) can be used without the need for double quotes (Hello World^^!).

To display a pipe (|), ampersand (&) or redirection character (< or >) when you are using echo, use a caret (^) immediately before that character. For example, ^|, ^&, ^>, or ^<. To display a caret, type two carets in succession (^^).

Arithmetic Operations and Expressions:

The SET /A command allows the result of a mathematical expression to be assigned to a variable: SET /A c = %a% - %b%

Create Arrays and Lists

An array is created by using the set command: set a[0]=1 or set list = 1 2 3 5 8 13. Access the value of an array or a list: %a[1]%, Length of array: there is no direct function, length of an array can be calculated by iterating over the list of values in the array.
set "n = 0" 
:arrayLength 
if defined Ar[%n%] ( 
   call echo %%Ar[%n%]%% 
   set /a "n = n + 1"
   GOTO :arrayLength 
)
echo "The length of the array is" %n%

Reference: learn.microsoft.com/en-us/ windows-server/administration/ windows-commands/findstr

findstr [/b] [/e] [/l | /r] [/s] [/i] [/x] [/v] [/n] [/m] [/o] [/p] [/f:<file>:] [/c:<string>] [/g:<file>:] [/d:<dirlist>] [/a:<colorattribute>] [/off[line]] <strings> [<drive>:][<path>]<filename>[ ...] ---Options--- /b: Matches the text pattern if it is at the beginning of a line. /e: Matches the text pattern if it is at the end of a line. /l: Processes search strings literally. /r: Processes search strings as regular expressions. This is the default setting. /s: Searches the current directory and all subdirectories. /i: Ignores the case of the characters when searching for the string. /x: Prints lines that match exactly. /v: Prints only lines that don't contain a match. /n: Prints the line number of each line that matches. /m: Prints only the file name if a file contains a match. /o: Prints character offset before each matching line. /p: Skips files with non-printable characters. /off[line]: Does not skip files that have the offline attribute set. /f:<file>: Gets a file list from the specified file.

Example: To find all occurrences of lines that begin with DEFGH and are preceded by zero or more spaces, and to display the line number where each occurrence is found: findstr /b /n /r /c:^ *DEFGH *.txt

Example: To search for 'hello' or 'there' in file List.txt: findstr hello there x.y, To search for "Batch Script" in file UserGuide.txt, type: findstr /c:"Batch Script" UserGuide.txt

/c:<string>: Uses the specified text as a literal search string. /g:<file>: Gets search strings from the specified file. /d:<dirlist>: Searches the specified list of directories. Each directory must be separated with a semicolon (;), for example dir1;dir2;dir3. /a:<colorattribute> - Specifies color attributes with two hexadecimal digits. Type color /? for additional information. <strings> - Specifies the text to search for in filename. Required. [\<drive>:][<path>]<filename>[...] - Specifies the location and file or files to search. At least one file name is required. /?: Displays Help at the command prompt.


String Concatenation: Simply type the strings or variable like a sentence. E.g. echo This is String Concatenation, set str=%str1% %str2% %str3% - note NO space between 'str' and '='. Mid-string and sub-strings are created with :~ operator such as echo %str:~5,8% shall display characters 5 to 8 in string 'str'. set stg=%stg:~-5% shall use 5 character from the right (end of the string). Convert a string into number or evaluate an expression: set /A x = 10.

Delayed Expansion: In a command block ( ... ), all % variables are expanded before the block gets executed. !var_name! is used for delayed expansion.

Loops in Batch Scripts: To process a file: The arguments within brackets should be used without bracket - for example ["options"] should be replaced with something like "skip=10 tokens=5 delims=" where default delimiter for strings is a space or TAB. Almost any character can be used as a delimiter, but they are case sensitive. SKIP will skip processing a number of lines from the beginning of the file including empty lines, but after the SKIP is complete, FOR /F ignores (does not iterate) empty lines. It is recommended to always place delims as the last option before the closing quotation. File names with spaces have to be surrounded in "quotes" which have to be escaped using ^ such as ^"c:\Program Files\*.txt^"

FOR /F ["options"] %%var IN (filename) DO (
  command
)
To process a string: string or string variable should be within double quotes "...". A string of text is treated just like a single line of input from a file.
FOR /F ["options"] %%var IN ("Text String") DO (
  command
)
To process a command:
FOR /F ["options"] %%var IN ('command to run') DO (
  command
  echo Press any key to exit . . .
  pause>nul
)
Tokens
  • tokens=1,3,5 ( automatically sorted) will cause the first, third and fith items on each line to be processed
  • tokens=2-6 will cause the second, third, fourth, fifth and sixth items on each line to be processed
  • tokens=* will cause all items on each line to be processed
  • tokens=3* will process the third token and all subsequent items, this can also be written as tokens=3,*
  • Each token specified will cause a corresponding parameter letter to be allocated. The letters used for tokens are case sensitive
  • If the last character in the tokens= string is an asterisk (*), then additional parameters are allocated for all the remaining text on the line.

EXAMPLES

To find all occurrences of lines that begin with 'Users' and are preceded by spaces, and to display the line number where each occurrence is found, type: findstr /b /n /r /c:^ *Users List.txt. Use the following expression as part of a larger expression to match any string beginning with 'b' and ending with 'ing': b.*ing

Loops and Conditional Operators

Execute a command repeatedly: For /L %%a in (1, 1, 50) do echo %%a. Arument /L instructs 'for' command to Loop through a range of numbers, rather than operating on a set of files. for /D: Loop on directories only, for /R: recurse.

FOR /F "tokens=1,3 delims=," %%G IN (file.txt) DO @echo %%G %%H ≡ FOR /F "tokens=1,2,3 delims=," %%G IN (file.txt) DO @echo %%G %%I. for /f eol=; tokens=2,3* ... ignores any line starting with character semi-colon. This method can be used to ignore comments.

Merge Files:
FOR %f IN (in*.f) 
 DO 
  type %f >> ..\merge.txt & echo. >> ..\merge.txt

@echo off 
set list=1 2 3 4 
(for %%a in (%list%) do ( 
    echo %%a 
  )
  echo Press any key to exit . . .
  pause>nul
)

Open many files using NOTEPAD:
cd C:\Test
for %X in (*.f) 
 do 
   notepad %X

Create a file name based on current date and time:
Set Mn = %DATE:~7,2%
Set Yr = %DATE:~10,4%
Set Hr = %TIME:~0,2%
Set Mi = %TIME:~3,2%
dir "C:\XYZ"  /-C /O:GN /Q /S /T:A > "%Day%-%Mn%-%Yr% %Hr%-%Mi%.log"

Use of CONDITIONAL statements: Check if a file or directory exists

@echo off
if exist c:\XYZ goto exists
  echo Directory not found
  pause
goto end
:exists
  echo The directory exists
  echo .
:end
  Set FilePath=%FilePath%\%Day%
  IF NOT EXIST %FilePath% MKDIR %FilePath%
  @echo off

For if-else loops: both the closing and opening parentheses for else block should be on same line. That is ') else (' otherwise you will get an error: "else is not recognized as an internal or external command, operable program, or bath file".

find: Searches for a string of text in a file or files, and displays lines of text that contain the specified string

To search for a set of files, use wildcards. To search the current directory for files that start with 'Emp' and have the extension .txt and that contain the string UserID ignoring the case: find /i "userid" Emp*.txt . To find files names in a directory that contain the string CPU, use the pipe '|' to direct the output of the 'dir' command to the 'find' command: dir c:\Users /s /b | find "CPU".

Find Total Number of Occurrences: The example below counts the total number of e-mail ID by counting @ in the file Email.txt

set "count=0"
  for /F %N in ('find /C "@" ^< "Email.txt"') do (
    set "count=%N"
  )
  echo %count% 

Sort: Reads input, sorts data, and writes the results to the screen, to a file, or to another device. find /i "userid" Emp*.txt | sort.

Content in sample.batCommand in DOS shellOutput
echo %n0sample.batsample
echo %~x0sample.bat.bat
echo %~x1sample.bat input.txt.txt
copy %0 %~n0_new.txtsample.batsample.bat copied to sample_new.txt
copy %1 %~n1_new.txtsample.bat input.txtinput.txt copied to input_new.txt

Linux Commands and Utilities

Multiline comments: ;' ... ... '

Substring: subStr = ${str:5:3} where 5 is the starting point and 3 is the length of the string. Date can be parsed using Y, m, d, H, M and S characters. echo `date +%Y` or day = `date +%d`

String Concatenation a='Shell' b='Script' c="${a} ${b}" echo "${c}" -- Output would be "Shell Script".

Shell Parameter Expansion: Unlike in DOS, instead of '%' character, the ‘$’ character is used for parameter expansion, command substitution, or arithmetic expansion. If parameter is ‘@’ or ‘*’, the result is length positional parameters beginning at specified offset that is ${@:5} shall start at fifth position. ${#parameter} - the '#' or hash parameter expands into the length of the parameter. Other hash and double hash expansions are ${parameter#string} and ${parameter##string}: The 'string' is expanded to produce a pattern.

Let's consider a shell script names sample.sh and a command ./sample.sh input.txt is issued at the Bash prompt.
filename=$(basename "$1")
name="${filename%.*}"
# '##' parameter expansion operator
extn="${filename##*.}"
echo "File $name has extension $extn"
echo "${#name}" 
The output of each echo statement is as follow. echo "File $name has extension $extn" -- File input has extension txt, echo "${#name}" -- 5. If following lines are added to sample.sh, the file input.txt shall get copied to input_new.txt.
new_name="$name"_new."$extn"
cp $1 $new_name

Read Files

fileName = 'List.txt'
while read line; do
  echo $line
done < $fileName 
Print summary of size of directories: du -BM -c -d 1 -h Documents/ -- This prints size of only folder inside Documents/ and excludes files and sub-directories (their sizes are not printed but included in size calculation for patent folder). The size is automatically converted into human-readable Mega, Giga or kB formats. In order to sort the listings, you may pass the output from 'du' to 'sort' through a pipe: du -BM -c -d 1 -h Documents/ | sort -h where -h option instructs 'sort' to compare human-readable numbers such as 1k, 2.5M... In other words, the output shall get sorted in increasing order of size of the folders. You may add -r to reverse the order of listing. To exclude hidden files or folder, add --exclude="./.*" to the command. Similarly, to exclude files of type *.log, add --exclude='*.log'.

To print a folder size in specific format: du -c -s Documents/ | tail -1 | awk '{printf "\n Folder size is %.4f MB\n", ($1/1024)}' or du -c -s Documents/ | tail -1 | awk '{printf "\n Folder size is %.4f GB\n", ($1/1024^2)}' du prints file size in kB.

Note that the name of the folder is in the middle and you cannot pass it as argument. The likely next option to create an alias but it does not accept parameters. The option that shall work is to write a function which can be called just like an alias. Bash functions can be added to .bashrc file and accessed as commands within Bash shell. For example:
xdu() {
    du -c -s "$1" | tail -1 | awk '{printf "\n Folder size is %.4f GB\n", ($1/1024^2)}'
}
To get one-line syntax like aliases, you can append command using &&: dClean() { rm -i "$1" && cp -i "$2" "$1"; }

Install a package (program): sudo apt install okular

Uninstall a package excluding dependent packages: sudo apt remove okular

Uninstall a package including dependent packages: sudo apt remove --auto-remove okular

Uninstall a package including configuration and dependent packages: sudo apt purge okular

Uninstall everything related to a package (recommended before reinstalling a package): sudo apt purge --auto-remove okular


Before running any of the command dealing with file copy, remove, delete - make sure to back-up your data.

                   D A N G E R
                 .:^~!DDDDD!~^:.
              .~?YDDDDDDDDDDDDDY?!: 
            .?DDDDDDDDDDDDDDDDDDDDD?: 
           :YDDDDDDDDDDDDDDDDDDDDDDDD:
           ?DDDDDDDDDDDDDDDDDDDDDDDDD?
           DDDDDJ~^^~?DDDDDY!^^~DDDDD!
           \JDDY  Q  YDDDD:   Q  ?DD?
             DDD~.  .~DDDDDD.  .^YDD
             `YDDDYYDDDD  YDDYYYDDY
              ^?YDDDDDD   !DDDDDY?                             
      .~D~:       DYY?DDDDD?YY!       .^!~.
       .DDDDJ!.    ||JDDDDDJ||       ^?DDDD
        DDDDDD?!^:.             .^~DYDDDDD
     DDDDY??JYDDDDDJD~:. .:^!?YDDDDY?D?YDDDD
               :^!?JDDDYJYDDDY?!^:
                 .^DYDDDDDDDYD^.
             .^DJDDDD?!:.^!JDDDDJ!^.
      :~!D??JYDDDYD^.       .^DYDDDDJ?D!~^.
     !DDDDDDDDDD^               ^DDDDDDDDDD
       DDJDDDD                    ~DDDDY?

Note: All the commands and shell scripts mentioned here have been tested on Ubuntu 20.04 on Lenovo G50-45 x86_64 with GNOME version 3.36.8. Find or list all the files in current directory and sub-directrories modified in last 30 days. For any other directory, replace . with path of that folder: find . -mtime -90 -ls > toCopyBackup.txt --Note that 'ls' is interpreted as "ls -dils" which lists the complete details of each file including the size, owner, last modified date... To list only the full relative path of desired files: find . -mtime -90 > toCopyBackup.txt --Numeric arguments such as '90' here can be specified as: +n - for > n, -n for < n and n for exactly n.

The utility 'find' by default shall print the names of the folder (as folder are a type of file). To prevent printing the folder names, use: find . -mtime -90 -type f > toCopyBackup.txt.

Find and recursively copy all the files in current directory and sub-directrories modified in last 10 days (precisely 10 * 24 hours and not calendar days). Keep the source directory in parent folder to pwd (where this command is run) else you would get warning the files aleardy exist in backUpFolder. find . -mtime -10 -exec cp -r {} ../backUpFolder \; To exclude listing from a folder 'excludeFolder': find . -mtime -90 -not -path "./excludeFolder/*" > toCopyBackup.txt

-exec: Execute command until an argument consisting of ';' is encountered. The string '{}' is replaced by the current file name being processed Both of these constructions might need to be escaped (with a '\') or quoted to protect them from expansion by the shell.

What if a folder of same name already exist in destination folder ../backUpFolder? It (the folder) shall be overwritten and you may lose existing data. Use -n that is --no-clobber option which instructs cp to not overwrite an existing file (overrides a previous -i option). Thus it will be: find . -mtime -10 -exec cp -rn {} ../backUpFolder \;

If you want to specify a date: cp -rn `find . -type f -newermt '27 Apr 2023'` ../backUpFolder --- this method uses -newerXY option for command find where X = m and Y = t in this case.

Search for files modified between two dates find Documents/ -type f -mtime -90 ! -mtime -15 [Prints file modified between 90 to 15 days before today]. Next example prints only the file having rounded-up value of size ≥ 2 MB: find Documents/ -type f -size 2M -mtime -90 ! -mtime -5. Next example prints only the total sum: find Documents/ -type f -mtime -20 ! -mtime -10 -printf "%s\\n" | awk '{s = s+$1} END {printf "%.2f MB \n", s/1024^2}'. For files modified between two particular dates: find Documents/ -type f -newermt '10 Apr 2023' ! -newermt '10 Apr 2023'. To print folders, change -type f to -type d.

Search of folder modified between two dates and then print the size of files modified within same period. Remove -maxdepth 1 if you want to print the information for every sub-folder inside main or parent or root folder specified by variable dirName.

clear
d1='10 Apr 2023'
d2='30 Apr 2023'
dirName='Documents'
for dr in `find $dirName -maxdepth 1 -type d -newermt "$d1" ! -newermt "$d2"`; 
 do
  echo Processing $dr
  echo "---------------------------------------------------------------"
  fs=0
  for ss in `find $dr -type f -newermt "$d1" ! -newermt "$d2" -printf "%s\\n"`;
    do
      #In Bash shell, only integer arithmetic can be performed
      fs=$(((ss + fs)/1024))
    done
    echo Total size of files is approx. $fs MB
    echo $'===============================================================\n'
 done

Incremental Back-up of Files: Use the methods explained earlier to save the names of the desired files (based on modification date, size, type...) to a text file. Use the following shell script (save the content in a file say backUp.sh) and run it in terminal. Note that it dumps all the files listed in cat toCopyBackup.txt into target folder irrespective the absolute path of source files.

TARGET_PATH="./BackUp/" #Note there shouldn't be any space before or after =
clear
if [ -d "$TARGET_PATH" ]; then
  for file in `cat toCopyBackup.txt`; 
    do 
      cp "$file" $TARGET_PATH;
      filePath=(${file//// })
      echo Copied file ${filePath[-1]} 
    done
else
   echo Target directory $TARGET_PATH does not exist! 
fi 

Copy a Folder Structure: Before creating an incremental copy (added and modfified files or folders), one may first try to check the folder structure and update the missing or modified folders using following shell script. Note that the script checks for existence of only the TARGET folder and not the SOURCE folder.

clear
SOURCE_PATH="./Payment/"
TARGET_PATH="./back_Up/"
dirList='folderStruct.txt'
find $SOURCE_PATH -mtime -90 -type d > "$dirList"

if [ ! -d "$TARGET_PATH" ]; then
  echo Target directory $TARGET_PATH does not exist!
  mkdir $TARGET_PATH
  echo Target directory $TARGET_PATH created!
  echo "=============================================================="
fi
for file in $(cat $dirList);
    do
      echo Processing folder $file
      if [ ! $file = "." ]; then
        newPath=$TARGET_PATH${file:2:${#file}}
        if [ ! -d "$newPath" ]; then
          echo Target Folder: $newPath
          echo TARGET Folder Does not Exist, Creating it
          mkdir $newPath;
          echo -- Folder $newPath created
          echo "--------------------------------------------------------------"
          echo
        else
          echo "Target folder already exists, no new folder created!"
          echo "--------------------------------------------------------------"
        fi   
      fi
    done

Sometimes it may be required to copy the source files into target folder structure where only the root folder may change. For example: ./dir1/file1.pdf needs to be copied or moved to /home/user/backUp/dir1/file.pdf. This is not strictly a data back-up process as it may overwrite existing files. The following script works but it has not been tested for all possible scenarios and user inputs.

find . -mtime -30 -ls > toCopyBackup.txt
TARGET_PATH="./BackUp/"
clear
if [ -d "$TARGET_PATH" ]; then
  for file in `cat toCopyBackup.txt`; 
    do 
      filePath=(${file//// })
      #Get length of an array filePath
      np=${#filePath[@]}
      
      #Get relative path of file trimming last characters defined by file name
      nf=${#filePath[-1]}
      rPath=${file::-nf}
      echo Relative path of SOURCE file is: $rPath
    
      #Check if relative path starts with a .
      stg=${rPath:0:2}
      e=${#rPath}
      if [ $stg == "./" ]; then
        newPath=$TARGET_PATH${rPath:2:e}
        
        if [ ! -d "$newPath" ]; then
          echo Target Folder: $newPath
          echo "----------------------------------------"
          echo TARGET Folder Does not Exist, Creating it
          mkdir $newPath;
          echo New Folder $newPath created
          echo "----------------------------------------"
          echo 
        fi
        
        cp "$file" $newPath;
        filePath=(${file//// })
        echo Copied file ${filePath[-1]} to $newPath
        echo "=========================================="
      fi

    done
else
   echo Target directory $TARGET_PATH does not exist!
fi

AWK Programming: Due to some inherent limitations in Bash shell (such as only integer arithmetic operations, less number of format styles available...) AWK programming (named after Alfred Aho, Peter Weinberger, and Brian Kernighan) needs to be used in conjuction with shell scripting. It can be used to scan files line by line, split each input line into fields or tokens, compare input lines and fields to patterns, performing specified actions on matching lines...

Examples:

To print the first and third columns: $ awk '{print $1 "\t" $3}' empList.txt, To match all entries with letter or string 'strg': $ awk '/strg/ {print $0}' empList.txt, ls -l | awk '{print $1}': print the first column of output from command ls -l. To run multiple commands, separate them with the vertical bar '|' known as pipe.

Field Separator: Space is the default field separator. OFS (Output Field Separator) variable is used to specify custom field separator. date | awk 'OFS="/" {print$2,$3,$6}' shall give ouput as Mar/15/2022. Input field separator is specified by option -F. Date command produces output: Saturday 06 May 2023 09:58:31 AM IST, date | awk -F: '{print $1}' will result in Saturday 06 May 2023 09.

Pre- and Post-Processing: shell scripts are a set of commands. They come into action immediately. To delay or add operations before or after the actual AWK action, BEGIN and END options are available. As expected, BEGIN rule is executed once before any text processing starts whereas END rule is executed after all processing has completed. Example: date | awk -F: 'BEGIN {printf "%s", "Output of Date split with FS : "} {print $1}'

Read AWK Script from a File: awk -F: -f awkScript.sh empList.txt

Pattern Matching: The search for string can be made more specific by adding pattern such as start of line, end of a string... awk '/^KUMAR/ {print $0}' empList.txt mathes lines that start with KUMAR.


Monitor Usage of a Remote Server (HPC Cluster)

SSH (secure shell) client ia a piece of software for establishing secure connections and for executing commands on a remote machines. ssh connects and logs into the specified destination, which may be specified as either [user@]hostname or a URI of the form ssh://[user@]hostname[:port]. The user must prove his/her identity to the remote machine.

Tips and Tricks on Handling Devices

  1. If you want to transfer data from one device (say computer) to another device (say mobile or external hard disk), either ZIP the source files or transfer one folder (few files) at a time. Copy-paste function on large number of files (say > 10,000) slows down the data transfer speed.
  2. In case you want to cut-paste some data, it is safer to use copy-paste and then delete the source data after the file transfer is successful.
  3. Like in previous case if you want to replace some data, it is safer to rename the destination folder and delete once data transfer is complete. An overwrite operation cannot be corrected (which files were overwritten) if there is any error during the process.
  4. The Print Screen key does not work when some pop-up or sub-menu window is open in a Program. In Ubuntu Linux, Screenshot application with delay can be used to capture window in such cases. Turn the Screenshot with 5 seconds delay as shown below, click "Take Screenshot" tab, go to the program where a sub-menu needs to be open, wait for set number of seconds for screen to get captured.

    Screen capture with delay


Windows Powershell

An enhancement over DOS shell, this is analogous to linux Bash where files are stored with extension PS1. The commands are called cmdlets and variables are assigned with prefixing $. $loc = Get-Location - here Get-Location is equivalent to pwd. $HOME: Represents the full path of the user's home directory. Powershell codes or scripts can be run from legacy cmd terminal using the command 'powershell'. echo ≡ Write-Host, variable; $x = 1.0

From Microsoft Website: "PowerShell is a cross-platform task automation solution made up of a command-line shell, a scripting language, and a configuration management framework. PowerShell runs on Windows, Linux, and macOS."

Powershelll commands are in the format Verb-Object or Action-Method such as Write-Host where Write is an action and Host is object. Frequently used Verbs or Actions are: Copy, Convert, Clear, Get, Import, List, Measure, Move, Out, New, Rename, Remove, Restart, Resume, Select, Set, Stop, Suspend, Where, Write, Update ...

Frequently used Objects are: ChildItem, Command, Content, History, Host, Item, Location, Member, Object, Transcript, Service...

Examples:

  • Comments: # is used for single line comment, <# ... #> = multiline comments
  • Escape Sequence: The escape sequence is backtick ` as compared to backslash \ used in most other scripting and programming language. Thus, to add a tab, use "`t" including double quotes.
  • Chain or Group Commands: Refer the explanation given earlier in DOS Batch section.
  • DIR ≡ Get-ChildItem -Path C:\Users -Force -Recurse. Note DIR gives size in Bytes. $dirName = Get-Item .
  • cp, COPY ≡ Copy-Item -Path C:\Users\oldFile.pdf -Destination C:\Users\newFile.pdf -Force. Copy-Item -Filter *.pdf -Path C:\Users -Recurse -Destination C:\Users\BackUp
  • mkdir, MD ≡ New-Item -Path 'C:\Users\Data' -ItemType Directory
  • rm, DEL ≡ Remove-Item -Path C:\Users\Data -Recurse
  • for file in $(cat fileName.txt) ≡ Get-Content -Path C:\Users\fileName.txt --- Reading a text file into an array: read text data from a file with separate lines treated as distinct data elements. $empName = Get-Content -Path C:\Users\empList.txt: $empName is an array containing a employee name in each element.
  • ${#filePath} ≡ (Get-Content -Path C:\Users\empList.txt).Length - Get 'Length' of list or arrays (here total number of lines in the input file).
  • pwd ≡ Get-Location: current working directing
  • cd, chdir ≡ Set-Location -Path C:\Data\Personal
  • One-Liners: A PowerShell one-liner is one continuous pipeline and not necessarily a command that's on one physical line. Not all commands that are on one physical line are one-liners.
  • Pipe ≡ Where-Object: Complex filtering
  • String Manipulation: 'PowerShell' -replace 'Shell' Point: output would be PowerPoint. 'PowerShell' -replace 'Shell' would result in 'Shell'. 'I Use Ubuntu OS'.Replace('Ubuntu', 'Windows'). Note the line continuation character in Windows PowerShell is the backtick `.
  • -NoNewLine parameter can be used to concatenate the input object from previous command to output from next command
  • du ≡ $dirName | Get-ChildItem | Measure-Object -Sum Length. Get-DirStats -Path C:\Users\Data -Every. (Get-ChildItem C:\Users\Data | Measure Length -s).Sum / 1Gb). (Get-ChildItem C:\Users\Data | Measure Length -s).Sum / 1Mb). Format output up to two decimal places --- "{0:N2} GB" -f ((Get-ChildItem C:\Users\Data | Measure Length -s).Sum / 1Gb)
  • More examples equivalent to du: (Get-ChildItem C:\Users\Data Force -Recurse -ErrorAction SilentlyContinue | ? {$_.CreationTime -gt ‘01/01/2021’ -AND $_.CreationTime -lt ‘01/31/2021’}| Measure Length -s).Sum / 1Gb

File files in a folder based on size and last modified date

Get-ChildItem -Path C:\Users\Data -Recurse -Include *.DOC |
  Where-Object -FilterScript {
     ($_.LastWriteTime -gt '2023-01-01') -and ($_.Length -ge 1mb) -and ($_.Length -le 5mb)
  }
The PassThru parameter can be used with many Set commands in PowerShell to return information about the result for cases in which there is no default output.

Get total numer of lines in a file: $nL = (get-content "C:\Users\EmpList.dat" | measure-object).count

Get the size of all first-level subfolders in the specified directory, reference: woshub.com/powershell-get-folder-sizes - save this block of code in a file with extension PS1 and right click to use the option "Run in Powershell".

$targetFolder='C:\Users\Data'
Get-ChildItem -force $targetFolder -ErrorAction SilentlyContinue | ? { 
  $_ -is [io.directoryinfo] } | ForEach-Object {
    $len = 0
    Get-ChildItem -recurse -force $_.fullname -ErrorAction `
    SilentlyContinue | ForEach-Object { 
      $len = $len + $_.length 
    }
    $_.fullname, "`t | `t", '{0:N2} GB' -f ($len / 1Gb)
    Read-Host -Prompt "Press Any Key to Exit..."
    
  }

Timeout options: cmd /c pause -> Press any key to Continue. timeout /t 15 -> Waiting for 15 seconds, press a key to continue ... timeout /t -1: keep waiting for until the user presses any key including Cntr, Shift, Alt and Function keys.

Function to get file size of a folder, reference: woshub.com/powershell-get-folder-sizes. The function can be used as GetFolderSize($targetFolder).

function GetFolderSize {
  [CmdletBinding()] Param (
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
    $Path
  )
  if((Test-Path $Path) -and (Get-Item $Path).PSIsContainer ) {
    $Measure = Get-ChildItem $Path -Recurse -Force -ErrorAction `
      SilentlyContinue | Measure-Object -Property Length -Sum
    $Sum = '{0:N2}' -f ($Measure.Sum / 1Gb)
    [PSCustomObject]@{
      "Path" = $Path
       Size($Gb)" = $Sum
    }
  }
  Write-Host -NoNewLine 'Press any key to exit...';
  #Following line is optional
  $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}

Arrays and Lists in Powershell

Array in Powershell is created by adding prefix @: $data = @('This', 'is', 'Sample', 'Array') or just $data = 'This', 'is', 'Sample', 'Array'. $data.count shows length of the array. Array elements can be added on multiple lines and comma is optional in this case and generally omitted. Individual items can be accessed by using the brackets [] with an offset value starting at 0. This means arrays in Powershell are 0-based. -1 refers to the last element of the array, [-3..-1] is used to access last 3 items. Plus operator (+) to combine a ranges with a list of elements in an array. For example, to display the elements at index positions 0, 3, and 5 through 8, $a = 0 .. 9, $a[0, 3+5..8].
$data = @(
  'This'
  'is'
  'Sample'
  'Array'
)

Range Operator: $C = 5..8. Iterate over elements of an array.

foreach ($e in $a) {
  $x = $e * $e
}

Computer Networks

Computer Networking

The following table is being developed only to list the activity and typical method. Before jumping to the command, read the manual pages to unserstand the complete syntax.

Activity Command in Linux Command in Windows
01: Get MAC Addresscat /sys/class/net/*/address, ifconfig
02: Get IP Addressifconfig, ip link
03: Spoof MAC Address sudo ip link set dev enp3s0 down -> sudo ip link set dev enp3s0 address new_MAC -> sudo ip link set dev enp3s0 up
04: Add a Static IP AddressEdit /etc/network/interfaces file
05: Configure a DHCP Client Edit /etc/network/interfaces file
06: Install SQL ServerLAMP: Linux - Apache - MySQL - PHP, WAMP
07: Install Apache ServerLAMP, WAMP: Windows - Apache - MySQL - PHP
08: Add Guest Userssudo adduser guest; sudo passwd -d guest
09: Check / set Proxy Serverexport http_proxy=http://proxy.server.com:8080
10: View Active Network Connectionsnetstat -tn src :80 or src :443

Additional Explanation:

01: A MAC address is the unique identifier that is assigned by the manufacturer to a piece of network hardware (like a wireless card or an ethernet card). Wireless device are named starting wl* while the wired device named as eth* depends on the machine.

03: Network nodes have three identities: Hostname, logical address, and physical address. When you connect to a public or open network, the MAC address gets exposed. Spoofing or changing your MAC address keeps your ID hidden from other users.

10: Network connection occur through ports - these are not any physical devices but a standard to identify the type of connection. HTTP (Port 80) or HTTPS (Port 443). Foreign Address is the IP adress of the remote machine to which your machine is connected with. Local address is IP address of host with port number.


Good Scripting and Programming Practices

First and foremost, learn the recommended guidelines for the chosen programming language. Decide your own skill gap and chose whether procedural (functional) programming approach shall be easier to handle or the object oriented programming (OOP) method shall be needed.

Write the version of each piece of code at the beginning of respective file. Create naming conventions for files and folders. Split the main program into functions and subroutine. Develop naming standard for each variable type. Chose variable name easy to interpret (such as with minimum 4 characters except loop counters) or multiple words separated by underscore. Create a list of 'include' modules and variables in a separate file (for example, import modules in Python such as cv2, numpy, PyPDF2...).

Write descriptions of input variables and output(s) from each function and subroutine. Identify basic error logic and terminate the program with appropriate user message such as missing file or image. Use appropriate format statements for numbers and change the format style based on values. For example, do not print more than 3 decimals for any number > 100. For numbers > 105, switch to exponential notation. Similarly, for values < 0.0001, it is better to switch to exponential notation.

Understand the auto-generated help texts: First comment after function definition is used as Documentation String in MATLAB, Similarly, in Python first block of comments in the body of a method or function (those within triple quotes ''' ... ''') are used as Documentation String for that functions which can be printed by command help (funcName). In most of the cases, it is advised that the comments and user message should be restricted to 72 characters in the width (horizontal direction).

Think of options and arguments (parameters) required for Command Line Interface (CLI) in case you are not planning a Graphical User Interface (GUI). As you add the functionalities, the number and varieties of arguments shall increase. A positional parameter in one module may be an optional parameter in another module and vice versa.


Excel or Spreadsheet Functions:

How to split word into individual characters: mid($B3, columns($B$3:B$3), 1). Split string based on multiple delimiters, Extract text between two characters, Split text or string and get first or n-th item

Contact us
Disclaimers and Policies

The content on CFDyna.com is being constantly refined and improvised with on-the-job experience, testing, and training. Examples might be simplified to improve insight into the physics and basic understanding. Linked pages, articles, references, and examples are constantly reviewed to reduce errors, but we cannot warrant full correctness of all content.