VMEC 8.52
3D Equilibrium solver with nested flux surfaces.
Loading...
Searching...
No Matches
precal.f90
Go to the documentation of this file.
1
3
6SUBROUTINE precal
7 USE vacmod
8
9 use dbgout
11
12 IMPLICIT NONE
13
14 REAL(rprec), PARAMETER :: p25 = p5*p5
15 REAL(rprec), PARAMETER :: bigno = 1.e50_dp
16 REAL(rprec), PARAMETER :: epstan = epsilon(one)
17
18 INTEGER :: kp, ku, kuminus, kv, kvminus, i, m, n, mn, &
19 imn, jmn, kmn, l, istat1, smn
20 REAL(rprec), DIMENSION(0:mf + nf,0:mf,0:nf) :: cmn
21 REAL(rprec) :: argu, argv, argp, dn1, f1, f2, f3, alp_per
22
23 ! THIS ROUTINE COMPUTES INITIAL CONSTANTS AND ARRAYS
24
25 pi2 = 8*atan(one) ! 2 pi
26 pi3 = p5*pi2**3 ! 4 pi^3 = pi * (2 pi)^2
27 pi4 = 2*pi2 ! 4 pi
28 onp = one/nfper ! 1/nfp
29 onp2 = onp*onp ! 1/nfp^2
30 alu = pi2/nu ! (2 pi)/nu
31 alv = pi2/nv ! (2 pi)/nv
32 alp = pi2*onp ! (2 pi)/nfp
33 alvp = onp*alv ! (2 pi)/(nv * nfp)
34
35 alp_per = pi2/nvper ! (2 pi)/nvper
36
37 DO kp = 1, nvper
38 cosper(kp) = cos(alp_per*(kp - 1))
39 sinper(kp) = sin(alp_per*(kp - 1))
40 END DO
41
42 ! IMIRR(I) GIVES THE INDEX OF THE POINT (TWOPI-THETA(I), TWOPI-ZETA(I))
43 ! k(u,v)minus count from the other side of the grid
44 ! imirr is then the linear index correponding to (kuminus, kvminus)
45 DO ku = 1, nu
46 kuminus = mod(nu - (ku-1), nu) + 1
47 DO kv = 1, nv
48 kvminus = mod(nv - (kv-1), nv) + 1
49
50 i = kv + nv*(ku - 1)
51 imirr(i) = kvminus + nv*(kuminus - 1)
52
53 cosuv(i) = cos(alvp*(kv - 1))
54 sinuv(i) = sin(alvp*(kv - 1))
55 END DO
56 END DO
57
58 ! NOTE: ANGLE DIFFERENCE IS PI2*{[NUV + (KUP-1)] - (KU-1)}
59 ! THIS DIFFERENCE IS ACCOUNTED FOR BY THE OFFSET IUOFF IN GREENF ROUTINE
60 !
61 ! THE KP SUM BELOW IS USED ONLY FOR NV == 1. IT PERFORMS THE V-INTEGRAL
62 ! IN AN AXISYMMETRIC PLASMA
63
64 if (nv .eq. 1) then
65 ! Tokamak; nvper = 64
66 DO kp = 1, nvper
67 argp = p5*alp_per*(kp-1)
68 IF (abs(argp - p25*pi2) < epstan) THEN
69 tanv_1d(kp) = bigno
70 ELSE
71 tanv_1d(kp) = 2*tan(argp)
72 ENDIF
73 end do
74 else
75 ! Stellarator
76 DO kv = 1, nv
77 argv = p5*alv*(kv - 1)
78 IF (abs(argv - p25*pi2) < epstan) THEN
79 tanv_1d(kv) = bigno
80 ELSE
81 tanv_1d(kv) = 2*tan(argv)
82 ENDIF
83 end do
84 end if
85
86 DO ku = 1, 2*nu
87 argu = p5*alu*(ku - 1)
88 IF (abs(argu - p25*pi2)<epstan .or. abs(argu - 0.75_dp*pi2) < epstan) THEN
89 tanu_1d(ku) = bigno
90 ELSE
91 tanu_1d(ku) = 2*tan(argu)
92 ENDIF
93 end do
94
95 i = 0
96 DO kp = 1, nvper
97 IF (kp.gt.1 .and. nv.ne.1) EXIT
98 argp = p5*alp_per*(kp-1)
99 DO ku = 1, 2*nu
100 argu = p5*alu*(ku - 1)
101 DO kv = 1, nv
102 i = i + 1
103 argv = p5*alv*(kv - 1) + argp
104
105 IF (abs(argu - p25*pi2)<epstan .or. abs(argu - 0.75_dp*pi2) < epstan) THEN
106 tanu(i) = bigno
107 ELSE
108 tanu(i) = 2*tan(argu)
109 ENDIF
110
111 IF (abs(argv - p25*pi2) < epstan) THEN
112 tanv(i) = bigno
113 ELSE
114 tanv(i) = 2*tan(argv)
115 ENDIF
116
117 ! print *, i, kp, argp, ku, argu, kv, argv, tanu(i), tanv(i)
118 END DO
119 END DO
120 END DO
121
122 ! poloidal Fourier transform basis functions
123 DO m = 0, mf
124 l40: DO ku = 1, nu
125 cosu(m,ku) = cos(alu*(m*(ku - 1)))
126 sinu(m,ku) = sin(alu*(m*(ku - 1)))
127 DO kv = 1, nv
128 i = kv + nv*(ku - 1)
129 IF (i > nuv2) then
130 ! This crops the linear index i to the stellarator-symmetric half of a toroidal module.
131 ! ku == poloidal is the slow direction, so there the index ku will only run up to nu2.
132 ! Above ku loop was probably not directly ended at nu2 to have the full set of Fourier basis functions in cosu, sinu.
133 cycle l40
134 end if
135 cosu1(i,m) = cosu(m,ku)
136 sinu1(i,m) = sinu(m,ku)
137 END DO
138 END DO l40
139 DO ku = 1, nu2
140 cosui(m,ku) = cosu(m,ku)*alu*alv*2
141 sinui(m,ku) = sinu(m,ku)*alu*alv*2
142 IF (ku.eq.1 .or. ku.eq.nu2) then
143 ! wint-like functionality to take stellarator-symmetric
144 ! "folding-over" into first half-period into account
145 cosui(m,ku) = p5*cosui(m,ku)
146 end if
147
148 ! alternative, maybe more reasonable way:
149 ! endpoints weighted by 1, inner points weighted by 2
150 ! --> no need to have a product 2*0.5 in here...
151 END DO
152 END DO
153
154 ! toroidal Fourier transform basis functions
155 DO n = -nf, nf
156 dn1 = alvp*(n*nfper)
157 csign(n) = sign(one,dn1)
158 l50: DO ku = 1, nu
159 DO kv = 1, nv
160 i = kv + nv*(ku - 1)
161 cosv(n,kv) = cos(dn1*(kv - 1))
162 sinv(n,kv) = sin(dn1*(kv - 1))
163 IF (i.gt.nuv2 .or. n.lt.0) then
164 ! This crops the linear index i to the stellarator-symmetric half of a toroidal module.
165 ! ku == poloidal is the slow direction, so there the index ku will only run up to nu2.
166 ! Above ku loop was probably not directly ended at nu2 to have the full set of Fourier basis functions in cosv, sinv.
167 cycle l50
168 end if
169 cosv1(i,n) = cosv(n,kv)
170 sinv1(i,n) = sinv(n,kv)
171 END DO
172 END DO l50
173 END DO
174
175 ! Fourier mode number arrays for potsin, potcos
176 mn = 0
177 DO n = -nf, nf
178 DO m = 0, mf
179 mn = mn + 1
180 xmpot(mn) = m
181 xnpot(mn) = n*nfper
182 END DO
183 END DO
184
185 ! COMPUTE CMNS AND THE COEFFICIENTS OF T+- IN EQ (A14 AND A13) IN J.COMP.PHYS PAPER (PKM)
186 ! NOTE: HERE, THE INDEX L IN THE LOOP BELOW IS THE SUBSCRIPT OF T+-. THEREFORE,
187 ! L = 2L' + Kmn (L' = INDEX IN EQ. A14, Kmn = |m-n|), WITH LMIN = K AND LMAX = Jmn == m+n.
188 !
189 ! THE FOLLOWING DEFINITIONS PERTAIN (NOTE: kmn <= L <= jmn):
190 !
191 ! F1 = [(L + jmn)/2]! / [(jmn - L)/2]! == [(jmn + kmn)/2 + L']!/[(jmn - kmn)/2 + L']!
192 !
193 ! F2 = [(L + kmn)/2]! == (L' + kmn)!
194 !
195 ! F3 = [(L - kmn)/2]! == (L')!
196
197 DO m = 0, mf
198 DO n = 0, nf
199 jmn = m + n
200 imn = m - n
201 kmn = abs(imn)
202
203 ! Integer: J+K always even
204 smn = (jmn + kmn)/2
205 f1 = 1
206 f2 = 1
207 f3 = 1
208 DO i = 1, kmn
209 f1 = f1*(smn + 1 - i)
210 f2 = f2*i
211 END DO
212 cmn(0:mf+nf,m,n) = 0
213 DO l = kmn, jmn, 2
214 cmn(l,m,n) = f1/(f2*f3)*((-1)**((l - imn)/2))
215 f1 = f1*p25*((jmn + l + 2)*(jmn - l))
216 f2 = f2*p5*(l + 2 + kmn)
217 f3 = f3*p5*(l + 2 - kmn)
218 END DO
219 END DO
220 END DO
221
222 ! Now combine these into a single coefficient (cmns), Eq. A13).
223 ! NOTE: The ALP=2*pi/nfper factor is needed to normalize integral over field periods
224
225 DO m = 1,mf
226 DO n = 1,nf
227 cmns(0:mf+nf,m,n) = p5*alp*( cmn(0:mf+nf,m,n ) + cmn(0:mf+nf,m-1,n ) &
228 + cmn(0:mf+nf,m,n-1) + cmn(0:mf+nf,m-1,n-1))
229 END DO
230 END DO
231 cmns(0:mf+nf,1:mf,0) = (p5*alp)*(cmn(0:mf+nf,1:mf,0) + cmn(0:mf+nf,:mf-1,0))
232 cmns(0:mf+nf,0,1:nf) = (p5*alp)*(cmn(0:mf+nf,0,1:nf) + cmn(0:mf+nf,0,:nf-1))
233 cmns(0:mf+nf,0,0) = (p5*alp)*(cmn(0:mf+nf,0,0) + cmn(0:mf+nf,0,0))
234
235 precal_done = .true.
236
237 if (open_dbg_context("vac1n_precal", num_eqsolve_retries)) then
238
239 call add_int("nvper", nvper)
240 call add_int("nuv_tan", nuv_tan)
241
242 call add_real_1d("cosper", nvper, cosper)
243 call add_real_1d("sinper", nvper, sinper)
244
245 call add_real_1d("tanu_1d", 2*nu, tanu_1d)
246 call add_real_1d("tanv_1d", nuv_tan/(2*nu), tanv_1d)
247
248 call add_real_2d("tanu", 2*nu, nuv_tan/(2*nu), tanu)
249 call add_real_2d("tanv", 2*nu, nuv_tan/(2*nu), tanv)
250
251 call add_real_3d("cmns", mf+nf+1, mf+1, nf+1, cmns)
252
253 call close_dbg_out()
254 end if
255
256END SUBROUTINE precal
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
real(rprec) alv
Definition vacmod.f90:22
real(rprec) pi4
Definition vacmod.f90:19
real(rprec) onp2
Definition vacmod.f90:25
real(rprec) alu
Definition vacmod.f90:21
real(rprec) pi3
Definition vacmod.f90:18
real(rprec) alp
Definition vacmod.f90:20
real(rprec), parameter p5
Definition vacmod.f90:13
real(rprec) pi2
Definition vacmod.f90:17
real(rprec) alvp
Definition vacmod.f90:23
logical precal_done
Definition vacmod.f90:27
real(rprec) onp
Definition vacmod.f90:24
integer num_eqsolve_retries
subroutine precal
Pre-compute constant terms required for NESTOR.
Definition precal.f90:7