switch (op) { case INIT_RULES: // Name, Datum, Variablen, Phasen, Reaktoren, Kinetik case PREP_ROOT: // Vorbehandlungsfunktion für die Ausgangsmaterialien case PREP_EDUCT: // Vorbehandlungsfunktion für die Edukte case DISTRIBFUNC: // Nachbehandlungs(Verteilungs)funktion für alle Produkte case MODFUNC: // Modellfunktionen case FINISH: // Cleanup default: return BAD; } return OK;
switch $op { INIT_RULES { # Name, Datum, Variablen, Phasen, Reaktoren, Kinetik } PREP_ROOT { # Vorbehandlungsfunktion für die Ausgangsmaterialien } PREP_EDUCT { # Vorbehandlungsfunktion für die Edukte } DISTRIBFUNC { # Nachbehandlungs(Verteilungs)funktion für alle Produkte } MODFUNC { # Modellfunktionen } FINISH { # Cleanup } default { return BAD } }
val
der C++-Regelfunktion ist ein Zeiger auf ein Objekt der Klasse rx_datex
, über das der Austausch der Zeiger auf die Variablen erfolgt. Für die verschiedenen Variablentypen gibt es die Elementfunktionen
put
und get
für Variablen sowie putco
und getco
für konstante Werte.
Die Deklaration der Variablen, die vom Kernsystem geholt werden bzw. an das übergeben werden, müssen in der ganzen Regelfunktion zugreifbar sein und dürfen nach dem Verlassen ihren Wert nicht verlieren. Variablen, die an das Kernsystem übergeben
werden, wie zum Beispiel die Reaktivität (double
), werden static
deklariert und mit einem Anfangswert initialisiert. Für Variablen des Kernsystems, die gelesen werden, wie das Reaktionslevel (int
), wird ein static
const
-Pointer deklariert.
In Tcl greifen die Funktionen put
, get
und putco
intern auf den in Tcl nicht sichtbaren Pointer val
zu.
static const int *var_level; static double var_reactivity = 0.;
# Für Variablen vom Kernsystem ist in Tcl # keine Deklaration nötig. Sie werden intern # automatisch als global deklariert. global var_reactivity set var_reactivity 0.0Die Übergabe der Adressen der Variablen erfolgt dann unter
INIT_RULES
mit:val->get("level", &var_level); val->put("reactivity", &var_reactivity);
get level var_level put reactivity var_reactivityKann die Adresse der Variable
"level"
nicht geholt werden, wird in C++ var_level
auf 0 gesetzt. Um in Tcl zu überprüfen, ob die Variable "level"
geholt werden konnte, kann der Rückgabewert des Kommandos
get
überprüft werden:set flag [get level var_level]Hat die Variable
flag
den Wert 1
, konnte die Variable var_level
abgeholt werden. Im anderen Fall hat flag
den Wert 0
. In Tcl besteht außerdem die Möglichkeit, bei put
und
putco
den Namen der Variablen wegzulassen. Er ist dann identisch mit dem Namen, unter dem die Variable übergeben wird.Die Variablen können dann in beliebigen Regelteilen folgendermaßen gelesen bzw. gesetzt werden:
int i = *var_level; var_reactivity = 1.4e-8;
set i var_level set var_reactivity 1.4e-8Immer, wenn man
*var_level
verwendet, erhält man das aktuell gültige Level. Für die Reaktivität holt sich das Kernsystem nach jeder erfolgreichen Reaktion den aktuellen Wert. Dies gilt im übrigen auch für alle anderen
an das Kernsystem übergebenen Variablen, die vom Typ int
oder double
sind. Eine Reaktion ist beendet, wenn der entsprechende Regelteil verlassen wird oder wenn eine der beiden Funktionen save_active_ens_as_product
bzw. save_ens_as_product
aufgerufen wird. Die Werte der Variablen werden im Reaktionsfile unter /REACLOG
mit ausgegeben. Wenn die Kinetik angeschaltet ist, wird die Variable reactivity
vom Typ double
benötigt.
Sie gibt die Geschwindigkeitskonstante der Reaktion an bzw. die Wahrscheinlichkeit beim Modus prob_kin
der Kinetik.Als Variablen vom Kernsystem stehen zur Verfügung:
level
, phase
und reactor
(alle vom Typ int
), sowie zu Testzwecken temperature, pressure (beide double
), hihi (int
), program_name (Konstante const char*
), string_array
(Konstante const char *const *
), variable_string (const char*
) und array_probe (vector<int>
).
rx_datex
auch konstante Werte übergeben werden. Dies wird beispielsweise für den Namen und das Datum der Regeln verwendet.val->putco("name","Regelname"); val->putco("date","13.11.1996");
set name_var "Regelname" putco name name_var set date_var 13.11.1996 putco date date_varVom Kernsystem wird der Regelname dann folgendermaßen abgeholt:
const char *name; var->getco("name", &name); cout << "The name of the rules is " << name << endl;Vergleicht man den C++-Code für die Übergabe von Konstanten mit dem der Variablen, so erkennt man, daß bei den Konstanten im Aufruf von
putco
die Variable selbst steht und bei getco
der Zeiger auf die Variable und nicht,
wie bei der Übergabe der Variablen in den Funktionen put
und get
, der Zeiger auf die Variable bzw. der Zeiger auf den Zeiger. Die Referenzierung der Konstanten ist gegenüber den Variablen bei der Übergabe also um eins
erniedrigt.INIT_RULES
der Regeln festgelegt. Zunächst müssen die Anzahl der Reaktoren und Phasen sowie die Zugehörigkeit der Phasen zu den Reaktoren angegeben werden. Dies geschieht
mit der Konstante "phases_per_reactor"
, die von Typ const int[]
ist. Jede Zahl in diesem int-Array steht dabei für die Anzahl der Phasen im Reaktor. Das int-Array wird mit 0 abgeschlossen. Im folgenden Beispiel werden 2 Reaktoren
mit zwei Phasen bzw. einer Phase definiert. Der Reaktor 1 enthält die Phasen 1 und 2 und der Reaktor 2 die Phase 3.{ static const int ppr[] = { 2, 1, 0 }; val->putco("phases_per_reactor", ppr); }
global ppr set ppr {2,1,0} putco phases_per_reactor pprAls nächstes muß festgelegt werden, welche Verbindungen als Ausgangsmaterialien für die einzelnen Reaktoren dienen. Dabei ist zu beachten, daß die Startmaterialien für jeden Reaktor in die erste Phase dieses Reaktors gegeben werden. Im obigen Beispiel also in Phase 1 für den Reaktor 1 und in Phase 3 für den Reaktor 2. Für alle Reaktoren wird angegeben, wo die Startmaterialien herkommen. Dies sind grundsätzlich alle Verbindungen einer bestimmten Phase, die angegeben wird. Dementsprechend wird für jeden Reaktor die Nummer der Phase mit den Ausgangsmaterialien angegeben, wobei für den ersten Reaktor noch keine Strukturen aus einer anderen Phase zur Verfügung stehen. Für ihn wird die Phase 0 angegeben. Sollen nun im obigen Beispiel die Produkte aus Phase 2 in den Reaktor 2 übernommen werden, ist dies folgendermaßen zu kodieren:
{ static const int inp_phase[] = { 0, 2 }; val->putco("input_phase_for_reactors", inp_phase); }
global inp_phase set inp_phase {0,2} putco input_phase_for_reactors inp_phaseNormalerweise werden alle vom File eingelesenen Ausgangsmaterialien der Phase 1 zugeteilt, es besteht aber auch die Möglichkeit, sie in beliebige andere Phasen zu geben. Dazu kann im CTX-File für jedes Molekül die Eigenschaft
M_PHASE
angegeben werden, die dann die Nummer der Phase enthält. Beim Einfügen der Aggregate wird diese in die Eigenschaft AG_PHASE
kopiert, die dann ausgewertet wird. Enthält das Eingabefile keine Phasenangabe, wird noch nachgesehen, ob
in INIT_RULES
eine Variable des Typs vector<int>
unter dem Namen start_phase
übergeben wurde. Ist dies der Fall, gibt sphs[0]
die Phase für das erste Aggregat an. Kann keine Angabe über
die Anfangsphase gefunden werden, kommt das Aggregat in die Phase 1. Im folgenden Beispiel wird angegeben, daß das Aggregat 1 in die Phase 3 kommt:static vector<int> sphs(1); sphs[0] = 3; val->put("start_phase", &sphs);
global sphs set sphs {3} put start_phase sphsDabei ist es nur wichtig, daß in
INIT_RULES
die Variable für die Einträge der Phasen für die Ausgangsmaterialien übergeben wird. Die Einträge können auch erst während der Vorbehandlung der Ausgangsmaterialien
gesetzt werden. Die Vorbehandlung kann abhängig von der Zahl der Eduktensembles mehrfach aufgerufen werden, wobei nach jedem Aufruf die Phasen für alle gerade vorbehandelten Aggregate gesetzt sein müssen, da sie direkt danach von EROS7 gelesen
werden. Alle Aggregate werden von null ab mit jedem Aufruf von PREP_ROOT
durchnumeriert, wobei für jedes Aggregat im Ensemble hochgezählt wird. Ist ein Aggregat ein zweites Mal enthalten, wird nicht hochgezählt.Desweiteren kann für jeden Reaktor noch festgelegt werden, ob die Edukte ein Ausgangsgemisch darstellen oder ob sie getrennt voneinander behandelt werden sollen. Dafür gibt es für jeden Reaktor ein Flag (1=Gemisch, 0=jede Verbindung einzeln). Sollen zunächst im ersten Reaktor alle Ausgangsmaterialien miteinander reagieren, werden aber danach chromatografisch getrennt und getrennt voneinander, aber gleich, aufgearbeitet, ergibt sich folgender Code:
{ static const int all_educts[] = { 1, 0 }; val->putco("use_all_educts_together", all_educts); }
global all_educts set all_educts {1,0} putco use_all_educts_together all_eductsJetzt fehlt nur noch, daß festgelegt wird, welche Verbindungen im Strukturfile ausgegeben werden. Um die Verbindungen der Phase 3 auszugeben, schreibt man:
val->putco("output_phase",3);
global ophase set ophase 3 putco output_phase ophaseDie Angabe der Ausgabephase kann jedoch beim Aufruf von EROS7 mit der Option
-p
überschrieben werden.
Bei der Kodierung von "input_phase_for_reactors"
und "use_all_educts_together"
ist darauf zu achten, daß für alle Reaktoren ein entsprechender Wert angegeben ist, da intern die Größe des allocierten int-Arrays nicht
abgeprüft werden kann.
const int
s und die Modi der Phasen 1, 2, und 3 werden zum Beispiel folgendermaßen für obige Reaktoren gesetzt:
{ static const int phprop[]={MIX, MIX, MONOMOLEC}; val->putco("phase_property", phprop); }In Tcl sind die oben angegebenen Modi als interne Variablen definiert, die nur gelesen werden können.
global phprop set phprop "$MIX,$MIX,$MONOMOLEC" putco phase_property phprop
INERT
gekennzeichnet ist, generiert selbst keine Reaktionen, dient allerdings als Aggregatspeicher für andere Phasen, die den Modus SURFACE
oder auch MIX
oder MIX_NO_A_A
hat. Funktionsweise
siehe Modus SURFACE
.MONOMOLEC
ist von monomolekular abgeleitet. In diesem Modus erzeugt die Phase Reaktionen, bei denen ein einziges Aggregat als Edukt verwendet wird. Die Phase erzeugt so Reaktionen erster und pseudoerster Ordnung.MIX
, produziert sie alle Reaktionen ausgehend von einem Aggregat und alle Reaktionen, die von allen möglichen Paaren aller Aggregate dieser Phase ausgehen. Im Modus MIX
werden dabei auch die Reaktionen erzeugt,
die zweimal das Aggregat X als Edukte haben. Im Modus MIX_NO_A_A
werden diese Reaktionen nicht erzeugt. Zusätzlich werden noch alle Reaktionen wie im Modus SURFACE
durchgeführt.SURFACE
erzeugt die Phase alle Reaktionen, die von zwei Aggregaten ausgehen, wobei eines der Aggregate aus der Phase selbst stammt, wohingegen das andere aus einer angrenzenden Phase kommt. Dazu muß festgelegt werden, welche Phasen
benachbart sind (oder in Kontakt stehen). Die Nachbarschaften werden als 0-terminiertes Array aus Zahlenpaaren angegeben. Zum Beispiel: 1, 2, 2, 3, 0. Dies bedeutet, daß Phase 1 mit Phase 2 in Kontakt steht und Phase 2 mit Phase 3. Die andere Phase ist
häufig im Modus INERT
und speichert nur eine bestimmte Gruppe von Verbindungen, wie für dem Einsatz zur kombinatorischen Chemie.{ static const int phct[]={ 1, 2, 2, 3, 0 }; val->putco("phase_contacts",phct); }
global phct set phct {1, 2, 2, 3, 0} putco phase_contacts phctUm Reaktionen nicht doppelt zu erzeugen, ist bei der Angabe der Phasenkontakte die Reihenfolge von Bedeutung. 1, 2 ist also nicht gleich 2, 1. Im ersten Fall werden die Reaktionen von Phase 1 und im zweiten von Phase 2 erzeugt. Dies macht keinen Unterschied, solange weder in Phase 1 noch in Phase 2 während der Reaktionsgenerierung neue Aggregate in einer der Phasen gebildet werden. Dies ist allerdings oft nicht der Fall, weshalb die Reihenfolge von Bedeutung ist.
Im Modus Tube ist keine Kinetik möglich.
none
wird die Kinetik abgeschaltet. gear
, runge_kutta
und runge_kutta_merson
sind Methoden zur Lösung der Differentialgleichungen der Reaktionsgeschwindigkeiten. prob_kin
berechnet die
Substanzkonzentrationen aufgrund von Reaktionswahrscheinlichkeiten.
Die Methoden runge_kutta
und runge_kutta_merson
sind Methoden vom Typ Runge-Kutta vierter Ordnung mit automatisch bestimmten Integrationsschritten und zählen zu den klassischen numerischen Methoden zur Lösung von Differentialgleichungen.
Sie besitzen eine höhere Lösungsgenauigkeit als z.B. die Methoden von Euler, auf denen grundsätzlich der Gear-Algorithmus basiert. Der Gear-Algorithmus wurde speziell für die Lösung von Differentialgleichungen physikalischer Prozesse
geschrieben und enthält sogenannte multiple time scales", einen Mechanismus zur Auswahl des Integrationsschrittes durch eine komplizierte Analyse des Verhaltens der Differentialgleichungen. Wie alle Implicit Integration Schemes", zu denen der Gear-Algorithmus
zählt, kann er numerical damping"- und Resonanzprobleme haben, die besonders bei einem großen System aus Differentialgleichungen zu Tage treten. Die Methoden runge_kutta
und runge_kutta_merson
sind überdies nicht, wie
gear
, auf Differentialgleichungen erster Ordnung beschränkt. Es treten allerdings zur Zeit in EROS7 nur Differentialgleichungen erster Ordnung auf.
Für die Wahrscheinlichkeitskinetik ist zu beachten, daß sie nur für monomolekulare Reaktionen geeignet ist. Hat eine der Reaktionen im Kinetikmodus prob_kin
das Attribut rearrangement
, gibt die Variable reactivity
den Prozentsatz an, der reagiert. Mehr dazu steht in Kapitel 6.9.2.
Die Werte der double-Variablen reactivity
sind die Geschwindigkeitskonstanten bzw. die Wahrscheinlichkeit (prob_kin
) der Reaktionen. Die Konzentrationen der Ausgangsmaterialien werden bevorzugt aus dem Struktureingabefile gelesen (AG_CONCENTRATION
bzw. M_CONCENTRATION
). Sind dort keine Konzentrationen angegeben, kann man sie, wie unten für einen einzigen Ausgangsstoff gezeigt, auch in der Regel setzen. Die tatsächliche Zuweisung der Konzentration kann auch erst während der
Vorbehandlung der Ausgangsmaterialien geschehen (siehe B.2.3). Werden auch hier keine Konzentrationen angegeben (kein val->put("start_conc", ...)
), werden die Konzentrationen der Ausgangsverbindungen auf 0.1
mol/l gesetzt. Gleiches gilt für die kontinuierlichen Zuflüsse der Ausgangsmaterialien. Hier sind es AG_FLOW
bzw. M_FLOW
oder gegebenenfalls der vector<double>
unter dem Namen start_flow
. Wird
so kein Zufluß der Ausgangsmaterialien gefunden, wird er auf 0.0 mol/s (keine Zufluß) gesetzt.
Mit minimal_concentration
wird diejenige Konzentration angegeben, die ein Reaktionsprodukt mindestens haben muß, damit ausgehend von ihm noch weitere Reaktionen erzeugt werden. Da zu diesem Zeitpunkt noch keine Reaktionen ausgehend von diesem
Produkt erzeugt wurden, ist die Konzentration, die zum Vergleich herangezogen wird, diejenige ohne Berücksichtigung etwaiger Abbaureaktionen. Die beiden Werte conversion_limit
und reaction_time bestimmen die Reaktionszeit. reaction_time ist
die maximale Reaktionszeit in Sekunden, die allerdings nicht erreicht wird, wenn vorher mindestens 50% (conversion_limit
= 0.5
) der Ausgangssubstanzen umgesetzt sind.
Arbeitet man mit mehreren Phasen, ist es unter Umständen noch interessant, die Volumina der einzelnen Phasen zu setzen. Werden keine Volumina gesetzt, werden sie intern all mit 1.0 l angenommen. Außerdem kann man noch die Flüsse der Phasen und
wohin sie fließen angeben. Der vector<double>
phase_flow
gibt die Flüsse der Phasen in l/s (default 0.0) und der vector<int>
phase_flow_to
die Phase im gleichen Reaktor, in die die Flüsse
gehen, an (0 bedeutet: der Fluß wird nicht von einer anderen Phase aufgenommen). Dabei ist es unerheblich, ob beide Phasen den gleichen Fluß aufweisen, da der Stoffstrom, der aus der einen Phase herauskommt, in die neue Phase hineingeht. Es wird angenommen,
daß genau soviel Lösungsmittel zugesetzt bzw. entzogen wird, daß der Volumenstrom der einen Phase in den Volumenstrom der anderen Phase übergeht.
{ static vector<double> sconc(1), vols(3), flow(3); static vector<int> to_phase(1), flow_to(3); sconc[0] = 0.10; to_pahse[0] = 1; // Aggregat 1 kommt in Phase 1 (default) vols[0] = 1.0; // Volumen für Phase 1 vols[1] = 1.0; // Volumen für Phase 2 vols[2] = 1.0; // Volumen für Phase 3 flow[0] = 0.; flow[1] = 0.; flow[2] = 0.; flow_to[0] = 0; flow_to[1] = 0; flow_to[2] = 0; static const char *const kin_mode[]={ "gear", "gear" }; val->putco("kinetic_model", kin_mode); val->putco("conversion_limit", 0.5); val->putco("reaction_time", 5.e7); val->putco("minimal_concentration", 1.e-10); val->put("start_conc",&sconc); val->put("start_phase", &to_pahse); val->put("phase_volume", &vols); val->put("phase_flow", &flow); val->put("pahse_flow_to", &flow_to): }
global kin_mode min_conc conv_lim reac_time sconc vols global to_phase set sconc(0) 0.1 set to_phase(0) 1 # Aggregat 1 kommt in Phase 1 (default) set vols {1.0,1.0,1.0} set flow {0.,0.,0.} set flow_to {0,0,0} set kin_mode {"gear","gear"} set min_conc 1.e-10 set conv_lim 0.5 set reac_time 5.e7 putco kinetic_model kin_mode putco conversion_limit conv_lim putco reaction_time reac_time putco minimal_concentration min_conc put start_conc sconc put start_phase to_phase put phase_volume vols put phase_flow flow put phase_flow_to flow_toHat man einen der Kinetikmodi
gear
, runge_kutta
oder runge_kutta_merson
gewählt, ist es auch möglich, für einzelne Reaktionstypen eine Kinetik nach Michaelis-Menten oder nullter Ordnung festzulegen. Diese
Arten der Kinetik treten bei enzymatischen Reaktionen auf. Bei ihnen ist eine Gleichgewichtsreaktion zur Bildung des Enzym-Substrat-Komplexes der enzymkatalysierten Reaktion vorgelagert (siehe Abbildung 213).
Sind solche Reaktionstypen in den Regeln enthalten, übergibt man zusätzlich zur reactivity
-Variablen auch eine double
-Variable unter dem Namen Km
, in der für diese Reaktionstypen der Wert der Michaelis-Konstante
übergeben wird. Der reactivity
-Variable wird bei diesen Reaktionstypen das Produkt aus k2 und der Enzymkonzentration [E]0 zugewiesen. Der Reaktionstyp erhält das Attribut michaelis_menten_kinetics
(siehe B.3.1).
Befindet sich die Enzymreaktion ständig im Sättigungsbereich, kann man durch die Angabe des Attributs force_zero_order
für den Reaktionstyp eine Kinetik nullter Ordnung erzwingen.
Ist der Gear-Algorithmus als Kinetik gewählt, kann mit EROS7 auch eine Mehrfachdosierung simuliert werden. Hierzu übergibt man eine const double
unter dem Namen multi_dose
mit der Zeit zwischen den Dosierungen. EROS7 erhöht
dann die Konzentration der Ausgangsverbindungen in gleichen Zeitintervallen um die Anfangskonzentrationen. Soll mehrfach dosiert werden, aber nicht in gleichen Zeitabständen, kann unter dem Namen multi_dose
auch ein vector<double>
mit den Zeiten der Dosierung übergeben werden. Auch in diesem Fall wird mit der Anfangskonzentration der Ausgangsverbindungen begonnen. Wird als erste Zeit 0.0 Sekunden angegeben, kann jedoch auch mit der doppelten Konzentration angefangen werden.
FUNC
mit OK
zurückkehrt. Schreibt man Regeln, bei denen alle
Fehlerflags überprüft werden und der Regelteil davon abhängig weitergeführt wird, kann man die interne Löschung von Reaktionen mit Fehlern folgendermaßen im Regelteil INIT_RULES
abschalten:val->putco("no_discard_on_error", 1);
global nodisonerr set nodisonerr 1 putco no_discard_on_error nodissonerrAnalog der internen Fehlerüberprüfung findet auch eine Überprüfung der Korrektheit der Produkte statt. Der Modus für diese Valenzüberprüfung kann gesetzt werden mit:
val->putco("valence_mode", "organic");
global vmode set vmode organic putco valence_mode vmodeEs stehen die Möglichkeiten
organic
, inorganic
, ms
und ms-inorganic
zur Verfügung. Hat der Modus den Wert none
, ist die Valenzüberprüfung abgeschaltet. FUNC
der einzelnen Regeln (siehe unten). Im Unterschied von FUNC
findet keinerlei Variablenaustausch statt und das vorbehandelte Ausgangsensemble ist dasjenige, das nach ein oder mehreren Reaktionen herausgekommen ist. In aller Regel ist allerdings
keine Vorbehandlung nötig und es genügt folgende Zeile in dieser Funktion:return OK;
return OK
return OK;
return OK
Der folgende Code zeigt, was intern ausgeführt wird, wenn die Verteilungsfunktion lediglich aus dem Befehl return OK
; besteht:
{ print << "DISTRIBFUNC called.\n"; int n_rxs=-1, irx, cur_rx; val->getco("#rxs", &n_rxs); if (n_rxs < 0) return BAD; static vector<int> ok_var; ok_var.resize(n_rxs); const vector<double> *vprob; val->get("reactivity", &vprob); const vector<int> *eqv_rxn, *ophs; val->get("eqv_rxs", &eqv_rxn); val->get("rxn_phase", &ophs); int cur_rx = 2, iphs = (*ophs)[0], cphs, irx2, cphs2; for (irx=1; irx<=n_rxs; irx++) { if ((*eqv_rxn)[irx] == cur_rx) { cur_rx++; ok_var[irx-1] = 1; } else { ok_var[irx-1] = 0; } cphs = (*ophs)[irx]; if (((*eqv_rxn)[irx]==1)&&(iphs!=cphs)) { bool take = true; for (irx2=1; irx2<irx; irx2++) { cphs2 = (*ophs)[irx2]; if (((*eqv_rxn)[irx2]==1)&&(cphs==cphs2)) { take = false; break; } } if (take) ok_var[irx-1] = 1; } print << "eqv product " << (*eqv_rxn)[irx] << " "; if (ok_var[irx-1] == 1) { print << "accepting reaction "; } else { print << "rejecting reaction "; } print << irx << " with a probability of "; print << (*vprob)[irx-1] << endl; } val->put("rx_ok", &ok_var); return OK; }
print "DISTRIBFUNC called.\n" get "#rxs" n_rxns if {$n_rxs < 0} {return BAD} global ok_var resize ok_var $n_rxs get reactivity vprob get eqv_rxs eqv_rxn get rxn_phase ophs set cur_rx 2 set iphs $ophs(0) for {set irx 1} {$irx<=$n_rxs} {incr irx} { set idx [expr $irx-1] if {$eqv_rxn($irx) == $cur_rx} { incr cur_rx set ok_var($idx) 1 } else { set ok_var($idx) 0 } set cphs $ophs($irx) if {{$eqv_rxn($irx)==1}&&{$iphs!=$cphs}} { set take 1 for {set irx2 1} {$irx2<$irx} {incr irx2} { set cphs2 $ophs($irx2) if {{$eqv_rxn($irx2)==1}&&{$cphs==$cphs2}} { set take 0 break } } if {$take} {set ok_var($idx) 1} } print "eqv product $eqv_rxn($irx) " if {$ok_var($idx) == 1} { print "accepting reaction" } else { print "rejecting reaction" } print " $irx with a probability of $vprob($idx)\n" } put rx_ok ok_var return OKDie Variable
#rxs
gibt die Zahl der erfolgreich durchgeführten Reaktionen an und gibt damit die Dimension der Vektoren der anderen Variablen an. eqv_rxs
ist die Äquivalenzklasse des Produkts, wobei 1
das Edukt
selbst ist. Die Äquivalenzklasse des Produkts der ersten Reaktion bzw. die Phase für die Produkte (rxn_phase
) erhält man mit dem Index 1
; der Index 0
ist für das Edukt. Das Ergebnis der Verteilungsfunktion
ist die Variable rx_ok
, die mit 1
angibt, daß die Reaktion behalten wird bzw. mit 0
, daß die Reaktion verworfen wird. Neben den Variablen #rxs
, eqv_rxn
, rxn_phase
, rx_symmerty
,
rx_rule_nr
und reactivity
stehen in dieser Funktion auch alle Variablen der Reaktion zur Verfügung, die wie der Reaktivitätswert EROS7 bekanntgegeben wurden und vom Typ int
oder double
sind. Sie
kommen dann hier als vector<int>
bzw. vector<double>
für alle Reaktionen eines Edukts an. Für die Reaktivität und alle weiteren während der Reaktion berechneten Variablen gilt Index 0
für
die erste Reaktion. Nur für eqv_rxn
, rxn_phase
und rx_ok
hat der Eintrag für die Reaktion 1 den Index 1.
Liefert die DISTRIBFUNC
keinen vector<int>
unter dem Namen rx_ok
, wird der oben angegebene in EROS7 eingebaute Algorithmus verwendet, der alle Reaktionen verwirft, die identisch sind und deren Produkte in die gleiche
Phase gehen (siehe Beispiel oben). Behalten wird nur die erste Reaktion. Daneben werden auch noch die invarianten Reaktionen verworfen, bei denen Edukt und Produkt identisch sind und der gleichen Phase angehören. Soll dies genutzt werden, sieht der Regelteil
folgendermaßen aus:
return OK;
return OKKehrt die Funktion mit
BAD
zurück, werden alle Reaktionen dieses Edukts verworfen.
Will man hier die Reaktivität und / oder die Symmetriezahl einer Reaktion anpassen, so kann man dies tun, indem man die einen vector<double>
als reactivity
und einen vector<int>
als symmetry
übergibt. Die Reaktivität muß in diesem Fall von den Reaktionen in eine andere Variable geschrieben werden. Der von EROS7 berechnete Symmetriefaktor wird als vector<int>
unter dem Namen rx_symmetry
bereitgestellt.
Es können hier aber auch weitere Werte für die Reaktionen berechnet werden. Werden sie an EROS7 zurückgegeben, werden diese auch bei den Reaktionen abgespeichert und im Reaktionsfile ausgegeben.
return BAD;
return BADWenn sie implementiert werden soll, sieht sie etwa folgendermaßen aus:
if (test) { val->putco("name", "meine Modellfunktion"); return OK; } else { static vector<double> *in, out; val->get("var_of_eros7", &in); if (!in) return BAD; // mache etwas out[0] = 17.34; val->put("result_of_my_func", &out); return OK; }
if {$test} { set tvar "meine Modellfunktion" putco name tvar return OK } else { set flag [get var_of_eros7 in] if {$flag == 0} return BAD # mache etwas set out(0) 17.34 put result_of_my_func out return OK }
return OK;
return OK