Table of Contents: SCHEME Summary | FLUENT TUI | Set volumetric heat source | Examples of UDF | Script: volume mesh in Batch Mode | Macros in STAR-CCM+ | Batch Scripts | Windows PowerShell | Linux Shell Scripts | AWK Programming | Scripting in ANSA | Parametric Studies in ANSYS FLUENT | Named Expressions | Scripting in ANSYS Discovery | DO Loop in Scheme | IF Loop in Scheme | Read Multiple Data Files and Save Contour as PNG | Export Zone Names | PyFluent: Accessing FLUENT from Python | Python Library for Fluid Mechanics | Scripting in CFD-Post | The PICK command | Naming of Files for Auto-save | Folder Management | Scripting in ANSYS Workbench | Array Definition and Usage in C | Arrays in Java | File and String Handling in Java | Scripting in MS-Office | Handling Files and Folders in VBA | UDF for Temperature Dependent Viscosity
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.
ICEM CFD | STAR-CCM+ | FLUENT* | CFX | OpenFOAM | ParaView | ANSA | HyperMesh |
Tck/Tk | Java | SCHEME, C | CCL, PERL, FORTRAN | C++ | Python | Python | Tcl/Tk |
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.
Feature | Tcl/Tk | FORTRAN | C | JAVA |
Case-sensitive | Y | N | Y | Y |
Comment | # | C, ! | /* ... */ | // and /* ... */ |
End of Statement | ; | Newline character | ; | ; |
Line Continuation | \ | Any character | \ | Not required |
Variable Definition | set x = 1; | real x = 1 | real x = 1; | real x = 1; |
If Loop | if { 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 Loop | for (i=0; i<= 10, i++) { ... } | for (i=0; i<= 10, i++) { ... } |
Arrays | $x(5); | x(5) | x[5]; | x[5]; |
File Embedding | source "common.dat"; | include "common.dat" | #include "common.h"; | import common.class; |
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.
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)).
(ti-menu-load-string) is used to invoke a TUI command in SCHEME journal i.e. to convert a journal command to Scheme command. In other words, (ti-menu-load-string "string") means execute the specified "string" as 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 State | Cold Flow | SIMPLE | Gravity OFF | Energy OFF |
Steady State | Cold Flow | Coupled Psuedo-Transient | Gravity OFF | Energy OFF |
Steady State | Cold Flow | Coupled | Gravity OFF | Energy OFF |
Steady State | Conjugate Heat Transfer | SIMPLE | Gravity OFF | Energy ON |
Steady State | Conjugate Heat Transfer | Coupled Psuedo-Transient | Gravity 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 change from case to case depending upon which models are enabled. For example, the TUI commands 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 requires inputs based on models so the command is different whether 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 are 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.
Some commands return a list of objects and symbols, rather than a list of strings. If any such command is typed into the Fluent TUI window, it (FLUENT GUI) attempts to display the results (output of the command), and this may crash the session fatally if the objects are not easy to display such as interior mesh.
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-f" or s in ini. Matching of hyphens is optional though a space is mandatory to separate phrases. A command is matched by matching an initial sequence of its phrases -> A phrase is matched by matching an initial sequence of its characters -> A character is matched by typing that character -> If an abbreviation matches more than one command, then the command with the greatest number of matched phrases is chosen -> If more than one command has the same number of matched phrases, then the first command to appear in the menu is chosen. Note that not all phrases are to be specified though full path is required. Thus, "so ini" cannot represent "/solve/initialize/initialize-flow" based on the criteria mentioned earlier.
File names are actually just character strings. For convenience, file name prompts do not require the string to be surrounded with double quotes if they do not contains an embedded space character else the name must be within double quotes "...". One consequence of this convenience is that filename prompts do not evaluate the response. For example, (define fn "case_1.png") followed by display hardcopy fn will end up writing a picture file with the name fn, not case_1.png. Since the filename prompt did not evaluate the response, 'fn' did not get a chance to evaluate 'case_1.png' as it would have done for most other prompts.
(define rf 0.7) (define pAbsMin 5000) (define pAbsMax 200000) (define tvrMax 2000) (define tkeMin 1e-10) (define tdrMin 1e-10) (define convCriteria 1e-4) ; ;Prefix of the files saved as back-up (define backup_prefix "backUp_") ;Load a SCHEME file (load utilities.scm) ;Suffix to be added to file after completion of runs (define backup_sufix "_end") (define case_name "sim-ss-ke-") (define casename_final (format #f "~a_~a" case_name backup_suffix)) ; ; Interpolate data from previous simulations /file/read-case baseline_geom.cas.h5 /file/interpolate/write-data baseline.ip yes yes /file/read-case fluent.msh /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/modify-zones/make-periodic p_z11 p_z12 n y y /mesh/modify-zones/slit-interior-between-different-solids ; /file/set-batch-options no yes yes no (set! *cx-exit-on-error* #t) /define/units length mm /define/units pressure atm ; /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 /define/models/viscous/turbulence-expert/production-limiter yes 10 /define/models/viscous/turbulence-expert/kato-launder-model yes /define/models/viscous/near-wall-treatment enhanced-wall-treatment yes (ti-menu-load-string "/define/models/viscous/turbulence-expert/low-re-ke? 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 ; ;Change solid-domains into fluid type /define/boundary-conditions/modify-zones/zone-type 4 fluid /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 /file/read-profile b_inlet.csv /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 z-t if_tet_hex () interface ;Create mesh interface: iface is the prefix of the interface name /define mesh-interface create iface no if_side_a if_side_b () no. ;define b-c set: can be used to change any specific input /define/b-c/set velocity-inlet z-inlet () vmag yes par-in-vel 5 q /define/b-c/set velocity-inlet z-inlet () temperature yes par-in-tp 50 q ; /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 /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/operating-conditions gravity yes 0 0 -9.806 ; /define/model/dpm/options erosion-accretion yes /define/model/dpm/options saffman-lift-force yes /define/model/dpm/options stochastic-collision yes /define/b-c/set wall w_pipe () dpm-bc-erosion finnie? yes q ;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 ;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/set/limits pAbsMin pAbsMax viscRatioTurbMax tkeMin tdrMin tvrMax ; /solve/monitors/residual convergence-criteria 1.0e-6 1.0e-6 1.0e-6 1.0e-6 1.0e-6 1.0e-6 /solve/report-definitions/add force_valve force force-vector 1 0 0 thread-names wall_valve () q /solve/report-definitions/add moment_valve moment scaled? no thread-names wall_valve () q ;Number of iterations to store /solve/monitors/residual/n-save 5000 /solve/monitors/residual plot y /solve/monitors/residual print y ; ;Initialize the solution and set auto-save data frequency: 3 options /file/interpolate/read-data baseline.ip /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 mp 0.2 /solve/patch phase-2 () air-vol () mp 0.2 ; ;Store residuals, set variables by File > Data File Quantities /solve/set/expert yes yes no ;Data File Quantities not available in *.h5 format /file/data-file-options yes q /file/data-file-options x-vel-res y-vel-res () ; /file/auto-save/data-frequency 250 /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 ;List all valid variable names /define/custom-field-functions/list-valid-cell-function-names ; ;Set up display commands to print contours every 50 time steps /solve/execute-commands/add-edit cmd_d yes no "time-step" 50 "/display/objects/display contour_vf 0 1" /solve/execute-commands/add-edit cmd_s yes no "time-step" 50 "/display/save-picture vf_water_%t.png" /solve/execute-commands/add-edit save_pics y y "/file/read-jou save_pics.jou" /solve/execute-commands/add-edit save_pics_5 y n iteration 500 "/file/read-jou save_pics.jou" /solve/execute-commands/add-edit save_pics_every_5 n 500 iteration "/file/read-jou save_pics.jou" ;-----------Steady State Runs--------- ; Record the start time in a txt file !date >> solution_time.txt /solve/set/reporting-interval 2 /solve/set/expert no yes no no /define/profiles/update-interval 1 ;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 ; /report/volume-integrals/maximum zn* wx* () no /report/volume-integrals/maximum (hx*) no ; ; Creating animation on a contour named 'vf_pipe' /solve/animate/objects/create vf_anim animate-on vf_pipe storage-dir "." q ; Change the frequency of saving animation files /solve/animate/objects/edit vf_anim frequency 200 q ; /display/set/contours/filled-contours yes ;Set number format to floating with 2 places after decimal /display/set/windows/scale/format "%0.2f" /display/set/picture/color-mode color /display/set/contours/n-contour 10 /display/set/contours/auto-range no /display/set/lights headlight-on no /display/set/lights lights-on no /disp obj create contour cnt_t field temperature surf-list wall_f () 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 set-window 2 /display/views/read-views "saved_view.vw" /display/set/picture/driver png /display/set/picture use-window-resolution? no /display/set/picture/landscape yes /display/set/picture x-resolution 1920 /display/set/picture y-resolution 1080 /display/views save-view pic_view /display/views restore-view pic_view /display/views/auto-scale /display/save-picture pic_view.png views restore-view [front / back / left / right / top / bottom] ;front = +x+y, back = -x+y, left = +z+y, right = -z+y, top = -x+z, bottom = -x-z ;Here + direction is towards right and up ; ;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 ;Cold flow, single phase, k-e, add one 'y' each for energy on and multiphase /plot/residuals y y y y y y /solve/dpm-update /report/dpm-summary ; Change injection properties: particle diameter or number of injections... ; Here 0.1 is diameter of particles in the unit of length selected /define/injections/set-injection-properties inj_1 inj_1 (inj_plane) yes no no no no no no 0.1 0 0 0 0.005 ; 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 ; Write report to file (ti-menu-load-string (format #f "report surface-integrals area-weighted-avg wall_valve () pressure yes valve_pressure.srp")) !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
Save quantitative data to a text file:
report surface-integrals area w_rear () yes q_output.txt - to create q_output.txt first time. To append data to existing file: report surface-integrals area w_rear () yes q_output.txt yes.Save Variables and Case/Data files to specified folder, Export to Ensight format
(define saveDir "/home/user/Projects") (define casePrefix "SPH_SS_") ; Booleans to save case, data and EnSight Gold files (define save_casdat 1) (define save_ensight 1) ; Define variables that should be exported (define saveVariables "pressure x-velocity y-velocity z-velocity density viscosity-lam viscosity-turb turb-kinetic-energy turb-diss-rate dynamic-pressure total-pressure velocity-magnitude production-of-k viscosity-eff ()") ; Save Case and Data based on value defined for save_casdat: case loop used (case save_casdat ((1) (ti-menu-load-string (format #f "/file/data-file-options ~a" saveVariables)) (ti-menu-load-string (format #f "/file/write-case-data ~a~a~a" saveDir casePrefix calcCase)) ) ) ; Save Data in EnSight Gold files, arguments are: Filename, Variables to save ; Binary File?, Cell Zone ID, Name, Interior Zone Surfaces, Cell-centered? (case saveensight ((1) (ti-menu-load-string (format #f "/file/export/ensight-gold ~a~a~a~a () no 2 () () no" saveDir casePrefix calcCase saveVariables) ) ) )
Sample TUI from GUI Operations: (cx-gui-do cx-set-list-selections "Boundary Conditions*Table1*List2(Zone)" '( 4))
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). The concept of "Dotted Pairs" is explained in later paragraphs.
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 given below. Note that this works when radiation model is not active. The values are in the order of density, specific heat and thermal conductivity. When radiation is active, you need to add 'no' 4 times where each no is an answer to the questions "Change Absorption Coefficient?", "Change Scattering Coefficient?", "Change Scattering Phase Function?" and "Change Refractive Index?" respectively. Last 'no' is response to the prompt "Change/create mixture and overwrite aluminum?".
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:
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 ;TUI: /objects/volume-regions compute objectName useMaterialPoint? ;/objects/volume-regions compute simRegion yes ; /mesh/poly/controls cell-sizing geometric 1.2 /mesh/tet/controls use-max-cellsize yes /mesh/tet/controls max-cell-length 10 ; uniform first-layer-ht number-of-layers growth-ratio /mesh/scoped-prisms create prism_sizing uniform 0.1 8 1.25 obj_name fluid-region grow-on only-walls ;Set auto-mesh parameters as per syntax below ;TUI: /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 yesOptions to grow prism layers are: grow-on {only-walls, all-zones, selected-face-zones solid-fluid-interface selected-labels}. A mesh can be converted into polyhedral format within FLUENT Pre-post: /mesh/polyhdra/convert-domain. To convert only skewed cells: mesh polyhedra convert-skewed-cells zone_fluid () 0.95 (target maximum cell skewness) yes (convert skewed cells?).
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 () q. Alternatively: (ti-menu-load-string (format #f "solve report-definitions add avg_vx surface-areaavg surface-names inlet_x () per-surface? no field x-velocity q q q")).
/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. (pick-a-real (format #f "report surface-integrals area-weighted-avg wall-pipe () temperature Save intermediate resultsno"))
The command (pick "/report/projected-surface-area 1 () 0.1 0 1 0") or identically same (pick "/report/projected-surface-area (1) 0.1 0 1 0") returns a single string that can be converted to a number using (string->number ...). The string is the last token of the output of the TUI commmand. The command (pick "/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.
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.
Default Value Binding: The default value at any prompt is bound to the Scheme symbol '_' (underscore) so that the default value can form part of a Scheme expression. For example, if you want to decrease a default value so that it is half of the original value, you could enter shrink-factor [0.5] (/ _ 2)
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) )
A Scheme loop that will open windows 1 and 2 and display the front view of the mesh in window 1 and the back view in window 2 is given by:
(for-each (lambda (window view) (ti-menu-load-string (format #f "display open-window ~a gr view restore-view ~a" window view)) ) ’(1 2) ’(front back) )
This loop can also be written without using ti-menu- commands, but one should know the Scheme functions that get executed by the menu commands to do it:
(for-each (lambda (window view) (cx-open-window window) (display-mesh) (cx-restore-view view) ) ’(1 2) ’(front back) )
Automatic Numbering of Files
Folder Management: ANSYS FLUENT includes three system command aliases (pwd, ls, dir and chdir) that gets executed in the working directory with output displayed in the ANSYS FLUENT console. cd and !cd are not same: !cd (cd with ! or bang shell escape character) executes in a subshell, so it will not change the working directory either for ANSYS FLUENT or for Cortex - it simply displays the current working directory in the ANSYS FLUENT console.
Some commands such as /file/write-settings refers to the path returned by the command pwd, while other commands like /file/write-data or /file/read-case refers to the path where the last case or data file were written or read. TUI command 'pwd' = check current working directory, synch-chdir or chdir D:\Projects\HTX = Change to a new direcotry (full absolute path required), cd = change to 'home' directory (that is typing cd with no arguments will move cwd to the home directory in the console), !mkdir /home/users/cfd = create a folder 'cfd' (assumes /home/users exits, full path required), "/display/save-picture vel_plot D:\Projects\HTX\v_plot.png" = save the hard copy of a contour plot in specified directory, Period '.' prompts for the name of journal file and then runs it when specified, alias = display the list of symbols currently aliased.
pwd: #[alias] (LAMBDA () (BEGIN (SET! pwd-cmd ((LAMBDA n n) 'system (IF (cx-send '(unix?)) "pwd" "cd")) ) (cx-send pwd-cmd) ) )
Wildcard character can be used to navigate file system: for example !ls multiphase*.*.h5 can be used to print all files in h5 format starting with string 'multiphase'. Tilde Expansion (UNIX Systems Only): if you specify ~/ as the first two characters of a filename, the ~ will be expanded to be your home directory. Thus, "/file/write-case ~/case_file.h5" will save the file as case_file.cas.h5 in user's home directory. A subdirectory of user's home directory can be specified, for example, "/file/write-case ~/projects/case_file.cas.h5", FLUENT will save the file as case_file.cas.h5 in the 'projects' subdirectory.
(if (not (file-directory? "pictures")) (system "mkdir pictures") ) (system "mv *.png ./pictures")
Variable names in FLUENT, which can be used in TUI scripts or named expressions or UDF. Similar lists can be found for STAR-CCM+ and CFX.
abs-angular-coordinate, absolute-pressure, fangular-coordinate, anisotropic-adaption-cells, aspect-ratio, axial-coordinate, axial-velocity, boundary-cell-dist, boundary-layer-cells, boundary-normal-dist, boundary-volume-dist, cell-convective-courant-number, cell-elenent-type, cell-equiangie-skew, cell-equivolume-skew, cell-id, cell-normalized-sum-face-area, cell-parent-index, cell-partition-active, a fetine-lev stored, cell-refine-level, cell-reynolds-number, cell-squish-index, cell-surface-area, cell-type, cell-volume, cell-volume-change, cell-wall-distance, cell-warp, cell-weight, cell-zone, density, density-all, dp-dt, dp-dx, dp-dy, dp-dz, dpm-wall-normal-pressure, dpm-wall-x-force, dpm-wall-y-force, dpm-wall-z-force, dx-velocity-dx, dx-velocity-dy, dx-velocity-dz, dy-velocity-dx, dy-velocity-dy, dy-velocity-dz, dynamic-pressure, dz-velocity-dx, dz-velocity-dy, dz-velocity-dz, edge-length-ratio, enthalpy, entropy, expansion-ratioface-area-magnitude, face-handedness, face-squish-index, face-warp, heat-flux, heat-transfer-coef, heat-transfer-coef-wall, heat-transfer-coef-wall-adj, heat-transfer-coef-yplus, helicity, interface-overlap-fraction, internal-energy, lambda2-criterion, mark-poor-elements, mass-imbalance, mesh-x-velocity, mesh-y-velocity, mesh-z-velocity, moving-mesh-courant-number, nusselt-number, orthogonal-quality, partition-neighbors, Prandtl-number-eff, prandt-nunber-lam, pressure, pressure-coefficient, pressure-hessian-indicator, production-of-k, q-criterion, radial-coordinate, radial-velocity, raw-q-eriterion, reference-tenperature-at-y+, rel-axial-velocity, rel-radial-velocity, rel-tangential-velocity, rel-total-pressure, rel-total-temperature, rel-velocity-nagnituge, relative-velocity-angle, relative-velocity-angle, relative-x-velocity, relative-y-velocity, relative-z-velocity, rothalpy
skin-friction-coef, smoothed-cell-refine-level, specific-diss-rate, specific-heat-cp, stanton-number, strain-rate-mag, tangential-velocity, temperature, thermal-conductivity-eff, thermal-conductivity-lam, total-energy, total-enthalpy, total-enthalpy-deviation, total-pressure, total-temperature, turb-diss-rate, turb-intensity, turb-kinetic-energy, turb-reynolds-number-rey, user-energy-source, user-volumetric-energy-source, velocity-angle, velocity-magnitude, viscosity-eff, viscosity-lam, viscosity-ratio, viscosity-turb, user-energy-source, user-volumetric-energy-source, velocity-angle, velocity-magnitude, viscosity-eff, viscosity-lam, viscosity-ratio, viscosity-turb, vorticity-mag, wall-adjacent-temperature, wall-shear, wall-temp-in-surf, wall-temp-out-surf, wall-temp-thin, wall-temperature, x-coordinate, x-face-area, x-velocity, x-vorticity, x-wall-shear, y-coordinate, y-face-area, y-plus, y-star, y-velocity, y-vorticity, y-wall-shear, z-coordinate, z-face-area, z-velocity, z-vorticity, z-wall-shear
Set data sampling for transient simulations: /solve/set data-sampling 100 y y y y where 100 is sampling internal and each 'y' is answer to following questions respectively: Collect statistics for flow shear stress?, Collect statistics for heat fluxes?, Collect wall statistics?, Collect force statistics?
Add data sampling options: /solve/set/data-sampling-options/add-datasets zone_name () wall-shear () #t #t #t #t #t 25 where each #t is for minimum, maximum, mean, RMSE, moving-average and 25 is number for time-steps used for moving-average.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" was 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
ZID | Zone ID or name of the zone |
y | Change current value? |
n | Change shear-bc-noslip? |
n | Change rough-bc-standard? |
n | Wall motion relative to cell zone? |
y | Apply rotation velocity? |
n | Define wall velocity components? |
n | Use profile for wall-roughness height? |
0 | Wall roughness height |
n | |
0 | |
n | |
RPM | Wall rotation speed in RPM |
XC | X-coordinate of a point on axis of rotation |
YC | Y-coordinate of a point on axis of rotation |
ZC | Z-coordinate of a point on axis of rotation |
1 | Direction cosine of X-axis |
0 | Direction cosine of Y-axis |
0 | Direction 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.
ZID | Zone ID or name of the zone |
y | Change current value? |
MATNAME | Name of the material defined |
y | Specify source terms? |
1 | Number of energy sources |
y | Use constant or expression for Energy 1 |
1250 | Heat density in [W/m3] |
n | Specify fixed value? |
no | Frame motion? |
n | Use profile for reference frame X-origin of rotation axis? |
0 | X-coordinate of the origin |
n | Use 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 |
n | Use 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
zNAME | Name of the zone |
y | Reference Frame: Absolute? |
y | Mass Flow Specification Method: Mass Flow Rate? |
n | Use Profile for Mass Flow Rate? |
0.75 | Mass Flow Rate in [kg/s] |
n | Use Profile for Total Temperature? |
50 | Total Temperature [in unit selected i.e. K or °C] |
n | Use profile for Supersonic / Initial Gauge Pressure? |
10000 | Supersonic Initial Gauge Pressure (in [Pa]) |
n | Direction Specification Method: Direction Vector? |
y | Direction Specification Method: Normal to Boundary? |
n | Turbulence Specification Method: K and Epsilon? |
n | Turbulence 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: These are not same as Custom Field Functions.
/define/named-expressions add exprName definition "1.25 [m/s]" q: the last entry 'q' is needed to bring the TUI to root position. If a named expression created for a boundary zone (which require x, y and z as inputs), this can be plotted as any other contour plots. This is a quick way to ensure that the Named Expressions are correctly defined.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 examples of expressions: avgT = Average(StaticTemperature, ['pr_outlet'], Weight = 'Area'), area_ex = Area(['pr_outlet']), out_rad = 0.250 [m], r_max = sqrt(Area(['inlet'])/PI), xc = 0.1 [m], yc = 0.2 [m], zc = 0.3 [m], rad = sqrt((x - xc)^2 + (y - yc)^2 + (z - zc)^2), v_in_parabolic = 5.0 [m/s] * (1 - rad / r_max)^2. Conditionals such as IF, AND, OR... should be capital letters.
Some of the actions which one may need during automation activities are:
(display get-thread-list): output is #[compound-procedure]
(display (get-thread-list)): it results in error with following message:
Error: eval: unbound variableError 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
(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.
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
(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") ) )
Print volume of all solid zones. Note that as on version 2023R2, the case should be initialized before generating any report other than reporting projected area.
(for-each (lambda (zone_name) (ti-menu- load-string (format #f "report volume-integrals volume ~a () no" zone_name)) ) (map thread-name (get-threads-of-type 'solid) ) )/report/volume-integrals/mass-integral specific-heat-cp zone_name () no can be used to estimate the thermal inertia of all solids. "report/volume-integrals/volume-integral density zone_name () no" calculates mass of each zone.
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 "define/b-c m-f-i 10 yes yes yes yes \"udf\" \"mdot::libudf\" no 0 no yes") ) ) )
DO-Loop: Every time something is evaluated in Schemes prompt or Command Interface, return value is printed. For do loops, one has to provide return expression. If not, it is unspecified and what do loop will return is nothing which #f meaning false.
Dynamically create a list:
(do ( (z 3 (+ 1 z))) ((> z 12)) ( cx-gui-do cx-set-list-selections "Boundary Conditions*Table1*List2(Zone)" (list z) ) )
Another example of a DO lopp
(do ( (x start-x (+ x delta-x)) ((> x x-end)) ... loop body ... ) Merge free and non-free nodes 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") ) ) ) )
; Write to file (define call-with-output-file (lambda (filename proc) (let (p (open-output-file filename "a")) (let (v (proc p)) (close-output-port p) v ) ) ) ) ; Write to file in format: Filename | Data (as a list) (define (write_this filename data) (call-with-output-file filename (lambda (p) (let f ((ls data)) (if (not (null? ls)) (begin (write (car ls) p) (write #\tab p) (f (cdr ls)) ) (newline p) ) ) ) ) )
; Convert list from pairs (define (flatten x) (cond ((null? x) x) ( (and (pair? x) (not (pair? (car x))) ) (cond ((null? (car x)) (flatten (cdr x))) (else (cons (car x) (flatten (cdr x)))) ) ) ( (and (pair? x) (pair? (car x)) ) (flatten (cons (caar x) (cons (cdar x) (cdr x))) ) ) (else (cons x '()) ) ) )Put surface name inside double quotes, for example (get_surface_avg "surface_name") where
(define (get_surface_avg surface_name) (pick-a-real (format #f "report surface-integrals area-weighted-avg ~a () variable_name no" surface_name)) )To execute the function, use the following command inside the loop which reads the data files: (write_this "v_surface_avg" (flatten (get_surface_avg "surface_name")))
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 pict (string-append datfile (number->string i) ".png")) (ti-menu-load-string (string-append "display save-picture " pict)) )One will need to format variable 'i' with zero padding so that files are named Run-1-A-0001.png, Run-1-A-0002.png, ... Run-1-A-0010.png. In CFD-Post, to read series of data files associated with a single case file, store all the .dat files and the single case file in a common folder. Then read the most recent data file into CFD-Post, and select the option to "Load complete history as a single case". All the data files will be available in CFD-Post for transient analysis.
The dat file can be loaded with this TUI directly: (do ( (n 1 (+ n 1))) ((> n 50)) (ti-menu-load-string (format #f "file read-data C:\Users\Projects\Case-1-0000~a.dat.gz" n)))
The *.dat.gz files can be read using "dir" command as well. Following lines of code needs to be customized to append items to create list_data. Ensure that the expected length of list matches the specified range of counter 'i'.
(do ((i 1 (+ i 1))) ((> i 20)) (define list_data (pick (system "dir /b *.dat.gz") i)) )
(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.") ) ) )
Yet another script to create animations: cfd-online.com/Forums/fluent-udf/240857-fluent-scheme-get-contour-names-list.html
; Define names of the contours as string (define contour_list "contour-pr contour-v contour-t streamline-1 streamline-2") ; Split the string to store contour names as list or array (define contours (string-split contour_list)) ; Get length of the contour names (define len_contours (length contours)) (do ((i 0 (+ i 1))) ((> i 200)) (begin ; Get i-th item from the list named 'contours' (define list_item (list-ref contours i)) ; Save animation object named as list_itme-animation-i (ti-menu-load-string (format #f "solve anim object create ~a-animation-~a animate-on ~a sd ./ st png view from-selected-object frequency-of time-step frequency 2 q" list_item i list_item)) (if (equal? i len_contours) (begin (define i 100) ;break loop ) ) ) )
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 () q |
solve report-files add mf-inlet report-definitions mf-inlet () file-name mf-inlet.out print yes () q |
solve report-definitions add p-inlet surface-areaavg field pressure surface-names srf-1 srf-2 () q |
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 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"}Save in a string-list the name and id of all threads and surfaces - ref: cfd-online.com/Forums/fluent-udf/202214-get-surface-string-list.html
(rp-var-define 'a () 'string-list #f) (rpsetvar 'a ()) (for-each (lambda (t) (rpsetvar 'a (list-add (rpgetvar 'a) (thread-name t))) ) (get-all-threads) ;(map symbol->string (inquire-surface-names)) ) (rpgetvar 'a)
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. One can get another script at innovationspace.ansys.com/ ... /how-to-get-a-consistent-naming-of-internals-between-fluid-and-solid-cell-zones/
; 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 ) ) )
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) ) ) ) )
(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") ) )
Few examples from posts on cfd-online.com: This piece of code prints centroid of boundaries defined as 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"
ANSYS FLUENT Post-Processing Commands Get wall moments: report forces wall-moments (all wall zones?) no wall_x wall_y () xc yx zc i j k (write to file?) no. Here the axis is represented by a centre point and direction cosines (unit vector components). To report forces; report forces wall-forces no wall_x wall_y () i j k no.
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") )
Returns the sublist of list obtained by omitting the first k elements
(define list-tail (lambda (x k) (if (zero? k) x (list-tail (cdr x) (- k 1)) ) ) )
Some examples available at GITHUB:
(define (create-line-surf s_name xy_pos) (ti-menu-load-string (format #f "/surface/line-surface ~a ~a 0 ~a 1" s_name xy_pos xy_pos) ) )
(define display-file-content (lambda (file_name) (let ((p (open-input-file (format #f "~a" file_name)))) (let f ((x (read-line p))) (if (eof? p) (begin (close-input-port p) ) (begin (display x) (newline) (f (read-line p)) ) ) ) ) ) )
(define read-data-from-file (lambda (file_name) (let ((p (open-input-file (format #f "~a" file_name)))) (let f ((x (read p))) (if (eof? p) (begin (close-input-port p) ) (begin (if (number? x) (begin (display x) (newline) ) ) (f (read p)) ) ) ) ) ) )
(define (read-report-file file_name) (let ((p (open-input-file (format #f "~a" file_name)))) (do ((x (read p) (read p))) ( (or (number? x) (eof-object? x)) (close-input-port p) (if (number? x) x #f) ) ) ) )
(define read-file-data-to-list (lambda (file_name) (let ((p (open-input-file (format #f "~a" file_name)))) (let f ((x (read p)) (l '())) (if (or (eof? p) (eof-object? x)) (begin (close-input-port p) l ) (begin (if (number? x) (set! l (append l (list x))) ) (f (read p) l) ) ) ) ) ) )
(define display-list (lambda (l) (do ((i 0 (+ i 1))) ((>= i (length l))) (display (format #f "~a --- ~a\n" i (list-ref l i))) ) ) ) (define (export-xy-plot file_name zone-id) ; direction y (ti-menu-load-string (format #f "plot/plot-direction 0 1") ) (newline) (ti-menu-load-string (format #f "plot/plot yes ~a yes no no temperature no no y-coordinate ~a" file_name zone-id) ) (newline) ) (define read-xyplot-file (lambda (file_name) (let ((p (open-input-file (format #f "~a" file_name))) (l '())) (begin (read p) (read p) (set! l (cdr (read p))) (close-input-port p) l ) ) ) )
(define (create-plane-surf-x s_name x_pos) (ti-menu-load-string (format #f "/surface/plane ~a ~a 0 0 ~a 1 0 ~a 0 1" s_name x_pos x_pos x_pos) ) ) (define (create-plane-surf-z s_name z_pos) (ti-menu-load-string (format #f "/surface/plane ~a 0 0 ~a 0 1 ~a 1 0 ~a" s_name z_pos z_pos z_pos) ) ) ;/surface/iso-surface x-coordinate tp_000 w_pipe () f_air () range [0, 0.5] 0 (define (create-iso-surface-x iso_name from-surf from-zone x_pos) (ti-menu-load-string (format #f "/surface/iso-surface x-coordinate ~a ~a () ~a () ~a ()" is_name from-surf from-zone x_pos) ) ) (define (export-report-favg file_name surf_name var_name) (ti-menu-load-string (format #f "/report/surface-integrals/area-weighted-avg ~a () ~a yes ~a" surf_name var_name file_name ) ) )
(define list-position (lambda (o l) (let loop ((i 0) (l l)) (if (null? l) #f (if (and (>= o (car l)) (<= o (car (cdr l)))) i (loop (+ i 1) (cdr l)) ) ) ) ) )
(define interpolate (lambda (x1 x2 y1 y2 x) (let ((i 0)) (+ y1 (* (- y2 y1) (/ (- x x1) (- x2 x1) ) ) ) ) ) )
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 menu: (cx-add-item um "CFD Steps" #\O #f and (lambda () (system "chrome.exe https://cfdyna.com &")))
(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) |
(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") |
(thread-domain-id) | (thread-id), (domain-id) |
Error eval: unbound variable | Error 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 | Extensibility |
In-product operation | Out of product feature expansion |
Modify existng functionality, Create new feature | Enhance a software package with minimum development |
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. Any UDF function has first argument as the name of the function which user can select wherever needed. In general, second argument gives the index of the cell, which is actually an integer, and the third argument gives thread ID of the cell zone (volume or boundary zones), which is an integer pointer.
#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 required 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.
/* 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; }
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.
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); } }
DEFINE_EXECUTE_AT_END(vol_avg_tdr) { /******************************************************************** UDF for integrating turbulent dissipation and printing it to console window at the end of the current iteration or time step *********************************************************************/ Domain *d; Thread *t; /* Integrate dissipation. */ real sum_diss=0.; cell_t c; d = Get_Domain(1); /* mixture domain if multiphase */ thread_loop_c(t,d) { if (FLUID_THREAD_P(t)) { begin_c_loop(c,t) { sum_diss += C_D(c,t) * C_VOLUME(c,t); } end_c_loop(c,t) } } CX_Message("Volume integral of turbulent dissipation: %g\n", sum_diss); }
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:/*--------------------------------------------------------------------*/ /* 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.
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; }
DEFINE_PROPERTY(water_density, c, t) { real rho_water; real T = C_T(c, t); rho_water = 765.33 + 1.8142*T - 0.0035*pow(T, 2.0) C_UDMI(c, t, 0) = rho_water; return rho; }
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);
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:
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; } DEFINE_PROPERTY(density_t_p, c, t) { real rho; real p_operating = RP_Get_Real("operating-pressure"); real p_abs = C_P(c,t) + p_operating; real Tp = C_T(c, t); rho = add function here: f(temperature, pressure); return rho; }To make density function of pressure only:
DEFINE_PROPERTY(density_isothermal, cell, thread) { real density; real pressure = C_P(cell,thread) + RP_Get_Real("operating-pressure"); density = 101325.0 / 287.05 / pressure; return density; }
/*cfd-online.com/Forums/fluent-udf/196297-udf-density.html*/ DEFINE_PROPERTY(custom_density, c, t) { int i; float dT, dP, rho, al, o2, al2, n2; float Mw_i(int i); Material *sp; float rho_g = 1.225; float rho_s = 2700; float alp = 0.0002; float sum = 0.0; dT = C_T(c, t); dP = C_P(c, t) + RP_Get_Float("operating-pressure"); mixture_species_loop(THREAD_MATERIAL(t), sp, i) { /* Get mass fraction by C_YI(c, t, i) where int i is species index*/ al = C_YI(c, t, 0)/27.0; o2 = C_YI(c, t, 1)/32.0; al2 = C_YI(c, t, 2)/102.0; n2 = C_YI(c, t, 3)/28.0; sum = al + o2 + al2 + n2; } rho = (1.0 + alp*((rho_s/rho_g) - 1.0)) * dP/(sum*dT*8314.3); return rho; }
User-defined Mixing Law for Thermal Conductivity: generic_property function is used to obtain properties of individual species.
DEFINE_PROPERTY(mass_wtd_k, c, t) { real sum = 0.0; int i; Material *sp; real ktc; Property *prop; mixture_species_loop(THREAD_MATERIAL(t), sp, i) { prop = (MATERIAL_PROPERTY(sp)); ktc = generic_property(c, t, prop,PROP_ktc, C_T(c, t)); sum = sum + C_YI(c,t,i)*ktc; } return sum; }
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]); | ||
} |
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))) ) ) ) )
(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)
[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
PyFluent: This is the module which can be used to access FLUENT commands from Python code. The PyFluent TUI commands do not support TUI features such as aliases or command abbreviation. Example: dir(solver.tui.define.models.viscous) returns available turbulence models where 'solver' is session instance created as:import ansys.fluent.core as pyfluent solver = pyfluent.launch_fluent(precision="double", version="3d", mode="solver")"/define/b-c/set velocity-inlet inlet-1 () temperature no 300 q" is equivalent to solver.setup .boundary_conditions .velocity_inlet[ "inlet-1" ] = {"t" : 300} which can be further written as:
solver.setup.boundary_conditions.velocity_inlet["inlet-1"].t = { "option": "constant or expression", "constant": 293.15, }
solver.setup.boundary_conditions.velocity_inlet[ "inlet-1"].vmag = { "option": "constant or expression", "constant": 5.0, }
Rules to convert journal commands to Python statements:
More Examples
solver.tui.define.models.energy("yes", ", ", ", ", ", ", ", ") velocity_inlet = solver.tui.define.boundary_conditions.set.velocity_inlet velocity_inlet("inlet-1", [], "vmag", "no", 0.4, "quit") velocity_inlet("inlet-1", [], "ke-spec", "no", "no", "no", "yes", "quit") velocity_inlet("inlet-1", [], "turb-intensity", 5, "quit") velocity_inlet("inlet-1", [], "turb-hydraulic-diam", 4, "quit") velocity_inlet("inlet-1", [], "temperature", "no", 300, "quit") pressure_outlet = solver.tui.define.boundary_conditions.set.pressure_outlet pressure_outlet("outlet", [], "turb-intensity", 5, "quit") pressure_outlet("outlet", [], "turb-viscosity-ratio", 10, "quit")
A compilation of codes from examples provided by ANSYS website can be found here:
A very useful command for automation would be this which retrives list of wall zones: bc_state = solver.settings .setup .boundary_conditions .get_state(), w_zones = list(bc_state["wall"].keys()). This uses the list() constructor to make a List and converts the dictionary of solver settings object to a list using key() method. PyFluent works on solver settings objects where interfaces get_state(), set_state() and is_active() are commong methods, and allowed_values(), min() and max() can be applied on relevant items. It is good to know the functions available in Python to code scripts in PyFluent.Built-in | Dictionary | File |
all() | clear() | close() |
any() | copy() | detach() |
ascii() | fromkeys() | fileno() |
bin() | get() | flush() |
bool() | items() | isatty() |
bytearray() | keys() | read() |
bytes() | pop() | readable() |
callable() | popitem() | readline() |
chr() | setdefault() | readlines() |
classmethod() | update() | seek() |
compile() | values() | seekable() |
complex() | List | tell() |
delattr() | append() | truncate() |
dict() | clear() | writable() |
dir() | copy() | write() |
divmod() | count() | writelines() |
enumerate() | extend() | String |
eval() | index() | capitalize() |
exec() | insert() | casefold() |
filter() | pop() | center() |
float() | remove() | count() |
format() | reverse() | encode() |
frozenset() | sort() | endswith() |
getattr() | Set | expandtabs() |
globals() | add() | find() |
hasattr() | clear() | format() |
hash() | copy() | format_map() |
help() | difference() | index() |
hex() | difference_update() | isalnum() |
id() | discard() | isalpha() |
input() | intersection() | isascii() |
int() | isdecimal() | |
isinstance() | isdisjoint() | isdigit() |
issubclass() | issubset() | isidentifier() |
iter() | issuperset() | islower() |
len() | pop() | isnumeric() |
list() | remove() | isprintable() |
map() | istitle() | isupper() |
next() | union() | join() |
object() | update() | ljust() |
oct() | lower() | |
open() | Tuple | lstrip() |
ord() | count() | maketrans() |
pow() | index() | partition() |
print() | replace() | |
property() | rfind() | |
range() | rindex() | |
repr() | rjust() | |
reversed() | rpartition() | |
round() | rsplit() | |
set() | rstrip() | |
setattr() | split() | |
slice() | splitlines() | |
sorted() | startswith() | |
staticmethod() | strip() | |
str() | swapcase() | |
sum() | title() | |
super() | translate() | |
tuple() | upper() | |
type() | zfill() | |
vars() | ||
zip() |
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... Note that TUI /print/summary yes set_up.sum prints a text file containing summary of case set-up. The sections and sub-sections of this text file is as described below.
Section | Sub-section |
Models | None |
Material Properties | Material: Material-Name for all material(s) e.g. Material: air (fluid), Material: aluminum (solid), Material: anthracite (inert-particle)... |
Cell Zone Conditions | Zones, Setup Conditions. Under Zones, list of zones in order "name id type" |
Boundary Conditions | Zones, Setup Conditions. Under Zones, list of zones in order "name id type" |
Solver Settings | Equations, Numerics, Unsteady Calculation Parameters, Under-Relaxation Factors, Linear Solver, Pressure-Velocity Coupling, Discretization Scheme, Solution Limits |
Condition | Value |
Thermal BC Type | Convection |
Convective Heat Transfer Coefficient [W/ (m^2 K)] | 5 |
Wall Motion | Moving Wall |
Shear Boundary Condition | No Slip |
Wall Surface Roughness | rough-bc -standard |
Define wall motion relative to adjacent cell zone? | n |
Apply a rotational velocity to this wal1? | yes |
Internal Emissivity | 0.4 |
Wall Roughness Height [m] | 0.0005 |
Normal | 1 |
Tangent | 1 |
Rotation Speed [rad/s] | 5000 |
To look for changes in boundary conditions and solver setting, one has to compare the Reference file with new Modified set-up file. However, any file comparison works well only when the content follow similar structure including blank lines. Two files with identical content but differing by just one blank line shall make most of the script demonstrate the content as very different. Following code summarizes the commong and different lines but suffers from same limitation as mentioned earlier.
def printDifferentLines(file_1, file_2, prefix_1, prefix_2): ''' Adapted from: geeksforgeeks.org/compare-two-files-line-by-line-in-python Prints lines common to the two files in a file named Lines_common.txt Prints lines different in two file in a file named Lined_different.txt. prefix_1 and prefix_2 are added at the beginning of lines. ''' fi_1 = open(file_1, 'r') fi_2 = open(file_2, 'r') f_comm = 'Lines_common.txt' f_diff = 'Lines_different.txt' f1_line = fi_1.readline() f2_line = fi_2.readline() line_num = 1 # Line number counter with open(file_1) as f_1: with open(file_2) as f_2: common_lines = set(f_1).intersection(f_2) with open(f_comm, 'w') as fo: # Print lines common in both files fo.write("Lines common in the two files \n") for line in common_lines: fo.write(line) with open(f_diff, 'w') as fo: fo.write("Lines different in the two files \n") while f1_line != '' or f2_line != '': f1_line = f1_line.rstrip() f2_line = f2_line.rstrip() if f1_line != f2_line: # Compare the lines from both files # Print the line from file_1 and add prefix_1 at start of line f1_str = prefix_1 + (" Line-%d " % line_num) + f1_line + '\n' fo.write(f1_str) # Print the line from file2 and add prefix_2 at start of line f2_str = prefix_2 + (" Line-%d " % line_num) + f2_line + '\n' fo.write(f2_str) # Read next line from the file f1_line = fi_1.readline() f2_line = fi_2.readline() line_num = line_num + 1 fi_1.close() fi_2.close() printDifferentLines('f1.txt', 'f2.txt', '1->', '2->')
Another option is a line-vs-file comparison where each line in the Reference file is checked for its presence in Modified file. This is a sequential operation requiring N1 x N2 loops where N1 and N2 are number of lines in file 1 and 2 respectively. This can be accomplished with following code. The same code can be used to find lines in file 1 and not in file 2 by switching (reversing) the arguments. printNewLines(file_1, file_2) shall print lines in 2 and not in 1. printNewLines(file_2, file_1) shall print lines in 1 and not in 2.
def printNewLines(file_1, file_2): ''' Prints lines not present in reference file (first file) and present in modified file (second file). Output is printed in Lines_in_x_not_in_y.txt ''' fi_1 = open(file_1, 'r') fi_2 = open(file_2, 'r') f_diff = 'Lines_in_x_not_in_y.txt' # f.readline() reads a single line of the file. readlines(): list of strings f1_lines = fi_1.readlines() line_num = 1 with open(f_diff, 'w') as fo: out_str = "Lines found in " +file_2+ " and not present in " +file_1+ '\n' fo.write(out_str) f2_line = fi_2.readline() # If f.readline() returns an empty string, EOF is reached while f2_line != '': print("Checking line number: ", line_num) line_exists = True #Check if the line f2_line exist in list f1_lines or not for line in f1_lines: if len(line.strip()) > 0: #Skip empty or blank lines if line.strip() != f2_line.strip(): line_exists = False else: line_exists = True break if (line_exists == False and f2_line.strip() != ''): fo.write(f2_line) line_num = line_num + 1 f2_line = fi_2.readline() fi_1.close() fi_2.close() printNewLines('f1.txt', 'f2.txt')
To prepare summary of specific blocks of statements, following code can be used.
def printBetweenPatterns(file_name, string_start, string_end): ''' Reads a file and prints the content between strings. No exact match is checked, only the lines between the lines string_start and string_end are printed. Boolean block_starts and block_ends are used to indicate start and end of the required block of lines. ''' in_file = open(file_name, 'r') lines = in_file.readlines() values_bw_patterns = [] tmp_values_bw_patterns = [] block_starts = False block_ends = False for line in lines: if string_start in line: block_starts = True block_ends = False elif string_end in line: block_ends = True block_starts = False if block_starts: #Store the lines in a temporary list tmp_values_bw_patterns.append(line) ''' Only if string_end is found, move the temporary list to final list. This loop can be customized to print only start and end of the block or given number of lines at start or tail of the block. ''' if not block_starts and block_ends: n_block = len(tmp_values_bw_patterns) for i in range(n_block): line_bw_pattern = tmp_values_bw_patterns[i].strip() values_bw_patterns.append(line_bw_pattern) # Reset the temporary list to store data for next block tmp_values_bw_patterns = [] n_lines = len(values_bw_patterns) if n_lines > 0: for i in range(n_lines): print(values_bw_patterns[i]) else: print("No matching block of start and end pattern found!\n")
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 # Access function Colebrook in ./fluids/friction.py fricFac = fluids.friction.Colebrook(nRe, RRH) print("\n Friction factor - Colebrook formula: {0:8.3f}".format(fricFac),'\n')
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}] }
Scripting in ANSYS Discovery
The main prerequisite is the familiarity with SpaceClaim GUI and nomenclature. Other than the official User Guide, a short and detailed resource is the appendix in the book "Computational Fluid Dynamics: An Introduction to Modeling and Applications, 1st Edition" from McGraw Hill. The appendix on SpaceClaim can be found at "accessengineeringlibrary.com/content/book/9781264274949/back-matter/appendix5". Few examples of scripts can be found at github.com/inr-kit/SpaceClaim_scripts. The Python API is found in <ANYSS_INSTALL_DIR>v212\scdm\SpaceClaim.Api.V212\API_Scripting_Class_Library.chm
It is important to know definitions of terms in SCDM such as 'Part', 'Body', 'Component', 'Surface'... A body with faces that form a closed (watertight) volume is considered a solid. Bodies whose faces do not 'close' fully are considered as surface bodies. Solid bodies and surface bodies can be distinguished by the icons before their names in the GUI. The Python script window in SCDM has autocomplete property of built-in variables and methods. A drop-down appears once you type the dot separator. To get properties and methods associated with a given SpaceClaim object, use Dir() command. For example, Dir(face .Edges[0] .Shape .Geometry) will give list of all properties and methods inside face .Edges[0] .Shape .Geometry.
Get the root part: part = GetRootPart(), bodyNames = GetRootPart() .GetAllBodies(), Get all named selections: groups = GetActiveWindow() .ActiveWindow .Groups. Such lists can be accessed by standard "for loop" in Python such as "for bd in bodyNames:" or "for ns in groupsNS:". To select all faces of a body: bd_faces = bd.Faces where bd is defined as a body earlier. To get name of a body: bd_name = bd.GetName().
Get all components: compList = GetRootPart() .GetAllComponents(). Make a component independent (break association with instancce array): makeIndep = ComponentHelper .MakeIndependent(compName, None). Get Instance Suffix of a component name: c_name = compName.Name, Get searchable name of a component: q_name = compName.GetName() - notice the parentheses. Rename a component: compName.setName( new_comp_name ). Rename a body: bd_name.SetName( new_body_name ). Get all bodies in a component: body_list_in_comp = compName.GetAllBodies(). Get number of bodies in a component: n_body = body_list_in_comp.Count. face_body_1 = Selection.Create( bodies[1].Faces ) where bodies = part.GetAllBodies(). Note that Selection.Create(body) creates a selection of 'body' and not creates the 'body'.Codes related to visibility and selections: To access any selected entity, select = Selection.GetActive() .ViewHelper .ShowAll(), result = ViewHelper.InvertVisibility() .selection = BodySelection.Create( list_of_bodies ). ColorHelper .SetFillStyle(selection, FillStyle.Defualt, FillStyle.Opaque). Select all faces of part: PartSel = Selection.Create(GetRootPart()), faces = PartSel.ConvertToFaces(). Selection of the face (using the Index values): Selection.Create( GetRootPart() .Bodies[0] .Faces[0] ). Selection for the body: Selection.Create( GetRootPart() .Bodies[0] ). Select existing datum plane: datumSel = Selection .Create(GetRootPart() .DatumPlanes[0])
Select faces by bounding box - selects faces if they are even partially inside the bounding box: innovationspace.ansys.com/ ... /spaceclaim-script-selection-by-filterbyboundingbox
PartSel_1 = Selection.Create(GetRootPart()) Faces_1 = PartSel_1.ConvertToFaces() PartSel_2 = Selection.Create(GetRootPart().Bodies[0]) Faces_2 = PartSel_2.ConvertToFaces() Faces = Selection.Difference(Faces_1, Faces_2) BBox = Box.Create(minX, minY, minZ, maxX, maxY, maxZ) Faces_in_BB = Faces.FilterByBoundingBox(BBox)
Smart Selection
selecton = PowerSelection .Faces .ByRoundRadius(Face1, PowerSelectionOptions(False), SearchCriteria .SizeComparison .SmallerOrEqual, SeachCriteria .RoundType .All)secondarySelection = Selection.Empty()
options = FillOptions()result = Fill.Execute(selection, secondarySelection, options, FillMode.ThreeD, Info1)
Codes related to body and components: selection = Body1, result = ComponentHelper.MoveBodiesToComponent( selection, Info1). Rename a component to Part_X: result = RenameOject.Execute( selection, "Part_X"). Move a body to a component: selections = Body2, result = ComponentHelper.MoveBodiesToComponet( selections, Component, False, Info2).
Create named selections: result = NamedSelection.Create( Selection.Create( w_hflux ), Selection() ). result = NamedSelection.Rename( "Group1", "w_heat_flux" ) where w_hflux is the name of the list containing faces selected based on certain criteria.
primarySelection = FaceSelection.Create(GetRootPart().Bodies[1].Faces[1]) secondarySelection = Selection.Empty() result = NamedSelection.Create(primarySelection, secondarySelection) result = NamedSelection.Rename("Group1", "w_faces_fixed_t")Create a named selection by using FilterByArea: part = Selection.Create( GetRootPart() ), face_list = comp.ConvertToFaces() .FilterByArea(minArea, maxArea), face_list.CreateAGroup( "w_fillets" ).
bodyNames = GetRootPart().GetAllBodies() bd_names_uniq = set(bodyNames) uniq_names_list = list(nd_names_uniq) for bd in bodyNames: bd_name = bd.GetName() bd_faces = bd.Faces # Create named selections ns_name = "w_" + bd_name Selection.Create(bd_faces).CreateAGroup(ns_name) if (bd_name.Contains("source")): ... do something ... # Loop over faces of a body. x_cg = cg[0], y_cg=cg[1] for face in body.Faces: cg = face.MidPoint().Point ViewHelper.ShowAll() ns_groups = Window.ActiveWindow.GroupsTo create unique names of bodies in a (root) part, following code can be used.
names_list = ['Mango', 'Banana', 'Guava', 'Mango', 'Grapes', 'Mango'] def createUniqList(names_list): size_list = len(names_list) names_uniq = set(names_list) # Conver unique names back to a list uniq_list = list(names_uniq) for uniq_item in uniq_list: n_repeat = names_list.count(uniq_item) i = 1 if (n_repeat > 1): for itr in range(size_list): if (names_list[itr] == uniq_item): names_list[itr] = uniq_item + "_" + "{:02d}".format(i) i = i + 1 return names_list
radSph = 100, sphBody.Create( Point.Create(MM(0), MM(0), MM(0)), Point.Create(MM(radSph), MM(radSph), MM(0)), ExtrudeType .None), x1 = 10, y1 = 25, x2 = 50, y2 = 75, start = Point2D .Create( MM(x1), MM(y1) ), end = Point2D .Create( MM(x2), MM(y2) ), result = SketchLine.Create(start, end), Create a sketch plane and point on that plane: plane = Plane.ZX, result = ViewHelper .SetSketchPlane(plane), point = Point2D .Create( MM(x1), MM(y1) ), result = SketchPoint .Create(point)
Change to Solid View mode: mode = InteractionMode .Solid, result = ViewHelper .SetViewMode(mode). Set Section View: sectionPlane = Plane .PlaneXY, result = ViewHelper .SetSectionPlane(sectionPlane). Create Datum Plane: plane = Plane.PlaneYZ, result = DatumPlaneCreater .Create(plane, False).
Ref: innovationspace.ansys.com/knowledge/forums/topic/discovery-spaceclaim-scripting-examples: scripts to (a)loop through bodies and its faces to identify face midpoint, compare it with center coordinates of inlet and outlet (b) create Named Selection groups – inlet, outlet, wall and fluid, by identifying the faces (inlet, outlet) based on their location.
Codes to repair geometry: result = FiexInterference .FindAndFix( Info1 ), result = FixSplitEdges .FindAndFix(), result = FixExtraEdges .FindAndFix( Info2 ). options = FixMissingfacesOptions(), result = FixMissingFaces .FindAndFix( options, None ). Share Topology: options = ShareToplogyOptions(), options .Tolerance = MM(0.05), result = ShareToplogy .FindAndFix(options, Info3). Merge Bodies: targets = BodySelection .Create(Body1), tools = BodySelection .Create(Body2), result = Combine .Merge( targets, tools ). Components in SpaceClaim are collection of bodies. The "Share Topology" property of a component can be set as: comp = GetRootPart().Components[i], comp.Content .ShareTopology = comp.Content .ShareTopology .Share. mat_name = GetRootPart() .Bodies[0] .Material
Get Geometry Information: Get area of a face - bd_faces[0]. bd_faces[0].Shape.Perimeter, bd_faces[1].Edges.Count, By selecting edges the vertices defining the edge can be accessed. bd_faces[2].Shape.Geometry.GetType() - get type of face such as cylinder or plane. Get centroid of a face: GetRootPart( ).Bodies[1] .Faces[2] .EvalMid( ).Point. Get face normal: GetRootPart( ).Bodies[0] .Faces[1] .GetFaceNormal(0, 0). Get radius: face.Edges[0] .Shape .Geometry .Radius or face.Edges[0] .Shape .GetGeometry[Circle]() .Radius. Get mid-point: face.MidPoint().Point. Get centre of an edge: edge.Shape .GetGeometry[Circle]() .Axis .Origin. Get the centre of volume: vol = body.MassProperties.RawSubject or vol = body.Shape.Volume, cen = vol.Center. Faces.AdjacentFaces, edge = face.Shape .Edges[i], face.Shape .GetAdjacentFace(edge), Faces[i].Edges .Count, Faces[i].GetTangentChain() .Count. To get the common face between two bodies, all the faces have to be iterated on one body and parent(s) of each faces should be checked.
get number of total faces: numFaces = len(GetRootPart() .Bodies[0] .Faces). Get normal: norm_value = str((GetRootPart() .Bodies[0] .Faces[i] .GetFaceNormal(0, 0))). Compare normal direction of a surface with +x direction: norm_value == 'Direction: (1, 0, 0)'. Get all edges of a body: GetRootPart() .Bodies[0] .Edges, Get Z-coodinate of start point of an edge: z0 = GetRootPart() .Bodies[0] .Edges[1] .Shape .StartPoint .Z, Create a datum plane aligned to zx-plane: datumPlane = DatumPlaneCreator .Create(Point .Create(0, y0, 0), Direction.DirY) .CreatedPlanes[0]Get centroid of a surface of a solid body, not surface bodies. Note that instances of solid bodies are known as 'DesignBody' and instances of surface bodies are called 'IDesignBody'. Thus, IsClosed property exists in the Shape property of the DesignBody and not in the instances of IDesignBody. Method-1: mass_prop = bodies[1].MassProperties .RawSubject, cen_body_1 = mass_prop.Center. Method-2: refer the code below.
selected_items = Selection.GetActive().Items for selected_item in selected_items: if not isinstance(selected_item, DesignFace): continue #if isinstance(selected_item, DesignFace): # or #is_solid = selected_item.GetMaster().Shape.IsClosed sel_i = Selection.Create(selected_item) pt = MeasureHelper.GetCentroid(sel_i) new_pt = SketchPoint.Create(pt)
Get mass properties: principal axes and moments about principal axes. Ref: discuss.ansys.com/ ... /how-to-get-the-combined-space-claim-mass-properties
body_list = BodySelection.Create(GetRootPart().Bodies) massProps = MeasureHelper.GetMassProperties(body_list) mass = massProps.Mass pa_x = massProps.PrincipleAxes.AxisX pa_y = massProps.PrincipleAxes.AxisY pa_z = massProps.PrincipleAxes.AxisZ principalMomentXAxis = massProps.GetMoment(pa_x) principalMomentYAxis = massProps.GetMoment(pa_y) principalMomentZAxis = massProps.GetMoment(pa_z) pa_x_dir = pa_x.Direction pa_y-dir = pa_y.Direction pa_z_dir = pa_z.Direction
Set Material Type: ref = discuss.ansys.com/ ... /how-can-i-assign-a-material-to-multiple-bodies-in-spaceclaim
mat = GetRootPart().Bodies[0].Material matId = SpaceClaim.Api.V24.MaterialPropertyId prop = SpaceClaim.Api.V24.MaterialProperty(matId.ElasticModulus, "Elastic Modulus", 15, None) mat.SetProperty(prop) mat_name = "Gray Cast Iron" succ_local, local_mat = Window.ActiveWindow.Document.Materials.TryGetValue(mat_name) if not succ_local: succ, mat = SpaceClaim.Api.V24.LibraryMaterial.Library.TryGetValue(mat_name) local_mat = SpaceClaim.Api.V24.DocumentMaterial.Copy(Window.ActiveWindow.Document, mat) for body in GetRootPart().GetAllBodies(): body.Material = local_mat
Scripting in ANSYS DesignModeler
The script file is written in JScript (extension *.js). // Two slashes indicate a comment. Access to the DesignModeler application functions is accessible via the prefix 'agb.', as in the command: agb.Regen(); //Run 'Generate' command. Create a Boolean operation: var bool_addBodies= ag.gui .CreateBoolean(); bool_addBodies.Name = "Add Bodies"; bool_addBodies.Operation = 0; ag.listview .ActivateItem("Tool Bodies"); agb.ClearSelections(); body_1 = ag.fm.Body(1); agb.AddSelect(agc.TypeBody, body_1); body_2 = ag.fm.Body(2); agb.AddSelect(agc.TypeBody, body_2); ag.listview .ItemValue = "Apply";Script Constants: These must be prefixed with agc to be usable such as agc.Add //Add Material. FormNewPartFromAllBodies(); FormNewPartFromSelectedBodies(); Properties: 'Name' allows the part to be named; for example, px.Name = "Origin_x";
Scripting in Cadence's Fidelity Pointwise
The scripting language is known as Glyphs which is implemented as a set of Tcl/Tk (Tool command Language / Tool kit) procedures. Pointwise supports non-Tcl scripting (or binary code) applications through a feature called Glyph Server.Scripting in ANSYS Workbench
Ref: "Scripted CFD simulations and postprocessing in Fluent and ParaVIEW" by Lukas Muttenthaler et al at Johannes Kepler University Linz# Import necessary Modules import os # Set Path and Project case_Path = "C:/Projects/" file_Proj = "Case_HTX.wbpj" # Project operations: Opens Project Open(FilePath = os.path.join(case_Path, file_Proj)) # Get the System with Name "FFF" system1 = GetSystem(Name = "FFF") # Get "Setup" - Container set_up = system1.GetContainer(ComponentName = "Setup" ) # Specify Filename of parameters file parsFilename = 'SimParameters' # Prefix of File with Commands prefixFilename = 'StudyA' # File with Commands for Fluent mainFilename = 'SimCommands' # Ending of the Filename with Scheme Commands suffixFilename = '. scm' # Specify inlet velocities [m/s] as Python 'list' inlet_velocities = [2, 4, 6] # Naming Parts for Saving File: should match number of cases saveFilename = ['SimA', 'SimB', 'SimC'] # Start and Stop Indices of the Loop: 0-based count_StartIndex = 0 count_StopIndex = len(inlet_velocities) # Load file with important parameters actualPars = prefixFilename + parsFilename + suffixFilename # Opens the specified file in 'read' mode and get the 'file' object parFile = open (actualPars, 'r') parCommands = parFile.read () parFile.close () # LOOP THROUGH THE SIMULATIONS for case_num in range (case_num_StartIndex, (case_num_StopIndex + 1)): # Reset the Fluent Container set_up.Reset() set_up.Refresh() # Run Fluent and set properties set_up.GetFluentLauncherSettings().ShowLauncher = False set_up.GetFluentLauncherSettings().Precision = 'Double' set_up.GetFluentLauncherSettings().RunParallel = True set_up.GetFluentLauncherSettings().NumberOfProcessors = 32 set_up.Edit() # Send changing Parameters set_up.SendCommand (Command = '(define calcCase %s)' %str(saveFilename[case_num])) set_up.SendCommand (Command = '(define velMax % d)' %inlet_velocities[case_num]) # Send the commands specified in the file as string to Fluent : set_up.SendCommand(Command = parCommands) set_up.SendCommand(Command = commands) set_up.Exit ()
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); }
// 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:\\STAR\\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(1600); hardcopyProperties_0.setCurrentResolutionHeight(900); 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"); } } 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)"); } }
Application Productivity Tools (APT)
These are template files containing predefined settings for the mesh, physics, and post-processing scenes to save engineering time. One such template available in STAR-CCM+ is Turbo Aerodynamics Workflow.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()
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). CFX Reference Guide provides detailed explanation of CEL and CCL. Some information are provided in <CFXROOT>/ etc/ CFXPostRules.ccl.
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.
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. Access environment variables in Perl: $ENV{PATH}; $ENV{USERNAME}; $ENV{USERDOMAIN};
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): Arrays are zero-based, which means that the first element's index number is 0. 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'.
File Handling in PERL: File handles are created using open() statements such as open(MYFILE, "infile.dat") to open a new file, open(MYFILE,">outfile.dat") opens and existing file and shall fail if file exists. open(MYFILE,">>log.dat") opens a file for appending content to an existing file. It can be piped to return true/false for success/failure: open(IN, "infile.dat") || print "Error: couldn’t open file\n"; Read from a filehandle by putting it inside angled brackets: <...>. For example to assign to scalar, returns next line in file and empty string at end:
open(INFILE, "infile.dat"); $i = 1; while($line = <INFILE>) { print "Readling line $i: $line\n”; $i = $i + 1; }
Assigned to array all lines from a file
open(INFILE, "log.dat"); @allLines = <INFILE>; $i = 1; foreach $line (@allLines) { print "The line $i contained: $line\n"; $i = $i + 1; }
List files of specified type (extension)
$dir_path = "."; $extn = "pdf"; opendir DIR, $dir_path or die "Cannot open dir $dir_path: $!"; my @files = sort readdir DIR; #my @files = sort glob "$dir_path/*.$extn"; for (0..$#files){ if($files[$_] =~ /\.$extn$/i) { print "$files[$_] \n"; } } closedir DIR;
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");
Important Note: While dealing with angular variables, divide the overall expression with 1 [rad]. For example, v_t = 2 * pi * 1000 [rev/min] / 60 is not a valid expression and shall not produce v_t in [m/s]. Correct statement would be v_t = 2 * pi [rad/rev] * 1000 [rev/min] / 60 [s/min] / 1 [rad]: this shall calculate tangential velocity in [m/s].
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:
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. A recommended practice is to have use strict and use warnings 'all' at the top of every Perl program. "use strict" tells Perl to prevent implicit creation of global variables.
! ($MFinlet, $MFunit) = evaluate("massFlow()\@Inlet"); ! printf ("Mass Flow at Inlet %10.5f [$MFunit] \n", $MFinlet); ! 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); ! }To have leading zeros in digits: printf "%05d\n", $n; Here The % denotes "beginning a format sequence", the 0 denotes "fill spaces with leading zeros", 5 indicates "number of fields to be used" and d is for variable type 'integer'. If the number exceeds 5 digit, it will be printed without any leading zero. For variables of type float: $num_str = sprintf("%05.2f", $n); where if the number requires more than 5 fields, it will still print the whole number without leading zero.
Note that the CCL statement can be inserted into PERL block of codes as demonstrated below.
! $numSteps = 20; ! for (my $i=0; $i<=$numSteps; $i++) { ! $transparency = $i/$numSteps; BOUNDARY:Default Transparency = $transparency END ! }Evaluate the value and units of any single-valued CEL expression: ($val, $units) = evaluate("expressionName"); Determine the value of any CCL parameter in the post-processor: $val = getValue("OBJECT:NAME", "Parameter Name"); List currently defined subroutines to command window: showSubs. List currently defined power syntax variables and values: showVars. getExprVal("exprName") function: set a perl variable to the expression value. probe($CP, PointXYZ) = get value of expression at PointXYZ.
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"; #Multiple results can be written on same line ! close(RESULT);
Evaluate expressions and print the result to a text file: here 'avgPressureInlet' is the name of the expression.
! ($AvgPr, $unit) = evaluate("avgPressureInlet"); ! $file_name = "./log.txt"; ! if (not -f $file_name) { ! open(RESULT, ">".$file_name); ! } else { ! open(RESULT, ">>".$file_name); ! } ! print RESULT "$AvgPr $unit \n";
Mutiple values can be printed on same line separated by comma or any other character. This will make it easier to transfer the data to a table. Some more examples: Pstf = areaAve(Total Presure in Stn Frame)@Inlet, $maxtemp = maxVal(“Temperature", "Default Domain"). CFD-Post offers option to generate quantitative data in table. In addition to GUI method, following session commands can be used.
Create a table:TABLE: Table_summary Table Exists = True EndEnter header name:
TABLE: Table_summary TABLE CELLS: A1 = "Description", False, False, False, Left, True, 0, Font Name, 1|1, \ %10.3e, True, ffffff, 000000, True END ENDGenerate unit reported by expression or function calculator
TABLE: Table_summary TABLE CELLS: B1 = "=massFlowAve(Pressure)@Inlet", False, Flase, False, Left, True, 0, 1|1, \ %10.3e, True, ffffff, 000000, False END ENDCalculate value as per expression or function calculator
TABLE: Table_summary TABLE CELLS: C1 = "=expression_name", False, Flase, False, Left, True, 0, 1|1, \ %10.3e, True, ffffff, 000000, True END END
Create a pressure contour on PlaneYZ created earlier.
Set Camera Views, Show/Hide Contours and save hardcopies. Note that in CFD-Post, +Z is Z-axis pointing away from the screen and hence using right hand rule, X-axis has to be in width (horizontally left to right direction) and Y-axis in height (vertically upward direction).
# Sending visibility action from ViewUtilities >show /CONTOUR:ContourPlaneYZ, view=/VIEW:View 1 >hide /CONTOUR:ContourPlaneYZ, view=/VIEW:View 1 # Sending visibility action from ViewUtilities >hide /PLANE:PlaneYZ, view=/VIEW:View 1 >show /PLANE:PlaneYZ, view=/VIEW:View 1 >setcamera viewport=1, camera=+Z HARDCOPY: Antialiasing = On Hardcopy Filename = Orifice_Duct_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 #Save the pictureShort code to save pictures:
# Define settings for saving a picture HARDCOPY: Hardcopy Format = jpg Hardcopy Filename = Contour_v1.jpg Image Scale = 70 White Background = Off END #Create an output file based on the settings in HARDCOPY >print #Create an identical output file with a different filename >print counter_v2.jpgUpdate camera view: Here Quaternion = 0, 0.707107, 0, 0.707107: -X-axis | 0, -0.707107, 0, 0.707107: +X-axis | -0.707107, 0, 0, 0.707107: -Y-axis | 0, 0.707107, 0.707107, 0: +Y-axis. There are another ways to set camera view: >setcamera viewport=1, camera=+Z
VIEW: View 1 Camera Mode: User Specified Camera: Option = Pivot Point and Quaternion Pivot Point = 0.05, 0.10, -1.50 Scale = 10 Pan = 0, 0 Rotation Quaternion = 0, 0, 0, 1 # +Z-axis END END > update >centerview 1 # Fit Window
CCL and PERL are case sensitive. Examples to create Expressions
# 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 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 MuAir = 1.72E-5 [kg m^-1 s^-1] *(T / 293 [K])^0.742 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 # Save .cfx file > writeCaseFile > update # Write .def file only > writeCaseFile filename=$DEF, operation=write def file > update # Write .def file and start solver > writeCaseFile filename=$DEF, operation=start solver interactive # operation="write def file" or "start solver batch"
Create a file name based on .RES file
! my $fileName = getValue("DATA READER", "Current Results File"); # Get filename for the output ! my @subStrings = split /\//, $fileName; ! my $size = @subStrings; ! my $outputFile = $subStrings[$size - 1]; # Following statement fails if a back-up file say 250_full.bak is opened ! $outputFile =~ s/\.res/_output\.txt/; # Open a text file for writing data, CFD-Post crashes if file name not defined ! open($outputFile, ">".$outputfile);
Post-processing statements in PERL
Examples from Web
# Ref: stackoverflow.com/questions/46793289/perl-cfd-post-calculating- # the-average-of-a-sequence-of-numbers-on-the-fly-to # Output file for storing the pressure values ! $outputfile = "pressure.txt"; ! open(outFile, ">>".$outputfile); # Print headings ! print outFile "time [s] location distance [mm] Max Pressure [Pa]\n"; # # Loop for creating locations ! for ($i = 0; $i > 101; $i += 10) { ! $location = "x${i}"; # xxx # Code for creating locations for extracting spatial data # xxx # Get timestep values from the current results file ! $timestepList = getValue("DATA READER", "Timestep List"); ! @timesteps = split(/, /, $timestepList ); ! foreach $ts (@timesteps) { # Load current timestep, > load timestep = $ts ! $time = getValue("DATA READER", "Current Timevalue"); # Retrieving the pressure value at each location ! $MaxPressure = maxVal("Pressure", "$location"); ! print outFile "$time $location $i $MaxPressure\n"; ! }; ! }; ! close outFile;
Another example from previous thread: Declare all your variables at their first point of use with 'my' which makes variable to be local to the enclosing block (e.g. for loop), file, or eval in which it is defined. If more than one value is listed, the list must be placed in parentheses. qq is an operator which can be used in place of double quotes, hence it can be deemed a short form of quote-quote.
my ($outFile, $avg_file) = (pressure.txt avg.txt); open my $out_fh, '>', $outFile" or die qq{Unable to open "$outFile": "$!}; open my $avg_fh, '>', $avg_file" or die qq{Unable to open "$avg_file": "$!}; print $out_fh "time [s] location distance [mm] Max Pressure [Pa]\n"; print $avg_fh "Distance [mm] Avg-Pressure [Pa]\n"; for ( 0 .. 10 ) { my $i = $_ * 10; # $i = 0, 10, 20, ... 100 my $location = "x$i"; my $timestep_list = getValue('DATA READER', 'Timestep List'); my @timesteps = split /,\s*/, $timestep_list; my ($n, $total_maxp) = (0, 0); for my $ts (@timesteps) { my $time = getValue('DATA READER', 'Current Timevalue'); my $max_pressure = maxVal('Pressure', $location); print $out_fh "$time $location $i $max_pressure\n"; ++$n; $total_maxp += $max_pressure; } printf $avg_fh "%-16d%-.3e\n", $i, $total_maxp / $n; } close $out_fh or die $!; close $avg_fh or die $!;foreach aliases the current element to the topic variable $_. Following lines of code reads a list and create file names by replacing whitespace (if present) with underscore. Note that no line continuation character is needed in PERL.
@contourNames = ("Contour Pressure 1", "Contour Pressure 2", "Velocity Vector 1", "Velocity Vector 2", "Steamline_1", "Streamline_2"); foreach (@contourNames) { $file_name = $_; $file_name =~ s/\ /_/g; $file_name = $file_name. ".png"; print "Contour file is saved as: $file_name\n"; } @a = (3, 5, 7, 9); foreach $number (@a) { $number += 2; } # @a is now (5, 7, 9, 11);
!@contourNames1 = ("Contour Pr 1", "Contour Pr 2", "Velocity Vel 1"); !@contourNames2 = ("Steamlines 1", "Streamlines 2", "Streamlines 3"); !$nContours = scalar(@contourNames1); !for ($i = 0; $i < $nContours; $i++) { ! $file_name = @contourNames1[i]; ! $file_name =~ s/\ /_/g; ! $file_name = $file_name. ".png"; > show /CONTOUR:@contourNames1[i], view=/VIEW:View 1 > show /CONTOUR:@contourNames2[i], view=/VIEW:View 1 HARDCOPY: Antialaising = On Hardcopy Format = png Hardcopy Filename = $file_name Image Scale = 70 Transparent Background = Off Use Screen Size = On White Background = Off END #Create an output file based on the settings in HARDCOPY > print ! print "Contour file is saved as: $file_name\n"; > hide /CONTOUR:@contourNames1[i], view=/VIEW:View 1 > hide /CONTOUR:@contourNames2[i], view=/VIEW:View 1 }
Load multiple *.res files for post-processing
!foreach $res_file ('Project_001.res', 'Project_002.res', 'Project_003.res') !{ ! print "Processing $res_file \n"; ! @temp_file = split('.res', $res_file); ! $file_name = $temp_file[0].".png"; ... DATA READER: ... END > load filename=$res ... ! $maxtemp = maxVal("Temperature", "solid_domain"); !}
Add text (annotations): note that not all inputs are required in CCL.
TEXT:Text 1 Colour = 0, 0, 0 Font = Sans Serif Position Mode = Two Coords Text Colour Mode = Default Text Position = 0.50, 0.10 # Fractions, X=0 at left, Y=0 at bottom X Justification = Center # Select None to use "Text Position" Y Justification = Top # Select None to use "Text Position" TEXT ITEM:Text Item 1 Embed Auto Annotation = Off Text Item Active = On Text String = Sample_Text END END #Sending visibility action from ViewUtilities > show /TEXT:Text 1, view=/VIEW:View 1
Create Surface Groups and create a banded contour on it: Note that object (planes, contours, tables, annotations...) names in CCL do not accept hyphen or any other special character including an underscore.
SURFACE GROUP: srf grp 1 Apply Instancing Transform = On Colour Mode = Variable Colour Variable = Total Pressure in Stn Frame Domain List = /DOMAIN GROUP: All Domains Draw Contours = On Draw Faces = On Draw Lines = Off Instancing Transform = /DEFAULT INSTANCE TRANSFORM: Default Transform Location List = /ISOSURFACE:Isosurface Z50, /ISOSURFACE:Isosurface X25 Max = 1.5E5 [Pal Min = 2.0E4 [Pa] Number of Contours = 11 Range = User Specified END
TUI commands for Parametric Studies in ANSYS FLUENT
For any parametric study, one of the key requirement is to define a naming standard for case file, not only considering parameters but also the requirements of post-processing (such as generating contour plots and hardcopies). It is better to use the file name or part of it to define case-specific variables and objects. For naming output or input file, use numbers with leading zero(s) so that they are sorted in acutal sequence. For example, Plot-1.png, Plot-11.png, Plot-12.png... Plot-19.png, Plot-2.png, Plot-21.png... will be sorted order instead of Plot-1.png, Plot-2.png, Plot-3.png. To avoid this, use file names like Plot-001.png, Plot-002.png ... Plot-011.png, Plot-012.png... Similaly, if the images are to be inserted into a PowerPoint document, a counter should be added to the images to be put on separate slides.The set-up for a parametric study cannot be automated even partially if the solution runs cannot be started from local (user's) host to a remote cluster.
The link parametric.fluent.docs.pyansys.com/dev/examples/00-parametric/index.html provides a Python-based example. It can be converted to a journal-based by converting Python statements into Scheme/TUI commands.
/parametric-study/study initialize yes , /parametric-study/design-points add no yesHere 'no yes' on the last statement is response to queries "Do you want to write data?" and "Do you want to capture simulation report data?".
Format of a .csv Design Point Input Table
Name | par_in_vel | par_in_temp | Write Data | Capture Simulation Report Data | Status |
Units | [m/s] | [C] | |||
DP_0 | 5 | 75 | Yes | No | Need Update |
DP_1 | 2 | 50 | Yes | No | Need Update |
DP_2 | 1 | 25 | Yes | No | Need Update |
The csv file shall have the format shown below. More columns can be added to introduce new input parameters and new rows can be added to increase number of design points.
Name, par_in_vel, par_in_temp, Write Data, Capture Simulation Report Data, Status Units, [m/s], [C] DP_0, 5, 75, Yes, No, Need Update DP_1, 2, 50, Yes, No, Need Update DP_2, 1, 25, Yes, No, Need Update
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".
The options and range of file size which is seached is summarized as follows: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:
Number | Colour | Number | Colour | Number | Colour | Number | Colour |
0 | Black | 4 | Red | 8 | Gray | C | Light Red |
1 | Blue | 5 | Purple | 9 | Light Blue | D | Light Purple |
2 | Green | 6 | Yellow | A | Light Green | E | Light Yellow |
3 | Aqua | 7 | White | B | Light Aqua | F | Bright White |
Command: "colour 70" (without double quotes) shall change the appearance of terminal to white background and black fonts.
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.
Examples:
Global and Local Scope of Variables: By default, variables are global for entire batch script. SETLOCAL ... ENDLOCAL block can be used to make variables local in scope.
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 or set list=A B C D (avoid space after and before '='). 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%
Convert a list into Array
setlocal EnableDelayedExpansion set n=0 for %%a in (AB BC CD DE) do ( set array_x[!n!]=%%a set /A n+=1 )Another way to create a list is:
set feature_list=cfd_base set feature_list=%feature_list%;cfd_preppost set feature_list=%feature_list%;anshpc_pack set feature_list=%feature_list%;cfd_fluent
Using the line-continuation character ^:
set feature_list=cfd_base;^ cfd_preppost;^ anshpc_pack;^ cfd_solve_level1;^ cfd_fluent;
Yet another way
set ar_elem[1]=First set ar_elem[2]=Second set ar_elem[3]=Third
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" List.txt, To search for "Batch Script" in file UserGuide.txt, type: findstr /c:"Batch Script" UserGuide.txt. When the search string contains multiple words, separated with spaces, then findstr will return lines that contain either word (OR). A literal search (/C:string) will reverse this behaviour and allow searching for a phrase or sentence.
/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.
More examples from superuser.com/questions/909127/findstr-dos-commands-multiple-string-argument
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, enclose the executable part of the for loop in single quotes:
FOR /F ["options"] %%var IN ('command to run') DO ( command echo Press any key to exit . . . pause>nul )Check number of occurrences of a word (string) in a file: count the lines that contain the string defined by 'wrd', not the number of occurences of the string on each line.
@echo off set "file=C:\Users\Summary.txt" set wrd=Users for /f %%F in ( 'findstr /I "%wrd%" %file% ^| find /I /C "%wrd%"' ) do ( set count=%%F ) if count neq 0 ( exit /B 1 ) else ( exit /B 0 )Alternatively: find.exe executed with /C outputs the number of lines containing the searched string. The delayed variable expansion has to be set (setlocal EnableDelayedExpansion) in order to be even able to use exclamation marks !count! instead of percent signs %count. Variables are substituted to their values before a command or block of commands (e.g. FOR loop enclosed in parentheses) is executed. Thus, the new value of a variable cannot be accessed if it was changed during the runtime of a command line or block, say in loops. To avoid this early substitution or expansion and to enable the delayed variable expansion, enclose variable names in !...! rather than %...%
@echo off setlocal EnableDelayedExpansion set wrd=Users for /f %%C in ('find /C "%wrd%" ^< %CD%\Summary.txt') do ( set count=%%C ) echo %wrd% found ... %count% time(s) > Summary.log echo %wrd% found ... %count% time(s) pauseTokens
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.*ingRead specific word ONLY on a specific line from a text file using batch script: "tokens=%word% can be used to split a line with 'word' into at most 3 strings: sub-string before 'word', the string 'word' itseld and 'sub-string after the 'word'.
Extract second word of a string: tokens=n,m,p,q... can be used to get the words at these positions. The batch script to get the third word of a string is described below.
set _string=some long string for /f "tokens=3" %%i in ("%_string%") do set third_word=%%i echo %third_word%
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" loops on directories only, "for /R" recurse to sub-directories. Get the fifth line of a file, use for loop and exit the loop after fifth instance.FOR /F "skip=5 delims=" %%a IN ('Summary.txt') DO ( ECHO %%a & goto done ) :done
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%
Extract the first word from all the lines of a file: /b switch in FINTSTR matches only at beginning of line, /i is case insensitive and findstr options can be grouped together. thus /b /i /m is the same as /bim. findstr /ib /c:"%var_name%" "%file_path%" >nul 2>nul matches first word and to match last word, use findstr /ie /c:" %var_name%" "%file_path%" >nul 2>nul
set var_name="user_id" set file_path=C:\Users\Summary.txt for /f "tokens=2 delims= " %%i in (%file_path%) do ( if /I "%%i" == "%var_name%" goto :found )
Batch script to save the test between two lines starting with specified strings into a file: reference - superuser.com/.../how-to-get-the-lines-between-two-specific-lines-multiples-times-in-windows-bat
@echo off setlocal enabledelayedexpansion Rem - Specify start string and end string to search for set start_string=string_first set end_string=string_last set "num_line=0" IF EXIST trimmedText.txt ( DEL trimmedText.txt ) Rem - store content of file into a variable FOR /f "tokens=* delims= " %%i in ('type "inputFile.txt"') do ( IF "!num_line!" == "0" ( Rem - if line counter is ZERO, skip till it finds start_string echo; %%i | findstr /c:"%start_string%" >nul && set "num_line=1" ) ELSE ( Rem - if end_string is found, reset num_line to ZERO echo; %%i | findstr /c:"%end_string%" >nul && set "num_line=0" ^ || (set /p "'=%%~i" <nul & echo\) >> trimmedText.txt ) ) PAUSESort: 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.bat | Command in DOS shell | Output |
echo %n0 | sample.bat | sample |
echo %~x0 | sample.bat | .bat |
echo %~x1 | sample.bat input.txt | .txt |
copy %0 %~n0_new.txt | sample.bat | sample.bat copied to sample_new.txt |
copy %1 %~n1_new.txt | sample.bat input.txt | input.txt copied to input_new.txt |
Functions in Batch Script
Functions are called with keyword 'call' where function body start with a colon..call :batch_func 10 "string abc"
:batch_func echo. Arguments type: first - integer, second: string ('command line') goto :eofPlacing the reusable commands into a separate batch file works like a function, though the call command (call batch_func.bat) should be used such that control returns to the caller script after the 'function' batch file finishes executing.
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 parameter 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 named 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 < $fileNamePrint 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 (along with + symbol) for time period > n, -n for duration < n and n for exactly n days. -mtime +n = finds the files and directories modified more than n days ago. -mtime -n = finds the files and directories modified less than n days ago.
The utility 'find' by default shall print the names of the folder (as folder are a type of file) along with regular files. To prevent printing the folder names, use: find . -mtime -90 -type f > toCopyBackup.txt
To print all (only) folders modified more than 5 days ago along with owner (%u), time and date when it was last modified: find . -type d -mtime +5 -printf "%u %TR %TD %p\n" > last_5days.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. -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. find . -mtime -10 -exec cp -r {} ../backUpFolder \; To exclude listing from a folder 'excludeFolder': find . -mtime -90 -not -path "./excludeFolder/*" > toCopyBackup.txt
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.
To delete only (all) folders and all the contents last updated/modified 7 days ago: find /user/home/Docs/* -type d -mtime +7 -exec rm -rf {} \; To prevent deletion of base directory (/home/user/Docs here), /user/home/Docs/* is used. Alternatively, use -mindepth 1 and and -maxdepth 1 to exclude the root /user/home/Docs from the matches: find /user/home/Docs -mindepth 1 -maxdepth 1 -type d -mtime +7 | xargs rm -rf
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 folders 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 by "cat toCopyBackup.txt" into target folder irrespective of 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
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:
Find 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 }
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 Address | cat /sys/class/net/*/address, ifconfig | |
02: Get IP Address | ifconfig, ip link | ipconfig |
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 Address | Edit /etc/network/interfaces file | |
05: Configure a DHCP Client | Edit /etc/network/interfaces file | |
06: Install SQL Server | LAMP: Linux - Apache - MySQL - PHP, WAMP | WAMP |
07: Install Apache Server | LAMP: Linux - Apache - MySQL - PHP | WAMP: Windows |
08: Add Guest Users | sudo adduser guest; sudo passwd -d guest | |
09: Check / set Proxy Server | export http_proxy=http://proxy.server.com:8080 | |
10: View Active Network Connections | netstat -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.
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 and PowerPoint Functions and Macros:
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
In simulations, many plots need to be generated and inserted into PowerPoint reports. Using snipping tool results in inconsistent sizes of the images. A better alternative is to use built-in option in the post-processor to generate full size images and then crop all images in PPT using a VB Macro. Ref: answers.microsoft.com/ ... /how-can-i-crop-all-the-pictures-on-a-ppt-slide. Note that images are internally names as 'Picture*' where * is a number. To work with VBA in PPT, some standard practices need to be followed. For example, do not use generic text box for everything. Use built-in objects like Title, Sub title, text box, rectangle, rounded rectangle... which will enable to identify them and format separately.
Sub cropImages() Dim slide_i As Slide Dim i As Long For Each slide_i In ActivePresentation.Slides For i = slide_i.Shapes.Count To 1 Step -1 With slide_i.Shapes(i) .PictureFormat.CropLeft = 10 .PictureFormat.CropTop = 20 .PictureFormat.CropRight = 50 .PictureFormat.CropBottom = 75 End With Next Next End SubThe crop dimensions and scale factor need to be worked out with trial and error to fit the layout of shapes (images) on the slides. Once correct crop values and scale factor is worked out, the subroutine can be put into the loop by changing j and n to appropriate numbers say third slide (j=3) to eighth slide (n=8).
Sub cropScaleImages() Dim i, j, n As Integer j = 1 n = 1 For i = j To n cropImages (i) scaleImages (i) Next i End Sub Sub cropImages (i As Integer) Dim img As Shape Set images = ActivePresentation.Slides(i).Shapes For Each img In images If img.Name Like "Picture*" Then With img .PictureFormat.CropLeft = 25 .PictureFormat.CropTop = 50 .PictureFormat.CropRight = 75 .PictureFormat.CropBottom = 25 End With End If Next img End Sub Sub scale Images (j As Integer) Dim img As Shape Set images = ActivePresentation. Slides (j).Shapes For Each img In images If img. Name Like "Picture*" Then With img .ScaleHeight 0.75, msoFalse .ScaleHeight 0.75, msoFalse End Withf End If Next img End SubAlign/arrange location of images, assuming six pictures of equal height and width on a slide arranged as 2 (rows) and 3 (columns). Note that in PPT, images are number with even number as suffix such as Picture 2, Picture 4, Picture 6... The other shapes such as Rectangle, Rounded Rectangle, Textbox, Title, Subtitle... are named in increasing sequence. Note that all dimensions are in points = 1/72 [inch].
Dim lf_x, tp_y, wd_x, ht_y, dx, dy, i As Integer lf_x = 50 'Horizontal position of Top-Left corner of first image tp_y = 75 'Vertical position of Top-Left corner of first image dx = 25 'Horizontal gap between images dy = 10 'Vertical gap between images Dim img As Shape Set images = ActivePresentation.Slides(1).Shapes For Each img In images 'Loop needed to skip other shapes such as Title If img.Name Like "Picture*" Then wd_x = img.Width ht_y = img.Height Exit For EndIf Next img i = 1 For Each img In images If img.Name Like "Picture*" Then img.Left = lf_x + ((i-1) MOD 3) * (wd_x + dx) img.Top = tp_y + (INT(i/4) MOD 2) * (ht_y + dy) i = i + 1 End If Next img
Get all pictures in a folder
Dim str_img_list As String Dim str_dir_path As String Dim str_img_type As String str_dir_path = "C:\Users\Projects\" 'Note \ as last character of the string str_img_type = "*.png" str_img_name = Dir(str_dir_path & str_img_type) 'To iterate over all files in a folder, specify an empty string: Dir() Do While str_img_name <> "" 'Returns 0-length string ("") = vbNullString if no match ... If InStr(1, UCase(str_img_name), "XYZ") then MsgBox str_img_name Exit Do EndIf str_img_name = Dir 'Get next .png file Loop
Insert images on a slide.
Set slide_i = ActivePresentation.Slides(i) Set image_k = slide_i.Shapes.AddPicture(FileName:=str_dir_path & str_img_list, _ LinkToFile:=msoFalse, SaveWithDocument:=msoTrue, _ Left:=20, Top:=50, Width:=-1, Height:=-1)Width and Height equal to -1 import the image as its ORIGINAL size. To get the height and width of slides: ActivePresentation .PageSetup .Slideheight and ActivePresentation .PageSetup .Slidewidth
Ref: techcommunity.microsoft.com/.../create-a-macro-to-crop-images: To crop images from the centre in MS-Word. Property .PictureFormat.Crop.PictureOffsetX offsets from the center of the image. Increasing the offset, by using .PictureFormat .Crop .PictureOffsetX = 10 reduces the crop from the left. A value of -10 increases the crop from the left.
With ActiveDocument For i = 1 To .InlineShapes.Count With .InlineShapes(i) .PictureFormat.Crop.ShapeWidth = .Height .PictureFormat.Crop.ShapeHeight = .Height .PictureFormat.Crop.PictureOffsetY = 0 .PictureFormat.Crop.PictureOffsetX = 0 End With Next i End With
Some other utilities of VBA macros can be to insert multiple images on a slide, add new slides and add more images. Similarly, the text in a PPT can be read and if they are numbers, the formatting can be made consistet by removing extra digits are decimal and converting very small / large number into scientific notations.
Resize and reposition an image
Dim img As Shape For Each slide_i In ActivePresentation.Slides For Each img In curSlide.Shapes With img .LockAspectRatio = msoTrue .Height = 250 .Left = 25 .Top = 100 End With Next img Next slide_i
Loops to iterate over only pictures in slides of a PowerPoint document. Use Dim imgWidth As Long: imgWidth = CentimetersToPoints(10) to set width of the image to 10 cm. img_h = shape_i.Height, img_w = shape_i.Width
For Each slide_i In ActivePresentation.Slides For Each shape_i In slide_i.Shapes If shape_i.Name Like "Picture*" Then 'Do something like Crop, Scale, Position.... shape_i.PictureFormat.CropLeft = 20 shape_i.PictureFormat.TransparentBackground = True shape_i.PictureFormat.TransparencyColor = RGB(255, 255, 255) ' Scale by half of its ORIGINAL height and width shape_i.ScaleHeight 0.5, msoTrue shape_i.ScaleWidth 0.5, msoTrue ' Scale by half of its CURRENT height and width shape_i.ScaleHeight 0.5, msoFalse shape_i.ScaleWidth 0.5, msoFalse ' Position image from the left and top edges of the slide shape_i.Left = 25 shape_i.Top = 75 End If Next shape_i Next slide_i
Format Titles of Slides Consistently
Set pptSlide = ActivePresentation.Slides(2) pptSlide.Shapes.Title.TextFrame.TextRange.Text = "Welcome!" Set title = Application.ActivePresentation.Slides(1).Shapes.Title With title.TextFrame.TextRange .ChangeCase ppCaseUpper 'ppCaseTitle, ppCaseSentence, ppCaseLower With .Font .Bold = msoTrue .Size = 24 .Name = "Palatino" .Color.RGB = RGB(0, 0, 255) End With End With
Add Rectangle with a Textframe: refer MsoAutoShapeType to get available shapes
With pptSlide.Shapes 'Position: 50, 100 | Size (w, h): 250, 75 | msoShapeRoundedRectangle .AddShape(msoShapeRectangle, 50, 100, 250, 75).TextFrame .TextRange.Text = "Text Box 1" .MarginBottom = 2 .MarginLeft = 5 .MarginRight = 5 .MarginTop = 2 .WordWrap = False If .TextRange.Characters.Count < 50 Then .AutoSize = ppAutoSizeShapeToFitText End If End WithExcel VBA
Set the marker background (fill) and foreground (border) colors for the first point in series one on Chart1.With Charts("Chart1") .SeriesCollection(1) .Points(1) .MarkerBackgroundColor = RGB(0,255,255) .MarkerForegroundColor = RGB(255,255,0) .MarkerSize = 5 .MarkerStyle = 8 '1=square, 2=diamond, 3=triangle, 5=star, 8=circle, 9=plus End With With Charts("Chart1") .SeriesCollection(1) .Format .Line 'Switching visibility on/off is necessary for code to work .Visible = msoTrue .ForeColor. RGB = RGB(255, 50, 0) .Weight = 1.5 .DashStyle = msoLineSysDotSets the marker colors to "automatic fill" and "automatic boarder" for the second point in series one on Chart1.
With Charts("Chart1") .SeriesCollection(1) .Points(2) .MarkerBackgroundColor = -1 .MarkerForegroundColor = -1 End WithRef: stackoverflow.com/.../export-chart-as-image-with-click-of-a-button
Sub exportChartsToPNG() Dim WS As Excel.Worksheet Dim SaveToDirectory As String Dim objChart As ChartObject Dim myChart As Chart Dim i as Integer i = 1 SaveToDirectory = ActiveWorkbook.Path & "\" For Each WS In ActiveWorkbook.Worksheets WS.Activate 'go there For Each objChart In WS.ChartObjects objChart.Activate Set myChart = objChart.Chart myFileName = SaveToDirectory & WS.Name & "_" & objChart.Index & ".png" On Error Resume Next Kill SaveToDirectory & WS.Name & Index & ".png" On Error GoTo 0 myChart.Export Filename:=myFileName, Filtername:="PNG" i = i + 1 Next Next MsgBox i & "images of charts created." End Sub
Resize charts and format axes / title, align charts in a worksheet with gap of 5 points between adjacent onces
Sub resizeFormatCharts() 'ref: peltiertech.com/Excel/ChartsHowTo/ResizeAndMoveChart.html Dim MyWidth as Single, MyHeight as Single Dim NumWide As Long Dim iChtIx As Long, iChtCt As Long MyWidth = 800 MyHeight = 450 Numwide = 3 iChtCt = ActiveSheet.Chartobjects.Count For ichtIx = 1 To iChtCt With ActiveSheet.ChartObjects(iChtIx) .Width = MyWidth .Height = MyHeight .Left = ((iChtIX - 1) Mod Numwide) * (MyWidth + 5) .Top = Int((iChtIx - 1) / NumWide) * (MyHeight + 5) .Chart.ChartTitle.Font.Size = 20 .Chart.ChartTitle.Font.Color = RGB (255, O, 0) .Chart.Axes(xlValue).TickLabels.Font.Size = 10 'Y-axis .Chart.Axes(xlValue).AxisTitle.Font.Size = 14 .Chart.Axes(x1Category).TickLabels.Font.Size = 10 'X-axis .Chart.Axes(xlCategory).AxisTitle.Font.Size = 14 End With Next End Sub
Format major gridlines for the category axis (X-axis) on the chart sheet named Chart1, and then formats the gridlines to be blue dashed lines.
With Charts("Chart1") With .Axes(xlCategory) .HasMajorGridlines = True .MajorGridlines.Border.Color = RGB(0, 0, 255) .MajorGridlines.Border.LineStyle = xlDash End With With .Axes(xlValue) If .HasMinorGridlines Then .MinorGridlines.Border.ColorIndex = 5 End If End With End With
VBA for Tables in PowerPoint
With Presentations.Add With .Slides.Addslide(1, ppLayoutBlank) .Shapes.AddTable(2, 3).Select .Shapes(1).Table.Cell(1, 2).Shape.TextFrame .TextRange.Text = "Cell 1_2" End With End With ActivePresentation.Slides(2).Shapes(5).Table .Cell(2, 1).Borders(ppBorderBottom).Weight = 2
Handling Files and Folders in VBA
'Generate a FileSystemObject using CreateObject function Set file_sys_obj = CreateObject("Scripting.FileSystemObject") 'CreateTextFile method creates the file as a TextStream object Set txt_file = file_sys_obj.CreateTextFile("C:Users\Output.txt", True) 'WriteLine method writes a line of text to the file txt_file.WriteLine("This is first line.") 'Close method flushes the buffer and closes the file txt_file.Close 'Get folder path Set str_path = file_sys_obj.GetFolder(str_dir_path) 'Get files in the folder Set file_list = str_path.Files 'Access files in file_list For Each fi in file_list file_name = fi.name If InStr(file_name, ".jpg") > 0 Then 'If UCase(Right(file_name, 4)) = ".JPG" Then ... End If Next 'Returns filename with specified extension. If more than one *.png file exists, 'the first file found is returned. img_file = Dir("C:\Users\*.png") 'Call Dir again without arguments to return next *.png file from same directory img_file = Dir Ref: support.microsoft.com/en-us/office/dir-function str_dir_path = "C:\Users" str_dir_Name = Dir(str_dir_path, vbDirectory) ' Retrieve the first entry Do While str_dir_Name <> "" 'Ignore the current directory and the encompassing directory If str_dir_Name <> "." And str_dir_Name <> ".." Then 'Use bitwise comparison to make sure str_dir_Name is a directory. If (GetAttr(str_dir_path & str_dir_Name) And vbDirectory) = vbDirectory Then Debug.Print str_dir_Name 'Display entry only if it is a directory End If End If str_dir_Name = Dir 'Get next entry Loop
Arrays
Arrays are the most important building block of numerical simulations and programs dealing with data. While there are high level packages such as NumPy and SciPy, a good understandings of the methods used to define and use arrays in vairous programming language would be helpful.Array definition and initialization in C
int array_1d[5]; int array_1d[] = {10, 20, 30, 40, 50}; sizeof operator returns the size of a type in bytes: len_array = sizeof(array_1d) / sizeof(array_1d[0]); Multi-dimensional array: int array_2d[2][3] = { {1, 3, 5}, {2, 4, 6} }; which is similar to Java.float array_2d[n_rows][n_cols]; for (i=0; i<n_rows; i=i+1) { for (j=0; j<n_cols; j=j+1) { array_2d[i][j] = 0.0; } }
Note that functions in C cannot return arrays. As explained at stackoverflow.com/.../returning-an-array-using-c: Option-1 is to dynamically allocate the memory inside the function and deallocate the memory inside the caller function. Option-2 is to fill a preallocated memory buffer provided by the caller. Pointers; int* ptr_var: Variable ptr_var is pointer 'to' and not 'of' integer type. int int_var: Integer variable. int int_var = *ptr_var: value (of type integer) that pointer 'ptr_var' is pointing to is assigned to int_var. int* ptr_int = &int_var: pointer ptr_int points to the variable int_var. int i = *array_1d: the value of the first element of array_1d. int i = *(array_1d + 1): the value of the second element of array_1d.
Example of option-1
#include <stdio.h> #include <string.h> #include <stdlib.h> char *return_array(int arr_size) { char *ret_array = malloc(arr_size); if(!ret_array) return NULL; for(int i = 0; i < arr_size; i++) ret_array[i] = i*i; return ret_array; } int main() { int len_array; char *processed_array = return_array(10); if(processed_array) { len_array = sizeof(processed_array) / sizeof(processed_array[0]); for(int i = 0; i < len_array; i++) { printf("%d \n", processed_array[i]); } printf("Lenth of array is: %d \n", len_array); free(processed_array); } return 0; }
Option-2: both option-1 and option-2 tested using gcc and Ubuntu.
void return_array(char *array_buffer, int arr_size) { for(int i = 0; i < arr_size; i++) { array_buffer[i] = i*i; printf("%d \n", array_buffer[i]); } } int main() { int len_array = 5; char dummy_array[len_array]; return_array(dummy_array, len_array); }
Use of Arrays in Python
def demo_array(array_2d, i, j): n_rows = len(array_2d) n_cols = len(array_2d[0]) if i <= n_rows and j <= n_cols: print("Element at index (", i, j, "): ", array_2d[i][j]) else: print("Indices out of array range") # Print total number of elements print("Total items in rows:", sum(len(row) for row in array_2d)) arr_2d = [[1, 2, 3, 5], [4, 5, 9, 7], [7, 8, 2, 3]] demo_array(arr_2d, 1, 2) # Prints 9
Arrays in Java
int array_2d[n_rows][n_cols]; int[][] array_2d = { {1, 2, 3}, {5, 6, 7}, {8, 9, 0} };Arrays are passed by values and by reference. There are subtle differences between the two. Use of arrays can occur in following scenarios: [a] the function takes an array as argument and returns nothing or primitive data type [2] the function takes nothing or primitive data as argument and returns an array [3] the function takes an array as argument and returns a processed array.
import java.io.*; public class ReadArrays { public static void getArrays(double[] arr_data) { // Pass array by reference for (int i = 0; i < arr_data.length; i++) { arr_data[i] = arr_data[i]*5; } } public static void main(String[] args) { // Define input array double[] arr_items = {10, 20, 30, 50}; // Modify the input array and print each item on a separate line getArrays(arr_items); for(double item : arr_items) { System.out.println(item); } // Following shall print garbled text System.out.println(arr_items); } }
Function that takes an array as argument and returns an array.
public class ReadArrays { public static double[] getArrays(double[] arr_data) { for (int i = 0; i < arr_data.length; i++) { arr_data[i] = arr_data[i]*5; } return arr_data; } public static void main(String[] args) { // Define input array double[] arr_items = {10, 20, 30, 50}; // Modify the input array and print each item on a separate line double[] x; x = getArrays(arr_items); for(double item : x) { System.out.println(item); } } }If "public static double getArrays(double[] arr_data)" is used instead of "public static double[] getArrays(double[] arr_data)", the error would occur: "incompatible types: double cannot be converted to double[]". This is because double is a data type and not an array.
File Handling in Python
def readDataIntoArray(in_file, col='x', row='y', var_2d ='z', com_char="#"): ''' Read a two-dimensional data into a two-dimensional array, space = delimiter It is assumed that col and row are sorted in ascending or descending order Ignores a line starting with com_char, default is # 'col' is the variable name of column variable: Left to Right 'row' is the variable name of row variable: Top to Bottom First row without any comment character is considered column headers First column of valid row is considere row vector x1 x2 x3 x4 x5 y1 z11 z12 z13 z14 z15 y2 z21 z22 z23 z24 z25 y3 z31 z32 z33 z34 z35 ''' input_data = open(in_file,"r") lines = input_data.readlines() # Define row and column vectors, 2D array for field variable var_2d array_z = [ [0]*5 for i in range(5)] col_x = [] row_y = [] # Define counter to check first valid row (vector for col_var) row_num = 0 i = 0 for row in lines: if not row.startswith(com_char): row = ' '.join(row.split()) # Store variable x (x1 x2 x3 x4 x5 in the demonstation table) if (row_num == 0): for v in row.split(' '): #Split on consecutive whitespaces: x.split() col_x.append(float(v)) else: if row != "": # Store first column as vector for row_var (y1 y2 y3) row_y.append(float(row.split(' ')[0])) row_i = row.split(' ')[1:] # Append data from second column till end (z11 ... z25) j = 0 for v in row_i: array_z[i][j] = float(v) j = j + 1 i = i + 1 row_num = row_num + 1 input_data.close() return col_x, row_y, array_z
A simple version that shall work on file containing only required data, no header or comment line:
def readDataIntoList(in_file): input_data = open(in_file, "r") lines = input_data.readlines() x_c = [] y_c = [] z_c = [] for row in lines: if row != "": #Split row on any consecutive runs of whitespace: row.split() x_c.append(float(row.split()[0])) y_c.append(float(row.split()[1])) z_c.append(float(row.split()[2])) input_data.close() return x_c, y_c, z_c
File Handling in C: 'sscanf' stands for "string scanf", function is included in the stdio.h header file. sscanf() only functions with strings up to a maximum size of 499 characters. Skip a line: fscanf(input_file, "%*[^\n]\n"); * means do not save the line, just increment the file position, [^\n] means any character except newline and hence [^\n]\n means a full text line ending with newline. It reads the whole line into the memory. fgets: gets 1 line, and set the file pointer starting at the next line, works as long as line is less than 100 characters. fscanf returns the number of input items successfully matched and assigned, zero in the event of a matching failure.
#include <stdio.h> #include <string.h> #include <stdlib.h> int main() { /* Read file, ignore empty and lines starting with character '#' Store the data into header column, header row and 2d array. Note Note that 'strings' in C are arrays of char elements, hence a function cannot return a string. */ FILE *file_ptr; int len_buffer = 255; int i; int j; int row_num = 0; int offset; int n_rows = 6; int n_cols = 6; int is_empty; int len_x_vec; int len_y_vec; char cmnt_char='#'; char first_char; char ch; double array_2d[n_rows][n_cols]; double n; double x_vec[n_cols]; double y_vec[n_rows]; // Open the file in read mode file_ptr = fopen("input_data.txt", "r"); if (file_ptr == NULL){ printf("Error Reading File\n"); exit (0); } // Store the content of the file in variable file_data char file_data[len_buffer]; // Read the lines 'file_data' and print it while(fgets(file_data, len_buffer, file_ptr)) { is_empty = 1; // Traversing the character array for (i = 0; i < strlen(file_data); i++) { if (file_data[0] == '\0') is_empty = 1; ch = file_data[i]; if (ch != ' ' && ch != '\n' && ch != '\r') { first_char = ch; is_empty = 0; break; } } if (first_char != cmnt_char && is_empty == 0) { if (row_num == 0) { //stackoverflow.com/.../how-to-use-sscanf-in-loops char *sub_string = file_data; j = 0; while(sscanf(sub_string, "%lf%n", &n, &offset) == 1) { sub_string = sub_string + offset; x_vec[j] = n; j = j + 1; } } else { char *sub_string = file_data; j = 0; while(sscanf(sub_string, "%lf%n", &n, &offset) == 1) { sub_string = sub_string + offset; if (j == 0) { y_vec[row_num-1] = n; } else { array_2d[row_num-1][j-1] = n; } j = j + 1; } } printf("%s", file_data); row_num = row_num + 1; } } // Close the file and print the input data fclose(file_ptr); len_x_vec = sizeof(x_vec) / sizeof(x_vec[0]); for (i = 0; i < len_x_vec; i++) printf("%lf \n", x_vec[i]); printf("\n"); len_y_vec = sizeof(y_vec) / sizeof(y_vec[0]); for (i = 0; i < len_y_vec; i++) printf("%lf \n", y_vec[i]); printf("\n"); for (i = 0; i < len_x_vec-2; i++) { for (j = 0; j < len_y_vec-2; j++) { printf("%lf ", array_2d[i][j]); } printf("\n"); } }
File and String Handling in Java
Example-1: check if a string start with a comment character.
import java.io.* public class checkComment { public static void main(String[] args) throws IOException { String str = " # This is a comment line."; boolean line_comment = is_comment(str, '#'); System.out.println(line_comment); } public static boolean is_comment(String str, char comment_char) { // Function that returns true if a comment line is read from a file // The comment character should be a single alphanumeric such as # or * char c; boolean comment_line = false; for (int i = 0; i < str.length(); i++) { c = str.charAt(i); if ( c == comment_char ) { comment_line = true; break; } } return comment_line; } }
Read CSV file with size known in advance
Example-2: read a csv file contain comment line(s).
import java.util.Arrays; import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; public class csvToArray { // Read a csv file separator by specified delimiter in 2d array. The // size of array MUST be known in advance. public static void main(String[] args) throws IOException { // If "throws IOException" not present, "error: unreported exception // FileNotFoundException; must be caught or declared to be thrown". String file_name = "csvToArray.txt"; int max_rows = 4; int max_cols = 4; String delimiter = ","; double [][] array_2d = new double[max_rows][max_cols]; BufferedReader buf_reader = new BufferedReader(new FileReader(file_name)); String line; int i = 0; while((line = buf_reader.readLine()) != null) { boolean comment_line = is_comment(line, '#'); if (!comment_line) { String[] line_data = line.trim().split(delimiter); if (line_data.length >= max_cols) { System.out.println("Number of columns in input exceeds size of array!"); System.exit(0); } for (int j=0; j<line_data.length; j++) { array_2d[i][j] = Double.parseDouble(line_data[j]); } i = i + 1; } if (i >= max_rows) { System.out.println("Number of row in input exceeds size of array!"); System.exit(0); } } System.out.println(Arrays.deepToString(array_2d)); buf_reader.close(); } }
Previous operation converted into a function
public static void main(String[] args) throws IOException { String file_name = "csvToArray.txt"; double [][] array_2d = readDateFromText(file_name, ",", 5, 5); System.out.println(Arrays.deepToString(array_2d)); } public static double[][] readDataFromText(String file_name, String delimiter, int max_rows, int max_cols) throws IOException { double [][] array_2d = new double[max_rows][max_cols]; BufferedReader buf_reader = new BufferedReader(new FileReader(file_name)); String line; int i = 0; while((line = buf_reader.readLine()) != null) { boolean comment_line = is_comment(line, '#'); if (!comment_line) { String[] line_data = line.trim().split(delimiter); if (line_data.length >= max_cols) { System.out.println("Number of columns in input exceeds size of array!"); System.exit(0); } for (int j=0; j<line_data.length; j++) { array_2d[i][j] = Double.parseDouble(line_data[j]); } i = i + 1; } if (i >= max_rows) { System.out.println("Number of row in input exceeds size of array!"); System.exit(0); } } buf_reader.close(); return array_2d; }
List all files of specified extension
import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; public class listFilesInFolder { public static void main(String[] args) throws IOException { File folder = new File("/home/Documents/XYZ"); //listFilesFolderSubFolders(folder); String dir_path = "XYZ"; listFilesRootFolder(dir_path, "*"); } public static void listFilesFolderSubFolders(final File folder) { /* This function prints the files of specified extension in folder and its sub-folders. The absolute path in input argument should be of type 'File'. */ for (final File fileEntry : folder.listFiles()) { if (fileEntry.isDirectory()) { listFilesFolderSubFolders(fileEntry); } else { System.out.println(fileEntry.getName()); } } } public static void listFilesRootFolder(String dir_path, String extn) { /* This function prints the files of specified extension in folder with relative to current working directory. The input argument should be of type 'String'. It prints only the file names and not the paths. To list all files, specify extension as "*". */ String cwd = Path.of("").toAbsolutePath().toString(); Path path_dir = Paths.get(cwd + "/" + dir_path); File root_dir = new File (path_dir.toString()); // Get list_of_files as array File[] array_of_files = root_dir.listFiles(); Arrays.sort(array_of_files); for (File f : array_of_files) { if (f.isFile()) { // Find the last occurrence of '.' in the filename. One may use // .endsWith(extn) but shall not work for all types of extensions String f_name = f.getName(); int dotIndex = f_name.lastIndexOf('.'); String f_extn = (dotIndex > 0) ? f_name.substring(dotIndex + 1) : ""; if (new String("*").equals(extn)) { System.out.println(f_name); } else if (f_extn.equals(extn)) { System.out.println(f_name); } } } } }
Step-0: Define problem set-up: Steady or Transient, Initial Temperature, Total Run Time, Time Step Solution, Time Step Data Save.
Step-1: Define input table for the network. For Steady state cases, Cp and Mass shall be neglected.
Node | T | Qdot | Cp | Mass | Connected Nodes | ||
[No.] | [C] | [W] | [J/kg-K] | [kg] | [No.] | ||
1 | 0 | 50 | 2700 | 0.10 | 2 | 3 | - |
2 | 0 | 0 | 1200 | 0.05 | 1 | 3 | 4 |
3 | 40 | 0 | 1200 | 0.02 | 1 | 5 | 2 |
4 | 0 | 0 | 500 | 0.01 | 3 | - | - |
... | ... | ... | ... | ... | ... | ... | ... |
Step-2: Define resistance table. Define Rij = -1 to indicate it as convection resistor. Specify negative value of k to specify Heat Transfer Coefficient in W/m2-K. In case of convection, specify wetted area under area (length shall be ignored).
Node_i | Node_j | Rij [K/W] | k [W/m-K] | Area [mm2] | Length [mm] |
1 | 2 | 5.0 | - | - | - |
2 | 3 | -1 | -20 | 10.0 | 5 |
3 | 4 | -1 | 380 | 5.0 | 50 |
... | ... | ... | ... | ... | ... |
Step-3: Define governing equations using energy balance at each nodes with unknown temperatures and nodes with known temperatures.
For node-1 above: (T1 - T2)/R12 + (T1 - T3)/R13 = Qdot1
or
A1 T1 + B12T2 + B13T3 = Qdot1 where the second values in the subscripts correpond to entry under "Connected Nodes".
For node-2 above: (T2 - T1)/R12 + (T2 - T3)/R23 + (T2 - T4)/R24 = Qdot2
or
A2 T2 + B21T1 + B23T3 + B24T4 = Qdot2 where the second values in the subscripts correpond to entry under "Connected Nodes".
Step-4: Convert the individual equations into equivalent index notation (subscripts converted into to indices of arrays).
Step-5: Define variables and arrays. NN = number of nodes, 1D arrays: nodes(NN), Qdot(NN), Cp(NN), mass(NN), cond(NN), areas(NN), lengths(NN). 2D arrays: coeff_a(NN, NN), coeff_b(NN, NN), coeff_c(NN, NN), th_res(NN, 10), con_nodes(NN, 10). Each node is assumed to be connected to maximum 10 nodes.
Sample class and method structure for JAVA macros in STAR-CCM+
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.
Template by OS Templates