Scheme-Programmierung in FLUENT 5 & 6
Mirko Javurek
Institut für Strömungsprozesse und Wärmeübertragung, Johannes Kepler Universität Linz, Österreich
fluid.jku.at
Begonnen im September 2000, ergänzt: 2003, 2004, 2007-11
Inhalt Vorwort (2)
Einleitung (2)
Schnittstellen Fluent-Scheme (2)
RP-Variablen (3)
CX-Variablen (3)
Package Variablen (3)
Schnittstelle Fluent-Scheme-UDFs (3)
Datenaustausch (3)
Aufruf von Funktionen (4)
Arithmetische Funktionen (4)
Globale Scheme-Variablen (4)
Lokale Scheme-Variablen (5)
Listen (5)
if-Befehl (5)
do-Schleife (6)
format-Befehl (7)
for-each Schleife (7)
Aliases im TUI (8)
Beispiel: Animation erstellen (8)
Beispiel: Reportdaten aus Datenfiles (9)
Beispiel: Werte aus Data- oder Case-files holen (10)
Beispiel: Fluent Zonennamen für UDF exportieren (10)
Iterationssteuerung (12)
Besonderheiten des Fluent-Schemes (13)
eval-Befehl und environment (13)
Listen-Befehle (13)
format-Befehl (13)
System-Befehle (13)
Fluent-Variablen und Funktionen (13)
Scheme-Literatur (14)
Fluent-Scheme Standardfunktionen (15)
Fluent-Scheme Environment (16)
This script is written in German.
An English translation "Scheme Programming in Fluent" is not yet available.
Vorwort
Scheme bietet sehr viele Möglichkeiten, Prozesse in Fluent automatisiert ablaufen zu lassen. Leider gibt es bis heute von Fluent so gut wie keine Dokumentationen zu diesem Thema. Dybviks Scheme-Buch (siehe Abschnitt Literatur) hat mir sehr geholfen, Scheme verstehen zu lernen. Zur Anwendung in Fluent bedarf es aber einiger
über das Standard-Scheme hinausgehende Kenntnisse. Um meine Erfahrungen mit Fluent-Scheme
auch anderen zukommen zu lassen, habe ich im September 2000 begonnen, dieses Skriptum zu schreiben. Das Skript ist etwas rudimentär, aber immer noch besser als nichts. In der Zwischenzeit sind ein paar Erweiterungen und Aktualisierungen dazugekommen; der Großteil des Dokuments entstand jedoch mit den Erfahrungen aus Fluent 5. Deswegen ist es möglich, dass sich einige Textinterface-Befehle und –Ergebnisse inzwischen geändert haben.  Jason DeGraw von der Pennsylvania State University ist dabei, das Skript auf Englisch zu übersetzen und es auf CDF-Online (www.cfd-online/) zu stellen. Durch seine Übersetzungstätigkeit hat er mich auf einige Fehler und überholte Passagen aufmerksam gemacht.
Es freut mich, immer wieder positive Rückmeldungen zu diesem Skript zu bekommen, und dass sogar FLUENT Deutschland das Skriptum seinen Kunden empfiehlt. FLUENT selbst wird nach Auskünften von FLUENT Deutschland keine offizielle Scheme-Dokumentation mehr herausbringen, da Scheme in Zukunft durch die Skriptsprache Python ersetzt werden soll.
Mirko Javurek, Linz im November 2007 Einleitung
Scheme ist LISP-Dialekt;
Einheitliches Befehlsformat:
(befehlsname argument1 argument2 ...)
Jeder Befehlsaufruf ist ein Funktionsaufruf und liefert daher ein Ergebnis.
Befehls- und Variablennamen sind nicht case-sensitive (sollten nur Kleinbuchstaben enthalten), müssen mit einem Buchstaben beginnen, und dürfen sonst neben a-z und 0-9 auch die Sonderzeichen +-*/<>=?.:%$!~^_ enthalten.
Kommentare werden mit ; eingeleitet und enden am Zeilenende.
Schnittstellen Fluent-Scheme
Aufruf von Scheme-Befehlen in Fluent:
•Befehl im Fluent-Textinterface eingeben (auch mit der Maus kopieren der Fluent-Befehle aus anderen Fenstern - z.B. Editor - über X-Selection in Unix möglich), oder
•Scheme-Programm mit Texteditor schreiben, speichern (.scm-Endung) und in Fluent-Menü mit "File/Read/Scheme" einlesen;
•Wenn sich im home-Verzeichnis eine Scheme-Datei namens .fluent befindet, wird sie beim Starten von Fluent automatisch ausgeführt.
•Im Menü "Solve/Monitor/Commands/Command" können Textinterface- und Scheme-Befehle eingegeben werden, die dann zu bestimmten Iterationen oder Zeitschritten ausgeführt werden;
Aufruf von Fluent-Befehlen in Scheme:
•Textinterface-Befehl:
(ti-menu-load-string "display/contour temperature 30 100")
Rückgabewert: #t wenn erfolgreich, #f wenn Fehler oder Abbruch durch Ctrl-C; Ctrl-C hält Fluent-Befehl, nicht aber Scheme-Programm an! Mit (with-output-to-file) kann die Ausgabe einer Scheme-Funktion statt ins Textinterface in eine Textdatei umgeleitet werden; beispielsweise für einen TUI-Befehl:
(with-output-to-file ""
(lambda ()
(ti-menu-load-string "…")))
Dabei erfolgt keine Ausgabe am Bildschirm.
•GUI-Befehl: Journal mit den gewünschten GUI-Aktionen aufzeichnen, Journal enthält direkt Scheme-Befehle, z.B.:
(cx-gui-do cx-activate-item "Velocity Vectors*PanelButtons*PushButton1(OK)")
Textinterface-Befehle sind schneller, kompakter und vielseitiger verwendbar. GUI-Kommandos sind langsam, unübersichtlich und müssen oft erst angepasst werden (Referenz auf Listeneintrag von Nummer auf Name des Eintrags ändern). Textinterface-Kommandos sind demnach GUI-Kommandos vorzuziehen; GUI-Kommandos sollten nur dann verwendet werden, wenn für die gesuchte Aktion kein Textinterface-Kommando verfügbar ist (z.B: ).
Textinterface Kommandos sind in der FLUENT Dokumentation nur oberflächlich dokumentiert, ihre Parameter hängen oft von den gewählten Modellen oder sogar von anderen Parametern ab. Vorgehensweise: Gewünschtes
Textkommando suchen, ausprobieren und alle gemachten Eingaben zusammenfassen (siehe Beispi
el 1). Ausgabe von Scheme ins Fluent-Textinterface:
(display object)
(newline)
Dateizugriff (lesen/schreiben) in Scheme: siehe Beispiele.
RP-Variablen
Variable auslesen, z.B. aktuelle Simulationszeit:
> (rpgetvar 'flow-time)
0.1
Variable setzen:
> (rpsetvar 'flow-time 0)
Alle RP-Variablen sind im Case-File definiert (Section "Variables").
CX-Variablen
Variable auslesen, z.B.: Farbverlauftabellen:
> (cxgetvar 'cmap-list)
0.1
Variable setzen:
> (cxsetvar 'def-cmap "rgb")
Alle CX-Variablen sind (nur teilweise?) im Case-File definiert (Section "Cortex Variables").
Package Variablen
Insbesondere der aktuelle Case-Dateiname ist im cl-file-package gespeichert. Auszulesen mit: > (in-package cl-file-package rc-filename)
(zuletzt gelesenes Casefile ohne Endung .cas oder .), oder
> (in-package cl-file-package wc-filename)
(als letztes geschriebenes bzw. als nächstes zu schreibenes Casefile ohne Endung .cas oder ., wenn das Datafile unter einem anderen Namen gespeichert oder ein anderes geladen wurde, also i.A. der Name des Datafiles ohne Endung).
Der Dateiname ist mit dem vollen Pfad gespeichert. Mit
> (strip-directory (in-package cl-file-package rc-filename))
kann dar Pfad entfernt werden, mit
> (directory (in-package cl-file-package rc-filename))
nur der Pfad herausgezogen werden.
Schnittstelle Fluent-Scheme-UDFs
Datenaustausch
Es können eigene RP-Variablen definiert werden, die in Fluent über das Textinterface und in UDFs über spezielle Funktionen angesprochen werden können.
Definition einer eigenen RP-Variable:
(rp-var-define name default-and-init-value type #f)
types: 'int 'real 'boolean 'string ...?
zum Beispiel:
> (rp-var-define 'udf/var1 0 'real #f)
Info über Variable:
> (rp-var-object 'udf/var1)
(udf/var1 0 real #f 0)
> (rp-var-object 'udf/var2)
#f
Ändern und Abfragen wie oben mit rpsetvar und rpgetvar.
Wenn eine RP-Variable einmal definiert ist, bleibt sie bis zum Beenden von Fluent erhalten (!), wird in jedem Case-File mit abgespeichert, und beim Hereinladen eines solchen Case-Files - falls nicht definiert - erzeugt und auf den abgespeicherten Wert gesetzt.
In UDFs können die RP-Variablen mit den C-Funktionen (deklariert in Fluent.Inc/fluentX.Y/src/var.h) real RP_Get_Real(char *s);
long RP_Get_Integer(char *s);
char *RP_Get_String(char *s);
boolean RP_Get_Boolean(char *s);
void RP_Set_Real(char *s, real v);
void RP_Set_Integer(char *s, long v);
void RP_Set_Boolean(char *s, boolean v);
void RP_Set_String(char *s, char *v);
void RP_Set_Symbol(char *s, char *v);
abgefragt bzw. gesetzt werden, z.B.:
var1 = RP_Get_Real("udf/var1");
RP_Set_Real("udf/var1", 3.2);
Bei UDFs im Parallelmodus ist beim Zugriff auf RP-Variablen zu beachten, dass RP-Variablen nur im Host-Prozess abgefragt werden können. Im FLUENT-UDF Handbuch ist beschrieben, wie Werte vom Host an Node-Prozesse übermittelt werden können. Achtung: Nicht alle UDF-Typen werden sowohl von Host- als auch den Node-Prozessen aufgerufen, sodass es z.B. innerhalb einer DEFINE_SOURCE UDF im Parallelmodus nicht direkt möglich ist, auf eine RP-Variable zuzugreifen.
Aufruf von Funktionen
UDFs vom Type EOD können aus Scheme über den Befehl
(%udf-on-demand "udf-eod-name")
aufgerufen werden.
Um Scheme-Funktionen aus einer UDF aufzurufen, ist zur Zeit keine Möglichkeit bekannt; die C-Funktion
CX_Interpret_String("scheme-command-string") - deklariert in Fluent.Inc/fluentX.Y/cortex/src/cx.h - interpretiert zwar den  "scheme-command-string", hat aber keinen Zugriff auf das Environment.
Arithmetische Funktionen
Grundfunktionen + - * / , entspricht UPN, mehr als 2 Argumente möglich:
> (+ 2 4 5)
11
> (/ 6 3)
2
> (/ 2)          ;; entspricht (/ 1 2)
0.5
Weiters (abs x), (sqrt x), (expt x y)[= x y], (exp x) [= e x], (log x) [= ln x], (sin x), (cos x), (atan x), (atan x y) [= arctan(x/y)], …
Integer(!)-Funktionen:
> (remainder 45 6)
3
> (modulo 5 2)
1
(truncate x), (round x), (ceiling x), (floor x), ...
weiters
(max x y ...), (min x y ...)
z.B. um aus Liste Maximum suchen:
> (apply max '(1 5 8 3 4))
8
und einige weitere (siehe Scheme-Literatur).
Globale Scheme-Variablen
Definieren mit:
> (define x 3)
> (+ x 1)
4
Keine Festlegung des Variablentyps (Integer, Real, String, ...) notwendig – jede Variable kann Wert von jedem Typ annehmen.
Wert ändern mit erneuter Definition (nicht innerhalb von Funktionen möglich, dort gilt ein lokaler Variablenbereich, sodass die Variable mit define lokal neu definiert wird) oder besser
(set! x 1)
Wert darstellen mit
(display x)
oder
(write x)
Write sollte nur verwendet werden, wenn Fluent-Variablen in eine Datei abgespeichert und später wieder eingelesen werden sollen; Write stellt z.B. Strings mit Anführungszeichen dar.
Konstanten: Integer (2), Float (2.5), Boolean (#t für true, #f false) Strings ("this is a text string")  und Symbole: 'symbol, z.B.:
(define x 'this-is-a-symbol)
Spezielle Zeichen für String-Definitionen:
\" "
\n neue Zeile
Globale Variablen und selbst definierte Scheme-Funktionen bleiben bis zum Beenden von Fluent erhalten. Lokale Scheme-Variablen
(let ((var1 value1) (var2 value2) ...)
... Kommandos im Gü
)
Listen
Definition z.B.:
> (define my-surfaces '(wall-top wall-bottom symmetry))
Länge beliebig, dynamische Verwaltung, Schachtelung möglich.
Listen Definieren mit ‘(elements ...) :
> (define l '(a b c))
Erstes Element einer Liste
> (car l)
a
"Rest" einer Liste (Liste ohne erstes Element)
> (cdr l)
(b c)
Anzahl der Listenelemente
> (length l)
3
i-tes Element einer Liste
(list-ref liste i)
Element in Liste suchen:
> (member 'd '(a b c d e f g))
(d e f g)
Funktion auf Liste(n) anwenden:
> (map (lambda (x) (* x x)) '(1 2 3))
(1 4 9)
> (apply + '(2 4 5))
11
> (apply max '(1 5 8 3 4))
8
if-Befehl
if-Befehl ist eine Funktion:
(if cond true-value false-value)
cond ist ein boolscher Ausdruck, der entweder  #t (true) oder #f (false) ist.
Vergleichsoperationen:
Gleichheit:
(= a b)  ;; Zahlen
(eq? a b)  ;; Objekte
(eqv? a b) ;; Objekte gleichen Wert
Relationen:
(positive? x)
(negative? x)
(< a b)
(> a b)
(<= a b)
(>= a b)
Boolsche Funktionen:
(not a)
(and a b c ...)
(or  a b c ...)
Erweiterung des "if"- und "else"-Zweiges für mehrere Kommandos mit Block-Befehl "begin" ("sequencing", allgemein anwendbar):
(if cond
(begin  ;; if
...
true-value
)
(begin  ;; else
...
false-value
)
)
Wenn der Ergebniswert des if-Befehls nicht benötigt wird, können "else"-Zweig und die Ergebniswerte weggelassen werden.
Komplexere Befehle für bedingte Ablaufsteuerung (z.B. für stückweise definierte Funktionen): (cond (test1 value1) (test2 value2) ... (else value))
und für diskrete Werte einer Variable
(case x ((x11 x12 x13 ...) value1) ((x21 x22 x23 ...) value2) ... (else value))
Wird x in einer der Listen gefunden (z.B. in (x11 x12 x13 ...)), so wird der entsprechende Wert zurückgegeben (value1).
do-Schleife
Einfachste Form (Variable, Startwert, Wert der der Schleifenvariable nach jedem Schleifendurchgang zugewiesen werden soll, Abbruchbedingung):
(do ((x x-start (+ x delta-x))) ((> x x-end))  ... )
Mehrere oder auch keine Schleifenvariablen möglich.
Beispiel 1: Iso-Surfaces erzeugen: mehrere Iso-Surfaces sollen in gleichmäßigen Abständen von Iso-Values generiert und automatisch benannt werden. Zuerst muss der Dialog im TUI für das Erzeugen einer Iso-Surface zusammengestellt werden:
>
adapt/                  grid/                  surface/
display/                plot/                  view/
define/                report/                exit
file/                  solve/variable used in lambda
> surface
/surface>
delete-surface          mouse-line              point-array
surface-cells          mouse-plane            rake-surface
iso-surface            mouse-rake              rename-surface
iso-clip                partition-surface      sphere-slice
list-surfaces          plane-slice            zone-surface
/surface> iso-surface
iso-surface of>
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            dp-dz
iso-surface of> x-coordinate
new surface id/name [x-coordinate-31] testname
range [-10.0131, 4.8575001]
from surface [()] ()
()
iso-value(1) (m) [()] 1.234
iso-value(2) (m) [()] ()
Einzeiliger TUI-Befehl lautet also (alle Eingaben in eine Zeile zusammengefasst, "nur Return" durch , (Beistrich) ersetzen):
surface/iso-surface x-coordinate testname () 1.234 ()
Daraus "parametrisierte" Scheme-Schleife:
(do ((x 0 (+ x 0.2)) ) ((> x 3.1))
(ti-menu-load-string
(format #f "surface/iso-surface x-coordinate x-~3.1f () ~a ()" x x))
)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。