diff options
Diffstat (limited to 'Physikunit.pas')
-rw-r--r-- | Physikunit.pas | 520 |
1 files changed, 376 insertions, 144 deletions
diff --git a/Physikunit.pas b/Physikunit.pas index 8c216c9..da9d56e 100644 --- a/Physikunit.pas +++ b/Physikunit.pas @@ -2,16 +2,20 @@ unit Physikunit; {$mode objfpc}{$H+} +{$IFNDEF UNIX} + {$ERROR This program can be compiled only on/for Unix/Linux based systems.} +{$ENDIF} + {$DEFINE Zeitschrittueberwachung} {$DEFINE Dichteueberwachung} interface uses - Classes, SysUtils, Math, protokollunit, matheunit, mystringlistunit, lowlevelunit; + Classes, SysUtils, Math, protokollunit, matheunit, mystringlistunit, lowlevelunit, baseUnix; type - tZeitverfahren = (zfEulerVorwaerts,zfRungeKuttaVier); + tZeitverfahren = (zfEulerVorwaerts,zfRungeKuttaDreiAchtel,zfRungeKuttaVier); tVerteilungsfunktion = function(x: extended): extended; tEMFeldInhalt = ( efA,efAX,efAY,efAZ, @@ -54,7 +58,7 @@ type ortsGrenzen: array of extended; dichteStuecke: array of string; public - nMax, // maximale Massendichte in nc + nMin,nMax, // minimale und maximale Massendichte in nc spezifischeLadung: extended; // q/m in e/me constructor create; destructor destroy; override; @@ -66,9 +70,9 @@ type { tWertePunkt } tWertePunkt = class(tObject) // repräsentiert alle Werte eines Punktes im Gitter und deren Zeitableitungen - matWerte: array of array[tMaterieFeldInhalt,boolean] of double; + matWerte: array of array[tMaterieFeldInhalt,boolean] of extended; // Materiefelder (getrennt für verschiedene Teilchenspezies) und deren Zeitableitungen - emWerte: array[tEMFeldInhalt,boolean] of double; + emWerte: array[tEMFeldInhalt,boolean] of extended; // EM-Felder und deren Zeitableitungen // A, p[xyz]? und i?Gamma haben keine sinnvolle Ableitung hier! lN,rN: tWertePunkt; @@ -76,10 +80,13 @@ type constructor create(linkerNachbar: tWertePunkt; materien: longint); destructor destroy; override; procedure berechneGammaUndP; - procedure berechneNAbleitung(iDX,pDNMax: extended); + procedure berechneNAbleitung(iDX,pDNMax: extended); overload; + procedure berechneNAbleitung(iDX,pDNMax: extended; rechts: boolean); overload; procedure berechneAbleitungen(dX,iDX: extended); - procedure liKo(in1,in2: tWertePunkt; fak2: extended); overload; // Werte werden auf (in1 + fak2*in2') gesetzt - procedure liKo(in1,in2,in3,in4,in5: tWertePunkt; fak2,fak3,fak4,fak5: extended); overload; // Werte werden auf (in1 + \sum_i faki * ini') gesetzt + procedure liKo(in1,in2: tWertePunkt; fak2: extended); overload; // Werte werden auf (in1 + \sum_i faki * ini') gesetzt + procedure liKo(in1,in2,in3: tWertePunkt; fak2,fak3: extended); overload; + procedure liKo(in1,in2,in3,in4: tWertePunkt; fak2,fak3,fak4: extended); overload; + procedure liKo(in1,in2,in3,in4,in5: tWertePunkt; fak2,fak3,fak4,fak5: extended); overload; function maxDT: extended; end; @@ -87,8 +94,9 @@ type tFelder = class(tObject) // repräsentiert eine Simulationsbox von Feldern inklusive deren Ableitungen private - matAnz: longint; - lichters: array[boolean] of tMyStringlist; + matAnz: longint; + spezLadungen: tExtendedArray; + lichters: array[boolean] of tMyStringlist; procedure setzeRaender(dT,iDX,iDT: extended); public inhalt: array of tWertePunkt; @@ -97,8 +105,10 @@ type constructor create(groesse: longint; teilchen: array of tTeilchenSpezies; lichter: tMyStringList; parent: tGitter); destructor destroy; override; procedure berechneAbleitungen(dT,dX,iDT,iDX,pDNMax: extended); - procedure liKo(in1,in2: tFelder; fak2: extended); overload; // Werte werden auf (in1 + fak2*in2') gesetzt - procedure liKo(in1,in2,in3,in4,in5: tFelder; fak2,fak3,fak4,fak5: extended); overload; // Werte werden auf (in1 + \sum_i faki * ini') gesetzt + procedure liKo(in1,in2: tFelder; fak2: extended); overload; // Werte werden auf (in1 + \sum_i faki * ini') gesetzt + procedure liKo(in1,in2,in3: tFelder; fak2,fak3: extended); overload; + procedure liKo(in1,in2,in3,in4: tFelder; fak2,fak3,fak4: extended); overload; + procedure liKo(in1,in2,in3,in4,in5: tFelder; fak2,fak3,fak4,fak5: extended); overload; function maxDT: extended; end; @@ -112,6 +122,7 @@ type dX,iDX,pDNMax,dTMaximum,xl,t: extended; kvs: tKnownValues; procedure diffusionsTermAnpassen(pro: tProtokollant); + function pruefeMaxDT(aF: longint; var mDT,dT: extended): boolean; // wurde verkleinert? public aktuelleFelder: longint; @@ -134,11 +145,14 @@ type fortschrittsAnzeige: boolean; ausgabeDateien: array of tAusgabeDatei; public + gotSighup: boolean; constructor create(inName: string; protokollant: tProtokollant; name: string); destructor destroy; override; function iteriereSchritt(start: extended; var zeitPhysik,zeitDatei: extended): boolean; // noch nicht zu Ende? end; +procedure SignalCapture(signal : longint); cdecl; + implementation const @@ -149,6 +163,9 @@ const 'N','DPSIDX','P','PX','PY','PZ','GAMMA','IGAMMA' ); +var + sighupSimulationen: array of tSimulation; + { tAusgabeDatei } constructor tAusgabeDatei.create(feldName,prefix,suffix: string; prot: tProtokollant; nam: string); @@ -284,7 +301,7 @@ begin for i:=0 to length(gitter.felders[gitter.aktuelleFelder].inhalt)-1 do begin while cX>=sX do begin dec(cnt); - blockWrite(datei,gitter.felders[gitter.aktuelleFelder].inhalt[i].emWerte[emInhalt,ableitung],sizeof(double)); + blockWrite(datei,gitter.felders[gitter.aktuelleFelder].inhalt[i].emWerte[emInhalt,ableitung],sizeof(extended)); sX:=sX+sDX; end; cX:=cX+gitter.dX; @@ -294,7 +311,7 @@ begin for i:=0 to length(gitter.felders[gitter.aktuelleFelder].inhalt)-1 do begin while cX>=sX do begin dec(cnt); - blockWrite(datei,gitter.felders[gitter.aktuelleFelder].inhalt[i].matWerte[teilchen,matInhalt,ableitung],sizeof(double)); + blockWrite(datei,gitter.felders[gitter.aktuelleFelder].inhalt[i].matWerte[teilchen,matInhalt,ableitung],sizeof(extended)); sX:=sX+sDX; end; cX:=cX+gitter.dX; @@ -317,7 +334,8 @@ begin setlength(ortsGrenzen,0); fillchar(dichteStuecke,sizeof(dichteStuecke),#0); setlength(dichteStuecke,0); - nMax:=0; + nMin:=1E-3; + nMax:=nMin; spezifischeLadung:=0; end; @@ -350,7 +368,7 @@ begin while (i<length(ortsGrenzen)) and (ortsGrenzen[i]<x) do inc(i); kvs.add('x',x); - result:=nMax*exprToFloat(false,dichteStuecke[i],kvs,nil); + result:=(nMax-nMin)*exprToFloat(false,dichteStuecke[i],kvs,nil)+nMin; kvs.rem('x'); end; @@ -479,15 +497,35 @@ begin for i:=0 to length(matWerte)-1 do // dn/dt = -d(n/Gamma p_x)/dx + (p_max*dx) * Laplace n matWerte[i,mfN,true]:= - ( rN.matWerte[i,mfN,false] * rN.matWerte[i,mfIGamma,false] * (pDNMax - rN.matWerte[i,mfPX,false]) - - ln.matWerte[i,mfN,false] * ln.matWerte[i,mfIGamma,false] * (-pDNMax - rN.matWerte[i,mfPX,false]) - - matWerte[i,mfN,false] * matWerte[i,mfIGamma,false] * 2 * pDNMax) * iDX/2; + ( rN.matWerte[i,mfN,false] * rN.matWerte[i,mfIGamma,false] * (pDNMax - rN.matWerte[i,mfPX,false]) + + lN.matWerte[i,mfN,false] * lN.matWerte[i,mfIGamma,false] * (pDNMax + lN.matWerte[i,mfPX,false]) + - matWerte[i,mfN,false] * matWerte[i,mfIGamma,false] * 2 * pDNMax) * iDX/2; // Der zweite Summand entspricht (in etwa) einer thermischen Verschmierung // und soll die numerische Stabilität bis zu p * dn/dx / n von 2*pDNMax gewährleisten. // Es handelt sich um einen Diffusionsterm dn/dt = alpha * Laplace n mit // alpha = pDNMax * dX end; +procedure tWertePunkt.berechneNAbleitung(iDX,pDNMax: extended; rechts: boolean); +var + i: longint; +begin + if rechts then begin + for i:=0 to length(matWerte)-1 do + // rechter Randterm von dn/dt = -d(n/Gamma p_x)/dx + (p_max*dx) * Laplace n + matWerte[i,mfN,true]:= + ( lN.matWerte[i,mfN,false] * lN.matWerte[i,mfIGamma,false] * (pDNMax + lN.matWerte[i,mfPX,false]) + - matWerte[i,mfN,false] * matWerte[i,mfIGamma,false] * (pDNMax - matWerte[i,mfPX,false])) * iDX/2; + end + else begin + for i:=0 to length(matWerte)-1 do + // linker Randterm von dn/dt = -d(n/Gamma p_x)/dx + (p_max*dx) * Laplace n + matWerte[i,mfN,true]:= + ( rN.matWerte[i,mfN,false] * rN.matWerte[i,mfIGamma,false] * (pDNMax - rN.matWerte[i,mfPX,false]) + - matWerte[i,mfN,false] * matWerte[i,mfIGamma,false] * (pDNMax + matWerte[i,mfPX,false])) * iDX/2; + end +end; + procedure tWertePunkt.berechneAbleitungen(dX,iDX: extended); // Zeitableitungen berechnen var i: longint; @@ -558,6 +596,68 @@ begin matWerte[i,maF,false]:= in1.matWerte[i,maF,false] + fak2 * in2.matWerte[i,maF,true]; end; +procedure tWertePunkt.liKo(in1,in2,in3: tWertePunkt; fak2,fak3: extended); // Werte werden auf (in1 + \sum_i faki * ini') gesetzt +var + emF: tEMFeldInhalt; + maF: tMaterieFeldInhalt; + i: longint; +begin +(* tEMFeldInhalt = ( + efA,efAX,efAY,efAZ, + efDAXDT,efDAYDT,efDAZDT, + efDPhiDX + ); *) + for emF:=efAX to efDPhiDX do // alles außer efA, welchen Ableitung ja nicht berechnet wurde + emWerte[emF,false]:= + in1.emWerte[emF,false] + + fak2 * in2.emWerte[emF,true] + + fak3 * in3.emWerte[emF,true]; + +(* tMaterieFeldInhalt = ( + mfN,mfDPsiDX, + mfP,mfPX,mfPY,mfPZ, + mfGamma,mfIGamma + ); *) + for i:=0 to length(matWerte)-1 do // siehe oben + for maF:=mfN to mfDPsiDX do + matWerte[i,maF,false]:= + in1.matWerte[i,maF,false] + + fak2 * in2.matWerte[i,maF,true] + + fak3 * in3.matWerte[i,maF,true]; +end; + +procedure tWertePunkt.liKo(in1,in2,in3,in4: tWertePunkt; fak2,fak3,fak4: extended); // Werte werden auf (in1 + \sum_i faki * ini') gesetzt +var + emF: tEMFeldInhalt; + maF: tMaterieFeldInhalt; + i: longint; +begin +(* tEMFeldInhalt = ( + efA,efAX,efAY,efAZ, + efDAXDT,efDAYDT,efDAZDT, + efDPhiDX + ); *) + for emF:=efAX to efDPhiDX do // alles außer efA, welchen Ableitung ja nicht berechnet wurde + emWerte[emF,false]:= + in1.emWerte[emF,false] + + fak2 * in2.emWerte[emF,true] + + fak3 * in3.emWerte[emF,true] + + fak4 * in4.emWerte[emF,true]; + +(* tMaterieFeldInhalt = ( + mfN,mfDPsiDX, + mfP,mfPX,mfPY,mfPZ, + mfGamma,mfIGamma + ); *) + for i:=0 to length(matWerte)-1 do // siehe oben + for maF:=mfN to mfDPsiDX do + matWerte[i,maF,false]:= + in1.matWerte[i,maF,false] + + fak2 * in2.matWerte[i,maF,true] + + fak3 * in3.matWerte[i,maF,true] + + fak4 * in4.matWerte[i,maF,true]; +end; + procedure tWertePunkt.liKo(in1,in2,in3,in4,in5: tWertePunkt; fak2,fak3,fak4,fak5: extended); // Werte werden auf (in1 + \sum_i faki * ini') gesetzt var emF: tEMFeldInhalt; @@ -596,11 +696,11 @@ function tWertePunkt.maxDT: extended; var i: longint; begin - result:=1; + result:=infinity; for i:=0 to length(matWerte)-1 do if (matWerte[i,mfN,true]<0) and (matWerte[i,mfN,false]>0) then - result:=min(result,matWerte[i,mfN,false]/matWerte[i,mfN,true]); + result:=min(result,-matWerte[i,mfN,false]/matWerte[i,mfN,true]); end; { tFelder } @@ -613,6 +713,10 @@ begin inherited create; par:=parent; matAnz:=length(teilchen); + fillchar(spezLadungen,sizeof(spezLadungen),#0); + setlength(spezLadungen,matAnz); + for i:=0 to length(spezLadungen)-1 do + spezLadungen[i]:=teilchen[i].spezifischeLadung; fillchar(inhalt,sizeof(inhalt),#0); setlength(inhalt,groesse+4); // zwei Felder links und rechts extra für Randbedingungen inhalt[0]:=tWertePunkt.create(nil,matAnz); @@ -634,7 +738,13 @@ begin end; destructor tFelder.destroy; +var + i: longint; begin + setlength(spezLadungen,0); + for i:=0 to length(inhalt)-1 do + inhalt[i].free; + setlength(inhalt,0); lichters[false].free; lichters[true].free; inherited destroy; @@ -645,7 +755,7 @@ var emF: tEMFeldInhalt; rechts: boolean; i: longint; - oVal: extended; + nVal: extended; begin for emF:=efAX to efAZ do begin // Vakuumrandbedingungen für das A-Feld inhalt[0].emWerte[emF,true]:= @@ -658,12 +768,12 @@ begin for rechts:=false to true do for i:=0 to lichters[rechts].count-1 do begin - par.kvs.add('t',par.t-dT); - oVal:=exprToFloat(false,lichters[rechts][i],par.kvs,nil); + par.kvs.add('t',par.t+dT); + nVal:=exprToFloat(false,lichters[rechts][i],par.kvs,nil); par.kvs.add('t',par.t); inhalt[(length(inhalt)-1)*byte(rechts)].emWerte[efAY,true]:= inhalt[(length(inhalt)-1)*byte(rechts)].emWerte[efAY,true] + - (exprToFloat(false,lichters[rechts][i],par.kvs,nil) - oVal)*iDT; + (nVal - exprToFloat(false,lichters[rechts][i],par.kvs,nil))*iDT; end; end; @@ -680,11 +790,15 @@ begin -abs(inhalt[length(inhalt)-2].matWerte[i,mfPX,false]); end; + for i:=2 to length(inhalt)-3 do + inhalt[i].berechneNAbleitung(iDX,pDNMax); + + inhalt[1].berechneNAbleitung(iDX,pDNMax,false); + inhalt[length(inhalt)-2].berechneNAbleitung(iDX,pDNMax,true); + setzeRaender(dT,iDX,iDT); for i:=1 to length(inhalt)-2 do - inhalt[i].berechneNAbleitung(iDX,pDNMax); - for i:=1 to length(inhalt)-2 do inhalt[i].berechneAbleitungen(dX,iDX); end; @@ -696,6 +810,22 @@ begin inhalt[i].liKo(in1.inhalt[i],in2.inhalt[i],fak2); end; +procedure tFelder.liKo(in1,in2,in3: tFelder; fak2,fak3: extended); // Werte werden auf (in1 + \sum_i faki * ini') gesetzt +var + i: longint; +begin + for i:=0 to length(inhalt)-1 do + inhalt[i].liKo(in1.inhalt[i],in2.inhalt[i],in3.inhalt[i],fak2,fak3); +end; + +procedure tFelder.liKo(in1,in2,in3,in4: tFelder; fak2,fak3,fak4: extended); // Werte werden auf (in1 + \sum_i faki * ini') gesetzt +var + i: longint; +begin + for i:=0 to length(inhalt)-1 do + inhalt[i].liKo(in1.inhalt[i],in2.inhalt[i],in3.inhalt[i],in4.inhalt[i],fak2,fak3,fak4); +end; + procedure tFelder.liKo(in1,in2,in3,in4,in5: tFelder; fak2,fak3,fak4,fak5: extended); // Werte werden auf (in1 + \sum_i faki * ini') gesetzt var i: longint; @@ -732,8 +862,10 @@ begin end else pDNMax:=pDNMa; case Zeitverfahren of - zfEulerVorwaerts: Setlength(Felders,2); - zfRungeKuttaVier: Setlength(Felders,5); + zfEulerVorwaerts: + Setlength(Felders,2); + zfRungeKuttaDreiAchtel,zfRungeKuttaVier: + Setlength(Felders,5); end{of Case}; xl:=dX/2; @@ -755,102 +887,178 @@ begin inherited destroy; end; +procedure tGitter.diffusionsTermAnpassen(pro: tProtokollant); +var + i,j: longint; +begin + for i:=1 to length(felders[aktuelleFelder].inhalt)-2 do + for j:=0 to felders[aktuelleFelder].matAnz-1 do + if abs(felders[aktuelleFelder].inhalt[i].matWerte[j,mfPx,false]* + (felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] - felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false])/ + max(felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] + felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false],1e-10)) + > pDNMax then begin + if pDNMaxDynamisch then begin + pDNMax:= + 2* + abs(felders[aktuelleFelder].inhalt[i].matWerte[j,mfPX,false]* + (felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] - felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false])/ + Max(felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] + felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false],1e-10)); + pro.schreibe('Neues maximales px * dn/dx / n: '+floattostr(pDNMax)+' (t='+floattostr(t)+')'); + end + else + if pDNMax>0 then begin + pro.schreibe('Warnung: maximaler Impuls * dn/dx / n von '+floattostr(pDNMax)+' wurde überschritten (t='+floattostr(t)+ + 'T), die numerische Stabilität ist nicht mehr gewährleistet!',true); + pro.schreibe(' Lösung: größeren Diffusionsterm wählen (-D)',true); + pro.schreibe(' außerdem empfohlen: Ortsauflösung in gleichem Maße verbessern (-x)',true); + pDNMax:=-1; + end; + end; +end; + +function tGitter.pruefeMaxDT(aF: longint; var mDT,dT: extended): boolean; // wurde verkleinert? +begin + mDT:=min(mDT,felders[aF].maxDT); + // das maximale dT, welches bei den Momentanen Ableitungen nicht zu + // unphysikalischen Effekten (z.B. negativen Dichten) führt + + result:=mDT<dT*2; + if result then begin // beabsichtigter Zeitschritt ist zu groß, + dT:=mDT/4; // dann machen wir ihn doch kleiner! + {$IFDEF Zeitschrittueberwachung} + prot.schreibe('pruefeMaxDT: dT -> '+floattostr(dT)); + if dT<1E-30 then begin + prot.schreibe('pruefeMaxDT: Zeitschritt geht gegen Null (ist bereits '+floattostr(dT)+' < 10^-30) - irgendwas scheint grundsätzlich kaputt zu sein!',true); + prot.destroyall; + halt(1); + end; + {$ENDIF} + exit; + end; +end; + procedure tGitter.iteriereSchritt(var dT: extended); var i: longint; {$IFDEF Zeitschrittueberwachung} - pro: tProtokollant; j: longint; {$ENDIF} + {$IFDEF Dichteueberwachung} + pro: tProtokollant; + {$ENDIF} iDT,mDT: extended; begin - kvs.add('t',t+dT); + kvs.add('t',t); diffusionsTermAnpassen(prot); + mDT:=infinity; + repeat iDT:=1/dT; felders[aktuelleFelder].berechneAbleitungen(dT,dX,iDT,iDX,pDNMax); // y' = y'(t,y(t)) - mDT:=felders[aktuelleFelder].maxDT; - // das maximale dT, welches bei den Momentanen Ableitungen nicht zu - // unphysikalischen Effekten (z.B. negativen Dichten) führt - - if mDT<dT*2 then begin // beabsichtigter Zeitschritt ist zu groß - dT:=mDT/4; // machen wir ihn kleiner! - {$IFDEF Zeitschrittueberwachung} - pro:=tProtokollant.create(prot,'iteriereSchritt'); - pro.schreibe('dT -> '+floattostr(dT)); - if dT<1E-30 then begin - pro.schreibe('Zeitschritt geht gegen Null (ist bereits '+floattostr(dT)+' < 10^-30) - irgendwas scheint grundsätzlich kaputt zu sein!',true); - pro.destroyall; - halt(1); - end; - pro.free; - {$ENDIF} + if pruefeMaxDT(aktuelleFelder,mDT,dT) then continue; - end; + + case zeitverfahren of + zfEulerVorwaerts: // y(t+dt) = y(t) + y' dt + felders[1-aktuelleFelder].liKo(felders[aktuelleFelder],felders[aktuelleFelder],dT); + zfRungeKuttaDreiAchtel: + begin + felders[2].liKo(felders[aktuelleFelder],felders[aktuelleFelder],dT/3); // ya = y(t) + y' dt/3 + felders[2].berechneAbleitungen(dT/3,dX,iDT,iDX,pDNMax); // ya' = y'(t+dt/3,ya) + + if pruefeMaxDT(2,mDT,dT) then + continue; + + felders[3].liKo(felders[aktuelleFelder],felders[aktuelleFelder],felders[2],-dT/3,dT); // yb = y(t) - y' dt/3 + ya' dt + felders[3].berechneAbleitungen(dT/3,dX,iDT,iDX,pDNMax); // yb' = y'(t+2dt/3,yb) + + if pruefeMaxDT(3,mDT,dT) then + continue; + + felders[4].liKo(felders[aktuelleFelder],felders[aktuelleFelder],felders[2],felders[3],dT,-dT,dT); // yc = y(t) + a' dt - ya' dt + yb' dt + felders[4].berechneAbleitungen(dT/3,dX,iDT,iDX,pDNMax); // yc' = y'(t+dt,yc) + + if pruefeMaxDT(4,mDT,dT) then + continue; + + felders[1-aktuelleFelder].liKo( + felders[aktuelleFelder], + felders[aktuelleFelder], + felders[2], + felders[3], + felders[4], + dT/8, + dT*3/8, + dT*3/8, + dT/8 + ); // y(t+dt) = y(t) + (y' + 3(ya' + yb') + yc') dt/8 + end; + zfRungeKuttaVier: + begin + felders[2].liKo(felders[aktuelleFelder],felders[aktuelleFelder],dT/2); // ya = y(t) + y' dt/2 + felders[2].berechneAbleitungen(dT/2,dX,iDT,iDX,pDNMax); // ya' = y'(t+dt/2,ya) + + if pruefeMaxDT(2,mDT,dT) then + continue; + + felders[3].liKo(felders[aktuelleFelder],felders[2],dT/2); // yb = y(t) + ya' dt/2 + felders[3].berechneAbleitungen(dT/2,dX,iDT,iDX,pDNMax); // yb' = y'(t+dt/2,yb) + + if pruefeMaxDT(3,mDT,dT) then + continue; + + felders[4].liKo(felders[aktuelleFelder],felders[3],dT); // yc = y(t) + yb' dt + felders[4].berechneAbleitungen(dT/2,dX,iDT,iDX,pDNMax); // yc' = y'(t+dt,yc) + + if pruefeMaxDT(4,mDT,dT) then + continue; + + felders[1-aktuelleFelder].liKo( + felders[aktuelleFelder], + felders[aktuelleFelder], + felders[2], + felders[3], + felders[4], + dT/6, + dT/3, + dT/3, + dT/6 + ); // y(t+dt) = y(t) + (y' + 2(ya' + yb') + yc') dt/6 + end; + end{of case}; break; until false; - if dT<mDT/1000 then - dT:=min(1,mDT)/1000; - - case zeitverfahren of - zfEulerVorwaerts: // y(t+dt) = y(t) + y' dt - felders[1-aktuelleFelder].liKo(felders[aktuelleFelder],felders[aktuelleFelder],dT); - zfRungeKuttaVier: - begin - felders[2].liKo(felders[aktuelleFelder],felders[aktuelleFelder],dT/2); // ya = y(t) + y' dt/2 - felders[2].berechneAbleitungen(dT/2,dX,iDT,iDX,pDNMax); // ya' = y'(t+dt/2,ya) - - felders[3].liKo(felders[aktuelleFelder],felders[2],dT/2); // yb = y(t) + ya' dt/2 - felders[3].berechneAbleitungen(dT/2,dX,iDT,iDX,pDNMax); // yb' = y'(t+dt/2,yb) - - felders[4].liKo(felders[aktuelleFelder],felders[3],dT); // yc = y(t) + yb' dt - felders[4].berechneAbleitungen(dT/2,dX,iDT,iDX,pDNMax); // yc' = y'(t+dt,yc) - - felders[1-aktuelleFelder].liKo( - felders[aktuelleFelder], - felders[aktuelleFelder], - felders[2], - felders[3], - felders[4], - dT/6, - dT/3, - dT/3, - dT/6 - ); // y(t+dt) = y(t) + (y' + 2(ya' + yb') + yc') dt/6 - end; - end{of case}; - aktuelleFelder:=1-aktuelleFelder; {$IFDEF Dichteueberwachung} - with felders[aktuelleFelder] do - for i:=0 to length(inhalt)-1 do - for j:=0 to matAnz-1 do - if inhalt[i].matWerte[j,mfN,false]<0 then begin - pro:=tProtokollant.create(prot,'iteriereSchritt'); - pro.schreibe( - 'n<=0 bei '+ - floattostr(t)+' '+ - inttostr(i)+' '+ - floattostr(inhalt[i-1].matWerte[j,mfDPsiDX,false]* - inhalt[i-1].matWerte[j,mfIGamma,false])+' '+ - floattostr(inhalt[i-1].matWerte[j,mfN,false])+' '+ - floattostr(inhalt[i-1].matWerte[j,mfN,true])+' '+ - floattostr(inhalt[i].matWerte[j,mfDPsiDX,false]* - inhalt[i].matWerte[j,mfIGamma,false])+' '+ - floattostr(inhalt[i].matWerte[j,mfN,false])+' '+ - floattostr(inhalt[i].matWerte[j,mfN,true])+' '+ - floattostr(inhalt[i+1].matWerte[j,mfDPsiDX,false]* - inhalt[i+1].matWerte[j,mfIGamma,false])+' '+ - floattostr(inhalt[i+1].matWerte[j,mfN,false])+' '+ - floattostr(inhalt[i+1].matWerte[j,mfN,true]),true); - pro.destroyall; - halt(1); - end; + for i:=0 to length(felders[aktuelleFelder].inhalt)-1 do + for j:=0 to felders[aktuelleFelder].matAnz-1 do + if felders[aktuelleFelder].inhalt[i].matWerte[j,mfN,false]<0 then + with felders[1-aktuelleFelder] do begin + pro:=tProtokollant.create(prot,'iteriereSchritt'); + pro.schreibe('n<0 bei:',true); + pro.schreibe(' t = ' +floattostr(t)+',',true); + pro.schreibe(' i = ' +inttostr(i)+' (x = '+floattostr(xl+i*dX)+'),',true); + pro.schreibe(' v_l = ' +floattostr(inhalt[i-1].matWerte[j,mfDPsiDX,false]* + inhalt[i-1].matWerte[j,mfIGamma,false])+',',true); + pro.schreibe(' n_l = ' +floattostr(inhalt[i-1].matWerte[j,mfN,false])+',',true); + pro.schreibe(' n_l'' = '+floattostr(inhalt[i-1].matWerte[j,mfN,true])+',',true); + pro.schreibe(' v = ' +floattostr(inhalt[i].matWerte[j,mfDPsiDX,false]* + inhalt[i].matWerte[j,mfIGamma,false])+',',true); + pro.schreibe(' n = ' +floattostr(inhalt[i].matWerte[j,mfN,false])+',',true); + pro.schreibe(' n'' = '+floattostr(inhalt[i].matWerte[j,mfN,true])+',',true); + pro.schreibe(' v_r = ' +floattostr(inhalt[i+1].matWerte[j,mfDPsiDX,false]* + inhalt[i+1].matWerte[j,mfIGamma,false])+',',true); + pro.schreibe(' n_r = ' +floattostr(inhalt[i+1].matWerte[j,mfN,false])+',',true); + pro.schreibe(' n_r'' = '+floattostr(inhalt[i+1].matWerte[j,mfN,true]),true); + pro.destroyall; + halt(1); + end; {$ENDIF} t:=t+dT; + dT:=max(dT,min(1,mDT)/100); end; function tGitter.dumpErhaltungsgroessen: boolean; @@ -885,35 +1093,6 @@ begin pro.free; end; -procedure tGitter.diffusionsTermAnpassen(pro: tProtokollant); -var - i,j: longint; -begin - for i:=1 to length(felders[aktuelleFelder].inhalt)-2 do - for j:=0 to felders[aktuelleFelder].matAnz-1 do - if abs(felders[aktuelleFelder].inhalt[i].matWerte[j,mfPx,false]* - (felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] - felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false])/ - max(felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] + felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false],1e-10)) - > pDNMax then begin - if pDNMaxDynamisch then begin - pDNMax:= - 2* - abs(felders[aktuelleFelder].inhalt[i].matWerte[j,mfPX,false]* - (felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] - felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false])/ - Max(felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] + felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false],1e-10)); - pro.schreibe('Neues maximales px * dn/dx / n: '+floattostr(pDNMax)+' (t='+floattostr(t)+')'); - end - else - if pDNMax>0 then begin - pro.schreibe('Warnung: maximaler Impuls * dn/dx / n von '+floattostr(pDNMax)+' wurde überschritten (t='+floattostr(t)+ - 'T), die numerische Stabilität ist nicht mehr gewährleistet!',true); - pro.schreibe(' Lösung: größeren Diffusionsterm wählen (-D)',true); - pro.schreibe(' außerdem empfohlen: Ortsauflösung in gleichem Maße verbessern (-x)',true); - pDNMax:=-1; - end; - end; -end; - procedure tGitter.berechne(was: char; teilchen: longint); var i: longint; @@ -957,6 +1136,7 @@ var teilchen: array of tTeilchenSpezies; lichter: tMyStringlist; pro: tProtokollant; + na: pSigActionRec; begin inherited create; prot:=tProtokollant.create(protokollant,name); @@ -986,6 +1166,7 @@ begin breite:=10.0; pDNMax:=-1; fortschrittsAnzeige:=false; + gotSighup:=false; // Standardeinstellungen Bereich 'ausgaben' aPrefix:=extractfilepath(paramstr(0)); @@ -1016,6 +1197,10 @@ begin halt(1); end; if s='allgemeinEnde' then break; + if s='runge-Kutta-3/8' then begin + Zeitverfahren:=zfRungeKuttaDreiAchtel; + continue; + end; if s='runge-Kutta-4' then begin Zeitverfahren:=zfRungeKuttaVier; continue; @@ -1140,6 +1325,11 @@ begin kvs.add('nmax'+inttostr(length(teilchen)),teilchen[length(teilchen)-1].nMax); continue; end; + if startetMit('minimaldichte ',s) then begin + teilchen[length(teilchen)-1].nMin:=exprToFloat(false,s,kvs,nil); + kvs.add('nmin'+inttostr(length(teilchen)),teilchen[length(teilchen)-1].nMin); + continue; + end; if startetMit('verteilung ',s) then begin teilchen[length(teilchen)-1].liesDichteFunktion(s,ifile,kvs,teilchen,prot); continue; @@ -1178,6 +1368,8 @@ begin case zeitverfahren of zfEulerVorwaerts: pro.schreibe('Iteration mittels Euler-Vorwärts'); + zfRungeKuttaDreiAchtel: + pro.schreibe('Iteration mittels Runge-Kutta-3/8'); zfRungeKuttaVier: pro.schreibe('Iteration mittels Runge-Kutta-4'); else @@ -1208,6 +1400,23 @@ begin end; pro.free; + if length(sighupSimulationen)=0 then begin + new(na); + na^.sa_Handler := sigActionHandler(@signalCapture); + fillchar(na^.sa_Mask,sizeof(na^.sa_mask),#0); + na^.sa_Flags := 0; + {$ifdef Linux} // Linux specific + na^.sa_Restorer := Nil; + {$endif} + if (fPSigaction(SIGHUP, na, nil) <> 0) then begin + writeln(stderr, 'Error: ', fpgeterrno, '.'); + halt(1); + end; + dispose(na); + end; + setlength(sighupSimulationen,length(sighupSimulationen)+1); + sighupSimulationen[length(sighupSimulationen)-1]:=self; + gitter:=tGitter.create(round(breite/deltaX)+1,dT,deltaX,pDNMax,kvs,teilchen,lichter,zeitverfahren,prot,'gitter'); for i:=0 to length(teilchen)-1 do teilchen[i].free; @@ -1216,9 +1425,17 @@ begin end; destructor tSimulation.destroy; +var + i,j: longint; begin gitter.free; prot.free; + for i:=length(sighupSimulationen)-1 downto 0 do + if sighupSimulationen[i]=self then begin + for j:=i+1 to length(sighupSimulationen)-1 do + sighupSimulationen[j-1]:=sighupSimulationen[j]; + setlength(sighupSimulationen,length(sighupSimulationen)-1); + end; inherited destroy; end; @@ -1240,22 +1457,37 @@ begin end; zeitDatei:=zeitDatei+now; - if fortschrittsAnzeige then begin - if (floor(100*Gitter.t/tEnde) < floor(100*(Gitter.t+dT)/tEnde)) then begin - prot.schreibe(inttostr(round(100*Gitter.t/tEnde))+'% (t='+floattostr(Gitter.t)+'T)',true); - prot.schreibe(timetostr(now-start)+' ('+floattostr(zeitPhysik/max(1e-11,zeitPhysik+zeitDatei))+')',true); - prot.schreibe('ETA: '+timetostr((now-start)*(tEnde-Gitter.t)/max(Gitter.t,dT)),true); - prot.schreibe('aktueller Zeitschritt: '+floattostr(dT)+'T',true); - if errorCode<2 then - if not gitter.dumpErhaltungsgroessen then begin - errorCode:=2; - exit; - end; - end; + if gotSighup or + (fortschrittsAnzeige and (floor(100*Gitter.t/tEnde) < floor(100*(Gitter.t+dT)/tEnde))) then begin + gotSighup:=false; + prot.schreibe(inttostr(round(100*Gitter.t/tEnde))+'% (t='+floattostr(Gitter.t)+'T)',true); + prot.schreibe(timetostr(now-start)+' ('+floattostr(zeitPhysik/max(1e-11,zeitPhysik+zeitDatei))+')',true); + prot.schreibe('ETA: '+timetostr((now-start)*(tEnde-Gitter.t)/max(Gitter.t,dT)),true); + prot.schreibe('aktueller Zeitschritt: '+floattostr(dT)+'T',true); + if errorCode<2 then + if not gitter.dumpErhaltungsgroessen then begin + errorCode:=2; + exit; + end; end; result:=gitter.t<tEnde; end; +// allgemeine Funktionen ******************************************************* + +procedure SignalCapture(signal : longint); cdecl; +var + i: longint; +begin + if signal=SIGHUP then + for i:=0 to length(sighupSimulationen)-1 do + sighupSimulationen[i].gotSighup:=true; +end; + +initialization + setlength(sighupSimulationen,0); +finalization + setlength(sighupSimulationen,0); end. |