diff options
Diffstat (limited to 'Physikunit.pas')
-rw-r--r-- | Physikunit.pas | 202 |
1 files changed, 78 insertions, 124 deletions
diff --git a/Physikunit.pas b/Physikunit.pas index 0a2ca5e..142ee4b 100644 --- a/Physikunit.pas +++ b/Physikunit.pas @@ -52,7 +52,7 @@ type destructor destroy; override; function dump: string; procedure schreibeKopf; - procedure speichereWerte(gitter: tGitter; sDX: extended); + procedure speichereWerte(gitter: tGitter; sT, sDX: extended); end; { tTeilchenSpezies } @@ -121,14 +121,14 @@ type matAnz: longint; spezLadungen: tExtendedArray; lichters: array[boolean] of tMyStringlist; - procedure setzeRaender(dT,iDX,iDT: extended); + procedure setzeRaender(iDX: extended); public inhalt: array of tWertePunkt; par: tGitter; constructor create(groesse: longint; teilchen: array of tTeilchenSpezies; lichter: tMyStringList; parent: tGitter); destructor destroy; override; - procedure berechneAbleitungen(dT,dX,iDT,iDX,pDNMax: extended); + procedure berechneAbleitungen(dX,iDX,pDNMax: extended); 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; @@ -163,7 +163,8 @@ type dX,iDX,pDNMax,dTMaximum,xl,t: extended; kvs: tKnownValues; procedure diffusionsTermAnpassen(pro: tProtokollant); - function pruefeMaxDT(aF: longint; var mDT,dT: extended; dTMin: extended): boolean; // wurde verkleinert? + function pruefeMaxDT(aF: longint; var dTMax,dT: extended; dTMin: extended): boolean; // wurde verkleinert? + procedure abbrechen; public aktuelleFelder: longint; @@ -334,7 +335,7 @@ begin closefile(datei); end; -procedure tAusgabeDatei.speichereWerte(gitter: tGitter; sDX: extended); +procedure tAusgabeDatei.speichereWerte(gitter: tGitter; sT, sDX: extended); var i,cnt: longint; sX,cX: extended; begin @@ -348,7 +349,7 @@ begin if (teilchen>=0) and (matInhalt=mfP) then gitter.berechne('P',teilchen); - if gitter.t>=nNum+sDT/2 then + if sT>=nNum+sDT/2 then schreibeKopf; cnt:=floor((length(gitter.felders[gitter.aktuelleFelder].inhalt)-1)/sDX*gitter.dX+1); @@ -749,12 +750,11 @@ begin inherited destroy; end; -procedure tFelder.setzeRaender(dT,iDX,iDT: extended); +procedure tFelder.setzeRaender(iDX: extended); var emF: tEMFeldInhalt; rechts: boolean; i: longint; - nVal: extended; begin for emF:=efAX to efAZ do begin // Vakuumrandbedingungen für das A-Feld inhalt[0].emWerte[emF,true]:= @@ -766,17 +766,13 @@ begin end; // (ein bisschen wird noch reflektiert, vmtl. durch numerische Fehler bzw. nicht beachtete numerische Dispersion) for rechts:=false to true do - for i:=0 to lichters[rechts].count-1 do begin - par.kvs.add('t',par.t+dT); - nVal:=exprToFloat(false,lichters[rechts][i],par.kvs,nil); - par.kvs.add('t',par.t); + for i:=0 to lichters[rechts].count-1 do inhalt[(length(inhalt)-1)*byte(rechts)].emWerte[efAY,true]:= inhalt[(length(inhalt)-1)*byte(rechts)].emWerte[efAY,true] + - (nVal - exprToFloat(false,lichters[rechts][i],par.kvs,nil))*iDT; - end; + exprToFloat(false,lichters[rechts][i],par.kvs,nil); end; -procedure tFelder.berechneAbleitungen(dT,dX,iDT,iDX,pDNMax: extended); +procedure tFelder.berechneAbleitungen(dX,iDX,pDNMax: extended); var i: longint; begin @@ -795,7 +791,7 @@ begin inhalt[1].berechneNAbleitung(iDX,pDNMax,false); inhalt[length(inhalt)-2].berechneNAbleitung(iDX,pDNMax,true); - setzeRaender(dT,iDX,iDT); + setzeRaender(iDX); for i:=1 to length(inhalt)-2 do inhalt[i].berechneAbleitungen(dX,iDX); @@ -863,49 +859,47 @@ end; procedure tGitter.diffusionsTermAnpassen(pro: tProtokollant); var - i,j: longint; + i,j: longint; + curMax: extended; begin + curMax:=0; 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]* + curMax:= + max(curMax, + 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; + max(felders[aktuelleFelder].inhalt[i+1].matWerte[j,mfN,false] + felders[aktuelleFelder].inhalt[i-1].matWerte[j,mfN,false],1e-100))); + if curMax > pDNMax then begin + if pDNMaxDynamisch then begin + pDNMax:=2*curMax; + 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',true); + pro.schreibe(' außerdem empfohlen: Ortsauflösung in gleichem Maße verbessern',true); + pDNMax:=0; // Term komplett abschalten + end; + end; end; -function tGitter.pruefeMaxDT(aF: longint; var mDT,dT: extended; dTMin: extended): boolean; // wurde verkleinert? +function tGitter.pruefeMaxDT(aF: longint; var dTMax,dT: extended; dTMin: extended): boolean; // wurde verkleinert? begin - mDT:=min(mDT,felders[aF].maxDT); - // das maximale dT, welches bei den Momentanen Ableitungen nicht zu + dTMax:=min(dTMax,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; + result:=dTMax<dT*2; if result then begin // beabsichtigter Zeitschritt ist zu groß, - dT:=mDT/4; // dann machen wir ihn doch kleiner! + dT:=dTMax/4; // dann machen wir ihn doch kleiner! {$IFDEF Zeitschrittueberwachung} - prot.schreibe('pruefeMaxDT: dT -> '+floattostr(dT)); + prot.schreibe('pruefeMaxDT: dT -> '+floattostr(dT)+' (t = '+floattostr(t)+')'); if dT<dTMin then begin prot.schreibe('pruefeMaxDT: Zeitschritt geht gegen Null (ist bereits '+floattostr(dT)+' < '+floattostr(dTMin)+') - irgendwas scheint grundsätzlich kaputt zu sein!',true); - abbruch:=true; -// prot.destroyall; -// halt(1); + abbrechen; end; prot.spuelen; {$ENDIF} @@ -913,6 +907,26 @@ begin end; end; +procedure tGitter.abbrechen; +var + i,j,k: longint; + maF: tMaterieFeldInhalt; + emF: tEMFeldInhalt; + abl: boolean; +begin + abbruch:=true; + for i:=0 to length(felders)-1 do + for j:=0 to length(felders[i].inhalt)-1 do begin + for emF:=low(tEMFeldInhalt) to high(tEMFeldInhalt) do + for abl:=false to true do + felders[i].inhalt[j].emWerte[emF,false]:=0; + for k:=0 to felders[i].matAnz-1 do + for maF:=low(tMaterieFeldInhalt) to high(tMaterieFeldInhalt) do + for abl:=false to true do + felders[i].inhalt[j].matWerte[k,maF,false]:=0; + end; +end; + procedure tGitter.iteriereSchritt(var dT: extended; dTMin: extended); var i: longint; {$IFDEF Zeitschrittueberwachung} @@ -921,7 +935,7 @@ var i: longint; {$IFDEF Dichteueberwachung} pro: tProtokollant; {$ENDIF} - iDT,mDT: extended; + dTMax: extended; begin if abbruch then begin t:=t+dT; @@ -929,97 +943,37 @@ begin end; kvs.add('t',t); diffusionsTermAnpassen(prot); - - mDT:=infinity; + dTMax:=dX*100; repeat - iDT:=1/dT; - felders[aktuelleFelder].berechneAbleitungen(dT,dX,iDT,iDX,pDNMax); // y' = y'(t,y(t)) + felders[aktuelleFelder].berechneAbleitungen(dX,iDX,pDNMax); // y' = y'(t,y(t)) - if pruefeMaxDT(aktuelleFelder,mDT,dT,dTMin) then + if pruefeMaxDT(aktuelleFelder,dTMax,dT,dTMin) then continue; 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,dTMin) 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,dTMin) 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,dTMin) 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,dTMin) 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,dTMin) 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,dTMin) 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; - zfRungeKuttaZehn: begin // Quelle: http://sce.uhcl.edu/rungekutta/rk108.txt + zfRungeKuttaDreiAchtel: begin + {$INCLUDE rk3_8.inc} + end; + zfRungeKuttaVier: begin + {$INCLUDE rk4.inc} + end; + zfRungeKuttaZehn: begin // Quelle: http://sce.uhcl.edu/rungekutta/rk108.txt {$INCLUDE rk108.inc} end; - zfRungeKuttaZwoelf: begin // Quelle: http://sce.uhcl.edu/rungekutta/rk1210.txt + zfRungeKuttaZwoelf: begin // Quelle: http://sce.uhcl.edu/rungekutta/rk1210.txt {$INCLUDE rk1210.inc} end; - zfRungeKuttaVierzehn: begin // Quelle: http://sce.uhcl.edu/rungekutta/rk1412.txt + zfRungeKuttaVierzehn: begin // Quelle: http://sce.uhcl.edu/rungekutta/rk1412.txt {$INCLUDE rk1412.inc} end; end{of case}; break; until abbruch; - + prot.schreibe('dT = '+floattostr(dT)); aktuelleFelder:=1-aktuelleFelder; {$IFDEF Dichteueberwachung} for i:=0 to length(felders[aktuelleFelder].inhalt)-1 do @@ -1047,7 +1001,7 @@ begin end; {$ENDIF} t:=t+dT; - dT:=max(dT,min(1,mDT)/100); + dT:=max(dT,dTMax/100); end; function tGitter.dumpErhaltungsgroessen: boolean; @@ -1462,7 +1416,7 @@ var begin result:=false; - if gitter.abbruch then + if gitter.abbruch or (dT>sDT) then dT:=sDT; zeitPhysik:=zeitPhysik-now; @@ -1471,9 +1425,9 @@ begin zeitPhysik:=zeitPhysik+now; zeitDatei:=zeitDatei-now; while (gitter.t>=sT) and (sT<tEnde) do begin - sT:=sT+sDT; for i:=0 to length(ausgabeDateien)-1 do - ausgabeDateien[i].speichereWerte(gitter,sDX); + ausgabeDateien[i].speichereWerte(gitter,sT,sDX); + sT:=sT+sDT; end; zeitDatei:=zeitDatei+now; |