VMEC 8.52
3D Equilibrium solver with nested flux surfaces.
Loading...
Searching...
No Matches
scalfor.f90
Go to the documentation of this file.
1
3
15SUBROUTINE scalfor(gcx, axm, bxm, axd, bxd, cx, iflag, skip_scalfor_dbg)
16
17 USE vmec_main
18 USE vmec_params
19 USE vmec_dim, ONLY: ns
20
21 use dbgout
22
23 IMPLICIT NONE
24
25 INTEGER, INTENT(in) :: iflag
26 REAL(rprec), DIMENSION(ns,0:ntor,0:mpol1,ntmax), INTENT(inout) :: gcx
27 REAL(rprec), DIMENSION(ns+1,2), INTENT(in) :: axm, bxm, axd, bxd
28 REAL(rprec), DIMENSION(ns), INTENT(in) :: cx
29 logical, intent(in) :: skip_scalfor_dbg
30
31 REAL(rprec), PARAMETER :: ftol_edge = 1.e-9_dp
32 REAL(rprec), PARAMETER :: fac=0.25_dp
33 REAL(rprec), PARAMETER :: edge_pedestal= 0.05_dp
34 INTEGER :: m , mp, n, js, jmax
35 REAL(rprec), DIMENSION(:,:,:), ALLOCATABLE :: ax, bx, dx
36 REAL(rprec) :: mult_fac
37 ! LOGICAL :: ledge ! improved convergence for free-boundary, see below
38 logical :: dbg_open
39
40 !if (iflag.eq.0) then
41 ! print *, "scalfor_R", funct3d_calls
42 !else
43 ! print *, "scalfor_Z", funct3d_calls
44 !end if
45
46 if (iflag.ne.0 .and. iflag.ne.1) then
47 stop "unknown iflag in dump_scalfor"
48 end if
49
50 ALLOCATE (ax(ns,0:ntor,0:mpol1), bx(ns,0:ntor,0:mpol1), dx(ns,0:ntor,0:mpol1))
51
52 ! clean state since not all entries are assigned
53 ax = 0.0_dp
54 dx = 0.0_dp
55 bx = 0.0_dp
56
57 jmax = ns
58 IF (ivac .lt. 1) jmax = ns1
59
60 ! FOR SOME 3D PLASMAS, THIS SOMETIME HELPS (CHOOSE mult_fac =1 otherwise)
61 ! TO AVOID JACOBIAN RESETS BY GIVING A SMOOTH TRANSITION FROM FIXED TO FREE ITERATIONS
62 ! mult_fac = 1._dp/(1._dp + 10*(fsqr+fsqz))
63 ! gcx(ns,:,:,:) = mult_fac*gcx(ns,:,:,:)
64
65 DO m = 0, mpol1
66 mp = mod(m,2) + 1
67 DO n = 0, ntor
68 DO js = jmin2(m), jmax
69 ax(js,n,m) = -(axm(js+1,mp) + bxm(js+1,mp)*m**2.0_dp)
70 bx(js,n,m) = -(axm(js,mp) + bxm(js,mp)*m**2.0_dp)
71 dx(js,n,m) = -(axd(js,mp) + bxd(js,mp)*m**2.0_dp + cx(js)*(n*nfp)**2.0_dp)
72 END DO
73
74 IF (m .eq. 1) THEN
75 dx(2,n,m) = dx(2,n,m) + bx(2,n,m)
76 ! OFF 050311
77 ! DO js = jmin2(m), jmax
78 ! ax(js,n,m) = c1p5*ax(js,n,m)
79 ! bx(js,n,m) = c1p5*bx(js,n,m)
80 ! dx(js,n,m) = c1p5*dx(js,n,m)
81 ! END DO
82 END IF
83 END DO
84 END DO
85
86 IF (jmax .ge. ns) THEN
87
88 ! SMALL EDGE PEDESTAL NEEDED TO IMPROVE CONVERGENCE
89 ! IN PARTICULAR, NEEDED TO ACCOUNT FOR POTENTIAL ZERO
90 ! EIGENVALUE DUE TO NEUMANN (GRADIENT) CONDITION AT EDGE
91 dx(ns,:,0:1) = (1.0_dp+ edge_pedestal)*dx(ns,:,0:1)
92 dx(ns,:,2:mpol1) = (1.0_dp+2.0_dp*edge_pedestal)*dx(ns,:,2:mpol1)
93
94 ! STABILIZATION ALGORITHM FOR ZC_00(NS)
95 ! FOR UNSTABLE CASE, HAVE TO FLIP SIGN OF -FAC -> +FAC FOR CONVERGENCE
96 ! COEFFICIENT OF < Ru (R Pvac)> ~ -fac*(z-zeq) WHERE fac (EIGENVALUE, OR
97 ! FIELD INDEX) DEPENDS ON THE EQUILIBRIUM MAGNETIC FIELD AND CURRENT,
98 ! AND zeq IS THE EQUILIBRIUM EDGE VALUE OF Z00
99 mult_fac = min(fac, fac*hs*15.0_dp)
100
101 IF (iflag .eq. 1) THEN ! this is only active for z
102 ! METHOD 1: SUBTRACT (INSTABILITY) Pedge ~ fac*z/hs FROM PRECONDITIONER AT EDGE
103 dx(ns,0,0) = dx(ns,0,0)*(1.0_dp-mult_fac)/(1.0_dp+edge_pedestal)
104 END IF
105 ENDIF
106
107 ! ACCELERATE (IMPROVE) CONVERGENCE OF FREE BOUNDARY.
108 ! THIS WAS ADDED TO DEAL WITH CASES WHICH MIGHT OTHERWISE DIVERGE.
109 ! BY DECREASING THE FSQ TOLERANCE LEVEL WHERE THIS KICKS IN (FTOL_EDGE),
110 ! THE USER CAN TURN-OFF THIS FEATURE
111 !
112 ! DIAGONALIZE (DX DOMINANT) AND REDUCE FORCE (DX ENHANCED) AT EDGE
113 ! TO IMPROVE CONVERGENCE FOR N != 0 TERMS
114
115 ! ledge = .false.
116 ! IF ((fsqr+fsqz) .lt. ftol_edge) ledge = .true.
117 ! IF ((iter2-iter1).lt.400 .or. ivac.lt.1) ledge = .false.
118
119 ! IF (ledge) THEN
120 ! dx(ns,1:,1:) = 3*dx(ns,1:,1:)
121 ! END IF
122
123 if (.not. skip_scalfor_dbg) then
124 ! check scalfor state == inputs to tridslv
125 ! prior knowledge about how this is called:
126 ! iflag = 0 --> R
127 ! iflag = 1 --> Z
128 dbg_open = .false.
129 if (iflag.eq.0) then
130 dbg_open = open_dbg_context("scalfor_R", num_eqsolve_retries)
131 end if
132 if (iflag.eq.1) then
133 if (dbg_open) then
134 stop "how can dbg_open be true here ?"
135 end if
136 dbg_open = open_dbg_context("scalfor_Z", num_eqsolve_retries)
137 end if
138
139 if (dbg_open) then
140 call add_real_3d("ax", ns, ntor1, mpol, ax)
141 call add_real_3d("bx", ns, ntor1, mpol, bx)
142 call add_real_3d("dx", ns, ntor1, mpol, dx)
143
144 call close_dbg_out()
145 end if ! open_dbg_context
146 end if ! skip_scalfor_dbg
147
148 ! SOLVES AX(I)*X(I+1) + DX(I)*X(I) + BX(I)*X(I-1) = GCX(I), I=JMIN3,JMAX AND RETURNS ANSWER IN GCX(I)
149 CALL tridslv (ax, dx, bx, gcx, jmin3, jmax, mnsize-1, ns, ntmax)
150
151 DEALLOCATE (ax, bx, dx)
152
153END SUBROUTINE scalfor
logical function open_dbg_context(context_name, repetition, id)
check if any output is desired for the current iteration check if the given context should be openend...
Definition dbgout.f90:17
integer mpol1
mpol-1
Definition vmec_dim.f90:6
integer ns1
ns-1
Definition vmec_dim.f90:18
integer ntor1
ntor+1
Definition vmec_dim.f90:7
integer ns
number of flux surfaces
Definition vmec_dim.f90:17
integer mnsize
Definition vmec_dim.f90:15
real(rprec) hs
radial mesh size increment
Definition vmec_main.f90:84
integer ivac
counts number of free-boundary iterations
integer num_eqsolve_retries
integer, dimension(0:mpold), parameter jmin2
starting js(m) values for which R,Z are evolved
integer ntmax
number of contributing Fourier basis function (can be 1, 2 or 4); assigned in read_indata()
subroutine scalfor(gcx, axm, bxm, axd, bxd, cx, iflag, skip_scalfor_dbg)
Build forces from different contributions.
Definition scalfor.f90:16
subroutine tridslv(a, d, b, c, jmin, jmax, mnd1, ns, nrhs)
Solve a tridiagonal system of equations.
Definition tridslv.f90:16