722 lines
21 KiB
Fortran
722 lines
21 KiB
Fortran
c===============================================================================
|
|
|
|
|
|
OPTIONS /EXTEND_SOURCE
|
|
|
|
SUBROUTINE READ_INFO_M2
|
|
c =======================
|
|
|
|
IMPLICIT NONE
|
|
|
|
character*(*) Nr
|
|
parameter (Nr='M2')
|
|
|
|
INCLUDE 'mutrack$sourcedirectory:COM_LUNS.INC'
|
|
INCLUDE 'mutrack$sourcedirectory:COM_DIRS.INC'
|
|
INCLUDE 'mutrack$sourcedirectory:MAP_DEF_M2.INC'
|
|
|
|
c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
namelist /grid_info/
|
|
+ Dx,Dr, imax,jmax, xmax,rmax
|
|
|
|
namelist /geometry/
|
|
+ xMCPfront,diamMCP,thickMCP,xFlansch,rTube
|
|
|
|
real xMCPfront,diamMCP,thickMCP,xFlansch,rTube
|
|
|
|
c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
logical map_error
|
|
COMMON /map_error/ map_error
|
|
|
|
c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
c Einlesen der Mappen-Informationen:
|
|
|
|
open (lunREAD,file=mappenName//'.INFO',defaultfile=mappenDir,
|
|
+ readonly,status='old')
|
|
read (lunREAD,nml=grid_info)
|
|
rewind(lunREAD)
|
|
read (lunREAD,nml=geometry)
|
|
close (lunREAD)
|
|
|
|
radius_MCP2 = diamMCP / 2.
|
|
|
|
|
|
c Pruefen, ob die eingelesene Mappe den Anforderungen genuegt:
|
|
|
|
if (xMCPfront.NE.xmax) then
|
|
write(*,*)' M2-Mappe: Mappenende stimmt nicht mit MCP2-Vorderseite ueberein'
|
|
write(*,*)' -> STOP'
|
|
STOP
|
|
endif
|
|
|
|
|
|
c eingelesene imax und jmax um 1 reduzieren, da in 'MUTRACK' die Feldindizes
|
|
c ab 0 laufen, bei 'RELAX3D' jedoch ab 1:
|
|
|
|
imax = imax-1
|
|
jmax = jmax-1
|
|
|
|
|
|
c die geometrischen Daten fuer Mutrack zusammenstellen:
|
|
|
|
xEnterMap = xMCP2-xmax
|
|
|
|
|
|
c Uebergabebereich am MappenEnde definieren:
|
|
|
|
xStartUeber = xMCP2 - 0.5*Dx
|
|
xEndUeber = xMCP2 + 0.5*Dx
|
|
|
|
|
|
c checken, ob der reservierte Speicherplatz ausreicht:
|
|
|
|
if ((imax+1)*(jmax+1).NE.maxmem+1) then
|
|
write(*,*)'----------------------------------------'//
|
|
+ '----------------------------------------'
|
|
write(*,*) Nr//'-Mappe: ',mappenName
|
|
write(*,*) ' BENOETIGTER Speicher: (imax+1)*(jmax+1) = ',(imax+1)*(jmax+1)
|
|
write(*,*) ' RESERVIERTER Speicher: maxmem + 1 = ',maxmem + 1
|
|
write(*,*)
|
|
if ((imax+1)*(jmax+1).GT.maxmem+1) then
|
|
write(*,*) '=> reservierter Speicherplatz ist ungenuegend.'
|
|
write(*,*)
|
|
write(*,*) '=> ''maxmem'' in mutrack$sourcedirectory:MAP_DEF_'//Nr//'.INC angleichen,'
|
|
write(*,*) ' dann Programm mit ''LINKMUV'' am DCL-Prompt neu kompilieren'
|
|
write(*,*) ' und linken.'
|
|
write(*,*)
|
|
write(*,*) ' Mindestwert fuer ''maxmem'' ist ',(imax+1)*(jmax+1)-1
|
|
write(*,*)
|
|
map_error = .true.
|
|
endif
|
|
endif
|
|
|
|
|
|
END
|
|
|
|
|
|
c===============================================================================
|
|
|
|
|
|
OPTIONS /EXTEND_SOURCE
|
|
|
|
SUBROUTINE READ_MAP_M2
|
|
c ======================
|
|
|
|
IMPLICIT NONE
|
|
|
|
character*(*) Nr
|
|
parameter (Nr='M2')
|
|
|
|
INCLUDE 'mutrack$sourcedirectory:MAP_DEF_M2.INC'
|
|
INCLUDE 'mutrack$sourcedirectory:READ_MAP.INC'
|
|
|
|
|
|
END
|
|
|
|
|
|
c===============================================================================
|
|
|
|
|
|
OPTIONS /EXTEND_SOURCE
|
|
|
|
SUBROUTINE INTEGRATIONSSTEP_RUNGE_KUTTA_M2(dt)
|
|
c ==============================================
|
|
|
|
IMPLICIT NONE
|
|
SAVE
|
|
|
|
character*(*) Nr
|
|
parameter (Nr='M2')
|
|
|
|
c Diese Subroutine berechnet zu einem vorgegebenen Zeitschritt dt den
|
|
c Integrationsschritt zweimal: einmal direkt mit dt und einmal ueber zwei
|
|
c aufeinanderfolgende Schritte mit dt/2. (die beiden dt/2-Schritte werden
|
|
c zuerst ausgefuehrt).
|
|
c
|
|
c Aus der Differenz der beiden Resultate wird eine Abschaetzung fuer den Fehler
|
|
c des dt-Schrittes gewonnen, die dazu verwendet wird zu entscheiden, ob der
|
|
c Integrationsschritt mit einem verkuerzten Zeitintervall wiederholt werden
|
|
c muss, oder ob das Zeitintervall fuer den folgenden ausgedehnt werden kann.
|
|
c
|
|
c Die beiden Einzelergebnisse aus dem dt- und den beiden dt/2-Schritten, die
|
|
c jeweils ueber Runge-Kutta-Rechnung vierter Ordnung erhalten werden, werden
|
|
c zum Schluss noch zusammengenommen, um ein Resultat mit Genauigkeit fuenfter
|
|
c Ordnung in dt zu erhalten.
|
|
c
|
|
c Der ganze Ablauf entspricht den Ausfuehrungen in Kapitel 15.2 der NUMERICAL
|
|
c RECIPIES: 'Adaptive Stepsize Control for Runge-Kutta' (vgl. Referenz im
|
|
c fileheader von 'MUTRACK.FOR')
|
|
|
|
|
|
INCLUDE 'mutrack$sourcedirectory:COM_MUTRACK.INC'
|
|
INCLUDE 'mutrack$sourcedirectory:MAP_DEF_M2.INC'
|
|
|
|
integer i ! Zaehlvariable
|
|
|
|
real dt,dt_half ! zeitl. Aenderung, halbe zeitl. Aenderung
|
|
real EFeld0(3), EFeld1(3) ! elektr. Felder
|
|
real x1(3),Dx1(3),Dx2(3) ! fuer Ortsintegration
|
|
real v1(3),Dv1(3),Dv2(3) ! fuer Geschw.Integration
|
|
real xDifferenz(3), vDifferenz(3)
|
|
real x_1 ! Hilfsvariable fuer testweises x(1)
|
|
|
|
real help,help1,help2
|
|
|
|
real maxErr_x,maxErr_v,maxErr ! fuer Fehlerbetrachtung
|
|
|
|
real errCon, safety ! fuer Schrittweitenkontrolle
|
|
real pShrink, pGrow ! fuer Schrittweitenkontrolle
|
|
|
|
PARAMETER (errCon = 6.e-4, safety = .9) ! vgl. Referenz
|
|
PARAMETER (pShrink = -.25, pGrow = -.2)
|
|
! errCon = (4./safety)**(1/pGrow)
|
|
|
|
logical flag_dtSmall ! wenn bei dt < dtsmall der Fehler
|
|
! immer noch zu gross ist.
|
|
|
|
logical found_lower ! obere und untere Grenze fuer dt um
|
|
logical found_upper ! Uebergabebereich zu treffen
|
|
real dtlower,dtupper
|
|
|
|
integer returnCode_EFeld
|
|
COMMON /returnCode_EFeld/ returnCode_EFeld
|
|
! 1: TESTORT HINTER DER MAPPE
|
|
! 2: TESTORT NEBEN DER MAPPE
|
|
! 3: TESTORT VOR DER MAPPE
|
|
|
|
c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
flag_dtSmall = .false. ! flag resetten
|
|
found_lower = .false.
|
|
found_upper = .false.
|
|
if (dt.LT.dtsmall) dt = dtsmall
|
|
|
|
c berechne EFeld am aktuellen Ort. Speichere in EFeld0, damit sie wiederverwendet
|
|
c werden kann, falls mit kuerzerem Zeitschritt wiederholt werden muss:
|
|
|
|
call EFeld_M2(x,EFeld0,*998)
|
|
|
|
c...............................................................................
|
|
10 continue ! hier gehts wieder von vorne los, falls Zeitschritt dt
|
|
! abgeaendert werden muss.
|
|
|
|
|
|
dt_half = dt / 2.
|
|
|
|
|
|
c mache ersten dt/2 - Schritt:
|
|
|
|
call SINGLESTEP_RUNGE_KUTTA_M2(dt_half,EFeld0,x,v, Dx1,Dv1 ,*999)
|
|
|
|
|
|
c berechne EFeld bei x1:
|
|
|
|
x1(1) = x(1) + Dx1(1)
|
|
x1(2) = x(2) + Dx1(2)
|
|
x1(3) = x(3) + Dx1(3)
|
|
|
|
v1(1) = v(1) + Dv1(1)
|
|
v1(2) = v(2) + Dv1(2)
|
|
v1(3) = v(3) + Dv1(3)
|
|
|
|
call EFeld_M2(x1,EFeld1,*999)
|
|
|
|
|
|
c mache zweiten dt/2 - Schritt:
|
|
|
|
call SINGLESTEP_RUNGE_KUTTA_M2(dt_half,EFeld1,x1,v1, Dx2,Dv2 ,*999)
|
|
|
|
|
|
c Summiere Ergebnisse der beiden dt/2 -Schritte und speichere in Dx1, Dv1:
|
|
|
|
Dx1(1) = Dx1(1) + Dx2(1)
|
|
Dx1(2) = Dx1(2) + Dx2(2)
|
|
Dx1(3) = Dx1(3) + Dx2(3)
|
|
|
|
Dv1(1) = Dv1(1) + Dv2(1)
|
|
Dv1(2) = Dv1(2) + Dv2(2)
|
|
Dv1(3) = Dv1(3) + Dv2(3)
|
|
|
|
|
|
c mache dt - Schritt:
|
|
|
|
call SINGLESTEP_RUNGE_KUTTA_M2(dt,EFeld0,x,v, Dx2,Dv2 ,*999)
|
|
|
|
|
|
c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
|
|
|
c Fehlerbetrachtung und Berechnung des endgueltigen Ergebnisses:
|
|
|
|
c Fehlerbetrachtung:
|
|
c der groesste (absolute bzw. relative) Fehler im Ort soll kleiner als eps_x
|
|
c sein, der groesste Fehler in der Geschwindigkeit kleiner als eps_v:
|
|
c -> Bestimme den jeweils groessten Fehler der drei Komponenten des Ortes und
|
|
c der Geschwindikeit (dh. die groesste Differenz der Aederungen):
|
|
|
|
maxErr_x = 0.
|
|
maxErr_v = 0.
|
|
|
|
do i = 1, 3
|
|
xDifferenz(i) = Dx1(i)-Dx2(i)
|
|
vDifferenz(i) = Dv1(i)-Dv2(i)
|
|
if (log_relativ) then
|
|
if (Dx1(i).NE.0.)
|
|
+ maxErr_x = Max( maxErr_x, Abs( xDifferenz(i)/Dx1(i) ) )
|
|
if (Dv1(i).NE.0.)
|
|
+ maxErr_v = Max( maxErr_v, Abs( vDifferenz(i)/Dv1(i) ) )
|
|
else
|
|
maxErr_x = Max( maxErr_x, Abs( xDifferenz(i) ) )
|
|
maxErr_v = Max( maxErr_v, Abs( vDifferenz(i) ) )
|
|
endif
|
|
enddo
|
|
|
|
|
|
c - Skaliere den jeweils groessten relativen Fehler auf das jeweilige Epsilon:
|
|
|
|
maxErr_x = maxErr_x / eps_x
|
|
maxErr_v = maxErr_v / eps_v
|
|
|
|
c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
|
|
|
c der groessere der beiden reskalierten Fehler bestimmt, ob der Integrations-
|
|
c schritt mit kleinerem Zeitintervall wiederholt werden muss, bzw. um welchen
|
|
c Faktor das Zeitintervall fuer den naechsten Schritt vergroessert werden kann:
|
|
|
|
c Liegt der Fehler ausserhalb des Toleranzbereiches und ist dt bereits jetzt
|
|
c kleiner als dtsmall, so mache keinen neuen Versuch sondern akzeptiere als Not-
|
|
c loesung den bestehenden Naeherungswert. Setze dt in diesem Fall als Default
|
|
c fuer den kommenden Integrationsschritt auf dtsmall. Setze aber auch das flag
|
|
c 'flag_dtsmall', damit gezaehlt werden kann, wie oft dieses Prozedur fuer ein
|
|
c bestimmtes Teilchen angewendet werden muss. Ist dies zu oft der Fall, so brich
|
|
c diese Trajektorienberechnung ganz ab (-> destiny = code_dtsmall).
|
|
c (2. Teil erfolgt weiter unten)
|
|
c
|
|
c Es kam vor, dass ohne Ueberschreitung der Fehlertoleranz ein 'dtupper'
|
|
c und ein 'dtlower' gefunden wurde, beim Ertasten des Uebergabebereiches
|
|
c die Fehlergrenze bei mittleren dt-Werten dann aber ueberschritten wurde,
|
|
c wodurch dt immer wieder verkuerzt wurde, ohne dass der Uebergabebereich
|
|
c erreicht werden konnte. Letztlich bildete das ganze eine unendliche Schleife.
|
|
c Daher werden jetzt jedesmal, wenn die Fehlergrenze ueberschritten wird
|
|
c 'found_upper' und 'found_lower' resettet.
|
|
|
|
|
|
maxErr = Max(maxErr_x,maxErr_v)
|
|
|
|
if (maxErr.GT.1.) then
|
|
found_upper = .false.
|
|
found_lower = .false.
|
|
if (dt.LT.dtsmall) then ! Fehler immer noch zu gross, obwohl
|
|
flag_dtsmall = .true. ! dtsmall schon unterschritten ist
|
|
else
|
|
!c Bestimme kuerzeren Zeitschritt fuer neuen Versuch (vgl. Referenz):
|
|
dt = safety * dt * (maxErr**pShrink)
|
|
goto 10
|
|
endif
|
|
endif
|
|
|
|
|
|
c Falls x(1) (== x_1) jetzt bereits jenseits des Uebergangsbereiches am Ende
|
|
c der Potentialmappe liegen sollte, behalte dieses Faktum im Gedaechtnis
|
|
c und verkuerze den aktuell verwendeten Zeitschritt so lange um Faktor 0.5, bis
|
|
c x(1) innerhalb oder vor dem Uebergabebereich liegt. Liegt es davor, suche
|
|
c einen mittleren Zeitschritt, bei dem es im Uebergangsbereich liegt. Schliesse
|
|
c dann die Integration in dieser Mappe ab.
|
|
c (Der Uebergabebereich geht von einer halben x-Gitterkonstanten vor xmax bis
|
|
c eine halbe x-Gitterkonstante hinter xmax. In diesem Bereich wird ein konstantes
|
|
c EFeld zurueckgegeben):
|
|
|
|
x_1 = x(1) + Dx1(1) + xDifferenz(1) / 15.
|
|
|
|
if (x_1.GT.xStartUeber) then
|
|
if (x_1.LT.xEndUeber) then
|
|
reachedEndOfMap = .true.
|
|
else
|
|
dtupper = dt
|
|
found_upper = .true.
|
|
if (.NOT.found_lower) then
|
|
dt = min(0.5*dt,(xStartUeber-x(1))/(x_1-x(1))*dt)
|
|
else
|
|
dt = (dtlower+dtupper)/2.
|
|
endif
|
|
goto 10 ! neue Berechnung
|
|
endif
|
|
elseif (found_upper) then
|
|
found_lower = .true.
|
|
dtlower = dt
|
|
dt = (dtlower+dtupper)/2.
|
|
goto 10 ! neue Berechnung
|
|
endif
|
|
|
|
|
|
c Nimm die Ergebnisse aus dem dt-Schritt und den beiden dt/2-Schritten und
|
|
c berechne damit den neuen Ort und die neue Geschwindigkeit mit Genauigkeit
|
|
c fuenfter Ordnung in dt:
|
|
|
|
x(1) = x_1
|
|
x(2) = x(2) + Dx1(2) + xDifferenz(2) / 15.
|
|
x(3) = x(3) + Dx1(3) + xDifferenz(3) / 15.
|
|
|
|
v(1) = v(1) + Dv1(1) + vDifferenz(1) / 15.
|
|
v(2) = v(2) + Dv1(2) + vDifferenz(2) / 15.
|
|
v(3) = v(3) + Dv1(3) + vDifferenz(3) / 15.
|
|
|
|
|
|
c alten Zeitschritt addieren:
|
|
|
|
t = t + dt
|
|
|
|
|
|
c falls Uebergabebereich erreicht wurde, berechne naeherungsweisen Schnittpunkt der
|
|
c Trajektorie mit x=xmax (exaktes Mappenende) unter Verwendung der im Uebergabebereich
|
|
c zurueckgegebenen Beschleunigung:
|
|
|
|
if (reachedEndOfMap) then
|
|
call EFeld_M2(x,EFeld0,*999)
|
|
help = v(1)*v(1) - 2.*EFeld0(1)*Beschl_Faktor*(x(1)-xMCP2)
|
|
if (help.LT.0.) then ! Teilchen wird noch vor MCP2 reflektiert werden
|
|
reachedEndOfMap = .false.
|
|
goto 3454
|
|
else
|
|
if (EFeld0(1)*Beschl_Faktor.NE.0) then
|
|
help = (sqrt(help) - v(1))/(EFeld0(1)*Beschl_Faktor) ! dt -> help
|
|
else
|
|
help = (xMCP2-x(1))/v(1)
|
|
endif
|
|
endif
|
|
t = t + help ! auch diesen Zeitschritt addieren
|
|
d dt = dt + help ! nur fuer dtmin_M2,dtmax_M2
|
|
help1 = Beschl_Faktor *help
|
|
help2 = help1*help/2.
|
|
x(1) = x(1) + v(1)*help + EFeld0(1)*help2 ! == xMCP2, wenn richtig
|
|
x(2) = x(2) + v(2)*help + EFeld0(2)*help2
|
|
x(3) = x(3) + v(3)*help + EFeld0(3)*help2
|
|
v(1) = v(1) + EFeld0(1)*help1
|
|
v(2) = v(2) + EFeld0(2)*help1
|
|
v(3) = v(3) + EFeld0(3)*help1
|
|
|
|
RETURN
|
|
endif
|
|
|
|
|
|
c neuen Zeitschritt so gross wie sinnvoller weise moeglich machen:
|
|
|
|
3454 if (flag_dtSmall) then
|
|
if (n_dtsmall.LT.maxBelowDtSmall) then
|
|
dt = dtSmall ! fuer naechsten RK-Schritt
|
|
n_dtsmall = n_dtsmall + 1
|
|
else
|
|
destiny = code_dtsmall ! gib Teilchen verloren
|
|
RETURN
|
|
endif
|
|
else
|
|
if (maxErr.GT.errCon) then
|
|
dt = safety * dt * (maxErr**pGrow) ! vgl. Referenz
|
|
else
|
|
dt = 4. * dt ! <- Vergroesserung des Zeitschritts max. um
|
|
endif ! Faktor 4!
|
|
! pruefen, ob Maximallaenge fuer ersten Testschritt nicht ueberschritten ist:
|
|
d if (log_confine) dt = min(dt,dl_max/sqrt(v(1)*v(1)+v(2)*v(2)+v(3)*v(3)))
|
|
endif
|
|
|
|
|
|
RETURN
|
|
|
|
|
|
c hier folgt der Code fuer 'returnCode_EFeld.NE.0':
|
|
|
|
998 continue
|
|
|
|
if (returnCode_EFeld.EQ.1) then
|
|
write(*,*) Nr//'-Mappe:'
|
|
write(*,*)' aktueller Teilchenort (nicht Testort!) hinter Potentialmappe!'
|
|
write(*,*)' -> STOP'
|
|
write(*,*)
|
|
STOP
|
|
! alternativ koennte man hier vielleicht auch nach x=xmax zurueckrechnen
|
|
endif
|
|
|
|
999 continue
|
|
|
|
if (returnCode_EFeld.EQ.1) then ! Testort hinter der Mappe
|
|
dt = 0.5*dt
|
|
found_lower = .false.
|
|
found_upper = .false.
|
|
goto 10
|
|
elseif (returnCode_EFeld.EQ.2) then ! Testort neben der Mappe
|
|
destiny = code_wand
|
|
elseif (returnCode_EFeld.EQ.3) then ! Testort vor der Mappe
|
|
if (v(1).LE.0) then ! reflektiert -> kann vorkommen
|
|
destiny = code_reflektiert
|
|
else ! in Vorwaertsbewegung -> darf nicht vorkommen!!
|
|
write(*,*)
|
|
write(*,*) Nr//'-Mappe: ',mappenName
|
|
write(*,*)
|
|
write(*,*)' Test-x liegt vor der Mappe!'
|
|
write(*,*)' x,y,z = ',x
|
|
write(*,*)' Teilchen-Nr = ',Start_Nr(1)
|
|
write(*,*)' xEnterMap_M2 = ',xEnterMap
|
|
write(*,*)' xEnterMap_M2 - x(1) = ',xEnterMap - x(1)
|
|
write(*,*)
|
|
write(*,*)' -> STOP'
|
|
write(*,*)
|
|
STOP
|
|
endif
|
|
elseif (returnCode_EFeld.NE.0) then
|
|
write(*,*)
|
|
write(*,*) 'SINGLESTEP_RUNGE_KUTTA_'//Nr//': '
|
|
write(*,*) 'unallowed value of ''returnCode_EFeld'': ',returnCode_Efeld
|
|
write(*,*) '-> STOP'
|
|
write(*,*)
|
|
STOP
|
|
endif
|
|
|
|
|
|
END
|
|
|
|
|
|
c===============================================================================
|
|
|
|
|
|
OPTIONS /EXTEND_SOURCE
|
|
|
|
SUBROUTINE SINGLESTEP_RUNGE_KUTTA_M2(dt,E0,x0,v0, Dx,Dv, *)
|
|
c ===========================================================
|
|
|
|
IMPLICIT NONE
|
|
|
|
c Diese Subroutine berechnet bei vorgegebenem Zeitschritt einen einzelnen
|
|
c Runge-Kutta-Integrationsschritt (4. Ordnung).
|
|
c Die Vorgehensweise entspricht den Ausfuehrungen in Kapitel 15.1 der
|
|
c NUMERICAL RECIPIES: 'Runge-Kutta Method'.
|
|
|
|
c Zurueckgegeben werden die errechneten Orts- und Geschwindigkeitsaenderungen
|
|
c anstatt direkt der neuen Werte, da sonst vor allem bei den Ortskoordinaten
|
|
c Schwierigkeiten auftreten koennen, wenn in der Subroutine 'INTEGRATIONSSTEP_
|
|
c RUNGE_KUTTA' aus der Differenz der neuen Werte aus den beiden dt/2- und dem
|
|
c dt-Schritt der Fehler abgeschaetzt werden soll (kleine Differenz moeglicher-
|
|
c weise grosser Werte).
|
|
|
|
|
|
real Beschl_Faktor
|
|
COMMON /Beschl_Faktor_M2/ Beschl_Faktor
|
|
|
|
real E0(3), x0(3), v0(3) ! Eingangsgroessen
|
|
real E1(3), E2(3), E3(3) ! E-Felder an Testorten
|
|
real v1(3), v2(3), v3(3) ! Geschwindigkeiten an Testorten
|
|
real dt,dt_half,dt_sixth ! zeitl. Aenderung, dt/2, dt/6
|
|
real help, help_half, help_sixth ! Hilfsvariable, help/2, help/6
|
|
real xTest(3) ! Test-Orte
|
|
real Dx(3), Dv(3) ! Ergebnisspeicher
|
|
|
|
integer i ! Zaehlvariable
|
|
|
|
c = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
|
|
|
dt_half = dt / 2.
|
|
dt_sixth = dt / 6.
|
|
help = Beschl_Faktor * dt
|
|
help_half = help / 2.
|
|
help_sixth = help / 6.
|
|
|
|
do i = 1, 3
|
|
xTest(i) = x0(i) + v0(i) * dt_half
|
|
v1(i) = v0(i) + E0(i) * help_half
|
|
enddo
|
|
call EFeld_M2(xTest,E1,*999)
|
|
|
|
do i = 1, 3
|
|
xTest(i) = x0(i) + v1(i) * dt_half
|
|
v2(i) = v0(i) + E1(i) * help_half
|
|
enddo
|
|
call EFeld_M2(xTest,E2,*999)
|
|
|
|
do i = 1, 3
|
|
xTest(i) = x0(i) + v2(i) * dt
|
|
v3(i) = v0(i) + E2(i) * help
|
|
enddo
|
|
call EFeld_M2(xTest,E3,*999)
|
|
|
|
do i = 1, 3
|
|
Dx(i) = (v0(i) + 2.*(v1(i)+v2(i)) + v3(i)) * dt_sixth
|
|
Dv(i) = (E0(i) + 2.*(E1(i)+E2(i)) + E3(i)) * help_sixth
|
|
enddo
|
|
|
|
RETURN
|
|
|
|
999 RETURN 1
|
|
|
|
|
|
END
|
|
|
|
|
|
c===============================================================================
|
|
|
|
|
|
OPTIONS /EXTEND_SOURCE
|
|
|
|
SUBROUTINE EFeld_M2(x,E,*)
|
|
c ==========================
|
|
|
|
IMPLICIT NONE
|
|
|
|
INCLUDE 'mutrack$sourcedirectory:MAP_DEF_M2.INC'
|
|
|
|
real real_i,real_j ! x,r im Mappensystem in Gittereinheiten
|
|
|
|
integer stuetzstelle_i(2) ! naechste Stuetzstellen in x- und
|
|
integer stuetzstelle_j(2) ! r-Richtung
|
|
|
|
real Abstand_i,Abstand_i_Betrag ! Entfernung zur naechsten Stuetzstelle
|
|
real Abstand_j,Abstand_j_Betrag ! (in Gittereinheiten!)
|
|
|
|
integer i,j, n, ihelp
|
|
|
|
real radius ! Betrag des Radiusvektors in y-z-Ebene
|
|
real x(3),E(3) ! Ort und Feldstaerke
|
|
real E_(2) ! Hilfsspeicher fuer Feldberechnung
|
|
real Erad ! radiale Feldstaerke
|
|
|
|
|
|
c Falls Testort ausserhalb der Mappe liegt oder Anode getroffen hat:
|
|
|
|
integer returnCode_EFeld
|
|
COMMON /returnCode_EFeld/ returnCode_EFeld
|
|
! 1: TESTORT HINTER DER MAPPE
|
|
! 2: TESTORT NEBEN DER MAPPE
|
|
! 3: TESTORT VOR DER MAPPE
|
|
|
|
c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
c Rechne in Gittereinheiten um:
|
|
|
|
radius = sqrt(x(2)*x(2)+x(3)*x(3))
|
|
|
|
real_i = (x(1) - xEnterMap) / Dx
|
|
real_j = radius / Dr
|
|
|
|
c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
c Mache die Tests und berechne die Feldstaerke:
|
|
|
|
c Teste, ob Raumpunkt innerhalb der Potentialmappe liegt:
|
|
|
|
if (real_j.GT.jmax) then
|
|
returnCode_EFeld = 2
|
|
RETURN 1
|
|
elseif (real_i.GT.real(imax)) then
|
|
if (real_i.GT.real(imax)+.5) then
|
|
returnCode_EFeld = 1
|
|
RETURN 1
|
|
else
|
|
real_i = imax
|
|
endif
|
|
elseif (real_i.LT.0.) then
|
|
returnCode_EFeld = 3
|
|
E(1) = 0.
|
|
E(2) = 0.
|
|
E(3) = 0.
|
|
RETURN 1
|
|
c else
|
|
c returnCode_EFeld = 0
|
|
endif
|
|
|
|
|
|
c Bestimme naechstgelegene Stuetzstellen und die Komponenten des Abstands-
|
|
c Gittervektors zur allernaechsten Stuetzstelle sowie deren Betraege:
|
|
|
|
stuetzstelle_i(1) = nint(real_i)
|
|
Abstand_i = real_i - stuetzstelle_i(1) ! Abstand zur naeheren Stuetzstelle
|
|
Abstand_i_Betrag = abs(Abstand_i)
|
|
if (Abstand_i.gt.0.) then
|
|
stuetzstelle_i(2) = stuetzstelle_i(1) + 1
|
|
elseif (Abstand_i.lt.0.) then
|
|
stuetzstelle_i(2) = stuetzstelle_i(1) - 1
|
|
else
|
|
stuetzstelle_i(2) = stuetzstelle_i(1)
|
|
endif
|
|
|
|
stuetzstelle_j(1) = nint(real_j)
|
|
Abstand_j = real_j - stuetzstelle_j(1)
|
|
Abstand_j_Betrag = abs(Abstand_j)
|
|
if (Abstand_j.gt.0.) then
|
|
stuetzstelle_j(2) = stuetzstelle_j(1) + 1
|
|
elseif (Abstand_j.lt.0.) then
|
|
stuetzstelle_j(2) = stuetzstelle_j(1) - 1
|
|
else
|
|
stuetzstelle_j(2) = stuetzstelle_j(1)
|
|
endif
|
|
|
|
|
|
c...............................................................................
|
|
c Berechnen des elektrischen Feldes:
|
|
c ----------------------------------
|
|
c
|
|
c Potentialverlauf ist symmetrisch zu j=0 (Linsenachse):
|
|
c
|
|
c map(i,-j) == map(i,j).
|
|
c
|
|
c Entlang j=0 ist also Erad=0 und damit E(2)=0 und E(3)=0.
|
|
c...............................................................................
|
|
|
|
c Berechne die x-Komponente der Feldstaerke:
|
|
|
|
c Um die Feldstaerke zu bekommen, interpoliere jeweils linear zwischen den
|
|
c Werten auf den beiden naechstgelegenen j-Ketten:
|
|
|
|
i = stuetzstelle_i(1)
|
|
|
|
do n = 1, 2
|
|
j = stuetzstelle_j(n)
|
|
ihelp = j*(imax+1) + i
|
|
if (i.EQ.imax) then
|
|
E_(n) = map(ihelp-1) - map(ihelp)
|
|
elseif (i.GT.0) then
|
|
E_(n) = (-0.5+Abstand_i)*(map(ihelp)-map(ihelp-1))
|
|
+ + ( 0.5+Abstand_i)*(map(ihelp)-map(ihelp+1))
|
|
else
|
|
E_(n) = map(ihelp) - map(ihelp+1)
|
|
endif
|
|
enddo
|
|
E(1) = E_(1) + Abstand_j_Betrag*(E_(2)-E_(1))
|
|
E(1) = E(1) / Dx ! Reskalierung entsprechend x-Gitterkonstanten
|
|
|
|
|
|
c Berechne die radiale Komponente der Feldstaerke:
|
|
|
|
if (real_j.LT.1e-10) then
|
|
E(2) = 0.
|
|
E(3) = 0.
|
|
RETURN
|
|
endif
|
|
|
|
j = stuetzstelle_j(1)
|
|
|
|
do n = 1, 2
|
|
i = stuetzstelle_i(n)
|
|
ihelp = j*(imax+1) + i
|
|
if (j.EQ.jmax) then
|
|
E_(n) = map(ihelp-(imax+1)) - map(ihelp)
|
|
elseif (j.GT.0) then
|
|
E_(n) = (-0.5+Abstand_j)*(map(ihelp)-map(ihelp-(imax+1)))
|
|
+ + ( 0.5+Abstand_j)*(map(ihelp)-map(ihelp+(imax+1)))
|
|
else ! j=0 -> map(i,j-1) = map(i,j+1) == map(i,1)
|
|
E_(n) = 2.0*Abstand_j*(map(ihelp)-map(ihelp+(imax+1)))
|
|
endif
|
|
enddo
|
|
Erad = E_(1) + Abstand_i_Betrag*(E_(2)-E_(1))
|
|
Erad = Erad / Dr ! Reskalierung entsprechend r-Gitterkonstanten
|
|
|
|
|
|
c Berechne E(2) und E(3) aus Erad:
|
|
|
|
E(2) = Erad * x(2) / radius
|
|
E(3) = Erad * x(3) / radius
|
|
|
|
|
|
END
|
|
|
|
|
|
c===============================================================================
|