VMEC 8.52
3D Equilibrium solver with nested flux surfaces.
Loading...
Searching...
No Matches
jxbforce.f90
Go to the documentation of this file.
1
3
19SUBROUTINE jxbforce(bsupu, bsupv, bsubu, bsubv, bsubsh, &
20 bsubsu, bsubsv, &
21 gsqrt, bsq, itheta, izeta, brho, ier_flag)
23 USE vmec_main
25 USE realspace, ONLY: shalf, wint, guu, guv, gvv, r1, ru, rv, zu, zv, phip
26 USE ezcdf
27
28 use dbgout
29
30 IMPLICIT NONE
31
32 REAL(rprec), DIMENSION(ns,nznt), INTENT(in) :: bsupu
33 REAL(rprec), DIMENSION(ns,nznt), INTENT(in) :: bsupv
34 REAL(rprec), DIMENSION(ns,nznt,0:1), TARGET, INTENT(inout) :: bsubu
35 REAL(rprec), DIMENSION(ns,nznt,0:1), TARGET, INTENT(inout) :: bsubv
36 REAL(rprec), DIMENSION(ns,nznt), INTENT(in) :: bsubsh
37 REAL(rprec), DIMENSION(ns,nznt,0:1) :: bsubsu
38 REAL(rprec), DIMENSION(ns,nznt,0:1) :: bsubsv
39 REAL(rprec), DIMENSION(ns,nznt), INTENT(in) :: gsqrt
40 REAL(rprec), DIMENSION(ns,nznt), INTENT(in) :: bsq
41 REAL(rprec), DIMENSION(ns,nznt), INTENT(out) :: itheta
42 REAL(rprec), DIMENSION(ns,nznt), INTENT(out) :: izeta
43 REAL(rprec), DIMENSION(ns,nznt), INTENT(out) :: brho
44 INTEGER, INTENT(in) :: ier_flag
45
46 REAL(rprec), DIMENSION(ns,nznt), TARGET :: bsubs
47
48 ! Prints out bsubs spectrum to fort.33
49 LOGICAL, PARAMETER :: lprint = .false.
50
51 INTEGER lk, lz, lt, k, m, js, j, n, injxbout, mparity, nznt1
52 INTEGER :: njxbout = jxbout0, info
53
54 REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: bdotk, bsubuv, bsubvu
55 REAL(rprec), DIMENSION(:,:,:,:), ALLOCATABLE :: bsubsmn
56 REAL(rprec), DIMENSION(:,:,:), ALLOCATABLE :: brhomn, &
57 bsubs3, bsubv3, bsubu3, jxb_gradp, jcrossb, sqrtg3, &
58 bsupv3, bsupu3, jsups3, jsupv3, jsupu3, jdotb_sqrtg
59
60 REAL(rprec), POINTER :: bs1(:), bu1(:,:), bv1(:,:)
61
62 REAL(rprec), DIMENSION(:), ALLOCATABLE :: kperpu, kperpv, &
63 sqgb2, sqrtg, kp2, jxb, jxb2, bsupu1, bsupv1, bsubu1, bsubv1, &
64 avforce, aminfor, amaxfor, toroidal_angle, phin, pprim, pprime
65 REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: bsubua, bsubva
66 REAL(rprec) :: &
67 bsubsmn1, bsubsmn2, bsubvmn1, bsubvmn2, bsubumn1, bsubumn2, &
68 bsubsmn3, bsubsmn4, bsubvmn3, bsubvmn4, bsubumn3, bsubumn4, &
69 dnorm1, tcos1, tcos2, tsini1, tsini2, tcosi1, tcosi2, &
70 tcosm1, tcosm2, tcosn1, tcosn2, tsinm1, tsinm2, tsin1, tsin2, &
71 tsinn1, tsinn2, tjnorm, ovp, pnorm, brho00(ns)
72 REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: bsubu_s, bsubu_a, bsubv_s, bsubv_a
73 REAL(rprec), DIMENSION(:), ALLOCATABLE :: bsubs_s, bsubs_a
74 CHARACTER(LEN=100) :: jxbout_file
75 CHARACTER(LEN=100) :: legend(13)
76 LOGICAL :: lprint_flag
77
78 CHARACTER(LEN=*), PARAMETER :: &
79 vn_legend = 'legend', &
80 vn_radial_surfaces = 'radial_surfaces', &
81 vn_poloidal_grid_points = 'poloidal_grid_points', &
82 vn_toroidal_grid_points = 'toroidal_grid_points', &
83 vn_mpol = 'mpol', &
84 vn_ntor = 'ntor', &
85 vn_phin = 'phin', &
86 vn_toroidal_angle = 'toroidal_angle', &
87 vn_avforce = 'avforce', &
88 vn_jdotb = 'surf_av_jdotb', &
89 vn_sqg_bdotk = 'sqrt(g)*bdotk', &
90 vn_sqrtg = 'sqrt(g)', &
91 vn_bdotgradv = 'bdotgradv', &
92 vn_amaxfor = 'amaxfor', &
93 vn_aminfor = 'aminfor', &
94 vn_pprime = 'pprime', &
95 vn_jsupu = 'jsupu', &
96 vn_jsupv = 'jsupv', &
97 vn_jsups = 'jsups', &
98 vn_bsupu = 'bsupu', &
99 vn_bsupv = 'bsupv', &
100 vn_jcrossb = 'jcrossb', &
101 vn_jxb_gradp = 'jxb_gradp', &
102 vn_bsubu = 'bsubu', &
103 vn_bsubv = 'bsubv', &
104 vn_bsubs = 'bsubs'
105
106
107
108 ! PROGRAM FOR COMPUTING LOCAL KXB = grad-p FORCE BALANCE
109 !
110 ! K = CURL(B) is the "effective" current (=J for isotropic pressure)
111 ! Compute u (=theta), v (=zeta) derivatives of B sub s
112
113 ! fixup input coming from bss: zero terms past magnetic axis
114 ! NOTE: FIXME: This is actually the target array for the interpolation to the half-grid !!!
115 ! TODO: This should probably be `bsubsh(1,:) = 0` instead !!!
116 bsubs(1,:) = 0
117
118 lprint_flag = (ier_flag.eq.successful_term_flag)
119 IF (lprint_flag) THEN
120 jxbout_file = 'jxbout_'//trim(input_extension)//'.nc'
121
122 CALL cdf_open(njxbout,jxbout_file,'w',injxbout)
123 IF (injxbout .ne. 0) THEN
124 print *,' Error opening JXBOUT file in jxbforce'
125 RETURN
126 END IF
127
128 legend(1) = " S = normalized toroidal flux (0 - 1)"
129 IF (lasym) THEN
130 legend(2) = " U = VMEC poloidal angle (0 - 2*pi, FULL period)"
131 ELSE
132 legend(2) = " U = VMEC poloidal angle (0 - pi, HALF a period)"
133 END IF
134 legend(3) = " V = VMEC (geometric) toroidal angle (0 - 2*pi)"
135 legend(4) = " SQRT(g') = |SQRT(g-VMEC)| / VOL': Cylindrical-to-s,u,v Jacobian normed to volume derivative"
136 legend(5) = " VOL = Int_s'=0,s Int_u Int_v |SQRT(g_VMEC)| : plasma volume enclosed by surface s'=s"
137 legend(6) = " VOL' = d(VOL)/ds: differential volume element"
138 legend(7) = " Es = SQRT(g') [grad(U) X grad(V)]: covariant radial unit vector (based on volume radial coordinate)"
139 legend(8) = " BSUP{U,V} = B DOT GRAD{U,V}: contravariant components of B"
140 legend(9) = " JSUP{U,V} = SQRT(g) J DOT GRAD{U,V}"
141 legend(10)= " K X B = Es DOT [K X B]: covariant component of K X B force"
142 legend(11)= " K * B = K DOT B * SQRT(g')"
143 legend(12)= " p' = dp/d(VOL): pressure gradient (based on volume radial coordinate)"
144 legend(13)= " <KSUP{U,V}> = Int_u Int_v [KSUP{U,V}]/dV/ds"
145 ENDIF
146
147 nznt1 = nzeta*ntheta2
148 ALLOCATE (avforce(ns),aminfor(ns),amaxfor(ns))
149 ALLOCATE (bdotk(ns,nznt), bsubuv(ns,nznt), &
150 bsubvu(ns,nznt), kperpu(nznt), kperpv(nznt), &
151 sqgb2(nznt), brhomn(0:mnyq,-nnyq:nnyq,0:1),kp2(nznt), &
152 jxb(nznt), jxb2(nznt), bsupu1(nznt), &
153 bsubua(nznt1,0:1), bsubva(nznt1,0:1), &
154 bsupv1(nznt), bsubu1(nznt), bsubv1(nznt), &
155 bsubsmn(ns,0:mnyq,-nnyq:nnyq,0:1), &
156 bsubs_s(nznt), bsubs_a(nznt), sqrtg(nznt), &
157 bsubu_s(nznt1,0:1), bsubu_a(nznt1,0:1), &
158 bsubv_s(nznt1,0:1), bsubv_a(nznt1,0:1), stat=j)
159 IF (j .ne. 0) stop 'Allocation error in jxbforce'
160
161 ! NOTE: bsubuv, bsubvu are used to compute the radial current (should be zero)
162 bsubsu = 0
163 bsubsv = 0
164 bsubuv = 0
165 bsubvu = 0
166 bsubsmn = 0
167
168 radial: DO js = 1, ns
169
170 ! Put bsubs on full mesh
171 IF (js.gt.1 .and. js.lt.ns) THEN
172 bsubs(js,:) = cp5*(bsubsh(js,:) + bsubsh(js+1,:))
173 END IF
174
175 ! undo radial scaling with sqrt(s) (done at iequi=1 case in bcovar)
176 bsubu(js,:,1) = bsubu(js,:,1)/shalf(js)
177 bsubv(js,:,1) = bsubv(js,:,1)/shalf(js)
178 bsubua = 0
179 bsubva = 0
180
181 ! _s: symmetric in u,v
182 ! _a: antisymmetric in u,v on half (ntheta2) interval
183 IF (lasym) THEN
184 bs1=>bsubs(js,:)
185 bu1=>bsubu(js,:,:)
186 bv1=>bsubv(js,:,:)
187 CALL fsym_fft (bs1, bu1, bv1, &
188 bsubs_s, bsubu_s, bsubv_s, & ! stellarator-symmetric parts
189 bsubs_a, bsubu_a, bsubv_a) ! non-stellarator-symmetric parts
190 ELSE
191 ! only stellarator-symmetric parts
192 bsubs_s(:) = bsubs(js,:)
193 bsubu_s = bsubu(js,:,:)
194 bsubv_s = bsubv(js,:,:)
195 END IF
196
197 ! FOURIER LOW-PASS FILTER bsubX
198 DO m = 0, mpol1 ! 0, 1, ..., (mpol-1)
199 mparity = mod(m, 2)
200 DO n = 0, ntor
201
202 ! FOURIER TRANSFORM
203 dnorm1 = one/r0scale**2
204 IF (m .eq. mnyq) dnorm1 = cp5*dnorm1
205 IF (n .eq. nnyq .and. n.ne.0) dnorm1 = cp5*dnorm1
206
207 bsubsmn1 = 0
208 bsubsmn2 = 0
209 bsubumn1 = 0
210 bsubumn2 = 0
211 bsubvmn1 = 0
212 bsubvmn2 = 0
213 IF (lasym) THEN
214 ! SPH012314 in FixAray
215 dnorm1 = 2*dnorm1
216
217 bsubsmn3 = 0
218 bsubsmn4 = 0
219 bsubumn3 = 0
220 bsubumn4 = 0
221 bsubvmn3 = 0
222 bsubvmn4 = 0
223 END IF
224
225 DO k = 1, nzeta
226 lk = k
227 DO j = 1, ntheta2
228 tsini1 = sinmui(j,m)*cosnv(k,n)*dnorm1 ! sin-cos
229 tsini2 = cosmui(j,m)*sinnv(k,n)*dnorm1 ! cos-sin
230 tcosi1 = cosmui(j,m)*cosnv(k,n)*dnorm1 ! cos-cos
231 tcosi2 = sinmui(j,m)*sinnv(k,n)*dnorm1 ! sin-sin
232
233 bsubsmn1 = bsubsmn1 + tsini1*bsubs_s(lk) ! sin-cos
234 bsubsmn2 = bsubsmn2 + tsini2*bsubs_s(lk) ! cos-sin
235 bsubvmn1 = bsubvmn1 + tcosi1*bsubv_s(lk, mparity) ! cos-cos
236 bsubvmn2 = bsubvmn2 + tcosi2*bsubv_s(lk, mparity) ! sin-sin
237 bsubumn1 = bsubumn1 + tcosi1*bsubu_s(lk, mparity) ! cos-cos
238 bsubumn2 = bsubumn2 + tcosi2*bsubu_s(lk, mparity) ! sin-sin
239
240 IF (lasym) THEN
241 bsubsmn3 = bsubsmn3 + tcosi1*bsubs_a(lk) ! cos-cos
242 bsubsmn4 = bsubsmn4 + tcosi2*bsubs_a(lk) ! sin-sin
243 bsubvmn3 = bsubvmn3 + tsini1*bsubv_a(lk, mparity) ! sin-cos
244 bsubvmn4 = bsubvmn4 + tsini2*bsubv_a(lk, mparity) ! cos-sin
245 bsubumn3 = bsubumn3 + tsini1*bsubu_a(lk, mparity) ! sin-cos
246 bsubumn4 = bsubumn4 + tsini2*bsubu_a(lk, mparity) ! cos-sin
247 END IF
248
249 lk = lk + nzeta
250
251 END DO
252 END DO
253
254 ! FOURIER INVERSE TRANSFORM
255 ! Compute on u-v grid (must add symmetric, antisymmetric parts for lasym=T)
256
257 DO k = 1, nzeta
258 lk = k
259 DO j = 1, ntheta2
260 tcos1 = cosmu(j,m)*cosnv(k,n)
261 tcos2 = sinmu(j,m)*sinnv(k,n)
262 bsubua(lk,0) = bsubua(lk,0) + tcos1*bsubumn1 + tcos2*bsubumn2
263 bsubva(lk,0) = bsubva(lk,0) + tcos1*bsubvmn1 + tcos2*bsubvmn2
264
265 tcosm1 = cosmum(j,m)*cosnv(k,n)
266 tcosm2 = sinmum(j,m)*sinnv(k,n)
267 bsubsu(js,lk,0) = bsubsu(js,lk,0) + tcosm1*bsubsmn1 + tcosm2*bsubsmn2
268
269 tcosn1 = sinmu(j,m)*sinnvn(k,n)
270 tcosn2 = cosmu(j,m)*cosnvn(k,n)
271 bsubsv(js,lk,0) = bsubsv(js,lk,0) + tcosn1*bsubsmn1 + tcosn2*bsubsmn2
272
273 tsinm1 = sinmum(j,m)*cosnv(k,n)
274 tsinm2 = cosmum(j,m)*sinnv(k,n)
275 bsubvu(js,lk) = bsubvu(js,lk) + tsinm1*bsubvmn1 + tsinm2*bsubvmn2
276
277 tsinn1 = cosmu(j,m)*sinnvn(k,n)
278 tsinn2 = sinmu(j,m)*cosnvn(k,n)
279 bsubuv(js,lk) = bsubuv(js,lk) + tsinn1*bsubumn1 + tsinn2*bsubumn2
280
281 IF (lasym) THEN
282 tsin1 = sinmu(j,m)*cosnv(k,n)
283 tsin2 = cosmu(j,m)*sinnv(k,n)
284 bsubua(lk,1) = bsubua(lk,1) + tsin1*bsubumn3 + tsin2*bsubumn4
285 bsubva(lk,1) = bsubva(lk,1) + tsin1*bsubvmn3 + tsin2*bsubvmn4
286
287 bsubsu(js,lk,1) = bsubsu(js,lk,1) + tsinm1*bsubsmn3 + tsinm2*bsubsmn4
288 bsubsv(js,lk,1) = bsubsv(js,lk,1) + tsinn1*bsubsmn3 + tsinn2*bsubsmn4
289
290 bsubvu(js,lk) = bsubvu(js,lk) + tcosm1*bsubvmn3 + tcosm2*bsubvmn4
291 bsubuv(js,lk) = bsubuv(js,lk) + tcosn1*bsubumn3 + tcosn2*bsubumn4
292 END IF
293
294 lk = lk + nzeta
295
296 END DO ! ntheta2
297 END DO ! nzeta
298
299 ! bsubsmn: coefficients of sin(mu)cos(nv), n>=0, cos(mu)sin(nv), n<0 (type=0)
300 ! cos(mu)cos(nv), n>=0, sin(mu)sin(nv), n<0 (type=1, nonzero only for lasym=T)!
301
302 ! Don't need these except for comparison
303 IF (lprint) then
304
305 bsubsmn(js,m,n,0) = bsubsmn1
306 IF (n .gt. 0) bsubsmn(js,m,-n,0) = bsubsmn2
307
308 IF (.not.lasym) cycle
309
310 bsubsmn(js,m,n,1) = bsubsmn3
311 IF (n .gt. 0) bsubsmn(js,m,-n,0) = bsubsmn4
312
313 end if ! lprint
314 END DO
315 END DO
316
317 IF (lasym) THEN
318 ! EXTEND FILTERED bsubu, bsubv TO NTHETA3 MESH
319 ! NOTE: INDEX 0 - COS(mu-nv) SYMMETRY
320 ! 1 - SIN(mu-nv) SYMMETRY
321 CALL fext_fft (bsubu(js,:,0), bsubua(:,0), bsubua(:,1))
322 CALL fext_fft (bsubv(js,:,0), bsubva(:,0), bsubva(:,1))
323 ELSE
324 bsubu(js,:,0) = bsubua(:,0)
325 bsubv(js,:,0) = bsubva(:,0)
326 END IF
327
328 END DO radial
329
330 DEALLOCATE (bsubua, bsubva)
331
332 ! EXTEND bsubsu, bsubsv TO NTHETA3 MESH
333 IF (lasym) CALL fsym_invfft (bsubsu, bsubsv)
334
335
336 if (open_dbg_context("jxbforce_bsub_lowpass", id=0)) then
337
338 ! overwrite in-place; half-grid
339 call add_real_3d("bsubu_e", ns, nzeta, ntheta3, bsubu(:,:,0))
340 call add_real_3d("bsubv_e", ns, nzeta, ntheta3, bsubv(:,:,0))
341 call add_real_3d("bsubu_o", ns, nzeta, ntheta3, bsubu(:,:,1))
342 call add_real_3d("bsubv_o", ns, nzeta, ntheta3, bsubv(:,:,1))
343
344 ! newly computed; full-grid
345 call add_real_3d("bsubsu_e", ns, nzeta, ntheta3, bsubsu(:,:,0)) ! order=(/1, 4, 2, 3/))
346 call add_real_3d("bsubsu_o", ns, nzeta, ntheta3, bsubsu(:,:,1)) ! order=(/1, 4, 2, 3/))
347 call add_real_3d("bsubsv_e", ns, nzeta, ntheta3, bsubsv(:,:,0)) ! order=(/1, 4, 2, 3/))
348 call add_real_3d("bsubsv_o", ns, nzeta, ntheta3, bsubsv(:,:,1)) ! order=(/1, 4, 2, 3/))
349
350 ! newly computed; full-grid
351 call add_real_3d("bsubuv", ns, nzeta, ntheta3, bsubuv)
352 call add_real_3d("bsubvu", ns, nzeta, ntheta3, bsubvu)
353
354 if (lprint) then
355 call add_real_4d("bsubsmn", 2, ns, mpol, 2*ntor+1, bsubsmn, &
356 order=(/ 4, 1, 2, 3 /))
357 end if
358
359 call close_dbg_out()
360 end if
361
362
363
364
365
366
367 ! SKIPS Bsubs Correction - uses Bsubs from metric elements
368 IF (lbsubs) then
369
370 ! Compute corrected Bsubs coefficients (brhomn) (impacts currents)
371 ! by solving es dot (KXB - gradp_parallel) = 0 equation for brhomn in REAL SPACE
372 ! Can be written Bsupu d(bs)/du + Bsupv d(bs)/dv = RHS (jxb below), bs==bsubs
373
374 ! ANIMEC:
375 ! brho==sigma B_s, pp1 and pp2 are the Jacobian times the hot particle parallel
376 ! pressure radial gradient Amplitudes on the full integer mesh
377 correct_bsubs: DO js = 2, ns-1
378
379 jxb(:) = cp5*(gsqrt(js,:) + gsqrt(js+1,:)) ! re-use jxb array for Jacobian on full grid
380 bsupu1(:) = cp5*(bsupu(js,:)*gsqrt(js,:) + bsupu(js+1,:)*gsqrt(js+1,:))
381 bsupv1(:) = cp5*(bsupv(js,:)*gsqrt(js,:) + bsupv(js+1,:)*gsqrt(js+1,:))
382 brho(js,:) = ohs* ( bsupu1(:)*(bsubu(js+1,:,0) - bsubu(js,:,0)) &
383 + bsupv1(:)*(bsubv(js+1,:,0) - bsubv(js,:,0))) &
384 + (pres(js+1) - pres(js))*ohs*jxb(:)
385
386 ! SUBTRACT FLUX-SURFACE AVERAGE FORCE BALANCE FROM brho, OTHERWISE
387 ! LOCAL FORCE BALANCE EQUATION B dot grad(Bs) = brho CAN'T BE SOLVED
388 brho00(js) = sum(brho(js,:)*wint(js:nrzt:ns))
389 brho(js,:) = brho(js,:) - signgs*jxb(:)*brho00(js)/(cp5*(vp(js) + vp(js+1)))
390
391 jxb(:) = brho(js,:)
392 ! bsubsmn, frho, bsupu, bsupv, mmax, nmax, info
393 CALL getbsubs (brhomn, jxb, bsupu1, bsupv1, mnyq, nnyq, info)
394 IF (info .ne. 0) THEN
395 print *, 'Error in GETBRHO: info= ',info, ' js= ',js
396 ELSE IF (lprint) THEN
397 WRITE (33, *) ' JS = ', js
398 IF (lasym) THEN
399 WRITE (33, '(a)') ' M N BSUBS(old) BSUBS(new) BSUBS(old) BSUBS(new)'
400 ELSE
401 WRITE (33, '(a)') ' M N BSUBS(old) BSUBS(new)'
402 END IF
403 DO m = 0, mpol1
404 DO n = -ntor, ntor
405 IF (lasym) THEN
406 WRITE(33,1223) m, n, bsubsmn(js,m,n,0), brhomn(m,n,0), bsubsmn(js,m,n,1), brhomn(m,n,1)
407 ELSE
408 WRITE(33,1224) m, n, bsubsmn(js,m,n,0), brhomn(m,n,0)
409 END IF
410 END DO
411 END DO
412 END IF
413 1223 FORMAT (i4,1x,i4,4(6x,1p,e12.3))
414 1224 FORMAT (i4,1x,i4,2(6x,1p,e12.3))
415
416 ! Recompute bsubsu,v now using corrected bsubs
417 ! Store old values (itheta,izeta) for checking force balance later
418 itheta(js,:) = bsubsu(js,:,0)
419 izeta(js,:) = bsubsv(js,:,0)
420
421 IF (info .ne. 0) cycle ! skip until next iteration of radial loop
422
423 bsubsu(js,:,:) = 0
424 bsubsv(js,:,:) = 0
425 bsubs_s = 0
426 IF (lasym) bsubs_a = 0
427
428 DO m = 0, mnyq
429 DO n = 0, nnyq
430 IF (n .eq. 0) THEN
431 bsubsmn1 = brhomn(m,0,0)
432 bsubsmn2 = 0
433 ELSE
434 bsubsmn1 = brhomn(m, n,0)
435 bsubsmn2 = brhomn(m,-n,0)
436 END IF
437
438 IF (lasym) THEN
439 IF (n .eq. 0) THEN
440 bsubsmn3 = brhomn(m,0,1)
441 bsubsmn4 = 0
442 ELSE
443 bsubsmn3 = brhomn(m, n,1)
444 bsubsmn4 = brhomn(m,-n,1)
445 END IF
446 END IF
447
448 DO k = 1, nzeta
449 lk = k
450 DO j = 1, ntheta2
451
452 tsin1 = sinmu(j,m)*cosnv(k,n)
453 tsin2 = cosmu(j,m)*sinnv(k,n)
454 bsubs_s(lk) = bsubs_s(lk) + tsin1*bsubsmn1 + tsin2*bsubsmn2
455
456 tcosm1 = cosmum(j,m)*cosnv(k,n)
457 tcosm2 = sinmum(j,m)*sinnv(k,n)
458 bsubsu(js,lk,0) = bsubsu(js,lk,0) + tcosm1*bsubsmn1 + tcosm2*bsubsmn2
459
460 tcosn1 = sinmu(j,m)*sinnvn(k,n)
461 tcosn2 = cosmu(j,m)*cosnvn(k,n)
462 bsubsv(js,lk,0) = bsubsv(js,lk,0) + tcosn1*bsubsmn1 + tcosn2*bsubsmn2
463
464 IF (lasym) THEN
465 tcos1 = cosmu(j,m)*cosnv(k,n)
466 tcos2 = sinmu(j,m)*sinnv(k,n)
467 bsubs_a(lk) = bsubs_a(lk) + tcos1*bsubsmn3 + tcos2*bsubsmn4
468
469 tsinm1 = sinmum(j,m)*cosnv(k,n)
470 tsinm2 = cosmum(j,m)*sinnv(k,n)
471 bsubsu(js,lk,1) = bsubsu(js,lk,1) + tsinm1*bsubsmn3 + tsinm2*bsubsmn4
472
473 tsinn1 = cosmu(j,m)*sinnvn(k,n)
474 tsinn2 = sinmu(j,m)*cosnvn(k,n)
475 bsubsv(js,lk,1) = bsubsv(js,lk,1) + tsinn1*bsubsmn3 + tsinn2*bsubsmn4
476 END IF
477
478 lk = lk + nzeta
479
480 END DO
481 END DO
482 END DO
483 END DO
484
485 IF (lasym) THEN
486 ! EXTEND TO FULL (ntheta3) u-GRID
487 bs1 => bsubs(js,:)
488 CALL fext_fft (bs1, bsubs_a, bsubs_s) ! TODO: a and s swapped ???
489 ELSE
490 bsubs(js,:) = bsubs_s(:)
491 END IF
492
493 END DO correct_bsubs ! radial loop: correct bsubs on every surface individually
494
495 ! EXTEND bsubsu, bsubsv TO NTHETA3 MESH
496 IF (lasym) CALL fsym_invfft (bsubsu, bsubsv)
497
498 ! CHECK FORCE BALANCE: SQRT(g)*(bsupu*bsubsu + bsupv*bsubsv) = brho
499 IF (lprint) then
500 WRITE (33, '(/,2a,/)') 'ANGLE INDEX B*grad(Bs) Frhs Fold'
501 check_fb: DO js = 2, ns-1
502 bsupu1(:) = cp5*(bsupu(js,:)*gsqrt(js,:) + bsupu(js+1,:)*gsqrt(js+1,:))
503 bsupv1(:) = cp5*(bsupv(js,:)*gsqrt(js,:) + bsupv(js+1,:)*gsqrt(js+1,:))
504 kp2(:) = bsupu1(:)*bsubsu(js,:,0) + bsupv1(:)*bsubsv(js,:,0)
505 jxb(:) = bsupu1(:)*itheta(js,:) + bsupv1(:)*izeta(js,:)
506
507 WRITE (33, '(/,a,i4)') 'JS = ',js
508 DO lk = 1, nznt
509 WRITE(33,1230) lk, brho(js,lk), kp2(lk), jxb(lk)
510 1230 FORMAT (i9,5x, 1p,3e14.4)
511 END DO
512 END DO check_fb
513 end if ! force balance printout
514
515 end if ! lbsubs
516
517 DEALLOCATE (bsubs_s, bsubs_a, bsubu_s, bsubu_a, bsubv_s, bsubv_a, stat=lk)
518
519 ! Compute end point values for bsubs
520 bsubs(1,:) = 2*bsubs(2,:) - bsubs(3,:)
521 !bsubs(ns,:) = 2*bsubs(ns,:) - bsubs(ns-1,:) ! TODO: from ns, ns-1 to ns ???
522 bsubs(ns,:) = 2*bsubs(ns-1,:) - bsubs(ns-2,:)
523
524
525
526
527
528
529
530
531
532
533
534
535 ! Now compute currents on the FULL radial mesh
536 ! Here:
537 !
538 ! Itheta = sqrt(g) * Ksupu
539 ! Izeta = sqrt(g) * Ksupv
540 ! Ksupx = K dot grad(x) x=(u,v)
541 ! jxb = (K X B) dot (grad-u X grad-v) sqrt(g)
542 ! bdotk = sigma*sqrt(g)*K dot B
543 ! kperpx = (B X gradp) dot grad(x) / |B|**2 x=(u,v)
544 ! sqgb2 = sigma*sqrt(g)*|B|**2
545 ! sqrtg = sqrt(g)
546 ! pprime = d(p||)/dV
547 !
548 ! kp2 == |k-perp|**2 = kperpu**2 * guu + 2*kperpu*kperpv*guv + kperpv**2 * gvv
549 ! This was compared to the alternative expression (agreed very well):
550 ! |j-perp|**2 = |grad-s|**2 * (dp/ds)**2 / |B|**2
551 !
552 ! Note: Multiply currents, pressure by 1/mu0 to get in mks units!
553 ! TWOPI*TWOPI factor incorporated in vp (thru ovp factor below), so V' = (2pi)**2*vp
554 !
555 ALLOCATE( &
556 bsubs3(ns,nzeta,ntheta3), bsubv3(ns,nzeta,ntheta3), &
557 bsubu3(ns,nzeta,ntheta3), jxb_gradp(ns,nzeta,ntheta3), &
558 jcrossb(ns,nzeta,ntheta3), bsupv3(ns,nzeta,ntheta3), &
559 bsupu3(ns,nzeta,ntheta3), jsups3(ns,nzeta,ntheta3), &
560 jsupv3(ns,nzeta,ntheta3), jsupu3(ns,nzeta,ntheta3), &
561 jdotb_sqrtg(ns,nzeta,ntheta3), sqrtg3(ns,nzeta,ntheta3), &
562 phin(ns), toroidal_angle(nzeta), stat=j)
563
564 ! delete incoming leftovers
565 itheta = 0.0_dp
566 izeta = 0.0_dp
567
568 bsubs3 = 0
569 bsubv3 = 0
570 bsubu3 = 0
571 jxb_gradp = 0
572 jcrossb = 0
573 bsupv3 = 0
574 bsupu3 = 0
575 jsups3 = 0
576 jsupv3 = 0
577 jsupu3 = 0
578 phin = 0
579 phin(ns) = 1
580 jdotb_sqrtg = 0
581 sqrtg3 = 0
582
583 bdotk = 0
584
585 ALLOCATE (pprime(nznt), pprim(ns),stat=j)
586 pprim = 0
587
588 avforce = 0
589 aminfor = 0
590 amaxfor = 0
591
592 dnorm1 = twopi*twopi
593
594 DO js = 2, ns1
595
596 ovp = c2p0/(vp(js+1) + vp(js))/dnorm1
597
598 tjnorm = ovp*signgs
599
600 sqgb2(:nznt) = gsqrt(js+1,:nznt) * (bsq(js+1,:nznt)-pres(js+1)) &
601 + gsqrt(js ,:nznt) * (bsq(js ,:nznt)-pres(js ))
602
603 ! TAKE THIS OUT: MAY BE POORLY CONVERGED AT THIS POINT....
604 ! IF (ANY(sqgb2(:nznt)*signgs .le. zero)) &
605 ! STOP ' SQGB2 <= 0 in JXBFORCE'
606
607 ! dp/ds here
608 pprime(:) = ohs*(pres(js+1)-pres(js))/mu0
609
610 kperpu(:nznt) = cp5*(bsubv(js+1,:nznt,0) + bsubv(js,:nznt,0))*pprime(:)/sqgb2
611 kperpv(:nznt) =-cp5*(bsubu(js+1,:nznt,0) + bsubu(js,:nznt,0))*pprime(:)/sqgb2
612
613 kp2(:nznt)=cp5*( kperpu**2.0_dp * (guu(js+1:nrzt:ns) + guu(js:nrzt:ns)) &
614 + 2.0_dp*kperpu*kperpv * (guv(js+1:nrzt:ns) + guv(js:nrzt:ns)) &
615 + kperpv**2.0_dp * (gvv(js+1:nrzt:ns) + gvv(js:nrzt:ns)))
616
617 itheta(js,:nznt) = bsubsv(js,:nznt,0) - ohs*(bsubv(js+1,:nznt,0) - bsubv(js,:nznt,0))
618 izeta(js,:nznt) = -bsubsu(js,:nznt,0) + ohs*(bsubu(js+1,:nznt,0) - bsubu(js,:nznt,0))
619
620 itheta(js,:nznt) = itheta(js,:nznt)/mu0
621 izeta(js,:nznt) = izeta(js,:nznt)/mu0
622
623 ! can be computed above (before lbsubs, where this appears as well)
624 sqrtg(:) = cp5*(gsqrt(js,:) + gsqrt(js+1,:))
625
626 bsupu1(:nznt) = cp5*(bsupu(js+1,:nznt)*gsqrt(js+1,:) + bsupu(js,:nznt)*gsqrt(js,:)) / sqrtg(:)
627 bsupv1(:nznt) = cp5*(bsupv(js+1,:nznt)*gsqrt(js+1,:) + bsupv(js,:nznt)*gsqrt(js,:)) / sqrtg(:)
628
629 bsubu1(:nznt) = cp5*(bsubu(js+1,:nznt,0) + bsubu(js,:nznt,0))
630 bsubv1(:nznt) = cp5*(bsubv(js+1,:nznt,0) + bsubv(js,:nznt,0))
631
632 jxb(:nznt) = ovp*(itheta(js,:nznt) * bsupv1(:nznt) - izeta(js,:nznt) * bsupu1(:nznt))
633
634 bdotk(js,:nznt) = itheta(js,:nznt) * bsubu1(:nznt) + izeta(js,:nznt) * bsubv1(:nznt)
635
636 pprime(:nznt) = ovp*pprime(:nznt)
637 pnorm = one/(abs(pprime(1)) + epsilon(pprime(1)))
638
639 amaxfor(js) = maxval(jxb(:nznt) - pprime(:))*pnorm
640 aminfor(js) = minval(jxb(:nznt) - pprime(:))*pnorm
641
642 amaxfor(js) = 100.0_dp*min(amaxfor(js), 9.999_dp)
643 aminfor(js) = 100.0_dp*max(aminfor(js),-9.999_dp)
644
645 avforce(js) = sum(wint(js:nrzt:ns)*(jxb(:nznt) - pprime(:)))
646
647 pprim(js) = sum(wint(js:nrzt:ns)*pprime(:))
648
649 ! Compute <K dot B>, <B sup v> = signgs*phip
650 ! jpar2 = <j||**2>, jperp2 = <j-perp**2>, with <...> = flux surface average
651
652 jdotb(js) = dnorm1*tjnorm*sum(bdotk(js,:nznt)*wint(js:nrzt:ns))
653 bdotb(js) = dnorm1*tjnorm*sum(sqgb2(:nznt) *wint(js:nrzt:ns))
654
655 bdotgradv(js) = cp5*dnorm1*tjnorm*(phip(js) + phip(js+1)) ! TODO: could also use phips here?
656
657 jpar2(js) = dnorm1*tjnorm*sum(bdotk(js,:nznt)**2 * wint(js:nrzt:ns)/sqgb2(:nznt))
658 jperp2(js)= dnorm1*tjnorm*sum(kp2(:nznt)*wint(js:nrzt:ns)*sqrtg(:nznt))
659
660 IF (lprint_flag) THEN
661 phin(js) = phi(js)/phi(ns)
662 DO lz = 1, nzeta
663 toroidal_angle(lz)=real(360*(lz-1),rprec)/nzeta ! TODO: unused!
664 DO lt = 1, ntheta3
665 lk = lz + nzeta*(lt-1)
666 ! lu (js,lz,lt ) = lt
667
668 jsupu3(js,lz,lt) = ovp*itheta(js,lk)
669 jsupv3(js,lz,lt) = ovp*izeta(js,lk)
670 jsups3(js,lz,lt) = ovp*(bsubuv(js,lk) - bsubvu(js,lk))/mu0
671
672 bsupu3(js,lz,lt) = bsupu1(lk)
673 bsupv3(js,lz,lt) = bsupv1(lk)
674
675 jcrossb(js,lz,lt) = jxb(lk)
676 jxb_gradp(js,lz,lt) = (jxb(lk) - pprime(lk))
677 jdotb_sqrtg(js,lz,lt) = ovp*bdotk(js,lk)
678
679 sqrtg3(js,lz,lt) = sqrtg(lk)*ovp
680
681 bsubu3(js,lz,lt) = bsubu(js,lk,0)
682 bsubv3(js,lz,lt) = bsubv(js,lk,0)
683 bsubs3(js,lz,lt) = bsubs(js,lk)
684 END DO
685 END DO
686 ENDIF ! lprint_flag
687
688 END DO ! radial
689
690 ! Need in wrout
691 izeta( 1,:nznt) = c2p0*izeta( 2,:nznt) - izeta( 3,:nznt)
692 izeta(ns,:nznt) = c2p0*izeta(ns-1,:nznt) - izeta(ns-2,:nznt)
693
694 jdotb(1) = c2p0*jdotb( 2) - jdotb( 3)
695 jdotb(ns) = c2p0*jdotb(ns-1) - jdotb(ns-2)
696
697 !bdotb(1) = c2p0*bdotb( 3) - bdotb( 2) ! TODO: 2 <--> 3 ???
698 bdotb(1) = c2p0*bdotb( 2) - bdotb( 3)
699 bdotb(ns) = c2p0*bdotb(ns-1) - bdotb(ns-2)
700
701 bdotgradv(1) = c2p0*bdotgradv( 2) - bdotgradv( 3)
702 bdotgradv(ns) = c2p0*bdotgradv(ns-1) - bdotgradv(ns-2)
703
704 jpar2(1) = 0
705 jpar2(ns) = 0
706
707 jperp2(1) = 0
708 jperp2(ns) = 0
709
710 !pprim( 1) = 2*pprim(ns-1) - pprim(ns-2) ! TODO: what is going on here ??
711 pprim( 1) = 2.0_dp*pprim( 2) - pprim( 3)
712 pprim(ns) = 2.0_dp*pprim(ns-1) - pprim(ns-2)
713
714
715 if (open_dbg_context("jxbout", id=0)) then
716
717 call add_real_3d("itheta", ns, nzeta, ntheta3, itheta)
718 call add_real_3d("izeta", ns, nzeta, ntheta3, izeta)
719 call add_real_3d("bdotk", ns, nzeta, ntheta3, bdotk)
720
721 call add_real_1d("amaxfor", ns, amaxfor)
722 call add_real_1d("aminfor", ns, aminfor)
723 call add_real_1d("avforce", ns, avforce)
724 call add_real_1d("pprim", ns, pprim)
725 call add_real_1d("jdotb", ns, jdotb)
726 call add_real_1d("bdotb", ns, bdotb)
727 call add_real_1d("bdotgradv", ns, bdotgradv)
728 call add_real_1d("jpar2", ns, jpar2)
729 call add_real_1d("jperp2", ns, jperp2)
730
731 call add_real_3d("jsupu3", ns, nzeta, ntheta3, jsupu3)
732 call add_real_3d("jsupv3", ns, nzeta, ntheta3, jsupv3)
733 call add_real_3d("jsups3", ns, nzeta, ntheta3, jsups3)
734 call add_real_3d("bsupu3", ns, nzeta, ntheta3, bsupu3)
735 call add_real_3d("bsupv3", ns, nzeta, ntheta3, bsupv3)
736 call add_real_3d("jcrossb", ns, nzeta, ntheta3, jcrossb)
737 call add_real_3d("jxb_gradp", ns, nzeta, ntheta3, jxb_gradp)
738 call add_real_3d("jdotb_sqrtg", ns, nzeta, ntheta3, jdotb_sqrtg)
739 call add_real_3d("sqrtg3", ns, nzeta, ntheta3, sqrtg3)
740 call add_real_3d("bsubu3", ns, nzeta, ntheta3, bsubu3)
741 call add_real_3d("bsubv3", ns, nzeta, ntheta3, bsubv3)
742 call add_real_3d("bsubs3", ns, nzeta, ntheta3, bsubs3)
743
744 call close_dbg_out()
745 end if
746
747
748
749
750
751 IF (lprint_flag) THEN
752 ! declare variables in netCDF file
753 CALL cdf_define(njxbout, vn_legend, legend)
754 CALL cdf_define(njxbout, vn_mpol, mpol)
755 CALL cdf_define(njxbout, vn_ntor, ntor)
756 CALL cdf_define(njxbout, vn_phin, phin)
757 CALL cdf_define(njxbout, vn_radial_surfaces, ns)
758 CALL cdf_define(njxbout, vn_poloidal_grid_points, ntheta3)
759 CALL cdf_define(njxbout, vn_toroidal_grid_points, nzeta)
760 CALL cdf_define(njxbout, vn_avforce, avforce)
761 CALL cdf_define(njxbout, vn_jdotb, jdotb)
762
763 CALL cdf_define(njxbout, vn_sqg_bdotk, jdotb_sqrtg)
764 CALL cdf_define(njxbout, vn_sqrtg, sqrtg3)
765
766 CALL cdf_define(njxbout, vn_bdotgradv, bdotgradv)
767 CALL cdf_define(njxbout, vn_pprime, pprim)
768 CALL cdf_define(njxbout, vn_aminfor, aminfor)
769 CALL cdf_define(njxbout, vn_amaxfor, amaxfor)
770 CALL cdf_define(njxbout, vn_jsupu, jsupu3)
771 CALL cdf_define(njxbout, vn_jsupv, jsupv3)
772 CALL cdf_define(njxbout, vn_jsups, jsups3)
773 CALL cdf_define(njxbout, vn_bsupu, bsupu3)
774 CALL cdf_define(njxbout, vn_bsupv, bsupv3)
775 CALL cdf_define(njxbout, vn_jcrossb, jcrossb)
776 CALL cdf_define(njxbout, vn_jxb_gradp, jxb_gradp)
777 CALL cdf_define(njxbout, vn_bsubu, bsubu3)
778 CALL cdf_define(njxbout, vn_bsubv, bsubv3)
779 CALL cdf_define(njxbout, vn_bsubs, bsubs3)
780
781 ! actually write data
782 CALL cdf_write(njxbout, vn_legend, legend )
783 CALL cdf_write(njxbout, vn_mpol, mpol )
784 CALL cdf_write(njxbout, vn_ntor, ntor )
785 CALL cdf_write(njxbout, vn_phin, phin )
786 CALL cdf_write(njxbout, vn_radial_surfaces, ns )
787 CALL cdf_write(njxbout, vn_poloidal_grid_points, ntheta3 )
788 CALL cdf_write(njxbout, vn_toroidal_grid_points, nzeta )
789 CALL cdf_write(njxbout, vn_avforce, avforce )
790 CALL cdf_write(njxbout, vn_jdotb, jdotb )
791
792 CALL cdf_write(njxbout, vn_sqg_bdotk, jdotb_sqrtg)
793 CALL cdf_write(njxbout, vn_sqrtg, sqrtg3 )
794
795 CALL cdf_write(njxbout, vn_bdotgradv, bdotgradv )
796 CALL cdf_write(njxbout, vn_pprime, pprim )
797 CALL cdf_write(njxbout, vn_aminfor, aminfor )
798 CALL cdf_write(njxbout, vn_amaxfor, amaxfor )
799 CALL cdf_write(njxbout, vn_jsupu, jsupu3 )
800 CALL cdf_write(njxbout, vn_jsupv, jsupv3 )
801 CALL cdf_write(njxbout, vn_jsups, jsups3 )
802 CALL cdf_write(njxbout, vn_bsupu, bsupu3 )
803 CALL cdf_write(njxbout, vn_bsupv, bsupv3 )
804 CALL cdf_write(njxbout, vn_jcrossb, jcrossb )
805 CALL cdf_write(njxbout, vn_jxb_gradp, jxb_gradp )
806 CALL cdf_write(njxbout, vn_bsubu, bsubu3 )
807 CALL cdf_write(njxbout, vn_bsubv, bsubv3 )
808 CALL cdf_write(njxbout, vn_bsubs, bsubs3 )
809
810 CALL cdf_close(njxbout)
811
812 DEALLOCATE( &
813 bsubs3, bsubv3, bsubu3, jxb_gradp, jcrossb, bsupv3, &
814 bsupu3, jsups3, jsupv3, jsupu3, jdotb_sqrtg, phin, &
815 toroidal_angle, sqrtg3, stat=j)
816 END IF ! lprint_flag
817
818 DEALLOCATE (kperpu, kperpv, sqgb2, sqrtg, kp2, brhomn, bsubsmn, &
819 jxb, jxb2, bsupu1, bsupv1, bsubu1, bsubv1, avforce, aminfor, &
820 amaxfor, pprim, stat=j)
821
822 ! COMPUTE MERCIER CRITERION
823 bdotk = mu0*bdotk
824
825 ! gsqrt, bsq, bdotj, iotas, wint
826 CALL mercier(gsqrt, bsq, bdotk, iotas, wint, &
827 ! r1, rt, rz, zt, zz
828 r1, ru, rv, zu, zv, &
829 ! bsubu, vp, phips, pres, ns, nznt
830 bsubu, vp, phips, pres, ns, nznt)
831
832 DEALLOCATE (bdotk, bsubuv, bsubvu, pprime, stat=j)
833
834END SUBROUTINE jxbforce
subroutine fext_fft(bout, bs_s, bs_a)
Extends from ntheta2 interval to full ntheta3 interval in angle .
Definition fext_fft.f90:10
subroutine fsym_fft(bs, bu, bv, bs_s, bu_s, bv_s, bs_a, bu_a, bv_a)
Contract bs,bu,bv from full nu interval to half-u interval so cos, sin integrals can be performed on ...
Definition fsym_fft.f90:19
subroutine fsym_invfft(bsubsu, bsubsv)
Extends function from ntheta2 to ntheta3 range.
subroutine getbsubs(bsubsmn, frho, bsupu, bsupv, mmax, nmax, info)
Solves the radial force balance for in real space using collocation.
Definition getbsubs.f90:14
subroutine jxbforce(bsupu, bsupv, bsubu, bsubv, bsubsh, bsubsu, bsubsv, gsqrt, bsq, itheta, izeta, brho, ier_flag)
Program for computing local force balance.
Definition jxbforce.f90:22
subroutine mercier(gsqrt, bsq, bdotj, iotas, wint, r1, rt, rz, zt, zz, bsubu, vp, phips, pres, ns, nznt)
Evaluate the Mercier stability criterion.
Definition mercier.f90:25
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), dimension(:,:), allocatable rv
Definition realspace.f90:10
real(rprec), dimension(:), allocatable wint
two-dimensional array for normalizing angle integrations
Definition realspace.f90:34
real(rprec), dimension(:,:), allocatable zv
Definition realspace.f90:13
real(rprec), dimension(:,:), allocatable ru
Definition realspace.f90:9
real(rprec), dimension(:), allocatable gvv
metric element
Definition realspace.f90:22
real(rprec), dimension(:), allocatable guv
metric element
Definition realspace.f90:21
real(rprec), dimension(:), allocatable shalf
sqrt(s) ,two-dimensional array on half-grid
Definition realspace.f90:31
real(rprec), dimension(:,:), allocatable r1
Definition realspace.f90:8
real(rprec), dimension(:), allocatable guu
metric element
Definition realspace.f90:20
real(rprec), dimension(:), allocatable phip
radial derivative of phi/(2*pi) on half-grid
Definition realspace.f90:29
real(rprec), dimension(:,:), allocatable zu
Definition realspace.f90:12
fault-tolerant file opening routines
real(rprec), dimension(:), allocatable vp
radial derivative of enclosed volume
Definition vmec_main.f90:56
real(rprec) ohs
Definition vmec_main.f90:87
real(rprec), dimension(:), allocatable phi
toroidal magnetic flux
Definition vmec_main.f90:37
real(rprec), dimension(:), allocatable jdotb
Definition vmec_main.f90:41
real(rprec), dimension(:), allocatable bdotgradv
Definition vmec_main.f90:44
real(rprec), dimension(:), allocatable pres
pressure profile
Definition vmec_main.f90:55
real(rprec), dimension(:), allocatable jpar2
Definition vmec_main.f90:57
real(rprec) r0scale
Definition vmec_main.f90:90
real(rprec), dimension(:), allocatable phips
toroidal flux (same as phip), one-dimensional array
Definition vmec_main.f90:68
real(rprec), dimension(:), allocatable bdotb
Definition vmec_main.f90:59
real(rprec), dimension(:), allocatable iotas
rotational transform , on half radial mesh
Definition vmec_main.f90:69
real(rprec), dimension(:), allocatable jperp2
Definition vmec_main.f90:58
real(rprec) signgs
sign of Jacobian : must be =1 (right-handed) or =-1 (left-handed)
integer, parameter successful_term_flag