V3FIT
ajax_mod.f90
1 MODULE ajax_mod
2 !-------------------------------------------------------------------------------
3 !AJAX-(Take your pick)
4 ! -Algebraic Jacobians for Advanced eXperiments
5 ! -The son of Telamon of Salamis and a warrior of great stature and prowess
6 ! who fought against Troy
7 ! -The son of Ileus of Locris and a warrior of small stature and arrogant
8 ! character who fought against Troy
9 ! -Brand name of a cleaning agent
10 !
11 !AJAX_MOD is an F90 module of routines that serve as an interface between a
12 ! transport code and MHD equilibrium solutions.
13 !
14 !References:
15 !
16 ! W.A.Houlberg, F90 free format 8/2004
17 !
18 !Contains PUBLIC routines:
19 !
20 ! Input:
21 !
22 ! AJAX_LOAD_RZBDY -loads approx to 2D MHD equilibria from boundary values
23 ! AJAX_LOAD_RZLAM -loads 2D/3D MHD equilibria in inverse coordinate form
24 ! AJAX_LOAD_MAGFLUX -loads magnetic flux data
25 !
26 ! Coordinate conversions:
27 !
28 ! AJAX_CAR2CYL -converts from Cartesian to cylindrical coordinates
29 ! AJAX_CYL2CAR -converts from cylindrical to Cartesian coordinates
30 ! AJAX_CYL2FLX -converts from cylindrical to flux coordinates
31 ! AJAX_FLX2CYL -converts from flux to cylindrical coordinates
32 !
33 ! Local magnetics:
34 !
35 ! AJAX_B -gets components of B in various forms
36 ! AJAX_LAMBDA -gets stream function and its derivatives
37 !
38 ! Flux surface quantities:
39 !
40 ! AJAX_FLUXAV_B -gets flux surface quantities that depend on B
41 ! AJAX_FLUXAV_G -gets flux surface quantities that depend on geometry
42 ! AJAX_I -gets enclosed toroidal and external poloidal currents
43 ! and maximum and minimum values
44 ! AJAX_MAGFLUX -gets poloidal and toroidal magnetic fluxes
45 ! AJAX_SHAPE -gets shift, elongation, triangularity, Rmax, Rmin, etc
46 !
47 ! Miscellaneous:
48 !
49 ! AJAX_GLOBALS -gets global characteristics of the data
50 ! AJAX_MINMAX_RZ -gets maximum or minimum of R or Z
51 !
52 !Comments:
53 !
54 ! This module is designed for use in a transport code that calculates MHD
55 ! equilibria (flux surface geometry) at infrequent intervals and updates the
56 ! the magnetic flux (e.g., safety factor or rotational transform) more
57 ! frequently (e.g., every time step) in a Grad-Hogan approach:
58 ! 1) After a new equilibrium (geometry and magnetic flux) call:
59 ! AJAX_LOAD_RZLAM or AJAX_LOAD_RZBDY
60 ! AJAX_LOAD_MAGFLUX
61 ! 2) After each additional timestep (magnetic flux) call:
62 ! AJAX_LOAD_MAGFLUX
63 !
64 ! The flux surface averaging routines are split to provide efficient
65 ! evaluation:
66 ! 1) After a new equilibrium (geometry dependent) call:
67 ! AJAX_FLUXAV_G
68 ! AJAX_SHAPE
69 ! 2) After each timestep (geometry and magnetic flux dependent) call:
70 ! AJAX_FLUXAV_B
71 !
72 ! There is extensive use of optional arguments to:
73 ! 1) Provide flexibility of input variables
74 ! 2) Give the user control over the fineness of the internal grids
75 !
76 ! The modernization of the code structure into an F90 module takes advantage of
77 ! some of the more attractive features of F90:
78 ! -use of KIND for precision declarations
79 ! -optional arguments for I/O
80 ! -generic names for all intrinsic functions
81 ! -compilation using either free or fixed form
82 ! -no common blocks or other deprecated Fortran features
83 ! -dynamic and automatic alocation of variables
84 ! -array syntax for vector operations
85 !-------------------------------------------------------------------------------
86 USE spec_kind_mod
87 USE linear1_mod
88 USE spline1_mod
89 IMPLICIT NONE
90 
91 !-------------------------------------------------------------------------------
92 !Private procedures
93 !-------------------------------------------------------------------------------
94 PRIVATE :: &
95  ajax_init, & !initializes or resets private data and its allocations
96  ! called from AJAX_LOAD_RZLAM
97  ajax_init_fluxav_b, & !initializes magnetic field arrays
98  ! called from AJAX_FLUXAV_B
99  ajax_init_fluxav_g, & !initializes geometry arrays
100  ! called from AJAX_FLUXAV_B
101  ! called from AJAX_FLUXAV_G
102  ajax_init_lambda, & !calculates the magnetic stream function from R,Z data
103  ! version is only valid for axisymmetric plasmas
104  ! called from AJAX_LOAD_RZLAM
105  ajax_load_lambda !loads the magnetic stream function
106  ! called from AJAX_LOAD_RZLAM
107 
108 !-------------------------------------------------------------------------------
109 !Private data
110 !-------------------------------------------------------------------------------
111 !Logical switches
112 LOGICAL, PRIVATE, SAVE :: &
113  l_fluxavb_3d, & !option for whether b-dependent integrals set up [-]
114  l_fluxavg_3d, & !option for whether geom-dependent integrals set up [-]
115  l_mfilter_3d !option for mode filtering [logical]
116 
117 !Poloidal and toroidal mode expansions
118 INTEGER, PRIVATE, SAVE :: &
119  krz_3d, & !no. of modes in RZ expansion [-]
120  klam_3d, & !no. of modes in lambda expansion [-]
121  km0n0_3d, & !index of (m,n)=(0,0) mode [-]
122  km1n0_3d, & !index of (m,n)=(1,0) mode [-]
123  nper_3d !no. of toroidal periods (3-D) [-]
124 
125 INTEGER, PRIVATE, SAVE, ALLOCATABLE :: &
126  m_3d(:), & !poloidal modes [-]
127  n_3d(:), & !toroidal modes [-]
128  mabs_3d(:) !|m| in normalization, but restricted by l_mfilter [-]
129 
130 !Radial, poloidal and toroidal grids
131 INTEGER, PRIVATE, SAVE :: &
132  nrho_3d, & !no. of radial nodes [-]
133  ntheta_3d, & !no. of poloidal nodes [-]
134  nzeta_3d !no. of toroidal nodes [-]
135 
136 REAL(KIND=rspec), PRIVATE, SAVE :: &
137  dtheta_3d, & !poloidal step size for integrals [rad]
138  dzeta_3d !toroidal step size for integrals [rad]
139 
140 REAL(KIND=rspec), PRIVATE, SAVE, ALLOCATABLE :: &
141  rho_3d(:), & !radial grid prop to sqrt(tor flux) [-]
142  wtheta_3d(:), & !pol weighting factor for integrals [-]
143  wzeta_3d(:) !tor weighting factor for integrals [-]
144 
145 !Toroidal flux and magnetic field directions
146 REAL(KIND=rspec), PRIVATE, SAVE :: &
147  phitot_3d, & !total toroidal flux [Wb]
148  signbp_3d, & !sign of the pol magnetic field [-]
149  signbt_3d !sign of the toroidal magnetic field [-]
150 
151 !Splined quantities in radial coordinate:
152 REAL(KIND=rspec), PRIVATE, SAVE, ALLOCATABLE :: &
153  iotabar_3d(:,:), & !rotational transform/2pi [-]
154  r_3d(:,:,:), & !expansion coefficients for R [m]
155  z_3d(:,:,:), & !expansion coefficients for Z [m]
156  lam_3d(:,:,:) !expansion coefficients for lambda [-]
157 
158 !Arrays for flux surface averaging
159 REAL(KIND=rspec), PRIVATE, SAVE, ALLOCATABLE :: &
160  az_3d(:), & !temp tor array [arb]
161  gt_3d(:), & !temp pol array [arb]
162  vp_3d(:), & !V'(rho) [m**3/rho]
163  rcyl_3d(:,:,:), & !R coords on internal grid [m]
164  zcyl_3d(:,:,:), & !Z coords on internal grid [m]
165  gsqrt_3d(:,:,:), & !3D Jacobian on internal grid [m**3/rho]
166  eltheta_3d(:,:,:), & !d(lambda)/d(theta) on internal grid [/rad]
167  elzeta_3d(:,:,:), & !d(lambda)/d(zeta) on internal grid [/rad]
168  b_3d(:,:,:), & !total B on internal grid [T]
169  btheta_3d(:,:,:), & !contravariant poloidal B on internal grid [T/m]
170  gcyl_3d(:,:,:,:) !R,Z derivatives
171  !=(R_rho,R_theta,R_zeta,Z_rho,Z_theta,Z_zeta)
172  ! [m/rho,m, m, m/rho,m, m ]
173 
174 !Major and minor radius quantities
175 REAL(KIND=rspec), PRIVATE, SAVE :: &
176  r000_3d, & !coefficient of (m,n)=(0,0) mode for R at axis [m]
177  rhomin_3d, & !inner radial boundary of R,Z domain [rho]
178  rhomax_3d, & !outer radial boundary of R,Z domain [rho]
179  rhores_3d !resolution factor for rho [rho]
180 
181 !Physical and conversion constants
182 REAL(KIND=rspec), PRIVATE, PARAMETER :: &
183  z_mu0=1.2566e-06, & !permeability of free space [H/m]
184  z_pi=3.141592654 !pi [-]
185 
186 REAL(KIND=rspec), PRIVATE, SAVE :: &
187  z_large, & !largest real number [-]
188  z_precision, & !machine precision [-]
189  z_small !smallest real number [-]
190 
191 !-------------------------------------------------------------------------------
192 ! Public procedures
193 !-------------------------------------------------------------------------------
194 CONTAINS
195 
196 SUBROUTINE ajax_load_rzbdy(r0,a0,s0,e0,e1,d1, &
197  iflag,message, &
198  NRHO_AJAX,NTHETA_AJAX,NKLAM_AJAX,RHOMAX_AJAX)
199 !-------------------------------------------------------------------------------
200 !AJAX_LOAD_RZBDY converts geometric boundary and axial constraints to values of
201 ! the R,Z coordinates then calls AJAX_LOAD_RZLAM to fill in the profiles
202 !
203 !References:
204 ! W.A.Houlberg, F90 free format 8/2004
205 !-------------------------------------------------------------------------------
206 
207 !Declaration of input variables
208 REAL(KIND=rspec), INTENT(IN) :: &
209  r0, & !major radius of geometric center [m]
210  a0, & !minor radius in midplane [m]
211  s0, & !axis shift normalized to a0 [-]
212  e0, & !axis elongation normalized to a0 [-]
213  e1, & !edge elongation normalized to a0 [-]
214  d1 !edge triangularity normalized to a0 [-]
215 
216 !Declaration of output variables
217 CHARACTER(LEN=1024), INTENT(OUT) :: &
218  message !warning or error message [character]
219 
220 INTEGER, INTENT(OUT) :: &
221  iflag !error and warning flag [-]
222  !=-1 warning
223  !=0 none
224  !=1 error
225 
226 !Declaration of optional input variables
227 INTEGER, INTENT(IN), OPTIONAL :: &
228  NRHO_AJAX, & !no. of radial nodes in internal data [-]
229  !=21 default
230  ntheta_ajax, & !no. of poloidal nodes in internal data [odd]
231  !=21 default
232  nklam_ajax !no. of lambda modes in nternal data [-]
233  !=5 default
234 
235 REAL(KIND=rspec), INTENT(IN), OPTIONAL :: &
236  rhomax_ajax !value of internal radial grid at R,Z boundary [rho]
237  !=1.0 default
238 
239 !-------------------------------------------------------------------------------
240 !Declaration of local variables
241 INTEGER :: &
242  i,k,nk_rz,nk_lam,nr_rz,nthetal
243 
244 INTEGER, ALLOCATABLE :: &
245  m(:),n(:)
246 
247 REAL(KIND=rspec) :: &
248  c,dm1,em1,r2,rhomaxl
249 
250 REAL(KIND=rspec), ALLOCATABLE :: &
251  rho_rz(:),r(:,:),z(:,:)
252 
253 !-------------------------------------------------------------------------------
254 !Initialization
255 !-------------------------------------------------------------------------------
256 !Null output
257 iflag=0
258 message=''
259 
260 !Check optional input
261 IF(PRESENT(rhomax_ajax)) THEN
262 
263  rhomaxl=rhomax_ajax
264 
265 ELSE
266 
267  rhomaxl=1
268 
269 ENDIF
270 
271 IF(PRESENT(nrho_ajax)) THEN
272 
273  nr_rz=nrho_ajax
274 
275 ELSE
276 
277  nr_rz=31
278 
279 ENDIF
280 
281 IF(PRESENT(nklam_ajax)) THEN
282 
283  nk_lam=nklam_ajax
284 
285 ELSE
286 
287  nk_lam=8
288 
289 ENDIF
290 
291 IF(PRESENT(ntheta_ajax)) THEN
292 
293  nthetal=ntheta_ajax
294 
295 ELSE
296 
297  nthetal=4*nk_lam+1
298 
299 ENDIF
300 
301 !Allocate and set poloidal mode information
302 ALLOCATE(m(nk_lam), &
303  n(nk_lam))
304 
305  nk_rz=3
306  m(:)=(/ (k-1,k=1,nk_lam) /)
307  n(:)=0
308 
309 !-------------------------------------------------------------------------------
310 !Convert from geometric to moments quantities
311 !-------------------------------------------------------------------------------
312 !Moments triangularity ~geometric triangularity/4
313 dm1=d1/4
314 c=0
315 
316 !Iterate for triangularity value, convergence is fast and robust
317 DO i=1,10 !Over iteration
318 
319  c=4*dm1/(sqrt(1.0+32*dm1**2)+1.0)
320  dm1=d1/(4.0-6*c**2)
321 
322 ENDDO !Over iteration
323 
324 !Elongation
325 em1=e1/(sqrt(1.0-c**2)*(1.0+2*dm1*c))
326 
327 !-------------------------------------------------------------------------------
328 !Fill in radial values of R,Z expansion coefficients
329 !-------------------------------------------------------------------------------
330 !Allocate radial grid and R,Z arrays
331 ALLOCATE(rho_rz(nr_rz), &
332  r(nr_rz,nk_rz), &
333  z(nr_rz,nk_rz))
334 
335  rho_rz(:)=0
336  r(:,:)=0
337  z(:,:)=0
338 
339 !Set radial grid
340 rho_rz(:)=(/ (real(i-1,rspec)/real(nr_rz-1,rspec),i=1,nr_rz) /)
341 
342 !Radial variation
343 DO i=1,nr_rz !Over radial nodes
344 
345  r2=rho_rz(i)**2
346  r(i,1)=r0+a0*(s0*(1.0-r2)-dm1*r2)
347  r(i,2)=a0*rho_rz(i)
348  z(i,2)=-r(i,2)*(e0*(1.0-r2)+em1*r2)
349  r(i,3)=a0*r2*dm1
350  z(i,3)=r(i,3)*em1
351 
352 ENDDO !Over radial nodes
353 
354 !Load private data
355 CALL ajax_load_rzlam(nr_rz,nk_rz,rho_rz,m,n,r,z, &
356  iflag,message, &
357  nrho_ajax=nr_rz, &
358  ntheta_ajax=nthetal, &
359  rhomax_ajax=rhomaxl, &
360  nk_lam=nk_lam)
361 
362 !Check messages
363 IF(iflag /= 0) message='AJAX_LOAD_RZBDY '// message
364 
365 !-------------------------------------------------------------------------------
366 !Cleanup and exit
367 !-------------------------------------------------------------------------------
368 9999 CONTINUE
369 
370 IF(ALLOCATED(m)) THEN
371 
372  !Deallocate mode information
373  DEALLOCATE(m, &
374  n)
375 
376 ENDIF
377 
378 IF(ALLOCATED(rho_rz)) THEN
379 
380  !Deallocate grid and R,Z arrays
381  DEALLOCATE(rho_rz, &
382  r, &
383  z)
384 
385 ENDIF
386 
387 END SUBROUTINE ajax_load_rzbdy
388 
389 SUBROUTINE ajax_load_rzlam(nr_rz,nk_rz,rho_rz,m,n,r,z, &
390  iflag,message, &
391  K_GRID,L_MFILTER_AJAX,NRHO_AJAX,NTHETA_AJAX, &
392  NZETA_AJAX,RHOMAX_AJAX,NR_LAM,NK_LAM,RHO_LAM,LAM)
393 !-------------------------------------------------------------------------------
394 !AJAX_LOAD_RZLAM loads 2D/3D MHD equilibria in inverse coordinate form
395 !
396 !References:
397 ! W.A.Houlberg, F90 free format 8/2004
398 !
399 !Comments:
400 ! Knowledge of the form of the input radial grid (see K_GRID) is necessary for
401 ! accurate mapping to the internal grid
402 ! The internal radial grid, rho_3d, is proportional to the square root of the
403 ! toroidal flux
404 ! The maximum value of the R,Z radial grid defines rho/rhomax=1
405 ! The internal radial grid will be scaled to rhomax if specified, otherwise it
406 ! will default to the domain [0,1]
407 ! The input poloidal and toroidal mode numbers are the same for the R,Z and
408 ! lambda expansions and dimensioned to the greater of the two; e.g., if there
409 ! are more poloidal and toroidal modes for the input lambda they should be
410 ! appended to the end of the sequence of values for the R,Z expansions
411 ! Mode filtering may be tried to improve calculations near the axis and the
412 ! outer boundary
413 !-------------------------------------------------------------------------------
414 
415 !Declaration of input variables
416 INTEGER, INTENT(IN) :: &
417  nr_rz, & !no. of radial nodes in the input R,Z [-]
418  nk_rz, & !no. of poloidal & toroidal modes in the input R,Z [-]
419  m(:), & !poloidal mode numbers [-]
420  n(:) !toroidal mode numbers [-]
421 
422 REAL(KIND=rspec), INTENT(IN) :: &
423  rho_rz(:), & !radial nodes in the input R,Z [arb]
424  r(:,:), & !expansion coeffs for R [m]
425  z(:,:) !expansion coeffs for Z [m]
426 
427 !Declaration of output variables
428 CHARACTER(LEN=1024), INTENT(OUT) :: &
429  message !warning or error message [character]
430 
431 INTEGER, INTENT(OUT) :: &
432  iflag !error and warning flag [-]
433  !=-1 warning
434  !=0 none
435  !=1 error
436 
437 !Declaration of optional input variables
438 LOGICAL, INTENT(IN), OPTIONAL :: &
439  L_MFILTER_AJAX !option for mode filtering [logical]
440 
441 INTEGER, INTENT(IN), OPTIONAL :: &
442  K_GRID, & !option designating type of input radial grid [-]
443  !=0 proportional to sqrt(toroidal flux)
444  !=1 proportional to toroidal flux
445  !=else not allowed
446  nrho_ajax, & !no. of radial nodes in internal data [-]
447  !=21 default
448  ntheta_ajax, & !no. of poloidal nodes in internal data [odd]
449  !=21 default
450  nzeta_ajax, & !no. of toroidal nodes per period in internal data [odd]
451  !=11 default for non-axisymmetric plasma
452  !=0 default for axisymmetric plasma
453  nr_lam, & !no. of radial nodes in the input lambda [-]
454  nk_lam !no. of poloidal & toroidal modes in the input lambda [-]
455 
456 REAL(KIND=rspec), INTENT(IN), OPTIONAL :: &
457  rhomax_ajax, & !value of internal radial grid at R,Z boundary [rho]
458  !=1.0 default
459  rho_lam(:), & !radial nodes in the input lambda [arb]
460  lam(:,:) !expansion coeffs for lambda [-]
461 
462 !-------------------------------------------------------------------------------
463 !Declaration of local variables
464 INTEGER :: &
465  i,j,k,kmax,nset1,k_grid_l,k_vopt(1:3)=(/1,0,0/),k_bc1=3,k_bcn=0
466 
467 REAL(KIND=rspec), ALLOCATABLE :: &
468  rho(:),rmn(:,:),zmn(:,:),fspl(:,:),values(:,:)
469 
470 !-------------------------------------------------------------------------------
471 !Initialization
472 !-------------------------------------------------------------------------------
473 !Null output
474 iflag=0
475 message=''
476 
477 !Set number of angular modes
478 krz_3d=nk_rz
479 
480 IF(PRESENT(nk_lam)) THEN
481 
482  klam_3d=nk_lam
483 
484 ELSE
485 
486  klam_3d=max(krz_3d,8)
487 
488 ENDIF
489 
490 kmax=max(krz_3d,klam_3d)
491 
492 !Set the number of toroidal field periods, < 100 periods
493 i=100
494 
495 DO k=1,kmax !Over modes
496 
497  !Find lowest non-zero toroidal mode number
498  IF(n(k) /= 0) i=min(i,abs(n(k)))
499 
500 ENDDO !Over modes
501 
502 IF(i == 100) THEN
503 
504  !Found no peiodicity in data, set to axisymmetric
505  nper_3d=0
506 
507 ELSE
508 
509  !Non-axisymmetric
510  nper_3d=i
511 
512  !Check periodicity
513  DO k=1,kmax !Over modes
514 
515  IF(n(k) /= 0) THEN
516 
517  j=mod(n(k),nper_3d)
518 
519  IF(j /= 0) THEN
520 
521  !Some mode does not fit the periodicity
522  iflag=1
523  message='AJAX_LOAD_RZLAM/ERROR(1):periodicity not found'
524  GOTO 9999
525 
526  ENDIF
527 
528  ENDIF
529 
530  ENDDO !Over modes
531 
532 ENDIF
533 
534 !-------------------------------------------------------------------------------
535 !Check optional input for internal grid initialization
536 !-------------------------------------------------------------------------------
537 !Set the number of internal radial nodes
538 IF(PRESENT(nrho_ajax)) THEN
539 
540  !Use input value
541  nrho_3d=nrho_ajax
542 
543 ELSE
544 
545  !Use default value
546  nrho_3d=31
547 
548 ENDIF
549 
550 !Set the number of internal poloidal nodes
551 IF(PRESENT(ntheta_ajax)) THEN
552 
553  !Use input value
554  ntheta_3d=ntheta_ajax
555 
556  !Make sure the number of modes is odd for 4th order Simpson integration
557  IF(mod(ntheta_3d,2) == 0) THEN
558 
559  ntheta_3d=ntheta_3d+1
560  iflag=-1
561  message='AJAX_LOAD_RZLAM/WARNING(2):poloidal nodes reset'
562 
563  ENDIF
564 
565 ELSE
566 
567  IF(nper_3d == 0) THEN
568 
569  !Axisymmetric
570  !4k+1 typically yields <0.1% error in B_zeta = RB_t ~ const
571  ntheta_3d=4*klam_3d+1
572 
573  ELSE
574 
575  !Non-axisymmetric
576  !Error estimate yet to be quantified, typically |m| <= 8
577  ntheta_3d=33
578 
579  ENDIF
580 
581 ENDIF
582 
583 !Set the number of internal toroidal nodes
584 IF(PRESENT(nzeta_ajax)) THEN
585 
586  !Use input value
587  nzeta_3d=nzeta_ajax
588 
589  IF(nper_3d == 0 .AND. nzeta_3d /= 1) THEN
590 
591  nzeta_3d=1
592  iflag=-1
593  message='AJAX_LOAD_RZLAM/WARNING(3):toroidal nodes reset to 1'
594 
595  ENDIF
596 
597  !Make sure the number of modes is odd for 4th order Simpson integration
598  IF(mod(nzeta_3d,2) == 0) THEN
599 
600  nzeta_3d=nzeta_3d+1
601  iflag=-1
602  message='AJAX_LOAD_RZLAM/WARNING(4):toroidal nodes reset'
603 
604  ENDIF
605 
606 ELSEIF(nper_3d == 0) THEN
607 
608  !Use axisymmetric value
609  nzeta_3d=1
610 
611 ELSE
612 
613  !Use non-axisymmetric default value
614  !Error estimate yet to be quantified, typically |n/nper| <= 5
615  nzeta_3d=21
616 
617 ENDIF
618 
619 !Set the option for mode filtering
620 IF(PRESENT(l_mfilter_ajax)) THEN
621 
622  !Use input value
623  l_mfilter_3d=l_mfilter_ajax
624 
625 ELSE
626 
627  !Use default value
628  l_mfilter_3d=.true.
629 
630 ENDIF
631 
632 !-------------------------------------------------------------------------------
633 !Set general information and initialize arrays
634 !-------------------------------------------------------------------------------
635 !Scale the outer radial boundary of R,Z to rhomax
636 IF(PRESENT(rhomax_ajax)) THEN
637 
638  !Use input value
639  rhomax_3d=rhomax_ajax
640 
641 ELSE
642 
643  !Use default value
644  rhomax_3d=1
645 
646 ENDIF
647 
648 !Set the mode numbers of the (m,n)=(0,0) and (m,n)=(1,0) modes
649 km0n0_3d=0
650 km1n0_3d=0
651 
652 loop_k: DO k=1,kmax
653 
654  IF(abs(m(k)) == 0 .AND. n(k) == 0) km0n0_3d=k
655  IF(abs(m(k)) == 1 .AND. n(k) == 0) km1n0_3d=k
656  IF(km0n0_3d /= 0 .AND. km1n0_3d /= 0) EXIT loop_k
657 
658 ENDDO loop_k !Over modes
659 
660 !Call initialization routine
661 CALL ajax_init
662 
663 !-------------------------------------------------------------------------------
664 !Poloidal and toroidal mode data
665 !-------------------------------------------------------------------------------
666 !Initialization
667 m_3d(:)=0
668 n_3d(:)=0
669 
670 !Copy data
671 m_3d(1:kmax)=m(1:kmax)
672 n_3d(1:kmax)=n(1:kmax)
673 
674 !Set |m| with mode filtering for rho**|m| normalization
675 DO k=1,kmax !Over modes
676 
677  mabs_3d(k)=abs(m_3d(k))
678 
679  !Check for filtering
680  IF(l_mfilter_3d) THEN
681 
682  IF(mabs_3d(k) > 3) THEN
683 
684  !Filtering for |m| > 3
685  IF(mod(mabs_3d(k),2) == 0) THEN
686 
687  !Even mode, remove rho**2
688  mabs_3d(k)=2
689 
690  ELSE
691 
692  !Odd mode, remove rho**3
693  mabs_3d(k)=3
694 
695  ENDIF
696 
697  ENDIF
698 
699  ENDIF
700 
701 ENDDO !Over modes
702 
703 !-------------------------------------------------------------------------------
704 !Load R and Z expansion data
705 !-------------------------------------------------------------------------------
706 !Initialization
707 r_3d(:,:,:)=0
708 z_3d(:,:,:)=0
709 
710 !Make copy of radial grid and expansion coefficients
711 !If the user does not provide an axial value for R,Z data, need to fill in
712 IF(rho_rz(1) > rhores_3d) THEN
713 
714  !Allocate radial grid and R,Z arrays, add radial node at axis
715  nset1=nr_rz+1
716  ALLOCATE(rho(nset1), &
717  rmn(nset1,nk_rz), &
718  zmn(nset1,nk_rz))
719 
720  rho(:)=0
721  rmn(:,:)=0
722  zmn(:,:)=0
723  rho(2:nset1)=rho_rz(1:nr_rz)/rho_rz(nr_rz)
724  rmn(2:nset1,1:nk_rz)=r(1:nr_rz,1:nk_rz)
725  zmn(2:nset1,1:nk_rz)=z(1:nr_rz,1:nk_rz)
726 
727 ELSE
728 
729  !Allocate radial grid and R,Z arrays, use input grid
730  nset1=nr_rz
731  ALLOCATE(rho(nset1), &
732  rmn(nset1,nk_rz), &
733  zmn(nset1,nk_rz))
734 
735  rho(:)=0
736  rmn(:,:)=0
737  zmn(:,:)=0
738  rho(1:nset1)=rho_rz(1:nset1)/rho_rz(nset1)
739  rmn(1:nset1,1:nk_rz)=r(1:nset1,1:nk_rz)
740  zmn(1:nset1,1:nk_rz)=z(1:nset1,1:nk_rz)
741 
742 ENDIF
743 
744 !Convert rho to sqrt(toroidal flux) if necesssary and scale
745 k_grid_l=0
746 IF(PRESENT(k_grid)) k_grid_l=k_grid
747 
748 IF(k_grid_l == 1) THEN
749 
750  !~toroidal flux
751  rho(:)=sqrt(rho(:))*rhomax_3d
752 
753 ELSEIF(k_grid_l == 0) THEN
754 
755  !~sqrt(toroidal flux)
756  rho(:)=rho(:)*rhomax_3d
757 
758 ELSE
759 
760  !Unallowed choice of input grid
761  iflag=1
762  message='AJAX_LOAD_RZLAM/ERROR(5):unallowed choice of K_GRID'
763  GOTO 9999
764 
765 ENDIF
766 
767 !Set the inner radial boundary of R,Z for checking axial extrapolation
768 rhomin_3d=rho(2)
769 
770 !Allocate spline arrays
771 ALLOCATE(fspl(4,nset1), &
772  values(3,nrho_3d))
773 
774  fspl(:,:)=0
775  values(:,:)=0
776 
777 !Normalize the expansion coefficients to rho**m
778 DO k=1,krz_3d !Over modes
779 
780  DO i=2,nset1 !Over radial nodes
781 
782  rmn(i,k)=rmn(i,k)/rho(i)**mabs_3d(k)
783  zmn(i,k)=zmn(i,k)/rho(i)**mabs_3d(k)
784 
785  ENDDO !Over radial nodes
786 
787 !Parabolic extrapolation to axis (user values ignored)
788  rmn(1,k)=(rmn(2,k)*rho(3)**2-rmn(3,k)*rho(2)**2)/(rho(3)**2-rho(2)**2)
789  zmn(1,k)=(zmn(2,k)*rho(3)**2-zmn(3,k)*rho(2)**2)/(rho(3)**2-rho(2)**2)
790 
791 !Map R_mn to internal radial grid
792  fspl(1,1:nset1)=rmn(1:nset1,k)
793  iflag=0
794  message=''
795  CALL spline1_interp(k_vopt,nset1,rho,fspl,nrho_3d,rho_3d,values, &
796  iflag,message, &
797  k_bc1=k_bc1, &
798  k_bcn=k_bcn)
799 
800  !Check messages
801  IF(iflag > 0) THEN
802 
803  message='AJAX_LOAD_RZLAM(6) '// message
804  GOTO 9999
805 
806  ENDIF
807 
808  !Respline the R coeffs for internal storage
809  r_3d(1,1:nrho_3d,k)=values(1,1:nrho_3d)
810  CALL spline1_fit(nrho_3d,rho_3d,r_3d(:,:,k), &
811  k_bc1=k_bc1, &
812  k_bcn=k_bcn)
813 
814 !Map Z_mn to internal radial grid
815  fspl(1,1:nset1)=zmn(1:nset1,k)
816  iflag=0
817  message=''
818  CALL spline1_interp(k_vopt,nset1,rho,fspl,nrho_3d,rho_3d, &
819  values,iflag,message, &
820  k_bc1=k_bc1, &
821  k_bcn=k_bcn)
822 
823  !Check messages
824  IF(iflag > 0) THEN
825 
826  message='AJAX_LOAD_RZLAM(7) '// message
827  GOTO 9999
828 
829  ENDIF
830 
831  !Respline the Z coeffs for internal storage
832  z_3d(1,1:nrho_3d,k)=values(1,1:nrho_3d)
833  CALL spline1_fit(nrho_3d,rho_3d,z_3d(:,:,k), &
834  k_bc1=k_bc1, &
835  k_bcn=k_bcn)
836 
837 ENDDO !Over modes
838 
839 !Set the length scale factors
840 r000_3d=r_3d(1,1,km0n0_3d)
841 
842 !-------------------------------------------------------------------------------
843 !Magnetic stream function
844 !-------------------------------------------------------------------------------
845 IF(PRESENT(nr_lam) .AND. &
846  PRESENT(nk_lam) .AND. &
847  PRESENT(rho_lam) .AND. &
848  PRESENT(lam)) THEN
849 
850  !Load lambda from input
851  iflag=0
852  message=''
853  CALL ajax_load_lambda(k_grid_l,nr_lam,nk_lam,rho_rz(nr_rz), &
854  rho_lam,lam,iflag,message)
855 
856  !Check messages
857  IF(iflag /= 0) message='AJAX_LOAD_RZLAM(8) '// message
858 
859 ELSEIF(nper_3d == 0) THEN
860 
861  !Calculate lambdas for axisymmetric plasma
862  !Set up 3d grid for flux surface integrals
863  iflag=0
864  message=''
865  CALL ajax_init_fluxav_g(iflag,message)
866 
867  !Check messages
868  IF(iflag /= 0) THEN
869 
870  message='AJAX_LOAD_RZLAM(9) '// message
871  IF(iflag > 0) GOTO 9999
872 
873  ENDIF
874 
875 
876  !Calculate lambda
877  CALL ajax_init_lambda
878 
879 ELSE
880 
881  !Need to specify stream function for non-axisymmetric plasmas
882  iflag=1
883  message='AJAX_LOAD_RZLAM/ERROR(10):need lambdas'
884 
885 ENDIF
886 
887 !-------------------------------------------------------------------------------
888 !Cleanup and exit
889 !-------------------------------------------------------------------------------
890 9999 CONTINUE
891 
892 IF(ALLOCATED(rho)) THEN
893 
894  !Deallocate radial grid and R,Z arrays
895  DEALLOCATE(rho, &
896  rmn, &
897  zmn)
898 
899 ENDIF
900 
901 IF(ALLOCATED(fspl)) THEN
902 
903  !Deallocate spline arrays
904  DEALLOCATE(fspl, &
905  values)
906 
907 ENDIF
908 
909 END SUBROUTINE ajax_load_rzlam
910 
911 SUBROUTINE ajax_load_magflux(phitot,k_pflx,nr_pflx,rho_pflx,pflx, &
912  iflag,message)
913 !-------------------------------------------------------------------------------
914 !AJAX_LOAD_MAGFLUX loads magnetic flux data
915 !
916 !References:
917 ! W.A.Houlberg, F90 free format 8/2004
918 !-------------------------------------------------------------------------------
919 
920 !Declaration of input variables
921 INTEGER, INTENT(IN) :: &
922  k_pflx, & !option for represention of poloidal flux [-]
923  !=1 iotabar (rotational transform)
924  !=2 d(Psi)/d(rho)
925  !=else q (safety factor)
926  nr_pflx !no. of radial nodes in input flux [-]
927 
928 REAL(KIND=rspec), INTENT(IN) :: &
929  rho_pflx(:), & !radial nodes in input flux [rho]
930  pflx(:), & !poloidal magnetic flux function
931  !=q [-]
932  !=iotabar [-]
933  !=d(Psi)/d(rho) [Wb/rho]
934  phitot !total toroidal flux [Wb]
935 
936 !Declaration of output variables
937 CHARACTER(LEN=1024), INTENT(OUT) :: &
938  message !warning or error message [character]
939 
940 INTEGER, INTENT(OUT) :: &
941  iflag !error and warning flag [-]
942  !=-1 warning
943  !=0 none
944  !=1 error
945 
946 !-------------------------------------------------------------------------------
947 !Declaration of local variables
948 INTEGER, PARAMETER :: &
949  k_vopt(1:3)=(/1,0,0/),k_bc1=3,k_bcn=0
950 
951 INTEGER :: &
952  nset1
953 
954 REAL(KIND=rspec) :: &
955  fspl(1:4,1:nr_pflx),values(1:3,1:nrho_3d)
956 
957 !-------------------------------------------------------------------------------
958 !Initialization
959 !-------------------------------------------------------------------------------
960 !Null output
961 iflag=0
962 message=''
963 
964 !-------------------------------------------------------------------------------
965 !Iotabar allocation
966 !-------------------------------------------------------------------------------
967 IF(ALLOCATED(iotabar_3d)) THEN
968 
969  !Radial dimension
970  nset1=SIZE(iotabar_3d,2)
971 
972  !If storage requirements have changed, reallocate
973  IF(nset1 /= nrho_3d) THEN
974 
975  !Reallocate iotabar
976  DEALLOCATE(iotabar_3d)
977  ALLOCATE(iotabar_3d(4,nrho_3d))
978 
979  iotabar_3d(:,:)=0
980 
981  ENDIF
982 
983 ELSE
984 
985  !Allocate iotabar
986  ALLOCATE(iotabar_3d(4,nrho_3d))
987 
988  iotabar_3d(:,:)=0
989 
990 ENDIF
991 
992 !-------------------------------------------------------------------------------
993 !Total toroidal flux in private data
994 !-------------------------------------------------------------------------------
995 phitot_3d=phitot
996 
997 !-------------------------------------------------------------------------------
998 !Set iotabar in private data
999 !-------------------------------------------------------------------------------
1000 !Initialize
1001 fspl(:,:)=0
1002 values(:,:)=0
1003 
1004 IF(k_pflx == 1) THEN
1005 
1006  !iotabar input
1007  fspl(1,1:nr_pflx)=pflx(1:nr_pflx)
1008 
1009 ELSEIF(k_pflx == 2) THEN
1010 
1011  !d(Psi)/d(rho) input
1012  fspl(1,1:nr_pflx)=pflx(1:nr_pflx)/rho_pflx(1:nr_pflx)
1013  fspl(1,1:nr_pflx)=rhomax_3d**2/phitot_3d/2*fspl(1,1:nr_pflx)
1014 
1015 ELSE
1016 
1017  !q input
1018  fspl(1,1:nr_pflx)=1/pflx(1:nr_pflx)
1019 
1020 ENDIF
1021 
1022 !Interpolate iotabar onto internal grid
1023 iflag=0
1024 message=''
1025 CALL spline1_interp(k_vopt,nr_pflx,rho_pflx,fspl,nrho_3d,rho_3d, &
1026  values,iflag,message, &
1027  k_bc1=k_bc1, &
1028  k_bcn=k_bcn)
1029 
1030 !Check messages
1031 IF(iflag > 0) THEN
1032 
1033  message='AJAX_LOAD_MAGFLUX(2) '// message
1034  GOTO 9999
1035 
1036 ENDIF
1037 
1038 !Get spline coefficients on internal grid
1039 iotabar_3d(:,:)=0
1040 iotabar_3d(1,1:nrho_3d)=values(1,1:nrho_3d)
1041 
1042 !If value at origin not supplied, overwrite with approximation
1043 IF(rho_pflx(1) > rhores_3d) THEN
1044 
1045  iotabar_3d(1,1)=iotabar_3d(2,1)-rho_3d(2)*(iotabar_3d(3,1)-iotabar_3d(2,1)) &
1046  /(rho_3d(3)-rho_3d(2))
1047 
1048 ENDIF
1049 
1050 CALL spline1_fit(nrho_3d,rho_3d,iotabar_3d, &
1051  k_bc1=k_bc1, &
1052  k_bcn=k_bcn)
1053 
1054 !-------------------------------------------------------------------------------
1055 !Set signs of poloidal and toroidal magnetic fields
1056 !-------------------------------------------------------------------------------
1057 signbt_3d=sign(1.0_rspec,phitot_3d)
1058 signbp_3d=sign(1.0_rspec,iotabar_3d(1,nrho_3d))*signbt_3d
1059 
1060 !-------------------------------------------------------------------------------
1061 !Set logical switches for flux surface averaging
1062 !-------------------------------------------------------------------------------
1063 l_fluxavb_3d=.false.
1064 
1065 !-------------------------------------------------------------------------------
1066 !Cleanup and exit
1067 !-------------------------------------------------------------------------------
1068 9999 CONTINUE
1069 
1070 END SUBROUTINE ajax_load_magflux
1071 
1072 SUBROUTINE ajax_car2cyl(r_car, &
1073  r_cyl)
1074 !-------------------------------------------------------------------------------
1075 !AJAX_CAR2CYL converts from Cartesian to cylindrical coordinates
1076 !
1077 !References:
1078 ! W.A.Houlberg, F90 free format 8/2004
1079 !-------------------------------------------------------------------------------
1080 
1081 !Declaration of input variables
1082 REAL(KIND=rspec), INTENT(IN) :: &
1083  r_car(:) !Cartesian coordinates (x,y,z) [m,m,m]
1084 
1085 !Declaration of output variables
1086 REAL(KIND=rspec), INTENT(OUT) :: &
1087  r_cyl(:) !cylindrical coordinates (R,phi,Z) [m,rad,m]
1088 
1089 !-------------------------------------------------------------------------------
1090 !Initialization
1091 !-------------------------------------------------------------------------------
1092 !Null output
1093 r_cyl(:)=0
1094 
1095 !-------------------------------------------------------------------------------
1096 !Cartesian to cylindrical conversion
1097 !-------------------------------------------------------------------------------
1098 r_cyl(1)=sqrt(r_car(1)**2+r_car(2)**2) !R
1099 r_cyl(2)=atan2(r_car(2),r_car(1)) !phi
1100 r_cyl(3)=r_car(3) !Z
1101 
1102 !Ensure 0 <= phi <= 2*pi
1103 IF(r_cyl(2) < 0.0) r_cyl(2)=r_cyl(2)+2*z_pi
1104 
1105 END SUBROUTINE ajax_car2cyl
1106 
1107 SUBROUTINE ajax_cyl2car(r_cyl, &
1108  r_car)
1109 !-------------------------------------------------------------------------------
1110 !AJAX_CYL2CAR converts from cylindrical to Cartesian coordinates
1111 !
1112 !References:
1113 ! W.A.Houlberg, F90 free format 8/2004
1114 !-------------------------------------------------------------------------------
1115 
1116 !Declaration of input variables
1117 REAL(KIND=rspec), INTENT(IN) :: &
1118  r_cyl(:) !cylindrical coordinates (R,phi,Z) [m,rad,m]
1119 
1120 !Declaration of output variables
1121 REAL(KIND=rspec), INTENT(OUT) :: &
1122  r_car(:) !Cartesian coordinates (x,y,z) [m,m,m]
1123 
1124 !-------------------------------------------------------------------------------
1125 !Initialization
1126 !-------------------------------------------------------------------------------
1127 !Null output
1128 r_car(:)=0
1129 
1130 !-------------------------------------------------------------------------------
1131 !Cylindrical to Cartesian conversion
1132 !-------------------------------------------------------------------------------
1133 r_car(1)=r_cyl(1)*cos(r_cyl(2)) !x
1134 r_car(2)=r_cyl(1)*sin(r_cyl(2)) !y
1135 r_car(3)=r_cyl(3) !z
1136 
1137 END SUBROUTINE ajax_cyl2car
1138 
1139 SUBROUTINE ajax_cyl2flx(r_cyl, &
1140  r_flx, &
1141  iflag,message, &
1142  G_CYL,GSQRT,TAU)
1143 !-------------------------------------------------------------------------------
1144 !AJAX_CYL2FLX converts from cylindrical to flux coordinates
1145 !
1146 !References:
1147 ! S.E.Attenberger, W.A.Houlberg, S.P.Hirshman J Comp Phys 72 (1987) 435
1148 ! W.A.Houlberg, F90 free format 8/2004
1149 !
1150 !Comments:
1151 ! The basic method is a Newton iteration in 2 dimensions
1152 ! Input values of r_flx are used as an initial guess
1153 ! Convergence is typically one order of magnitude reduction in the
1154 ! error in R and Z per iteration - should rarely exceed 5 iterations
1155 ! The toroidal angle in flux coordinates is the same as in cylindrical
1156 ! coordinates giving a right-handed system with positive Jacobian
1157 ! Point 0 is the previous best guess and point 1 is a trial point
1158 ! If point 1 is further from (R,Z) than point 0, a new trial point is
1159 ! generated by halving the step and using interpolated derivatives
1160 !-------------------------------------------------------------------------------
1161 
1162 !Declaration of input variables
1163 REAL(KIND=rspec), INTENT(IN) :: &
1164  r_cyl(:) !cylindrical coordinates (R,phi,Z) [m,rad,m]
1165 
1166 !Declaration of input/output variables
1167 REAL(KIND=rspec), INTENT(INOUT) :: &
1168  r_flx(:) !flux coordinates (rho,theta,zeta) [rho,rad,rad]
1169 
1170 !Declaration of output variables
1171 CHARACTER(LEN=1024), INTENT(OUT) :: &
1172  message !warning or error message [character]
1173 
1174 INTEGER, INTENT(OUT) :: &
1175  iflag !error and warning flag [-]
1176  !=-1 warning
1177  !=0 none
1178  !=1 error
1179 
1180 !Declaration of optional output variables
1181 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
1182  g_cyl(:), & !R,Z derivatives
1183  !=(R_rho,R_theta,R_zeta,Z_rho,Z_theta,Z_zeta)
1184  ! [m/rho,m, m, m/rho,m, m ]
1185  gsqrt, & !3D Jacobian [m**3/rho]
1186  tau !2D Jacobian in phi=zeta=constant plane [m**2/rho]
1187 
1188 !-------------------------------------------------------------------------------
1189 !Declaration of local variables
1190 INTEGER :: &
1191  it,itmax,nh
1192 
1193 REAL(KIND=rspec) :: &
1194  dr,dr0,dr1,dz,dz0,dz1,drho,dtheta,err0,err1,gsqrt1,tau0,tau1, &
1195  taut,tol
1196 
1197 REAL(KIND=rspec) :: &
1198  r_flx0(1:3),g_cyl0(1:6),r_flx1(1:3),r_cyl1(1:3),g_cyl1(1:6), &
1199  g_cylt(1:6)
1200 
1201 !-------------------------------------------------------------------------------
1202 !Initialization
1203 !-------------------------------------------------------------------------------
1204 !Null output
1205 iflag=0
1206 message=''
1207 
1208 !Coordinates and metrics for iteration
1209 r_flx0(:)=0
1210 g_cyl0(:)=0
1211 r_flx1(:)=0
1212 r_cyl1(:)=0
1213 g_cyl1(:)=0
1214 g_cylt(:)=0
1215 
1216 !Tolerance for convergence
1217 tol=0.1*rhores_3d/rhomax_3d
1218 
1219 !Maximum iterations
1220 itmax=20
1221 
1222 !Grid halving index
1223 nh=1
1224 
1225 !Set flux coordinate toroidal angle equal to cylindrical angle
1226 r_flx(3)=r_cyl(2)
1227 
1228 !Set starting points and parameters
1229 tau0=0
1230 err0=0.1*z_large
1231 r_flx0(1:3)=r_flx(1:3)
1232 r_flx1(1:3)=r_flx(1:3)
1233 
1234 !Move rho away from axis if necessary
1235 IF(r_flx1(1) < rhores_3d) r_flx1(1)=rhores_3d
1236 
1237 !-------------------------------------------------------------------------------
1238 !Iterate to find flux coordinates
1239 !-------------------------------------------------------------------------------
1240 DO it=1,itmax !Over iteration
1241 
1242  !Get cylindrical coordinates at point 1
1243  iflag=0
1244  message=''
1245  CALL ajax_flx2cyl(r_flx1,r_cyl1,iflag,message, &
1246  g_cyl=g_cyl1, &
1247  gsqrt=gsqrt1, &
1248  tau=tau1)
1249 
1250  !Check messages
1251  IF(iflag /= 0) THEN
1252 
1253  message='AJAX_CYL2FLX(1) '// message
1254  IF(iflag > 0) GOTO 9999
1255 
1256  ENDIF
1257 
1258  dr1=(r_cyl(1)-r_cyl1(1))
1259  dz1=(r_cyl(3)-r_cyl1(3))
1260  err1=(dr1**2+dz1**2)/r000_3d**2
1261 
1262  !Check convergence
1263  IF((abs(dr1) <= tol*r000_3d .AND. abs(dz1) <= tol*r000_3d) &
1264  .OR. (abs(err1-err0) < 5.0e-6)) THEN
1265 
1266  !Converged, but first check if solution is in the R,Z domain
1267  IF(r_flx1(1) > rhomax_3d) THEN
1268 
1269  iflag=-1
1270  message='AJAX_CYL2FLX(2)/WARNING:outside R,Z domain'
1271 
1272  ENDIF
1273 
1274  !Solution is at point 1, copy to output arrays and exit
1275  r_flx(1:3)=r_flx1(1:3)
1276  IF(r_flx(2) < 0.0) r_flx(2)=r_flx(2)+2*z_pi
1277  r_flx(2)=mod(r_flx(2),2*z_pi)
1278  IF(PRESENT(gsqrt)) gsqrt=gsqrt1
1279  IF(PRESENT(g_cyl)) g_cyl(:)=g_cyl1(:)
1280  IF(PRESENT(tau)) tau=tau1
1281  GOTO 9999
1282 
1283  ENDIF
1284 
1285  !Need improved estimate for rho and theta and get new Jacobian
1286  IF(r_flx1(1) < rhores_3d) r_flx1(1)=rhores_3d
1287 
1288  IF(abs(tau1) < 10*z_small) THEN
1289 
1290  !No solution exists for the Newton method
1291  !Assume the solution is at the origin where tau=0
1292  iflag=-1
1293  message='AJAX_CYL2FLX(3)/WARNING:solution at origin'
1294  r_flx(1)=0
1295  r_flx(2)=0
1296 
1297  ENDIF
1298 
1299  !Check consistency of sign of Jacobian
1300  IF(sign(1.0_rspec,tau1) /= sign(1.0_rspec,tau0) .AND. tau0 /= 0.0) THEN
1301 
1302  !Bad data
1303  iflag=1
1304  message='AJAX_CYL2FLX(4)/ERROR:bad Jacobian'
1305  GOTO 9999
1306 
1307  ENDIF
1308 
1309  !Check whether convergence is improving
1310  IF(err1 < err0) THEN
1311 
1312  !Converging, double step if possible and set point 0 = point 1
1313  IF(nh > 1) nh=nh/2
1314  r_flx0(:)=r_flx1(:)
1315  g_cyl0(:)=g_cyl1(:)
1316  err0=err1
1317  tau0=tau1
1318  dr0=dr1
1319  dz0=dz1
1320 
1321  ELSE
1322 
1323  !Not converging - halve step
1324  nh=nh*2
1325 
1326  ENDIF
1327 
1328  !Calculate new rho and theta steps
1329  !Use empirical combination of last two steps to avoid oscillation
1330  !0 and 1 may coincide here
1331  g_cylt(:)=0.75*g_cyl0(:)+0.25*g_cyl1(:)
1332  taut=0.75*tau0+0.25*tau1
1333  dr=dr0/nh
1334  dz=dz0/nh
1335 
1336  !Project to desired point using Jacobian information
1337  !drho=(R_theta*dZ-Z_theta*dR)/tau
1338  drho=(g_cylt(2)*dz-g_cylt(5)*dr)/taut
1339  !dtheta=(Z_rho*dR-R_rho*dZ)/tau
1340  dtheta=(g_cylt(4)*dr-g_cylt(1)*dz)/taut
1341  IF(abs(dtheta) > z_pi/4) dtheta=sign(z_pi/4,dtheta)
1342 
1343  !Set flux coordinates for new point 1
1344  r_flx1(1)=r_flx0(1)+drho
1345  r_flx1(2)=r_flx0(2)+dtheta
1346 
1347  IF(r_flx1(1) < 0.0) THEN
1348 
1349  !Stepped past minor axis, flip flux coordinates
1350  r_flx1(1)=-r_flx1(1)
1351  r_flx1(2)=r_flx1(2)+z_pi-2*dtheta
1352 
1353  ENDIF
1354 
1355 ENDDO !Over iteration
1356 
1357 !Exceeded maximum iterations
1358 iflag=1
1359 message='AJAX_CYL2FLX(5)/ERROR:max iterations exceeded'
1360 
1361 !-------------------------------------------------------------------------------
1362 !Cleanup and exit
1363 !-------------------------------------------------------------------------------
1364 9999 CONTINUE
1365 
1366 END SUBROUTINE ajax_cyl2flx
1367 
1368 SUBROUTINE ajax_flx2cyl(r_flx, &
1369  r_cyl,iflag,message, &
1370  G_CYL,GSQRT,TAU)
1371 !-------------------------------------------------------------------------------
1372 !AJAX_FLX2CYL converts from flux to cylindrical coordinates
1373 !
1374 !References:
1375 ! S.E.Attenberger, W.A.Houlberg, S.P.Hirshman J Comp Phys 72 (1987) 435
1376 ! W.A.Houlberg, F90 free format 8/2004
1377 !
1378 !Comments:
1379 ! The representation is extended beyond the rho_3d grid by linear
1380 ! extrapolation of the m=1, n=0 term in rho, with all other terms
1381 ! held fixed at the edge value
1382 ! This permits unique representation of all space for flux surfaces
1383 ! that are everywhere convex (does not include bean-shapes)
1384 ! rho**m is factored out of the Fourier coefficients prior to spline
1385 ! fitting for increased accuracy near the origin
1386 ! Mode filtering is used to improve calculations near the axis and the outer
1387 ! boundary
1388 !-------------------------------------------------------------------------------
1389 
1390 !Declaration of input variables
1391 REAL(KIND=rspec), INTENT(IN) :: &
1392  r_flx(:) !flux coordinates (rho,theta,zeta) [rho,rad,rad]
1393 
1394 !Declaration of output variables
1395 CHARACTER(LEN=1024), INTENT(OUT) :: &
1396  message !warning or error message [character]
1397 
1398 INTEGER, INTENT(OUT) :: &
1399  iflag !error and warning flag [-]
1400  !=-1 warning
1401  !=0 none
1402  !=1 error
1403 
1404 REAL(KIND=rspec), INTENT(OUT) :: &
1405  r_cyl(:) !cylindrical coordinates (R,phi,Z) [m,rad,m]
1406 
1407 !Declaration of optional output variables
1408 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
1409  g_cyl(:), & !R,Z derivatives
1410  !=(R_rho,R_theta,R_zeta,Z_rho,Z_theta,Z_zeta)
1411  ! [m/rho,m, m, m/rho,m, m ]
1412  gsqrt, & !3D Jacobian [m**3/rho]
1413  tau !2D Jacobian in phi=zeta=constant plane [m**2/rho]
1414 
1415 !-------------------------------------------------------------------------------
1416 !Declaration of local variables
1417 INTEGER :: &
1418  k
1419 
1420 INTEGER, SAVE :: &
1421  i=1
1422 
1423 INTEGER, PARAMETER :: &
1424  k_vopt(1:3)=(/1,1,0/)
1425 
1426 REAL(KIND=rspec) :: &
1427  ct,st,rho,rhom,drhom,rmnx,drmnx,zmnx,dzmnx,g_cylt(1:6),value(1:3)
1428 
1429 !-------------------------------------------------------------------------------
1430 !Initialization
1431 !-------------------------------------------------------------------------------
1432 !Null output
1433 iflag=0
1434 message=''
1435 r_cyl(:)=0
1436 
1437 !Null local values
1438 g_cylt(:)=0
1439 value(:)=0
1440 
1441 !phi = zeta
1442 r_cyl(2)=r_flx(3)
1443 
1444 !Limit to R,Z domain
1445 rho=min(r_flx(1),rhomax_3d)
1446 
1447 !Axial resolution
1448 rho=max(rho,rhores_3d)
1449 
1450 !-------------------------------------------------------------------------------
1451 !Evaluate R,Z and derivatives
1452 !-------------------------------------------------------------------------------
1453 !Loop over modes
1454 DO k=1,krz_3d !Over modes
1455 
1456  !Set sine and cosine values
1457  ct=cos(m_3d(k)*r_flx(2)-n_3d(k)*r_flx(3))
1458  st=sin(m_3d(k)*r_flx(2)-n_3d(k)*r_flx(3))
1459 
1460  !Calculate rho**m and its derivative
1461  IF(mabs_3d(k) == 0) THEN
1462 
1463  !rho**0
1464  rhom=1
1465  drhom=0
1466 
1467  ELSEIF(r_flx(1) < rhomax_3d+rhores_3d) THEN
1468 
1469  !Inside last closed surface, rho**|m|
1470  rhom=rho**mabs_3d(k)
1471  drhom=mabs_3d(k)*rho**(mabs_3d(k)-1)
1472 
1473  ELSE
1474 
1475  !Outside last closed surface, rhomax**|m|
1476  rhom=rhomax_3d**mabs_3d(k)
1477  drhom=0
1478 
1479  ENDIF
1480 
1481  !R_mn and dR_mn/drho from spline fits
1482  CALL spline1_eval(k_vopt,nrho_3d,rho,rho_3d, &
1483  r_3d(1:4,1:nrho_3d,k),i,value)
1484  rmnx=value(1)
1485  drmnx=value(2)
1486 
1487  !Z_mn and dZ_mn/drho from spline fits
1488  CALL spline1_eval(k_vopt,nrho_3d,rho,rho_3d,z_3d(1:4,1:nrho_3d,k),i,value)
1489  zmnx=value(1)
1490  dzmnx=value(2)
1491 
1492  !R = sum_mn [ R_mn * cos(m*theta-n*zeta) * rho**m ]
1493  r_cyl(1)=r_cyl(1)+rmnx*ct*rhom
1494 
1495  !Z = sum_mn [ Z_mn * sin(m*theta-n*zeta) * rho**m ]
1496  r_cyl(3)=r_cyl(3)+zmnx*st*rhom
1497 
1498  !dR/dtheta = sum_mn [ -m * R_mn * sin(m*theta-n*zeta) * rho**m ]
1499  g_cylt(2)=g_cylt(2)-m_3d(k)*rmnx*st*rhom
1500 
1501  !dR/dzeta = sum_mn [ n * R_mn * sin(m*theta-n*zeta) * rho**m ]
1502  g_cylt(3)=g_cylt(3)+n_3d(k)*rmnx*st*rhom
1503 
1504  !dZ/dtheta = sum_mn [ m * Z_mn * cos(m*theta-n*zeta) * rho**m ]
1505  g_cylt(5)=g_cylt(5)+m_3d(k)*zmnx*ct*rhom
1506 
1507  !dZ/dtheta = sum_mn [ -n * Z_mn * cos(m*theta-n*zeta) * rho**m ]
1508  g_cylt(6)=g_cylt(6)-n_3d(k)*zmnx*ct*rhom
1509 
1510  !Radial derivatives inside R,Z domain
1511  IF(r_flx(1) <= rhomax_3d+rhores_3d) THEN
1512 
1513  !dR/drho = sum_mn [ rho**m * dR_mn/drho + R_mn *d(rho**m)/drho ]
1514  ! * cos(m*theta-n*zeta)
1515  g_cylt(1)=g_cylt(1)+(drmnx*rhom+rmnx*drhom)*ct
1516 
1517  !dZ/drho = sum_mn [ rho**m * dZ_mn/drho + Z_mn *d(rho**m)/drho ]
1518  ! * sin(m*theta-n*zeta)
1519  g_cylt(4)=g_cylt(4)+(dzmnx*rhom+zmnx*drhom)*st
1520 
1521  ENDIF
1522 
1523 ENDDO !Over modes
1524 
1525 !Radial derivatives outside R,Z domain
1526 IF(r_flx(1) > rhomax_3d+rhores_3d) THEN
1527 
1528  !This point is off the grid toward the wall
1529  ct=cos(m_3d(km1n0_3d)*r_flx(2))
1530  st=sin(m_3d(km1n0_3d)*r_flx(2))
1531  r_cyl(1)=r_cyl(1)+(r_flx(1)-rhomax_3d)*r_3d(1,nrho_3d,km1n0_3d)*ct
1532  r_cyl(3)=r_cyl(3)+(r_flx(1)-rhomax_3d)*z_3d(1,nrho_3d,km1n0_3d)*st
1533  g_cylt(1)=r_3d(1,nrho_3d,km1n0_3d)*ct
1534  g_cylt(2)=g_cylt(2)-(r_flx(1)-rhomax_3d)*r_3d(1,nrho_3d,km1n0_3d)*st &
1535  *m_3d(km1n0_3d)
1536  g_cylt(4)=z_3d(1,nrho_3d,km1n0_3d)*st
1537  g_cylt(5)=g_cylt(5)+(r_flx(1)-rhomax_3d)*z_3d(1,nrho_3d,km1n0_3d)*ct &
1538  *m_3d(km1n0_3d)
1539 
1540 ENDIF
1541 
1542 !-------------------------------------------------------------------------------
1543 !Optional output
1544 !-------------------------------------------------------------------------------
1545 !R,Z derivatives
1546 IF(PRESENT(g_cyl)) g_cyl(:)=g_cylt(:)
1547 
1548 !2D Jacobian = dR/dtheta * dZ/drho - dR/drho * dZ/dtheta
1549 IF(PRESENT(tau)) tau=g_cylt(2)*g_cylt(4)-g_cylt(1)*g_cylt(5)
1550 
1551 !3D Jacobian = R * tau
1552 IF(PRESENT(gsqrt)) gsqrt=r_cyl(1)*(g_cylt(2)*g_cylt(4)-g_cylt(1)*g_cylt(5))
1553 
1554 END SUBROUTINE ajax_flx2cyl
1555 
1556 SUBROUTINE ajax_b(r_flx,r_cyl,g_cyl, &
1557  iflag,message, &
1558  B_CON,B_CO,B_CYL,B_CAR,B_POL,B_TOR,B_MOD)
1559 !-------------------------------------------------------------------------------
1560 !AJAX_B gets components of B in various forms
1561 !
1562 !References:
1563 ! S.E.Attenberger, W.A.Houlberg, S.P.Hirshman, J Comp Phys 72 (1987) 435
1564 ! W.A.Houlberg, F90 free format 8/2004
1565 !-------------------------------------------------------------------------------
1566 
1567 !Declaration of input variables
1568 REAL(KIND=rspec), INTENT(IN) :: &
1569  r_flx(:), & !flux coordinates (rho,theta,zeta) [rho,rad,rad]
1570  r_cyl(:), & !cylindrical coordinates (R,phi,Z) [m,rad,m]
1571  g_cyl(:) !R,Z derivatives
1572  !=(R_rho,R_theta,R_zeta,Z_rho,Z_theta,Z_zeta)
1573  ! [m/rho,m, m, m/rho,m, m ]
1574 
1575 !Declaration of output variables
1576 CHARACTER(LEN=1024), INTENT(OUT) :: &
1577  message !warning or error message [character]
1578 
1579 INTEGER, INTENT(OUT) :: &
1580  iflag !error and warning flag [-]
1581  !=-1 warning
1582  !=0 none
1583  !=1 error
1584 
1585 !Declaration of optional output variables
1586 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
1587  b_con(:), & !contravariant (B^rho,B^theta,B^zeta) [T*rho/m,T/m,T/m]
1588  b_co(:), & !covariant (B_rho,B_theta,B_zeta) [T*m/rho,T*m,T*m]
1589  b_cyl(:), & !cylindrical (B_R,B_phi,B_Z) [T,T,T]
1590  b_car(:), & !Cartesian (B_x,B_y,B_z) [T,T,T]
1591  b_pol, & !poloidal field [T]
1592  b_tor, & !toroidal field [T]
1593  b_mod !|B| [T]
1594 
1595 !-------------------------------------------------------------------------------
1596 !Declaration of local variables
1597 REAL(KIND=rspec) :: &
1598  gsqrt,iotabar(1),phiprm(1),lam_theta,lam_zeta,b_cont(1:3), &
1599  b_cylt(1:3)
1600 
1601 !-------------------------------------------------------------------------------
1602 !Initialization
1603 !-------------------------------------------------------------------------------
1604 !Null output
1605 iflag=0
1606 message=''
1607 
1608 !-------------------------------------------------------------------------------
1609 !Set primary variables
1610 !-------------------------------------------------------------------------------
1611 !3D Jacobian = R * (dR/dtheta * dZ/drho - dR/drho * dZ/dtheta)
1612 gsqrt=r_cyl(1)*(g_cyl(2)*g_cyl(4)-g_cyl(1)*g_cyl(5))
1613 
1614 !Magnetic stream function derivatives
1615 CALL ajax_lambda(r_flx, &
1616  lam_theta,lam_zeta)
1617 
1618 !Rotational transform and derivative of toroidal flux
1619 CALL ajax_magflux(1,r_flx, &
1620  iflag,message, &
1621  iotabar_r=iotabar, &
1622  phiprm_r=phiprm)
1623 
1624 !Check messages
1625 IF(iflag /= 0) THEN
1626 
1627  message='AJAX_B '// message
1628  IF (iflag > 0 ) GOTO 9999
1629 
1630 ENDIF
1631 
1632 !-------------------------------------------------------------------------------
1633 !Contravariant components
1634 !-------------------------------------------------------------------------------
1635 !B^rho
1636 b_cont(1)=0
1637 
1638 !B^theta
1639 b_cont(2)=phiprm(1)*(iotabar(1)-lam_zeta)/(2*z_pi*gsqrt)
1640 
1641 !B^zeta
1642 b_cont(3)=phiprm(1)*(1.0_rspec+lam_theta)/(2*z_pi*gsqrt)
1643 
1644 IF(PRESENT(b_con)) b_con(1:3)=b_cont(1:3)
1645 
1646 !-------------------------------------------------------------------------------
1647 !Cylindrical components
1648 !-------------------------------------------------------------------------------
1649 IF(PRESENT(b_cyl) .OR. &
1650  PRESENT(b_co) .OR. &
1651  PRESENT(b_car) .OR. &
1652  PRESENT(b_pol) .OR. &
1653  PRESENT(b_tor) .OR. &
1654  PRESENT(b_mod)) THEN
1655 
1656  !B_R
1657  b_cylt(1)=g_cyl(2)*b_cont(2)+g_cyl(3)*b_cont(3)
1658 
1659  !B_phi
1660  b_cylt(2)=r_cyl(1)*b_cont(3)
1661 
1662  !B_Z
1663  b_cylt(3)=g_cyl(5)*b_cont(2)+g_cyl(6)*b_cont(3)
1664 
1665  IF(PRESENT(b_cyl)) b_cyl(1:3)=b_cylt(1:3)
1666 
1667  !-------------------------------------------------------------------------------
1668  !Covariant components
1669  !-------------------------------------------------------------------------------
1670  IF(PRESENT(b_co)) THEN
1671 
1672  !B_rho
1673  b_co(1)=b_cylt(1)*g_cyl(1)+b_cylt(3)*g_cyl(4)
1674 
1675  !B_theta
1676  b_co(2)=b_cylt(1)*g_cyl(2)+b_cylt(3)*g_cyl(5)
1677 
1678  !B_zeta
1679  b_co(3)=b_cylt(1)*g_cyl(3)+b_cylt(2)*r_cyl(1)+b_cylt(3)*g_cyl(6)
1680 
1681  ENDIF
1682 
1683  !-------------------------------------------------------------------------------
1684  !Cartesian components
1685  !-------------------------------------------------------------------------------
1686  IF(PRESENT(b_car)) THEN
1687 
1688  !B_x
1689  b_car(1)=b_cylt(1)*cos(r_cyl(2))-b_cylt(2)*sin(r_cyl(2))
1690 
1691  !B_y
1692  b_car(2)=b_cylt(1)*sin(r_cyl(2))+b_cylt(2)*cos(r_cyl(2))
1693 
1694  !B_z
1695  b_car(3)=b_cylt(3)
1696 
1697  ENDIF
1698 
1699  !-------------------------------------------------------------------------------
1700  !Poloidal field
1701  !-------------------------------------------------------------------------------
1702  IF(PRESENT(b_pol)) THEN
1703 
1704  !B_pol
1705  b_pol=signbp_3d*sqrt(b_cylt(1)**2+b_cylt(3)**2)
1706 
1707  ENDIF
1708 
1709  !-------------------------------------------------------------------------------
1710  !Toroidal field
1711  !-------------------------------------------------------------------------------
1712  IF(PRESENT(b_tor)) THEN
1713 
1714  !B_tor
1715  b_tor=b_cylt(2)
1716 
1717  ENDIF
1718 
1719  !-------------------------------------------------------------------------------
1720  !|B|
1721  !-------------------------------------------------------------------------------
1722  IF(PRESENT(b_mod)) THEN
1723 
1724  !B_mod
1725  b_mod=sqrt(b_cylt(1)**2+b_cylt(2)**2+b_cylt(3)**2)
1726 
1727  ENDIF
1728 
1729 ENDIF
1730 
1731 !-------------------------------------------------------------------------------
1732 !Cleanup and exit
1733 !-------------------------------------------------------------------------------
1734 9999 CONTINUE
1735 
1736 END SUBROUTINE ajax_b
1737 
1738 SUBROUTINE ajax_lambda(r_flx, &
1739  lam_theta,lam_zeta)
1740 !-------------------------------------------------------------------------------
1741 !AJAX_LAMBDA gets the stream function and its derivatives
1742 !
1743 !References:
1744 ! S.E.Attenberger, W.A.Houlberg, S.P.Hirshman, J Comp Phys 72 (1987) 435
1745 ! W.A.Houlberg, F90 free format 8/2004
1746 !
1747 !Comments:
1748 ! Mode filtering is used to improve calculations near the axis and the outer
1749 ! boundary
1750 !-------------------------------------------------------------------------------
1751 
1752 !Declaration of input variables
1753 REAL(KIND=rspec), INTENT(IN) :: &
1754  r_flx(:) !flux coordinates (rho,theta,zeta) [rho,rad,rad]
1755 
1756 !Declaration of output variables
1757 REAL(KIND=rspec), INTENT(OUT) :: &
1758  lam_theta, & !d(lambda)/d(theta) [/rad]
1759  lam_zeta !d(lambda)/d(zeta) [/rad]
1760 
1761 !-------------------------------------------------------------------------------
1762 !Declaration of local variables
1763 INTEGER, PARAMETER :: &
1764  k_vopt(1:3)=(/1,0,0/)
1765 
1766 INTEGER, SAVE :: &
1767  i=1
1768 
1769 INTEGER :: &
1770  k
1771 
1772 REAL(KIND=rspec) :: &
1773  value(1:3),cosk,lam,rho
1774 
1775 !-------------------------------------------------------------------------------
1776 !Initialization
1777 !-------------------------------------------------------------------------------
1778 !Null output
1779 lam_theta=0
1780 lam_zeta=0
1781 
1782 !Spline values
1783 value(:)=0
1784 
1785 !Limit to R,Z domain
1786 rho=min(r_flx(1),rhomax_3d)
1787 
1788 !Axial resolution
1789 rho=max(rho,rhores_3d)
1790 
1791 !-------------------------------------------------------------------------------
1792 !Calculate derivatives of the magnetic stream function
1793 !-------------------------------------------------------------------------------
1794 !Loop over the modes
1795 DO k=1,klam_3d !Over modes
1796 
1797  cosk=cos(m_3d(k)*r_flx(2)-n_3d(k)*r_flx(3))
1798  CALL spline1_eval(k_vopt,nrho_3d,rho,rho_3d,lam_3d(1:4,1:nrho_3d,k),i,value)
1799  !Reintroduce normalization
1800  lam=value(1)*rho**mabs_3d(k)
1801  lam_theta=lam_theta+lam*m_3d(k)*cosk
1802  lam_zeta=lam_zeta-lam*n_3d(k)*cosk
1803 
1804 ENDDO !Over modes
1805 
1806 END SUBROUTINE ajax_lambda
1807 
1808 SUBROUTINE ajax_fluxav_b(nrho_r,rho_r, &
1809  iflag,message, &
1810  B2_R,BM2_R,FM_R,FTRAP_R,GR2BM2_R,GRTH_R,SUS11_R, &
1811  SUS12_R,SUS21_R,SUS22_R)
1812 !-------------------------------------------------------------------------------
1813 !AJAX_FLUXAV_B gets flux surface quantities that depend on B
1814 !
1815 !References:
1816 ! W.A.Houlberg, F90 free format 8/2004
1817 !-------------------------------------------------------------------------------
1818 
1819 !Declaration of input variables
1820 INTEGER, INTENT(IN) :: &
1821  nrho_r !no. of radial nodes [-]
1822 
1823 REAL(KIND=rspec), INTENT(IN) :: &
1824  rho_r(:) !radial nodes [rho]
1825 
1826 !Declaration of output variables
1827 CHARACTER(LEN=1024), INTENT(OUT) :: &
1828  message !warning or error message [character]
1829 
1830 INTEGER, INTENT(OUT) :: &
1831  iflag !error and warning flag [-]
1832  !=-1 warning
1833  !=0 none
1834  !=1 error
1835 
1836 !Declaration of optional output variables
1837 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
1838  b2_r(:), &
1839  bm2_r(:), &
1840  fm_r(:,:), & !poloidal moments of <[n.grad(B)]**2>/<B**2> [-]
1841  ftrap_r(:), & !trapped particle fraction [-]
1842  gr2bm2_r(:), &
1843  grth_r(:), & !n.grad(Theta) [/m]
1844  sus11_r(:), & !suceptance matrix element 11 (pol-pol) [-]
1845  sus12_r(:), & !suceptance matrix element 12 (pol-tor) [-]
1846  sus21_r(:), & !suceptance matrix element 21 (tor-pol) [-]
1847  sus22_r(:) !suceptance matrix element 22 (tor-tor) [-]
1848 
1849 !-------------------------------------------------------------------------------
1850 !Declaration of local variables
1851 INTEGER :: &
1852  i,j,k,m,nr
1853 
1854 REAL(KIND=rspec) :: &
1855  dbdt,h
1856 
1857 REAL(KIND=rspec) :: &
1858  b(1:nrho_3d),b2(1:nrho_3d),bmax(1:nrho_3d), &
1859  captheta(1:nrho_3d,1:ntheta_3d), &
1860  gam(1:nrho_3d),v1(1:nrho_3d),v2(1:nrho_3d)
1861 
1862 REAL(KIND=rspec) :: &
1863  v_r(1:nrho_r)
1864 
1865 !-------------------------------------------------------------------------------
1866 !Initialization
1867 !-------------------------------------------------------------------------------
1868 !Null output
1869 iflag=0
1870 message=''
1871 
1872 !-------------------------------------------------------------------------------
1873 !Check whether flux surface averaging arrays have been set
1874 !-------------------------------------------------------------------------------
1875 IF(.NOT. l_fluxavg_3d) THEN
1876 
1877  iflag=0
1878  message=''
1879  CALL ajax_init_fluxav_g(iflag,message)
1880 
1881  !Check messages
1882  IF(iflag /= 0) THEN
1883 
1884  message='AJAX_FLUXAV_B(1) ' // message
1885  GOTO 9999
1886 
1887  ENDIF
1888 
1889 ENDIF
1890 
1891 IF(.NOT. l_fluxavb_3d) CALL ajax_init_fluxav_b
1892 
1893 !-------------------------------------------------------------------------------
1894 !Check whether values outside R,Z domain are requested (nr is last point inside)
1895 !-------------------------------------------------------------------------------
1896 loop_i1: DO i=nrho_r,1,-1
1897 
1898  nr=i
1899  IF(rho_r(nr) < rhomax_3d+rhores_3d) EXIT loop_i1
1900 
1901 ENDDO loop_i1
1902 
1903 !-------------------------------------------------------------------------------
1904 
1905 !-------------------------------------------------------------------------------
1906 IF(PRESENT(b2_r) .OR. &
1907  PRESENT(fm_r) .OR. &
1908  PRESENT(ftrap_r)) THEN
1909 
1910  !Initialization
1911  b2(:)=0
1912  gt_3d(:)=0
1913  az_3d(:)=0
1914 
1915  !Calculate on internal grid
1916  DO i=2,nrho_3d !Over radial nodes
1917 
1918  DO k=1,nzeta_3d !Over toroidal nodes
1919 
1920  gt_3d(1:ntheta_3d)=gsqrt_3d(i,1:ntheta_3d,k)*b_3d(i,1:ntheta_3d,k)**2
1921  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
1922 
1923  ENDDO !Over toroidal nodes
1924 
1925  b2(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
1926 
1927  ENDDO !Over radial nodes
1928 
1929  !Extrapolate to axis
1930  b2(1)=b2(2)-rho_3d(2)*(b2(3)-b2(2))/(rho_3d(3)-rho_3d(2))
1931 
1932 ENDIF
1933 
1934 !-------------------------------------------------------------------------------
1935 !Theta and gam=n.grad(Theta) for Fm and n.grad(Theta) in axisymmetric plasmas
1936 !-------------------------------------------------------------------------------
1937 IF((PRESENT(fm_r) .OR. &
1938  PRESENT(grth_r)) .AND. &
1939  nper_3d == 0) THEN
1940 
1941  !Initialization
1942  captheta(:,:)=0
1943  gam(:)=0
1944 
1945  !Calculate on internal grid
1946  DO i=2,nrho_3d !Over radial nodes
1947 
1948  DO j=2,ntheta_3d !Over poloidal nodes
1949 
1950  captheta(i,j)=captheta(i,j-1)+dtheta_3d/2 &
1951  *(b_3d(i,j-1,1)/btheta_3d(i,j-1,1) &
1952  +b_3d(i,j,1)/btheta_3d(i,j,1))
1953 
1954  ENDDO !Over poloidal nodes
1955 
1956  gam(i)=2*z_pi/captheta(i,ntheta_3d)
1957  captheta(i,1:ntheta_3d)=gam(i)*captheta(i,1:ntheta_3d)
1958 
1959  ENDDO !Over radial nodes
1960 
1961  !Extrapolate to axis
1962  gam(1)=gam(2)-rho_3d(2)*(gam(3)-gam(2))/(rho_3d(3)-rho_3d(2))
1963 
1964 ENDIF
1965 
1966 !-------------------------------------------------------------------------------
1967 
1968 !-------------------------------------------------------------------------------
1969 IF(PRESENT(b2_r)) THEN
1970 
1971  !Initialization
1972  b2_r(1:nrho_r)=0
1973 
1974  !Interpolate to user grid inside R,Z domain
1975  iflag=0
1976  message=''
1977  CALL linear1_interp(nrho_3d,rho_3d,b2,nr,rho_r,b2_r,iflag,message)
1978 
1979  !Check messages
1980  IF(iflag /= 0) THEN
1981 
1982  message='AJAX_FLUXAV_B(2) ' // message
1983  IF(iflag > 0) GOTO 9999
1984 
1985  ENDIF
1986 
1987  IF(nr < nrho_r) THEN
1988 
1989  !Extrapolate to user grid outside R,Z domain
1990  b2_r(nr+1:nrho_r)=b2_r(nr)
1991 
1992  ENDIF
1993 
1994 ENDIF
1995 
1996 !-------------------------------------------------------------------------------
1997 
1998 !-------------------------------------------------------------------------------
1999 IF(PRESENT(bm2_r)) THEN
2000 
2001  !Initialization
2002  bm2_r(1:nrho_r)=0
2003  gt_3d(:)=0
2004  az_3d(:)=0
2005  v1(:)=0
2006 
2007  !Calculate on internal grid
2008  DO i=2,nrho_3d !Over radial nodes
2009 
2010  DO k=1,nzeta_3d !Over toroidal nodes
2011 
2012  gt_3d(1:ntheta_3d)=gsqrt_3d(i,1:ntheta_3d,k)/b_3d(i,1:ntheta_3d,k)**2
2013  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2014 
2015  ENDDO !Over toroidal nodes
2016 
2017  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2018 
2019  ENDDO !Over radial nodes
2020 
2021  !Extrapolate to axis
2022  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2023 
2024  !Interpolate to user grid inside R,Z domain
2025  iflag=0
2026  message=''
2027  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,bm2_r,iflag,message)
2028 
2029  !Check messages
2030  IF(iflag /= 0) THEN
2031 
2032  message='AJAX_FLUXAV_B(3) ' // message
2033  IF(iflag > 0) GOTO 9999
2034 
2035  ENDIF
2036 
2037  IF(nr < nrho_r) THEN
2038 
2039  !Extrapolate to user grid outside R,Z domain
2040  bm2_r(nr+1:nrho_r)=bm2_r(nr)
2041 
2042  ENDIF
2043 
2044 ENDIF
2045 
2046 !-------------------------------------------------------------------------------
2047 
2048 !-------------------------------------------------------------------------------
2049 IF(PRESENT(gr2bm2_r)) THEN
2050 
2051  !Initialization
2052  gr2bm2_r(1:nrho_r)=0
2053  gt_3d(:)=0
2054  az_3d(:)=0
2055  v1(:)=0
2056 
2057  DO i=2,nrho_3d !Over radial nodes
2058 
2059  DO k=1,nzeta_3d !Over toroidal nodes
2060 
2061  gt_3d(1:ntheta_3d)=((gcyl_3d(3,i,1:ntheta_3d,k) &
2062  *gcyl_3d(5,i,1:ntheta_3d,k) &
2063  -gcyl_3d(2,i,1:ntheta_3d,k) &
2064  *gcyl_3d(6,i,1:ntheta_3d,k))**2 &
2065  +rcyl_3d(i,1:ntheta_3d,k)**2 &
2066  *(gcyl_3d(2,i,1:ntheta_3d,k)**2 &
2067  +gcyl_3d(5,i,1:ntheta_3d,k)**2)) &
2068  /gsqrt_3d(i,1:ntheta_3d,k)/b_3d(i,1:ntheta_3d,k)**2
2069  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2070 
2071  ENDDO !Over toroidal nodes
2072 
2073  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2074 
2075  ENDDO !Over radial nodes
2076 
2077  !Extrapolate to axis
2078  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2079 
2080  !Interpolate to user grid inside R,Z domain
2081  iflag=0
2082  message=''
2083  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,gr2bm2_r,iflag,message)
2084 
2085  !Check messages
2086  IF(iflag /= 0) THEN
2087 
2088  message='AJAX_FLUXAV_B(4) ' // message
2089  IF(iflag > 0) GOTO 9999
2090 
2091  ENDIF
2092 
2093  IF(nr < nrho_r) THEN
2094 
2095  !Extrapolate to user grid outside R,Z domain
2096  gr2bm2_r(nr+1:nrho_r)=gr2bm2_r(nr)
2097 
2098  ENDIF
2099 
2100 ENDIF
2101 
2102 !-------------------------------------------------------------------------------
2103 !f_trap
2104 !-------------------------------------------------------------------------------
2105 IF(PRESENT(ftrap_r)) THEN
2106 
2107  !Initialization
2108  ftrap_r(1:nrho_r)=0
2109  gt_3d(:)=0
2110  az_3d(:)=0
2111  b(:)=0
2112  bmax(:)=0
2113  v1(:)=0
2114 
2115 
2116  DO i=2,nrho_3d !Over radial nodes
2117 
2118  DO k=1,nzeta_3d !Over toroidal nodes
2119 
2120  DO j=1,ntheta_3d !Over poloidal nodes
2121 
2122  gt_3d(j)=b_3d(i,j,k)*gsqrt_3d(i,j,k)
2123  IF(b_3d(i,j,k) > bmax(i)) bmax(i)=b_3d(i,j,k)
2124 
2125  ENDDO !Over poloidal nodes
2126 
2127  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2128 
2129  ENDDO !Over toroidal nodes
2130 
2131  b(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2132 
2133  ENDDO !Over radial nodes
2134 
2135  !Extrapolate to axis
2136  b(1)=b(2)-rho_3d(2)*(b(3)-b(2))/(rho_3d(3)-rho_3d(2))
2137  bmax(1)=bmax(2)-rho_3d(2)*(bmax(3)-bmax(2))/(rho_3d(3)-rho_3d(2))
2138 
2139  !Upper and lower trapped fractions bound solution
2140  DO i=2,nrho_3d !Over radial nodes
2141 
2142  !Flux surface average for upper estimate of trapped fraction
2143  DO k=1,nzeta_3d !Over toroidal nodes
2144 
2145  DO j=1,ntheta_3d !Over poloidal nodes
2146 
2147  h=b_3d(i,j,k)/bmax(i)
2148  gt_3d(j)=(1.0-sqrt(1.0-h)*(1.0+h/2))/h**2*gsqrt_3d(i,j,k)
2149 
2150  ENDDO !Over poloidal nodes
2151 
2152  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2153 
2154  ENDDO !Over toroidal nodes
2155 
2156  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2157 
2158  !Trapped fraction normalized to sqrt(rho) = 0.25*f_trap_low + 0.75*f_trap_upper
2159  h=b(i)/bmax(i)
2160  v1(i)=((1.0-b2(i)/bmax(i)**2*v1(i))/4+0.75*(1.0-b2(i)/b(i)**2 &
2161  *(1.0-sqrt(1.0-h)*(1.0+h/2))))/sqrt(rho_3d(i))
2162 
2163  ENDDO !Over radial nodes
2164 
2165 
2166  !Extrapolate to axis using constant normalized trapped fraction
2167  !Find index of first point away from axis in R,Z domain
2168  loop_i2: DO i=1,nrho_r !Over radial nodes
2169 
2170  j=i
2171  IF(rho_3d(j) > rhomin_3d) EXIT loop_i2
2172 
2173  ENDDO loop_i2 !Over radial nodes
2174 
2175  IF(j > 1) v1(1:j-1)=v1(j)
2176 
2177  !Interpolate to user grid inside R,Z domain
2178  iflag=0
2179  message=''
2180  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,ftrap_r,iflag,message)
2181 
2182  !Check messages
2183  IF(iflag /= 0) THEN
2184 
2185  message='AJAX_FLUXAV_B(5) ' // message
2186  IF(iflag > 0) GOTO 9999
2187 
2188  ENDIF
2189 
2190  IF(nr < nrho_r) THEN
2191 
2192  !Extrapolate to user grid outside R,Z domain
2193  ftrap_r(nr+1:nrho_r)=ftrap_r(nr)
2194 
2195  ENDIF
2196 
2197  !Reintroduce dominant radial dependence
2198  ftrap_r(1:nrho_r)=ftrap_r(1:nrho_r)*sqrt(rho_r(1:nrho_r))
2199 
2200 ENDIF
2201 
2202 !-------------------------------------------------------------------------------
2203 !F_m
2204 !-------------------------------------------------------------------------------
2205 IF(PRESENT(fm_r)) THEN
2206 
2207  !Initialization
2208  fm_r(:,:)=0
2209  gt_3d(:)=0
2210  v1(:)=0
2211  v2(:)=0
2212  v_r(:)=0
2213 
2214  IF(nper_3d /= 0) THEN
2215 
2216  !Non-axisymmetric plasma
2217  !q(rho) for fm_1 interpolation
2218  DO i=2,nrho_3d !Over radial nodes
2219 
2220  v1(i)=1/abs(iotabar_3d(1,i))
2221 
2222  ENDDO !Over radial nodes
2223 
2224  !Extrapolate to axis
2225  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2226 
2227  !Interpolate to user grid inside R,Z domain
2228  iflag=0
2229  message=''
2230  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,v_r,iflag,message)
2231 
2232  !Check messages
2233  IF(iflag /= 0) THEN
2234 
2235  message='AJAX_FLUXAV_B(6) ' // message
2236  IF(iflag > 0) GOTO 9999
2237 
2238  ENDIF
2239 
2240  IF(nr < nrho_r) THEN
2241 
2242  !Extrapolate to user grid outside R,Z domain
2243  v_r(nr+1:nrho_r)=v_r(nr)
2244 
2245  ENDIF
2246 
2247  !Reintroduce dominant radial dependence
2248  !If first node is not at the axis, include in calculation
2249  j=2
2250  IF(rho_r(1) > rhores_3d) j=1
2251 
2252  DO i=j,nrho_r !Over radial nodes
2253 
2254  !fm_r(2)=eps**1.5
2255  fm_r(2,i)=(rho_r(i)/r000_3d)**1.5
2256 
2257  !fm_r(1)=R_0*q/eps**1.5
2258  fm_r(1,i)=r000_3d*v_r(i)/fm_r(2,i)
2259 
2260  ENDDO !Over radial nodes
2261 
2262  ELSE
2263 
2264  !Axisymmetric plasma
2265  DO m=1,SIZE(fm_r,1) !Over poloidal moments
2266 
2267  DO i=2,nrho_3d !Over radial nodes
2268 
2269  !sin(Theta) terms
2270  DO j=1,ntheta_3d !Over poloidal nodes
2271 
2272  IF(j == 1 .OR. j == ntheta_3d) THEN
2273 
2274  !d(B)/d(theta) at end points noting periodicity
2275  dbdt=(b_3d(i,2,1)-b_3d(i,ntheta_3d-1,1))/2/dtheta_3d
2276 
2277  ELSE
2278 
2279  dbdt=(b_3d(i,j+1,1)-b_3d(i,j-1,1))/2/dtheta_3d
2280 
2281  ENDIF
2282 
2283  !sin(m*Theta)*B^theta/B*(dB/dtheta)
2284  gt_3d(j)=gsqrt_3d(i,j,1)*btheta_3d(i,j,1)/b_3d(i,j,1) &
2285  *sin(m*captheta(i,j))*dbdt
2286 
2287  ENDDO !Over poloidal nodes
2288 
2289  v1(i)=2*z_pi*sum(wtheta_3d*gt_3d)/vp_3d(i) !Over poloidal nodes
2290 
2291  DO j=1,ntheta_3d !Over poloidal nodes
2292 
2293  !sin(m*Theta)*B^theta*(dB/dtheta)
2294  gt_3d(j)=gt_3d(j)*b_3d(i,j,1)*gam(i)
2295 
2296  ENDDO !Over poloidal nodes
2297 
2298  v2(i)=v1(i)*2*z_pi*sum(wtheta_3d*gt_3d)/vp_3d(i) !Over poloidal nodes
2299 
2300  !cos(Theta) terms
2301  DO j=1,ntheta_3d !Over poloidal nodes
2302 
2303  IF(j == 1 .OR. j == ntheta_3d) THEN
2304 
2305  !d(B)/d(theta) at end points noting periodicity
2306  dbdt=(b_3d(i,2,1)-b_3d(i,ntheta_3d-1,1))/(2*dtheta_3d)
2307 
2308  ELSE
2309 
2310  dbdt=(b_3d(i,j+1,1)-b_3d(i,j-1,1))/2/dtheta_3d
2311 
2312  ENDIF
2313 
2314  !cos(m*Theta)*B^theta/B*(dB/dtheta)
2315  gt_3d(j)=gsqrt_3d(i,j,1)*btheta_3d(i,j,1)/b_3d(i,j,1) &
2316  *cos(m*captheta(i,j))*dbdt
2317 
2318  ENDDO !Over poloidal nodes
2319 
2320  v1(i)=2*z_pi*sum(wtheta_3d*gt_3d) &
2321  /vp_3d(i) !Over poloidal nodes
2322 
2323  !cos(m*Theta)*B^theta*(dB/dtheta)
2324  gt_3d(:)=gt_3d(:)*b_3d(i,:,1)*gam(i)
2325  v2(i)=v2(i)+v1(i)*2*z_pi*sum(wtheta_3d*gt_3d)/vp_3d(i) !Over poloidal nodes
2326 
2327 
2328  gt_3d(:)=gsqrt_3d(i,:,1)*btheta_3d(i,:,1)
2329  v1(i)=2*z_pi*sum(wtheta_3d*gt_3d)/vp_3d(i) !Over poloidal nodes
2330 
2331  !Multiply by 2/<B^theta>/<B**2> and normalize to rho**1.5
2332  v2(i)=v2(i)*2/v1(i)/b2(i)/rho_3d(i)**1.5
2333 
2334  ENDDO !Over radial nodes
2335 
2336  !Extrapolate to axis
2337  v2(1)=v2(2)-rho_3d(2)*(v2(3)-v2(2))/(rho_3d(3)-rho_3d(2))
2338 
2339  !Interpolate to user grid inside R,Z domain
2340  iflag=0
2341  message=''
2342  CALL linear1_interp(nrho_3d,rho_3d,v2,nr,rho_r,v_r,iflag,message)
2343 
2344  !Check messages
2345  IF(iflag /= 0) THEN
2346 
2347  message='AJAX_FLUXAV_B(7) ' // message
2348  IF(iflag > 0) GOTO 9999
2349 
2350  ENDIF
2351 
2352  IF(nr < nrho_r) THEN
2353 
2354  !Extrapolate to user grid outside R,Z domain
2355  v_r(nr+1:nrho_r)=v_r(nr)
2356 
2357  ENDIF
2358 
2359  !Reintroduce dominant radial dependence
2360  fm_r(m,1:nrho_r)=v_r(1:nrho_r)*rho_r(1:nrho_r)**1.5
2361 
2362  ENDDO !Over poloidal moments
2363 
2364  ENDIF
2365 
2366 ENDIF
2367 
2368 !-------------------------------------------------------------------------------
2369 !n.grad(Theta)
2370 !-------------------------------------------------------------------------------
2371 IF(PRESENT(grth_r)) THEN
2372 
2373  !Initialization
2374  grth_r(1:nrho_r)=0
2375 
2376  !Interpolate to user grid inside R,Z domain
2377  IF(nper_3d == 0) THEN
2378 
2379  iflag=0
2380  message=''
2381  CALL linear1_interp(nrho_3d,rho_3d,gam,nr,rho_r,grth_r,iflag,message)
2382 
2383  !Check messages
2384  IF(iflag /= 0) THEN
2385 
2386  message='AJAX_FLUXAV_B(8) ' // message
2387  IF(iflag > 0) GOTO 9999
2388 
2389  ENDIF
2390 
2391  ENDIF
2392 
2393  IF(nr < nrho_r) THEN
2394 
2395  !Extrapolate to user grid outside R,Z domain
2396  grth_r(nr+1:nrho_r)=grth_r(nr)
2397 
2398  ENDIF
2399 
2400 ENDIF
2401 
2402 !-------------------------------------------------------------------------------
2403 !Susceptance matrix element S11
2404 !-------------------------------------------------------------------------------
2405 IF(PRESENT(sus11_r)) THEN
2406 
2407  !Initialization
2408  sus11_r(1:nrho_r)=0
2409  gt_3d(:)=0
2410  az_3d(:)=0
2411  v1(:)=0
2412 
2413  !Calculate on internal grid
2414  DO i=2,nrho_3d !Over radial nodes
2415 
2416  DO k=1,nzeta_3d !Over toroidal nodes
2417 
2418  gt_3d(1:ntheta_3d)=( gcyl_3d(2,i,1:ntheta_3d,k)**2 &
2419  +gcyl_3d(5,i,1:ntheta_3d,k)**2 ) &
2420  /gsqrt_3d(i,1:ntheta_3d,k)
2421  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2422 
2423  ENDDO !Over toroidal nodes
2424 
2425  !Remove dominant radial dependence
2426  v1(i)=sum(wzeta_3d*az_3d)/rho_3d(i) !Over toroidal nodes
2427 
2428  ENDDO !Over radial nodes
2429 
2430  !Extrapolate to axis
2431  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2432 
2433  !Interpolate to user grid inside R,Z domain
2434  iflag=0
2435  message=''
2436  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,sus11_r,iflag,message)
2437 
2438  !Check messages
2439  IF(iflag /= 0) THEN
2440 
2441  message='AJAX_FLUXAV_B(9) ' // message
2442  IF(iflag > 0) GOTO 9999
2443 
2444  ENDIF
2445 
2446  IF(nr < nrho_r) THEN
2447 
2448  !Extrapolate to user grid outside R,Z domain
2449  sus11_r(nrho_r+1:nr)=sus11_r(nr)
2450 
2451  ENDIF
2452 
2453  !Reintroduce dominant radial dependence
2454  sus11_r(1:nrho_r)=sus11_r(1:nrho_r)*rho_r(1:nrho_r)/4/z_pi**2
2455 
2456 ENDIF
2457 
2458 !-------------------------------------------------------------------------------
2459 !Susceptance matrix element S12
2460 !-------------------------------------------------------------------------------
2461 IF(PRESENT(sus12_r)) THEN
2462 
2463  !Initialization
2464  sus12_r(1:nrho_r)=0
2465  gt_3d(:)=0
2466  az_3d(:)=0
2467  v1(:)=0
2468 
2469  !Calculate on internal grid
2470  DO i=2,nrho_3d !Over radial nodes
2471 
2472  DO k=1,nzeta_3d !Over toroidal nodes
2473 
2474  gt_3d(1:ntheta_3d)=( ( gcyl_3d(2,i,1:ntheta_3d,k) &
2475  *gcyl_3d(3,i,1:ntheta_3d,k) &
2476  +gcyl_3d(5,i,1:ntheta_3d,k) &
2477  *gcyl_3d(6,i,1:ntheta_3d,k)) &
2478  *(1.0+eltheta_3d(i,1:ntheta_3d,k)) &
2479  -( gcyl_3d(2,i,1:ntheta_3d,k)**2 &
2480  +gcyl_3d(5,i,1:ntheta_3d,k)**2 ) &
2481  *elzeta_3d(i,1:ntheta_3d,k) ) &
2482  /gsqrt_3d(i,1:ntheta_3d,k)
2483  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2484 
2485  ENDDO !Over toroidal nodes
2486 
2487  !Remove dominant radial dependence
2488  v1(i)=sum(wzeta_3d*az_3d)/rho_3d(i) !Over toroidal nodes
2489 
2490  ENDDO !Over radial nodes
2491 
2492  !Extrapolate to axis
2493  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2494 
2495  !Interpolate to user grid inside R,Z domain
2496  iflag=0
2497  message=''
2498  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,sus12_r,iflag,message)
2499 
2500  !Check messages
2501  IF(iflag /= 0) THEN
2502 
2503  message='AJAX_FLUXAV_B(10) ' // message
2504  IF(iflag > 0) GOTO 9999
2505 
2506  ENDIF
2507 
2508  IF(nr < nrho_r) THEN
2509 
2510  !Extrapolate to user grid outside R,Z domain
2511  sus12_r(nr+1:nrho_r)=sus12_r(nr)
2512 
2513  ENDIF
2514 
2515  !Reintroduce dominant radial dependence
2516  sus12_r(1:nrho_r)=sus12_r(1:nrho_r)*rho_r(1:nrho_r)/4/z_pi**2
2517 
2518 ENDIF
2519 
2520 !-------------------------------------------------------------------------------
2521 !Susceptance matrix element S21
2522 !-------------------------------------------------------------------------------
2523 IF(PRESENT(sus21_r)) THEN
2524 
2525  !Initialization
2526  sus21_r(1:nrho_r)=0
2527  gt_3d(:)=0
2528  az_3d(:)=0
2529  v1(:)=0
2530 
2531  !Calculate on internal grid
2532  DO i=2,nrho_3d !Over radial nodes
2533 
2534  DO k=1,nzeta_3d !Over toroidal nodes
2535 
2536  gt_3d(1:ntheta_3d)=( gcyl_3d(2,i,1:ntheta_3d,k) &
2537  *gcyl_3d(3,i,1:ntheta_3d,k) &
2538  +gcyl_3d(5,i,1:ntheta_3d,k) &
2539  *gcyl_3d(6,i,1:ntheta_3d,k) ) &
2540  /gsqrt_3d(i,1:ntheta_3d,k)
2541  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2542 
2543  ENDDO !Over toroidal nodes
2544 
2545  !Remove dominant radial dependence
2546  v1(i)=sum(wzeta_3d*az_3d)/rho_3d(i) !Over toroidal nodes
2547 
2548  ENDDO !Over radial nodes
2549 
2550  !Extrapolate to axis
2551  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2552 
2553  !Interpolate to user grid inside R,Z domain
2554  iflag=0
2555  message=''
2556  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,sus21_r,iflag,message)
2557 
2558  !Check messages
2559  IF(iflag /= 0) THEN
2560 
2561  message='AJAX_FLUXAV_B(11) ' // message
2562  IF(iflag > 0) GOTO 9999
2563 
2564  ENDIF
2565 
2566  IF(nr < nrho_r) THEN
2567 
2568  !Extrapolate to user grid outside R,Z domain
2569  sus21_r(nr+1:nrho_r)=sus21_r(nr)
2570 
2571  ENDIF
2572 
2573  !Reintroduce dominant radial dependence
2574  sus21_r(1:nrho_r)=sus21_r(1:nrho_r)*rho_r(1:nrho_r)/4/z_pi**2
2575 
2576 ENDIF
2577 
2578 !-------------------------------------------------------------------------------
2579 !Susceptance matrix element S22
2580 !-------------------------------------------------------------------------------
2581 IF(PRESENT(sus22_r)) THEN
2582 
2583  !Initialization
2584  sus22_r(1:nrho_r)=0
2585  gt_3d(:)=0
2586  az_3d(:)=0
2587  v1(:)=0
2588 
2589  !Calculate on internal grid
2590  DO i=2,nrho_3d !Over radial nodes
2591 
2592  DO k=1,nzeta_3d !Over toroidal nodes
2593 
2594  gt_3d(1:ntheta_3d)=( ( rcyl_3d(i,1:ntheta_3d,k)**2 &
2595  +gcyl_3d(3,i,1:ntheta_3d,k)**2 &
2596  +gcyl_3d(6,i,1:ntheta_3d,k)**2 ) &
2597  *(1.0+eltheta_3d(i,1:ntheta_3d,k)) &
2598  -( gcyl_3d(2,i,1:ntheta_3d,k) &
2599  *gcyl_3d(3,i,1:ntheta_3d,k) &
2600  +gcyl_3d(5,i,1:ntheta_3d,k) &
2601  *gcyl_3d(6,i,1:ntheta_3d,k) ) &
2602  *elzeta_3d(i,1:ntheta_3d,k) ) &
2603  /gsqrt_3d(i,1:ntheta_3d,k)
2604  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2605 
2606  ENDDO !Over toroidal nodes
2607 
2608  !Remove dominant radial dependence
2609  v1(i)=sum(wzeta_3d*az_3d)*rho_3d(i) !Over toroidal nodes
2610 
2611  ENDDO !Over radial nodes
2612 
2613  !Extrapolate to axis
2614  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2615 
2616  !Interpolate to user grid inside R,Z domain
2617  iflag=0
2618  message=''
2619  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,sus22_r,iflag,message)
2620 
2621  !Check messages
2622  IF(iflag /= 0) THEN
2623 
2624  message='AJAX_FLUXAV_B(12) ' // message
2625  IF(iflag > 0) GOTO 9999
2626 
2627  ENDIF
2628 
2629  IF(nr < nrho_r) THEN
2630 
2631  !Extrapolate to user grid outside R,Z domain
2632  sus22_r(nr+1:nrho_r)=sus22_r(nr)
2633 
2634  ENDIF
2635 
2636  !Reintroduce dominant radial dependence
2637  j=2
2638  !If first node is not at the axis, include in calculation
2639  IF(rho_r(1) > rhores_3d) j=1
2640 
2641  sus22_r(j:nrho_r)=sus22_r(j:nrho_r)/rho_r(j:nrho_r)/4/z_pi**2
2642 
2643 ENDIF
2644 
2645 IF(j == 2) sus22_r(1)=sus22_r(2)
2646 
2647 !-------------------------------------------------------------------------------
2648 !Cleanup and exit
2649 !-------------------------------------------------------------------------------
2650 9999 CONTINUE
2651 
2652 END SUBROUTINE ajax_fluxav_b
2653 
2654 SUBROUTINE ajax_fluxav_g(nrho_r,rho_r, &
2655  iflag,message, &
2656  AREA_R,DVOL_R,GRHO1_R,GRHO2_R,GRHO2RM2_R,RM2_R,VOL_R, &
2657  VP_R)
2658 !-------------------------------------------------------------------------------
2659 !AJAX_FLUXAV_G gets flux surface quantities that depend on geometry
2660 !
2661 !References:
2662 ! W.A.Houlberg, F90 free format 8/2004
2663 !-------------------------------------------------------------------------------
2664 
2665 !Declaration of input variables
2666 INTEGER, INTENT(IN) :: &
2667  nrho_r !no. of radial nodes [-]
2668 
2669 REAL(KIND=rspec), INTENT(IN) :: &
2670  rho_r(:) !radial nodes [rho]
2671 
2672 !Declaration of output variables
2673 CHARACTER(LEN=1024), INTENT(OUT) :: &
2674  message !warning or error message [character]
2675 
2676 INTEGER, INTENT(OUT) :: &
2677  iflag !error and warning flag [-]
2678  !=-1 warning
2679  !=0 none
2680  !=1 error
2681 
2682 !Declaration of optional output variables
2683 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
2684  area_r(:), & !surface area [m**2]
2685  dvol_r(:), & !cell volume between rho_r(i) and rho_r(i+1) [m**3]
2686  grho1_r(:), &
2687  grho2_r(:), &
2688  grho2rm2_r(:), &
2689  rm2_r(:), &
2690  vol_r(:), & !enclosed volume [-]
2691  vp_r(:) !dV/drho [m**3/rho]
2692 
2693 !-------------------------------------------------------------------------------
2694 !Declaration of local variables
2695 INTEGER :: &
2696  i,k,nr
2697 
2698 REAL(KIND=rspec) :: &
2699  gr(1:nrho_r),v1(1:nrho_3d),vp(1:nrho_r)
2700 
2701 !-------------------------------------------------------------------------------
2702 !Initialization
2703 !-------------------------------------------------------------------------------
2704 !Null output
2705 iflag=0
2706 message=''
2707 
2708 !Check whether flux surface averaging arrays have been set
2709 IF(.NOT. l_fluxavg_3d) THEN
2710 
2711  CALL ajax_init_fluxav_g(iflag,message)
2712 
2713  !Check messages
2714  IF(iflag /= 0) THEN
2715 
2716  message='AJAX_FLUXAV_G(1) ' // message
2717  GOTO 9999
2718 
2719  ENDIF
2720 
2721 ENDIF
2722 
2723 !Check whether values outside R,Z domain are requested (nr is last point inside)
2724 loop_i: DO i=nrho_r,1,-1 !Over nodes
2725 
2726  nr=i
2727  IF(rho_r(nr) < rhomax_3d+rhores_3d) EXIT loop_i
2728 
2729 ENDDO loop_i !Over nodes
2730 
2731 !-------------------------------------------------------------------------------
2732 !d(V)/d(rho) on user grid for area_r, dvol_r, vol_r and vp_r
2733 !-------------------------------------------------------------------------------
2734 IF(PRESENT(area_r) .OR. &
2735  PRESENT(dvol_r) .OR. &
2736  PRESENT(vol_r) .OR. &
2737  PRESENT(vp_r)) THEN
2738 
2739  !Initialization
2740  vp(:)=0
2741  v1(:)=0
2742 
2743  !Remove dominant radial dependence
2744  v1(2:nrho_3d)=vp_3d(2:nrho_3d)/rho_3d(2:nrho_3d)
2745 
2746  !Extrapolate to axis
2747  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
2748 
2749  !Interpolate to user grid inside R,Z domain
2750  iflag=0
2751  message=''
2752  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,vp,iflag,message)
2753 
2754  !Check messages
2755  IF(iflag /= 0) THEN
2756 
2757  message='AJAX_FLUXAV_G(2) ' // message
2758  IF(iflag > 0) GOTO 9999
2759 
2760  ENDIF
2761 
2762  IF(nr < nrho_r) THEN
2763 
2764  !Extrapolate to user grid outside R,Z domain
2765  vp(nr+1:nrho_r)=vp(nr)
2766 
2767  ENDIF
2768 
2769  !Reintroduce dominant radial dependence
2770  vp(1:nrho_r)=vp(1:nrho_r)*rho_r(1:nrho_r)
2771 
2772 ENDIF
2773 
2774 !-------------------------------------------------------------------------------
2775 
2776 !-------------------------------------------------------------------------------
2777 IF(PRESENT(area_r) .OR. &
2778  PRESENT(grho1_r)) THEN
2779 
2780  !Initialization
2781  gr(:)=0
2782  gt_3d(:)=0
2783  az_3d(:)=0
2784  v1(:)=0
2785 
2786  !Calculate on internal grid
2787  DO i=2,nrho_3d !Over radial nodes
2788 
2789  DO k=1,nzeta_3d !Over toroidal nodes
2790 
2791  gt_3d(1:ntheta_3d)=sqrt(( ( gcyl_3d(3,i,1:ntheta_3d,k) &
2792  *gcyl_3d(5,i,1:ntheta_3d,k) &
2793  -gcyl_3d(2,i,1:ntheta_3d,k) &
2794  *gcyl_3d(6,i,1:ntheta_3d,k))**2 &
2795  +rcyl_3d(i,1:ntheta_3d,k)**2 &
2796  *(gcyl_3d(2,i,1:ntheta_3d,k)**2 &
2797  +gcyl_3d(5,i,1:ntheta_3d,k)**2) ))
2798  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2799 
2800  ENDDO !Over toroidal nodes
2801 
2802  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2803 
2804  ENDDO !Over radial nodes
2805 
2806  v1(1)=v1(2)
2807 
2808  !Interpolate to user grid inside R,Z domain
2809  iflag=0
2810  message=''
2811  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,gr,iflag,message)
2812 
2813  !Check messages
2814  IF(iflag /= 0) THEN
2815 
2816  message='AJAX_FLUXAV_G(3) ' // message
2817  IF(iflag > 0) GOTO 9999
2818 
2819  ENDIF
2820 
2821  IF(nr < nrho_r) THEN
2822 
2823  !Extrapolate to user grid outside R,Z domain
2824  gr(nr+1:nrho_r)=gr(nr)
2825 
2826  ENDIF
2827 
2828 ENDIF
2829 
2830 !-------------------------------------------------------------------------------
2831 !Area
2832 !-------------------------------------------------------------------------------
2833 IF(PRESENT(area_r)) THEN
2834 
2835  !Initialization
2836  area_r(:)=0
2837 
2838  !Use temporary arrays
2839  area_r(1:nrho_r)=vp(1:nrho_r)*gr(1:nrho_r)
2840 
2841 ENDIF
2842 
2843 !-------------------------------------------------------------------------------
2844 !delta(Volume)
2845 !-------------------------------------------------------------------------------
2846 IF(PRESENT(dvol_r)) THEN
2847 
2848  !Initialization
2849  dvol_r(:)=0
2850 
2851  !Calculate from integral rho*drho*(V'/rho), where (V'/rho) is a weak function
2852  !Allow for first node to be away from the axis
2853  IF(rho_r(1) > rhores_3d) THEN
2854 
2855  !First node is off axis
2856  k=1
2857 
2858  ELSE
2859 
2860  !First node is on axis
2861  k=2
2862  dvol_r(1)=vp(2)*rho_r(2)/2
2863 
2864  ENDIF
2865 
2866  DO i=k,nrho_r-1 !Over radial nodes
2867 
2868  dvol_r(i)=(vp(i)/rho_r(i)+vp(i+1)/rho_r(i+1))/2 &
2869  *(rho_r(i+1)**2-rho_r(i)**2)/2
2870 
2871  ENDDO !Over radial nodes
2872 
2873  !Set ghost node value equal to last node
2874  dvol_r(nrho_r)=dvol_r(nrho_r-1)
2875 
2876 ENDIF
2877 
2878 !-------------------------------------------------------------------------------
2879 
2880 !-------------------------------------------------------------------------------
2881 IF(PRESENT(grho1_r)) THEN
2882 
2883  !Initialization
2884  grho1_r(:)=0
2885 
2886  !Copy from temporary array
2887  grho1_r(1:nrho_r)=gr(1:nrho_r)
2888 
2889 ENDIF
2890 
2891 !-------------------------------------------------------------------------------
2892 
2893 !-------------------------------------------------------------------------------
2894 IF(PRESENT(grho2_r)) THEN
2895 
2896  !Initialization
2897  grho2_r(:)=0
2898  gt_3d(:)=0
2899  az_3d(:)=0
2900  v1(:)=0
2901 
2902  !Calculate on internal grid
2903  DO i=2,nrho_3d !Over radial nodes
2904 
2905  DO k=1,nzeta_3d !Over toroidal nodes
2906 
2907  gt_3d(1:ntheta_3d)=( (gcyl_3d(3,i,1:ntheta_3d,k) &
2908  *gcyl_3d(5,i,1:ntheta_3d,k) &
2909  -gcyl_3d(2,i,1:ntheta_3d,k) &
2910  *gcyl_3d(6,i,1:ntheta_3d,k))**2 &
2911  +rcyl_3d(i,1:ntheta_3d,k)**2 &
2912  *(gcyl_3d(2,i,1:ntheta_3d,k)**2 &
2913  +gcyl_3d(5,i,1:ntheta_3d,k)**2) ) &
2914  /gsqrt_3d(i,1:ntheta_3d,k)
2915  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2916 
2917  ENDDO !Over toroidal nodes
2918 
2919  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2920 
2921  ENDDO !Over radial nodes
2922 
2923  !Extrapolate to axis
2924  v1(1)=v1(2)
2925 
2926  !Interpolate to user grid inside R,Z domain
2927  iflag=0
2928  message=''
2929  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,grho2_r,iflag,message)
2930 
2931  !Check messages
2932  IF(iflag /= 0) THEN
2933 
2934  message='AJAX_FLUXAV_G(4) ' // message
2935  IF(iflag > 0) GOTO 9999
2936 
2937  ENDIF
2938 
2939  IF(nr < nrho_r) THEN
2940 
2941  !Extrapolate to user grid outside R,Z domain
2942  grho2_r(nr+1:nrho_r)=grho2_r(nr)
2943 
2944  ENDIF
2945 
2946 ENDIF
2947 
2948 !-------------------------------------------------------------------------------
2949 
2950 !-------------------------------------------------------------------------------
2951 IF(PRESENT(grho2rm2_r)) THEN
2952 
2953  !Initialization
2954  grho2rm2_r(:)=0
2955  gt_3d(:)=0
2956  az_3d(:)=0
2957  v1(:)=0
2958 
2959  !Calculate on internal grid
2960  DO i=2,nrho_3d !Over radial nodes
2961 
2962  DO k=1,nzeta_3d !Over toroidal nodes
2963 
2964  gt_3d(1:ntheta_3d)=( (gcyl_3d(3,i,1:ntheta_3d,k) &
2965  *gcyl_3d(5,i,1:ntheta_3d,k) &
2966  -gcyl_3d(2,i,1:ntheta_3d,k) &
2967  *gcyl_3d(6,i,1:ntheta_3d,k))**2 &
2968  /rcyl_3d(i,1:ntheta_3d,k)**2 &
2969  +(gcyl_3d(2,i,1:ntheta_3d,k)**2 &
2970  +gcyl_3d(5,i,1:ntheta_3d,k)**2) ) &
2971  /gsqrt_3d(i,1:ntheta_3d,k)
2972  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
2973 
2974  ENDDO !Over toroidal nodes
2975 
2976  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
2977 
2978  ENDDO !Over radial nodes
2979 
2980  !Extrapolate to axis
2981  v1(1)=v1(2)
2982 
2983  !Interpolate to user grid inside R,Z domain
2984  iflag=0
2985  message=''
2986  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,grho2rm2_r,iflag,message)
2987 
2988  !Check messages
2989  IF(iflag /= 0) THEN
2990 
2991  message='AJAX_FLUXAV_G(5) ' // message
2992  IF(iflag > 0) GOTO 9999
2993 
2994  ENDIF
2995 
2996  IF(nr < nrho_r) THEN
2997 
2998  !Extrapolate to user grid outside R,Z domain
2999  grho2rm2_r(nr+1:nrho_r)=grho2rm2_r(nr)
3000 
3001  ENDIF
3002 
3003 ENDIF
3004 
3005 !-------------------------------------------------------------------------------
3006 
3007 !-------------------------------------------------------------------------------
3008 IF(PRESENT(rm2_r)) THEN
3009 
3010  !Initialization
3011  rm2_r(:)=0
3012  gt_3d(:)=0
3013  az_3d(:)=0
3014  v1(:)=0
3015 
3016  !Calculate on internal grid
3017  DO i=2,nrho_3d !Over radial nodes
3018 
3019  DO k=1,nzeta_3d !Over toroidal nodes
3020 
3021  gt_3d(1:ntheta_3d)=gsqrt_3d(i,1:ntheta_3d,k) &
3022  /rcyl_3d(i,1:ntheta_3d,k)**2
3023  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
3024 
3025  ENDDO !Over toroidal nodes
3026 
3027  v1(i)=sum(wzeta_3d*az_3d)/vp_3d(i) !Over toroidal nodes
3028 
3029  ENDDO !Over radial nodes
3030 
3031  !Extrapolate to axis
3032  v1(1)=v1(2)
3033 
3034  !Interpolate to user grid inside R,Z domain
3035  iflag=0
3036  message=''
3037  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,rm2_r,iflag,message)
3038 
3039  !Check messages
3040  IF(iflag /= 0) THEN
3041 
3042  message='AJAX_FLUXAV_G(6) ' // message
3043  IF(iflag > 0) GOTO 9999
3044 
3045  ENDIF
3046 
3047  IF(nr < nrho_r) THEN
3048 
3049  !Extrapolate to user grid outside R,Z domain
3050  rm2_r(nr+1:nrho_r)=rm2_r(nr)
3051 
3052  ENDIF
3053 
3054 ENDIF
3055 
3056 !-------------------------------------------------------------------------------
3057 !Volume
3058 !-------------------------------------------------------------------------------
3059 IF(PRESENT(vol_r)) THEN
3060 
3061  !Initialization
3062  vol_r(:)=0
3063 
3064  !Sum up dvol elements
3065  !Allow for first node to be away from the axis
3066  IF(rho_r(1) > rhores_3d) THEN
3067 
3068  !First node is off axis
3069  k=1
3070  vol_r(1)=vp(1)*rho_r(1)/2
3071 
3072  ELSE
3073 
3074  !First node is on axis
3075  k=2
3076  vol_r(1)=0
3077  vol_r(2)=vp(2)*rho_r(2)/2
3078 
3079  ENDIF
3080 
3081  DO i=k+1,nrho_r !Over radial nodes
3082 
3083  vol_r(i)=vol_r(i-1)+(vp(i-1)/rho_r(i-1)+vp(i)/rho_r(i))/2 &
3084  *(rho_r(i)**2-rho_r(i-1)**2)/2
3085 
3086  ENDDO !Over radial nodes
3087 
3088 ENDIF
3089 
3090 !-------------------------------------------------------------------------------
3091 !d(Volume)/d(rho)
3092 !-------------------------------------------------------------------------------
3093 IF(PRESENT(vp_r)) THEN
3094 
3095  !Initialization
3096  vp_r(:)=0
3097 
3098  !Copy from temporary array
3099  vp_r(1:nrho_r)=vp(1:nrho_r)
3100 
3101 ENDIF
3102 
3103 !-------------------------------------------------------------------------------
3104 !Cleanup and exit
3105 !-------------------------------------------------------------------------------
3106 9999 CONTINUE
3107 
3108 END SUBROUTINE ajax_fluxav_g
3109 
3110 SUBROUTINE ajax_i(nrho_r,rho_r, &
3111  iflag,message, &
3112  CUR_I_R,CUR_F_R,CUR_IMN_R,CUR_IMX_R,CUR_FMN_R,CUR_FMX_R)
3113 !-------------------------------------------------------------------------------
3114 !AJAX_I gets the enclosed toroidal and external poloidal currents for a set of
3115 ! flux surfaces from the covariant components of B, as well as maximum and
3116 ! minimum values for use as a diagnostic on the accuracy of the stream function
3117 !
3118 !References:
3119 ! W.A.Houlberg, F90 free format 8/2004
3120 !-------------------------------------------------------------------------------
3121 
3122 !Declaration of input variables
3123 INTEGER, INTENT(IN) :: &
3124  nrho_r !no. of radial nodes [-]
3125 
3126 REAL(KIND=rspec), INTENT(IN) :: &
3127  rho_r(:) !radial nodes [rho]
3128 
3129 !Declaration of output variables
3130 CHARACTER(LEN=1024), INTENT(OUT) :: &
3131  message !warning or error message [character]
3132 
3133 INTEGER, INTENT(OUT) :: &
3134  iflag !error and warning flag [-]
3135  !=-1 warning
3136  !=0 none
3137  !=1 error
3138 
3139 !Declaration of optional output variables
3140 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
3141  cur_i_r(:), & !enclosed toroidal current [A]
3142  cur_f_r(:), & !external poloidal current [A]
3143  cur_imn_r(:), & !minimum toroidal current on AJAX toroidal grid [A]
3144  cur_imx_r(:), & !maximum toroidal current on AJAX toroidal grid [A]
3145  cur_fmn_r(:), & !minimum poloidal current on AJAX poloidal grid [A]
3146  cur_fmx_r(:) !maximum poloidal current on AJAX poloidal grid [A]
3147 
3148 !-------------------------------------------------------------------------------
3149 !Declaration of local variables
3150 INTEGER :: &
3151  i,j,k,imin
3152 
3153 REAL(KIND=rspec) :: &
3154  cmax,cmin,r_flx(1:3),r_cyl(1:3),g_cyl(1:6)
3155 
3156 REAL(KIND=rspec), ALLOCATABLE :: &
3157  b_co(:,:,:),gt(:),gz(:)
3158 
3159 !-------------------------------------------------------------------------------
3160 !Initialization
3161 !-------------------------------------------------------------------------------
3162 !Null output
3163 iflag=0
3164 message=''
3165 
3166 !Allocate covariant B field array
3167 ALLOCATE(b_co(3,ntheta_3d,nzeta_3d))
3168 
3169  b_co(:,:,:)=0
3170 
3171 IF(PRESENT(cur_i_r) .OR. &
3172  PRESENT(cur_imn_r) .OR. &
3173  PRESENT(cur_imx_r)) THEN
3174 
3175  ALLOCATE(gz(nzeta_3d))
3176 
3177  gz(:)=0
3178 
3179 ENDIF
3180 
3181 IF(PRESENT(cur_f_r) .OR. &
3182  PRESENT(cur_fmn_r) .OR. &
3183  PRESENT(cur_fmx_r)) THEN
3184 
3185  ALLOCATE(gt(ntheta_3d))
3186 
3187  gt(:)=0
3188 
3189 ENDIF
3190 
3191 IF(PRESENT(cur_i_r)) cur_i_r(1:nrho_r)=0
3192 IF(PRESENT(cur_imn_r)) cur_imn_r(1:nrho_r)=0
3193 IF(PRESENT(cur_imx_r)) cur_imx_r(1:nrho_r)=0
3194 IF(PRESENT(cur_f_r)) cur_f_r(1:nrho_r)=0
3195 IF(PRESENT(cur_fmn_r)) cur_fmn_r(1:nrho_r)=0
3196 IF(PRESENT(cur_fmx_r)) cur_fmx_r(1:nrho_r)=0
3197 
3198 imin=1
3199 IF(rho_r(1) <= rhomin_3d) imin=2
3200 
3201 !-------------------------------------------------------------------------------
3202 !Perform integrals of covariant B components on each surface
3203 !-------------------------------------------------------------------------------
3204 DO i=imin,nrho_r !Over radial nodes
3205 
3206  r_flx(1)=rho_r(i)
3207 
3208  DO k=1,nzeta_3d !Over toroidal nodes
3209 
3210  r_flx(3)=(k-1)*dzeta_3d
3211 
3212  DO j=1,ntheta_3d !Over poloidal nodes
3213 
3214  r_flx(2)=(j-1)*dtheta_3d
3215 
3216  !Get cylindrical coordinates and metrics
3217  iflag=0
3218  message=''
3219  CALL ajax_flx2cyl(r_flx,r_cyl,iflag,message,g_cyl=g_cyl)
3220 
3221  !Check messages
3222  IF(iflag /= 0) THEN
3223 
3224  message='AJAX_I(1) ' // message
3225  IF(iflag > 0) GOTO 9999
3226 
3227  ENDIF
3228 
3229  !Get covariant B components
3230  iflag=0
3231  message=''
3232  CALL ajax_b(r_flx,r_cyl,g_cyl,iflag,message,b_co=b_co(:,j,k))
3233 
3234  !Check messages
3235  IF(iflag /= 0) THEN
3236 
3237  message='AJAX_I(2) ' // message
3238  IF(iflag > 0) GOTO 9999
3239 
3240  ENDIF
3241 
3242  ENDDO !Over poloidal nodes
3243 
3244  ENDDO !Over toroidal nodes
3245 
3246  !Toroidal current
3247  IF(PRESENT(cur_i_r) .OR. &
3248  PRESENT(cur_imn_r) .OR. &
3249  PRESENT(cur_imx_r)) THEN
3250 
3251  cmax=-z_large
3252  cmin=z_large
3253 
3254  DO k=1,nzeta_3d !Over toroidal nodes
3255 
3256  gz(k)=sum(wtheta_3d*b_co(2,1:ntheta_3d,k))/z_mu0
3257  IF(gz(k) < cmin) cmin=gz(k)
3258  IF(gz(k) > cmax) cmax=gz(k)
3259 
3260  IF(PRESENT(cur_i_r)) cur_i_r(i)=sum(wzeta_3d*gz)/2/z_pi
3261  IF(PRESENT(cur_imn_r)) cur_imn_r(i)=cmin
3262  IF(PRESENT(cur_imx_r)) cur_imx_r(i)=cmax
3263 
3264  ENDDO !Over toroidal nodes
3265 
3266  ENDIF
3267 
3268  !Poloidal current
3269  IF(PRESENT(cur_f_r) .OR. &
3270  PRESENT(cur_fmn_r) .OR. &
3271  PRESENT(cur_fmx_r)) THEN
3272 
3273  cmax=-z_large
3274  cmin=z_large
3275 
3276  DO j=1,ntheta_3d !Over poloidal nodes
3277 
3278  gt(j)=sum(wzeta_3d*b_co(3,j,1:nzeta_3d))/z_mu0
3279  IF(gt(j) < cmin) cmin=gt(j)
3280  IF(gt(j) > cmax) cmax=gt(j)
3281 
3282  IF(PRESENT(cur_f_r)) cur_f_r(i)=sum(wtheta_3d*gt)/2/z_pi
3283  IF(PRESENT(cur_fmn_r)) cur_fmn_r(i)=cmin
3284  IF(PRESENT(cur_fmx_r)) cur_fmx_r(i)=cmax
3285 
3286  ENDDO !Over toroidal nodes
3287 
3288  ENDIF
3289 
3290 ENDDO !Over radial nodes
3291 
3292 !Check whether axial values are requested
3293 IF(imin == 2) THEN
3294 
3295  !Use value of second node
3296  IF(PRESENT(cur_i_r)) cur_i_r(1)=0
3297  IF(PRESENT(cur_imn_r)) cur_imn_r(1)=0
3298  IF(PRESENT(cur_imx_r)) cur_imx_r(1)=0
3299  IF(PRESENT(cur_f_r)) cur_f_r(1)=cur_f_r(2)
3300  IF(PRESENT(cur_fmn_r)) cur_fmn_r(1)=cur_fmn_r(2)
3301  IF(PRESENT(cur_fmx_r)) cur_fmx_r(1)=cur_fmx_r(2)
3302 
3303 ENDIF
3304 
3305 !-------------------------------------------------------------------------------
3306 !Cleanup and exit
3307 !-------------------------------------------------------------------------------
3308 9999 CONTINUE
3309 
3310 !Deallocate arrays
3311 DEALLOCATE(b_co)
3312 IF(ALLOCATED(gt)) DEALLOCATE(gt)
3313 IF(ALLOCATED(gz)) DEALLOCATE(gz)
3314 
3315 END SUBROUTINE ajax_i
3316 
3317 SUBROUTINE ajax_magflux(nrho_r,rho_r, &
3318  iflag,message, &
3319  IOTABAR_R,Q_R,PHIPRM_R,PSIPRM_R,PHI_R,PSI_R)
3320 !-------------------------------------------------------------------------------
3321 !AJAX_MAGFLUX gets poloidal and toroidal magnetic fluxes
3322 !
3323 !References:
3324 ! W.A.Houlberg, F90 free format 8/2004
3325 !-------------------------------------------------------------------------------
3326 
3327 !Declaration of input variables
3328 INTEGER, INTENT(IN) :: &
3329  nrho_r !no. of radial nodes [-]
3330 
3331 REAL(KIND=rspec), INTENT(IN) :: &
3332  rho_r(:) !radial nodes [rho]
3333 
3334 !Declaration of output variables
3335 CHARACTER(LEN=1024), INTENT(OUT) :: &
3336  message !warning or error message [character]
3337 
3338 INTEGER, INTENT(OUT) :: &
3339  iflag !error and warning flag [-]
3340  !=-1 warning
3341  !=0 none
3342  !=1 error
3343 
3344 !Declaration of output variables
3345 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
3346  iotabar_r(:), & !rotational transform = d(Psi)/d(Phi) [-]
3347  q_r(:), & !safety factor = d(Phi)/d(Psi) [-]
3348  phiprm_r(:), & !d(Phi)/d(rho) [Wb/rho]
3349  psiprm_r(:), & !d(Psi)/d(rho) [Wb/rho]
3350  phi_r(:), & !toroidal flux [Wb]
3351  psi_r(:) !poloidal flux [Wb]
3352 
3353 !-------------------------------------------------------------------------------
3354 !Declaration of local variables
3355 INTEGER :: &
3356  i,j,nr
3357 
3358 INTEGER, PARAMETER :: &
3359  k_vopt(1:3)=(/1,0,0/)
3360 
3361 REAL(KIND=rspec) :: &
3362  iotabar_t(1:nrho_r),phiprm_t(1:nrho_r),value(1:3), &
3363  values(1:nrho_r)
3364 
3365 !-------------------------------------------------------------------------------
3366 !Initialization
3367 !-------------------------------------------------------------------------------
3368 !Null output
3369 iflag=0
3370 message=''
3371 
3372 !Internal values
3373 phiprm_t(:)=0
3374 iotabar_t(:)=0
3375 
3376 !Check whether values outside R,Z domain are requested (nr is last point inside)
3377 loop_i: DO i=nrho_r,1,-1 !Over nodes
3378 
3379  nr=i
3380  IF(rho_r(nr) < rhomax_3d+rhores_3d) EXIT loop_i
3381 
3382 ENDDO loop_i !Over nodes
3383 
3384 !-------------------------------------------------------------------------------
3385 !Get temporary base quantities for phiprm and iotabar
3386 !-------------------------------------------------------------------------------
3387 phiprm_t(1:nrho_r)=2*rho_r(1:nrho_r)*phitot_3d/rhomax_3d**2
3388 IF(rho_r(1) < rhores_3d) phiprm_t(1)=2*rhores_3d*phitot_3d/rhomax_3d**2
3389 
3390  !Inside MHD solution domain
3391  j=1
3392 
3393 DO i=1,nr !Over radial nodes
3394 
3395  CALL spline1_eval(k_vopt,nrho_3d,rho_r(i),rho_3d,iotabar_3d,j,value)
3396  iotabar_t(i)=value(1)
3397 
3398 ENDDO !Over radial nodes
3399 
3400 IF(nr < nrho_r) THEN
3401 
3402  !Extrapolate outside with constant slope in iotabar
3403  iotabar_t(nr+1:nrho_r)=iotabar_3d(1,nrho_3d) &
3404  +(rho_r(nr+1:nrho_r)-rhomax_3d) &
3405  *(iotabar_3d(1,nrho_3d) &
3406  -iotabar_3d(1,nrho_3d-1)) &
3407  /(rhomax_3d-rho_3d(nrho_3d-1))
3408 
3409 ENDIF
3410 
3411 !-------------------------------------------------------------------------------
3412 !Return the appropriate quantity
3413 !-------------------------------------------------------------------------------
3414 !Rotational transform
3415 IF(PRESENT(iotabar_r)) THEN
3416 
3417  iotabar_r(:)=0
3418  iotabar_r(1:nrho_r)=iotabar_t(1:nrho_r)
3419 
3420 ENDIF
3421 
3422 !Safety factor
3423 IF(PRESENT(q_r)) THEN
3424 
3425  q_r(:)=0
3426  q_r(1:nrho_r)=1/iotabar_t(1:nrho_r)
3427 
3428 ENDIF
3429 
3430 !d(Phi)/d(rho)
3431 IF(PRESENT(phiprm_r)) THEN
3432 
3433  phiprm_r(:)=0
3434  phiprm_r(1:nrho_r)=phiprm_t(1:nrho_r)
3435 
3436 ENDIF
3437 
3438 !d(Psi)/d(rho)
3439 IF(PRESENT(psiprm_r)) THEN
3440 
3441  psiprm_r(:)=0
3442  psiprm_r(1:nrho_r)=iotabar_t(1:nrho_r)*phiprm_t(1:nrho_r)
3443 
3444 ENDIF
3445 
3446 !Total toroidal flux
3447 IF(PRESENT(phi_r)) THEN
3448 
3449  phi_r(:)=0
3450  phi_r(1:nrho_r)=phitot_3d*(rho_r(1:nrho_r)/rhomax_3d)**2
3451 
3452 ENDIF
3453 
3454 !Total poloidal flux
3455 IF(PRESENT(psi_r)) THEN
3456 
3457  psi_r(:)=0
3458  iflag=0
3459  message=''
3460  CALL spline1_integ(1,nrho_3d,rho_3d,iotabar_3d,nr,rho_r,values,iflag,message)
3461 
3462  !Check messages
3463  IF(iflag /= 0) THEN
3464 
3465  message='AJAX_MAGFLUX ' // message
3466  IF(iflag > 0) GOTO 9999
3467 
3468  ENDIF
3469 
3470  psi_r(1:nr)=values(1:nr)*2*phitot_3d/rhomax_3d**2
3471 
3472  IF(nr < nrho_r) THEN
3473 
3474  DO i=nr+1,nrho_r !Over radial nodes
3475 
3476  psi_r(i)=psi_r(i-1)+phitot_3d/rhomax_3d**2 &
3477  *(rho_r(i-1)*iotabar_t(i-1)+rho_r(i)*iotabar_t(i)) &
3478  *(rho_r(i)-rho_r(i-1))
3479 
3480  ENDDO !Over radial nodes
3481 
3482  ENDIF
3483 
3484 ENDIF
3485 
3486 !-------------------------------------------------------------------------------
3487 !Cleanup and exit
3488 !-------------------------------------------------------------------------------
3489 9999 CONTINUE
3490 
3491 END SUBROUTINE ajax_magflux
3492 
3493 SUBROUTINE ajax_shape(nrho_r,rho_r, &
3494  iflag,message, &
3495  ZETA, &
3496  SHIFT_R,ELONG_R,TRIANG_R,RMAX_R,RMIN_R,ZMAX_R,ZMIN_R, &
3497  RBOT_R,RTOP_R)
3498 !-------------------------------------------------------------------------------
3499 !AJAX_SHAPE gets shift, elongation, and triangularity
3500 !
3501 !References:
3502 ! W.A.Houlberg, F90 free format 8/2004
3503 !-------------------------------------------------------------------------------
3504 
3505 !Declaration of input variables
3506 INTEGER, INTENT(IN) :: &
3507  nrho_r !no. of radial nodes [-]
3508 
3509 REAL(KIND=rspec), INTENT(IN) :: &
3510  rho_r(:) !radial nodes [rho]
3511 
3512 !Declaration of output variables
3513 CHARACTER(LEN=1024), INTENT(OUT) :: &
3514  message !warning or error message [character]
3515 
3516 INTEGER, INTENT(OUT) :: &
3517  iflag !error and warning flag [-]
3518  !=-1 warning
3519  !=0 none
3520  !=1 error
3521 
3522 !Declaration of optional input variables
3523 REAL(KIND=rspec), INTENT(IN), OPTIONAL :: &
3524  zeta !toroidal plane for the shape [-]
3525 ! !=0 by default
3526 
3527 !Declaration of optional output variables
3528 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
3529  shift_r(:), & !shift [-]
3530  elong_r(:), & !elongation [-]
3531  triang_r(:), & !triangularity [-]
3532  rmax_r(:), & !maximum R of plasma in zeta plane [m]
3533  rmin_r(:), & !minimum R of plasma in zeta plane [m]
3534  zmax_r(:), & !maximum Z of plasma in zeta plane [m]
3535  zmin_r(:), & !minimum Z of plasma in zeta plane [m]
3536  rbot_r(:), & !R at ZMIN_R in zeta plane [m]
3537  rtop_r(:) !R at ZMAX_R in zeta plane [m]
3538 
3539 !-------------------------------------------------------------------------------
3540 !Declaration of local variables
3541 LOGICAL :: &
3542  l_rminmax
3543 
3544 INTEGER :: &
3545  i,nr
3546 
3547 REAL(KIND=rspec) :: &
3548  a0,rg0,r_cyl(1:3),r_flx(1:3),v1(1:nrho_3d),rbot(1:nrho_3d), &
3549  rtop(1:nrho_3d),rmax(1:nrho_3d),rmin(1:nrho_3d),zmax(1:nrho_3d), &
3550  zmin(1:nrho_3d)
3551 
3552 !-------------------------------------------------------------------------------
3553 !Initialization
3554 !-------------------------------------------------------------------------------
3555 !Null output
3556 iflag=0
3557 message=''
3558 
3559 !Null local values
3560 r_flx(:)=0
3561 r_cyl(:)=0
3562 rbot(:)=0
3563 rtop(:)=0
3564 rmax(:)=0
3565 rmin(:)=0
3566 zmax(:)=0
3567 zmin(:)=0
3568 v1(:)=0
3569 
3570 !Set the toroidal angle for the calculations
3571 IF(PRESENT(zeta)) r_flx(3)=zeta
3572 
3573 !Check whether values outside R,Z domain are requested (nr is last point inside)
3574 loop_i: DO i=nrho_r,1,-1 !Over nodes
3575 
3576  nr=i
3577  IF(rho_r(nr) < rhomax_3d+rhores_3d) EXIT loop_i
3578 
3579 ENDDO loop_i !Over nodes
3580 
3581 !-------------------------------------------------------------------------------
3582 !Half diameter and center of plasma boundary
3583 !-------------------------------------------------------------------------------
3584 !Find coordinates where dR/dtheta=0 on inside for R_min
3585 l_rminmax=.true.
3586 r_flx(1)=rhomax_3d
3587 r_flx(2)=z_pi
3588 iflag=0
3589 message=''
3590 CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3591 
3592 !Check messages
3593 IF(iflag /= 0) THEN
3594 
3595  message='AJAX_SHAPE(1) ' // message
3596  IF(iflag > 0) GOTO 9999
3597 
3598 ENDIF
3599 
3600 rmin(nrho_3d)=r_cyl(1)
3601 
3602 !Find coordinates where dR/dtheta=0 on outside for R_max
3603 l_rminmax=.true.
3604 r_flx(1)=rhomax_3d
3605 r_flx(2)=0
3606 iflag=0
3607 message=''
3608 CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3609 
3610 !Check messages
3611 IF(iflag /= 0) THEN
3612 
3613  message='AJAX_SHAPE(2) ' // message
3614  IF(iflag > 0) GOTO 9999
3615 
3616 ENDIF
3617 
3618 rmax(nrho_3d)=r_cyl(1)
3619 
3620 !Major radius of center of plasma boundary
3621 rg0=(rmin(nrho_3d)+rmax(nrho_3d))/2
3622 
3623 !Minor radius = half diameter
3624 a0=(rmax(nrho_3d)-rmin(nrho_3d))/2
3625 
3626 !-------------------------------------------------------------------------------
3627 !Find inside, outside (dR/theta=0) and top, bottom (dZ/dtheta=0) of each surface
3628 !-------------------------------------------------------------------------------
3629 DO i=2,nrho_3d !Over radial nodes
3630 
3631  !dR/dtheta=0 on inside
3632  l_rminmax=.true.
3633  r_flx(1)=rho_3d(i)
3634  r_flx(2)=z_pi
3635  iflag=0
3636  message=''
3637  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3638 
3639  !Check messages
3640  IF(iflag /= 0) THEN
3641 
3642  message='AJAX_SHAPE(3) ' // message
3643  IF(iflag > 0) GOTO 9999
3644 
3645  ENDIF
3646 
3647  rmin(i)=r_cyl(1)
3648 
3649  !dR/dtheta=0 on outside
3650  l_rminmax=.true.
3651  r_flx(1)=rho_3d(i)
3652  r_flx(2)=0
3653  iflag=0
3654  message=''
3655  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3656 
3657  !Check messages
3658  IF(iflag /= 0) THEN
3659 
3660  message='AJAX_SHAPE(4) ' // message
3661  IF(iflag > 0) GOTO 9999
3662 
3663  ENDIF
3664 
3665  rmax(i)=r_cyl(1)
3666 
3667  !dZ/dtheta=0 on bottom
3668  l_rminmax=.false.
3669  r_flx(1)=rho_3d(i)
3670  r_flx(2)=z_pi/2
3671  iflag=0
3672  message=''
3673  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3674 
3675  !Check messages
3676  IF(iflag /= 0) THEN
3677 
3678  message='AJAX_SHAPE(5) ' // message
3679  IF(iflag > 0) GOTO 9999
3680 
3681  ENDIF
3682 
3683  rbot(i)=r_cyl(1)
3684  zmin(i)=r_cyl(3)
3685 
3686  !dZ/dtheta=0 on top
3687  l_rminmax=.false.
3688  r_flx(1)=rho_3d(i)
3689  r_flx(2)=-z_pi/2
3690  iflag=0
3691  message=''
3692  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3693 
3694  !Check messages
3695  IF(iflag /= 0) THEN
3696 
3697  message='AJAX_SHAPE(6) ' // message
3698  IF(iflag > 0) GOTO 9999
3699 
3700  ENDIF
3701 
3702  rtop(i)=r_cyl(1)
3703  zmax(i)=r_cyl(3)
3704 
3705 ENDDO !Over radial nodes
3706 
3707 !-------------------------------------------------------------------------------
3708 !Shift
3709 !-------------------------------------------------------------------------------
3710 IF(PRESENT(shift_r)) THEN
3711 
3712  !Initialization
3713  shift_r(1:nrho_r)=0
3714 
3715  !Shift relative to center of outer surface
3716  v1(2:nrho_3d)=((rmax(2:nrho_3d)+rmin(2:nrho_3d))/2-rg0)/a0
3717 
3718  !Set axial value
3719  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
3720 
3721  !Interpolate to external grid points inside R,Z domain
3722  iflag=0
3723  message=''
3724  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,shift_r,iflag,message)
3725 
3726  !Check messages
3727  IF(iflag /= 0) THEN
3728 
3729  message='AJAX_SHAPE(7) ' // message
3730  GOTO 9999
3731 
3732  ENDIF
3733 
3734  IF(nr < nrho_r) THEN
3735 
3736  !Extrapolate to external grid points outside R,Z domain
3737  shift_r(nr+1:nrho_r)=shift_r(nr)
3738 
3739  ENDIF
3740 
3741 ENDIF
3742 
3743 !-------------------------------------------------------------------------------
3744 !Elongation
3745 !-------------------------------------------------------------------------------
3746 IF(PRESENT(elong_r)) THEN
3747 
3748  !Initialization
3749  elong_r(1:nrho_r)=0
3750 
3751  !Elongation is total height over total width
3752  v1(2:nrho_3d)=(zmax(2:nrho_3d)-zmin(2:nrho_3d)) &
3753  /(rmax(2:nrho_3d)-rmin(2:nrho_3d))
3754 
3755  !Set axial value
3756  v1(1)=v1(2)-rho_3d(2)*(v1(3)-v1(2))/(rho_3d(3)-rho_3d(2))
3757 
3758  !Interpolate to external grid points inside R,Z domain
3759  iflag=0
3760  message=''
3761  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,elong_r,iflag,message)
3762 
3763  !Check messages
3764  IF(iflag /= 0) THEN
3765 
3766  message='AJAX_SHAPE(8) ' // message
3767  GOTO 9999
3768 
3769  ENDIF
3770 
3771  IF(nr < nrho_r) THEN
3772 
3773  !Extrapolate to external grid points outside R,Z domain
3774  elong_r(nr+1:nrho_r)=elong_r(nr)
3775 
3776  ENDIF
3777 
3778 ENDIF
3779 
3780 !-------------------------------------------------------------------------------
3781 !Triangularity
3782 !-------------------------------------------------------------------------------
3783 IF(PRESENT(triang_r)) THEN
3784 
3785  !Initialization
3786  triang_r(1:nrho_r)=0
3787 
3788  !Triangularity - average of upper and lower
3789  v1(2:nrho_3d)=((rmax(2:nrho_3d)+rmin(2:nrho_3d)) &
3790  -(rbot(2:nrho_3d)+rtop(2:nrho_3d))) &
3791  /(rmax(2:nrho_3d)-rmin(2:nrho_3d))
3792 
3793  !Set axial value
3794  v1(1)=0
3795 
3796  !Interpolate to external grid points inside R,Z domain
3797  iflag=0
3798  message=''
3799  CALL linear1_interp(nrho_3d,rho_3d,v1,nr,rho_r,triang_r,iflag,message)
3800 
3801  !Check messages
3802  IF(iflag /= 0) THEN
3803 
3804  message='AJAX_SHAPE(9) ' // message
3805  GOTO 9999
3806 
3807  ENDIF
3808 
3809  IF(nr < nrho_r) THEN
3810 
3811  !Extrapolate to external grid points outside R,Z domain
3812  triang_r(nr+1:nrho_r)=triang_r(nr)
3813 
3814  ENDIF
3815 
3816 ENDIF
3817 
3818 !-------------------------------------------------------------------------------
3819 !Maximum R
3820 !-------------------------------------------------------------------------------
3821 IF(PRESENT(rmax_r)) THEN
3822 
3823  !Initialization
3824  rmax_r(1:nrho_r)=0
3825 
3826  !To cover odd-shaped plasmas, look for maxima near pi/4 and 7pi/4
3827  DO i=2,nrho_3d !Over radial nodes
3828 
3829  l_rminmax=.true.
3830  r_flx(1)=rho_3d(i)
3831  r_flx(2)=z_pi/4
3832  iflag=0
3833  message=''
3834  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3835 
3836  !Check messages
3837  IF(iflag /= 0) THEN
3838 
3839  message='AJAX_SHAPE(10) ' // message
3840  GOTO 9999
3841 
3842  ENDIF
3843 
3844  IF(r_cyl(1) > rmax(i)) rmax(i)=r_cyl(1)
3845  r_flx(2)=7*z_pi/4
3846  iflag=0
3847  message=''
3848  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3849 
3850  !Check messages
3851  IF(iflag /= 0) THEN
3852 
3853  message='AJAX_SHAPE(11) ' // message
3854  GOTO 9999
3855 
3856  ENDIF
3857 
3858  IF(r_cyl(1) > rmax(i)) rmax(i)=r_cyl(1)
3859 
3860  ENDDO !Over radial nodes
3861 
3862  !Set axial value
3863  rmax(1)=rmax(2)-rho_3d(2)*(rmax(3)-rmax(2))/(rho_3d(3)-rho_3d(2))
3864 
3865  !Interpolate to external grid points inside R,Z domain
3866  iflag=0
3867  message=''
3868  CALL linear1_interp(nrho_3d,rho_3d,rmax,nr,rho_r,rmax_r,iflag,message)
3869 
3870  !Check messages
3871  IF(iflag /= 0) THEN
3872 
3873  message='AJAX_SHAPE(12) ' // message
3874  GOTO 9999
3875 
3876  ENDIF
3877 
3878 ENDIF
3879 
3880 !-------------------------------------------------------------------------------
3881 !Minimum R
3882 !-------------------------------------------------------------------------------
3883 IF(PRESENT(rmin_r)) THEN
3884 
3885  !Initialization
3886  rmin_r(1:nrho_r)=0
3887 
3888  !To cover odd-shaped plasmas, look for minima near 3pi/4 and 5pi/4
3889  DO i=2,nrho_3d !Over radial nodes
3890 
3891  l_rminmax=.true.
3892  r_flx(1)=rho_3d(i)
3893  r_flx(2)=3*z_pi/4
3894  iflag=0
3895  message=''
3896  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3897 
3898  !Check messages
3899  IF(iflag /= 0) THEN
3900 
3901  message='AJAX_SHAPE(13) ' // message
3902  GOTO 9999
3903 
3904  ENDIF
3905 
3906  IF(r_cyl(1) < rmin(i)) rmin(i)=r_cyl(1)
3907  r_flx(2)=5*z_pi/4
3908  iflag=0
3909  message=''
3910  CALL ajax_minmax_rz(l_rminmax,r_flx,r_cyl,iflag,message)
3911 
3912  !Check messages
3913  IF(iflag /= 0) THEN
3914 
3915  message='AJAX_SHAPE(14) ' // message
3916  GOTO 9999
3917 
3918  ENDIF
3919 
3920  IF(r_cyl(1) < rmin(i)) rmin(i)=r_cyl(1)
3921 
3922  ENDDO !Over radial nodes
3923 
3924  !Set axial value
3925  rmin(1)=rmin(2)-rho_3d(2)*(rmin(3)-rmin(2))/(rho_3d(3)-rho_3d(2))
3926 
3927  !Interpolate to external grid points inside R,Z domain
3928  iflag=0
3929  message=''
3930  CALL linear1_interp(nrho_3d,rho_3d,rmin,nr,rho_r,rmin_r,iflag,message)
3931 
3932  !Check messages
3933  IF(iflag /= 0) THEN
3934 
3935  message='AJAX_SHAPE(15) ' // message
3936  GOTO 9999
3937 
3938  ENDIF
3939 
3940 ENDIF
3941 
3942 !-------------------------------------------------------------------------------
3943 !Maximum Z
3944 !-------------------------------------------------------------------------------
3945 IF(PRESENT(zmax_r)) THEN
3946 
3947  !Initialization
3948  zmax_r(1:nrho_r)=0
3949 
3950  !Set axial value
3951  zmax(1)=zmax(2)-rho_3d(2)*(zmax(3)-zmax(2))/(rho_3d(3)-rho_3d(2))
3952 
3953  !Interpolate to external grid points inside R,Z domain
3954  iflag=0
3955  message=''
3956  CALL linear1_interp(nrho_3d,rho_3d,zmax,nr,rho_r,zmax_r,iflag,message)
3957 
3958  !Check messages
3959  IF(iflag /= 0) THEN
3960 
3961  message='AJAX_SHAPE(16) ' // message
3962  GOTO 9999
3963 
3964  ENDIF
3965 
3966 ENDIF
3967 
3968 !-------------------------------------------------------------------------------
3969 !Minimum Z
3970 !-------------------------------------------------------------------------------
3971 IF(PRESENT(zmin_r)) THEN
3972 
3973  !Initialization
3974  zmin_r(1:nrho_r)=0
3975 
3976  !Set axial value
3977  zmin(1)=zmin(2)-rho_3d(2)*(zmin(3)-zmin(2))/(rho_3d(3)-rho_3d(2))
3978 
3979  !Interpolate to external grid points inside R,Z domain
3980  iflag=0
3981  message=''
3982  CALL linear1_interp(nrho_3d,rho_3d,zmin,nr,rho_r,zmin_r,iflag,message)
3983 
3984  !Check messages
3985  IF(iflag /= 0) THEN
3986 
3987  message='AJAX_SHAPE(17) ' // message
3988  GOTO 9999
3989 
3990  ENDIF
3991 
3992 ENDIF
3993 
3994 !-------------------------------------------------------------------------------
3995 !R at maximum Z
3996 !-------------------------------------------------------------------------------
3997 IF(PRESENT(rtop_r)) THEN
3998 
3999  !Initialization
4000  rtop_r(1:nrho_r)=0
4001 
4002  !Set axial value
4003  rtop(1)=rtop(2)-rho_3d(2)*(rtop(3)-rtop(2))/(rho_3d(3)-rho_3d(2))
4004 
4005  !Interpolate to external grid points inside R,Z domain
4006  iflag=0
4007  message=''
4008  CALL linear1_interp(nrho_3d,rho_3d,rtop,nr,rho_r,rtop_r,iflag,message)
4009 
4010  !Check messages
4011  IF(iflag /= 0) THEN
4012 
4013  message='AJAX_SHAPE(18) ' // message
4014  GOTO 9999
4015 
4016  ENDIF
4017 
4018 ENDIF
4019 
4020 !-------------------------------------------------------------------------------
4021 !R at minimum Z
4022 !-------------------------------------------------------------------------------
4023 IF(PRESENT(rbot_r)) THEN
4024 
4025  !Initialization
4026  rbot_r(1:nrho_r)=0
4027 
4028  !Set axial value
4029  rbot(1)=rbot(2)-rho_3d(2)*(rbot(3)-rbot(2))/(rho_3d(3)-rho_3d(2))
4030 
4031  !Interpolate to external grid points inside R,Z domain
4032  iflag=0
4033  message=''
4034  CALL linear1_interp(nrho_3d,rho_3d,rbot,nr,rho_r,rbot_r,iflag,message)
4035 
4036  !Check messages
4037  IF(iflag /= 0) THEN
4038 
4039  message='AJAX_SHAPE(19) ' // message
4040  GOTO 9999
4041 
4042  ENDIF
4043 
4044 ENDIF
4045 
4046 !-------------------------------------------------------------------------------
4047 !Cleanup and exit
4048 !-------------------------------------------------------------------------------
4049 9999 CONTINUE
4050 
4051 END SUBROUTINE ajax_shape
4052 
4053 SUBROUTINE ajax_globals(iflag,message, &
4054  R000,PHITOT,RHOMAX,RHOMIN,SIGNBP,SIGNBT,NPER,NRHO, &
4055  NTHETA,NZETA)
4056 !-------------------------------------------------------------------------------
4057 !AJAX_GLOBALS gets global characteristics of the data
4058 !
4059 !References:
4060 ! W.A.Houlberg, F90 free format 8/2004
4061 !-------------------------------------------------------------------------------
4062 
4063 !Declaration of output variables
4064 CHARACTER(LEN=1024), INTENT(OUT) :: &
4065  message !warning or error message [character]
4066 
4067 INTEGER, INTENT(OUT) :: &
4068  iflag !error and warning flag [-]
4069  !=-1 warning
4070  !=0 none
4071  !=1 error
4072 
4073 !Declaration of optional output variables
4074 INTEGER, INTENT(OUT), OPTIONAL :: &
4075  NPER, & !number of field periods, =0 for axisymmetry [-]
4076  NRHO, & !number of radial nodes in internal data [-]
4077  NTHETA, & !number of poloidal nodes in internal data [-]
4078  NZETA !number of toroidal nodes in internal data [-]
4079 
4080 REAL(KIND=rspec), INTENT(OUT), OPTIONAL :: &
4081  r000, & !coefficient of (m,n)=(0,0) mode for R at axis [m]
4082  phitot, & !total toroidal flux [Wb]
4083  rhomin, & !inner radial boundary of R,Z domain [rho]
4084  rhomax, & !outer radial boundary of R,Z domain [rho]
4085  signbp, & !sign of the poloidal magnetic field [-]
4086  !positive is down on outside
4087  signbt !sign of the toroidal magnetic field [-]
4088  !positive is counterclockwise from top view
4089 
4090 !-------------------------------------------------------------------------------
4091 !Initialization
4092 !-------------------------------------------------------------------------------
4093 !Null output
4094 iflag=0
4095 message=''
4096 
4097 !-------------------------------------------------------------------------------
4098 !Return values
4099 !-------------------------------------------------------------------------------
4100 IF(PRESENT(r000)) r000=r000_3d
4101 IF(PRESENT(phitot)) phitot=phitot_3d
4102 IF(PRESENT(rhomax)) rhomax=rhomax_3d
4103 IF(PRESENT(rhomin)) rhomin=rhomin_3d
4104 IF(PRESENT(signbp)) signbp=signbp_3d
4105 IF(PRESENT(signbt)) signbt=signbt_3d
4106 IF(PRESENT(nper)) nper=nper_3d
4107 IF(PRESENT(nrho)) nrho=nrho_3d
4108 IF(PRESENT(ntheta)) ntheta=ntheta_3d
4109 IF(PRESENT(nzeta)) nzeta=nzeta_3d
4110 
4111 END SUBROUTINE ajax_globals
4112 
4113 SUBROUTINE ajax_minmax_rz(l_rminmax, &
4114  r_flx, &
4115  r_cyl,iflag,message)
4116 !-------------------------------------------------------------------------------
4117 !AJAX_MINMAX_RZ gets maximum or minimum of R or Z
4118 !
4119 !References:
4120 ! W.A.Houlberg, F90 free format 8/2004
4121 !-------------------------------------------------------------------------------
4122 
4123 !Declaration of input variables
4124 LOGICAL, INTENT(IN) :: &
4125  l_rminmax !switch to select search for R or Z [logical]
4126  !=.TRUE. find maximum or minimum R
4127  !=.FALSE. find maximum or minimum Z
4128 
4129 !Declaration of input/output variables
4130 REAL(KIND=rspec), INTENT(INOUT) :: &
4131  r_flx(:) !flux coordinates (rho,theta,zeta) [rho,rad,rad]
4132 
4133 !Declaration of output variables
4134 CHARACTER(LEN=1024), INTENT(OUT) :: &
4135  message !warning or error message [character]
4136 
4137 INTEGER, INTENT(OUT) :: &
4138  iflag !error and warning flag [-]
4139  !=-1 warning
4140  !=0 none
4141  !=1 error
4142 
4143 REAL(KIND=rspec), INTENT(OUT) :: &
4144  r_cyl(:) !cylindrical coordinates (R,phi,Z) [m,rad,m]
4145 
4146 !-------------------------------------------------------------------------------
4147 !Declaration of local variables
4148 INTEGER :: &
4149  i,ig
4150 
4151 REAL(KIND=rspec) :: &
4152  g_cyl0(1:6),g_cyl1(1:6),r_flx0(1:3),r_flx1(1:3)
4153 
4154 !-------------------------------------------------------------------------------
4155 !Initialization
4156 !-------------------------------------------------------------------------------
4157 !Null output
4158 iflag=0
4159 message=''
4160 
4161 !Null local values
4162 r_flx0(:)=0
4163 r_flx1(:)=0
4164 g_cyl0(:)=0
4165 g_cyl1(:)=0
4166 
4167 !Index for derivative
4168 IF(l_rminmax) THEN
4169 
4170  !d(R)/d(theta)
4171  ig=2
4172 
4173 ELSE
4174 
4175  !d(Z)/d(theta)
4176  ig=5
4177 
4178 ENDIF
4179 
4180 !-------------------------------------------------------------------------------
4181 !Find extrema
4182 !-------------------------------------------------------------------------------
4183 r_flx0(1:3)=r_flx(1:3)
4184 r_flx0(2)=r_flx0(2)-0.05*z_pi
4185 iflag=0
4186 message=''
4187 CALL ajax_flx2cyl(r_flx0,r_cyl,iflag,message, &
4188  g_cyl=g_cyl0)
4189 
4190 !Check messages
4191 IF(iflag /= 0) THEN
4192 
4193  message='AJAX_MINMAX_RZ(1) ' // message
4194  IF(iflag > 0) GOTO 9999
4195 
4196 ENDIF
4197 
4198 r_flx1(1:3)=r_flx(1:3)
4199 r_flx1(2)=r_flx1(2)+0.05*z_pi
4200 iflag=0
4201 message=''
4202 CALL ajax_flx2cyl(r_flx1,r_cyl,iflag,message, &
4203  g_cyl=g_cyl1)
4204 
4205 !Check messages
4206 IF(iflag /= 0) THEN
4207 
4208  message='AJAX_MINMAX_RZ(2) ' // message
4209  IF(iflag > 0) GOTO 9999
4210 
4211 ENDIF
4212 
4213 !Normally 1 or 2 iterations are required
4214 loop_i: DO i=1,10 !Over iteration
4215 
4216  r_flx(2)=r_flx0(2)-g_cyl0(ig)*(r_flx1(2)-r_flx0(2))/(g_cyl1(ig)-g_cyl0(ig))
4217  r_flx0(1:3)=r_flx1(1:3)
4218  g_cyl0(:)=g_cyl1(:)
4219  r_flx1(1:3)=r_flx(1:3)
4220  iflag=0
4221  message=''
4222  CALL ajax_flx2cyl(r_flx,r_cyl,iflag,message, &
4223  g_cyl=g_cyl1)
4224 
4225  !Check messages
4226  IF(iflag /= 0) THEN
4227 
4228  message='AJAX_MINMAX_RZ(3) ' // message
4229  IF(iflag > 0) GOTO 9999
4230 
4231  ENDIF
4232 
4233  IF(abs(g_cyl1(ig)) < 1.0e-5*r000_3d/z_pi) EXIT loop_i
4234 
4235 ENDDO loop_i !Over iteration
4236 
4237 !-------------------------------------------------------------------------------
4238 !Cleanup and exit
4239 !-------------------------------------------------------------------------------
4240 9999 CONTINUE
4241 
4242 END SUBROUTINE ajax_minmax_rz
4243 
4244 SUBROUTINE ajax_init
4245 !-------------------------------------------------------------------------------
4246 !AJAX_INIT initializes or resets private data for the radial, poloidal and
4247 ! toroidal grids, and allocates storage for the R, Z, and stream function
4248 ! expansions
4249 !
4250 !References:
4251 ! W.A.Houlberg, F90 free format 8/2004
4252 !-------------------------------------------------------------------------------
4253 
4254 !Declaration of local variables
4255 INTEGER :: &
4256  i,nset1,nset2,kmax
4257 
4258 !-------------------------------------------------------------------------------
4259 !Initialization
4260 !-------------------------------------------------------------------------------
4261 !Machine constants
4262 z_large=huge(1.0_rspec)
4263 z_precision=epsilon(1.0_rspec)
4264 z_small=tiny(1.0_rspec)
4265 
4266 !Resolution of rho
4267 rhores_3d=1.0e-3*rhomax_3d
4268 
4269 !-------------------------------------------------------------------------------
4270 !Radial grid and R,Z
4271 !-------------------------------------------------------------------------------
4272 IF(ALLOCATED(rho_3d)) THEN
4273 
4274  !Check dimensions
4275  nset1=SIZE(r_3d,2)
4276  nset2=SIZE(r_3d,3)
4277 
4278  !If storage requirements have changed, reallocate
4279  IF(nset1 /= nrho_3d .OR. &
4280  nset2 /= krz_3d) THEN
4281 
4282  !Reallocate radial grid and R,Z
4283  DEALLOCATE(rho_3d, &
4284  r_3d, &
4285  z_3d)
4286  ALLOCATE(rho_3d(nrho_3d), &
4287  r_3d(4,nrho_3d,krz_3d), &
4288  z_3d(4,nrho_3d,krz_3d))
4289 
4290  rho_3d(:)=0
4291  r_3d(:,:,:)=0
4292  z_3d(:,:,:)=0
4293 
4294  ENDIF
4295 
4296 ELSE
4297 
4298  !Allocate radial grid and R,Z
4299  ALLOCATE(rho_3d(nrho_3d), &
4300  r_3d(4,nrho_3d,krz_3d), &
4301  z_3d(4,nrho_3d,krz_3d))
4302 
4303  rho_3d(:)=0
4304  r_3d(:,:,:)=0
4305  z_3d(:,:,:)=0
4306 
4307 ENDIF
4308 
4309 !Set radial grid
4310 rho_3d(:)=real((/ (i-1,i=1,nrho_3d) /),rspec)*rhomax_3d/(nrho_3d-1)
4311 
4312 !-------------------------------------------------------------------------------
4313 !Lambda
4314 !-------------------------------------------------------------------------------
4315 IF(ALLOCATED(lam_3d)) THEN
4316 
4317  !Check dimensions
4318  nset1=SIZE(lam_3d,2)
4319  nset2=SIZE(lam_3d,3)
4320 
4321  !If storage requirements have changed, reallocate
4322  IF(nset1 /= nrho_3d .OR. &
4323  nset2 /= klam_3d) THEN
4324 
4325  !Realloate lambda
4326  DEALLOCATE(lam_3d)
4327  ALLOCATE(lam_3d(4,nrho_3d,klam_3d))
4328 
4329  lam_3d(:,:,:)=0
4330 
4331  ENDIF
4332 
4333 ELSE
4334 
4335  !Allocate lambda
4336  ALLOCATE(lam_3d(4,nrho_3d,klam_3d))
4337 
4338  lam_3d(:,:,:)=0
4339 
4340 ENDIF
4341 
4342 !-------------------------------------------------------------------------------
4343 !Toroidal and poloidal modes
4344 !-------------------------------------------------------------------------------
4345 kmax=max(krz_3d,klam_3d)
4346 
4347 IF(ALLOCATED(m_3d)) THEN
4348 
4349  !Check dimension
4350  nset1=SIZE(m_3d)
4351 
4352  !If storage requirements have changed, reallocate
4353  IF(nset1 /= kmax) THEN
4354 
4355  !Reallocate toroidal and poloidal modes
4356  DEALLOCATE(m_3d, &
4357  n_3d, &
4358  mabs_3d)
4359  ALLOCATE(m_3d(kmax), &
4360  n_3d(kmax), &
4361  mabs_3d(kmax))
4362 
4363  m_3d(:)=0
4364  n_3d(:)=0
4365  mabs_3d(:)=0
4366 
4367  ENDIF
4368 
4369 ELSE
4370 
4371  !Allocate toroidal and poloidal modes
4372  ALLOCATE(m_3d(kmax), &
4373  n_3d(kmax), &
4374  mabs_3d(kmax))
4375 
4376  m_3d(:)=0
4377  n_3d(:)=0
4378  mabs_3d(:)=0
4379 
4380 ENDIF
4381 
4382 !-------------------------------------------------------------------------------
4383 !Poloidal grid spacing and weighting
4384 !-------------------------------------------------------------------------------
4385 dtheta_3d=2*z_pi/(ntheta_3d-1)
4386 
4387 IF(ALLOCATED(wtheta_3d)) THEN
4388 
4389  !Check dimension
4390  nset1=SIZE(wtheta_3d)
4391 
4392  IF(nset1 /= ntheta_3d) THEN
4393 
4394  !Reallocate poloidal weighting
4395  DEALLOCATE(wtheta_3d)
4396  ALLOCATE(wtheta_3d(ntheta_3d))
4397 
4398  wtheta_3d(:)=0
4399 
4400  !Set poloidal weights
4401  wtheta_3d(1)=1
4402  wtheta_3d(ntheta_3d)=1
4403 
4404  DO i=2,ntheta_3d-1 !Over poloidal nodes
4405 
4406  IF(mod(i,2) == 0) THEN
4407 
4408  !Even node
4409  wtheta_3d(i)=4
4410 
4411  ELSE
4412 
4413  !Odd mode
4414  wtheta_3d(i)=2
4415 
4416  ENDIF
4417 
4418  ENDDO !Over poloidal nodes
4419 
4420  wtheta_3d(:)=wtheta_3d(:)*2*z_pi/3/(ntheta_3d-1)
4421 
4422  ENDIF
4423 
4424 ELSE
4425 
4426  !Allocate poloidal weighting
4427  ALLOCATE(wtheta_3d(ntheta_3d))
4428 
4429  wtheta_3d(:)=0
4430 
4431  !Set poloidal weights
4432  wtheta_3d(1)=1
4433  wtheta_3d(ntheta_3d)=1
4434 
4435  DO i=2,ntheta_3d-1 !Over poloidal nodes
4436 
4437  IF(mod(i,2) == 0) THEN
4438 
4439  !Even node
4440  wtheta_3d(i)=4
4441 
4442  ELSE
4443 
4444  !Odd mode
4445  wtheta_3d(i)=2
4446 
4447  ENDIF
4448 
4449  ENDDO !Over poloidal nodes
4450 
4451  wtheta_3d(:)=wtheta_3d(:)*2*z_pi/3/(ntheta_3d-1)
4452 
4453 ENDIF
4454 
4455 !-------------------------------------------------------------------------------
4456 !Poloidal grid spacing and weighting
4457 !-------------------------------------------------------------------------------
4458 IF(nzeta_3d == 1) THEN
4459 
4460  dzeta_3d=2*z_pi
4461 
4462 ELSE
4463 
4464  dzeta_3d=2*z_pi/(nzeta_3d-1)/nper_3d
4465 
4466 ENDIF
4467 
4468 !Check allocation of toroidal weighting
4469 IF(ALLOCATED(wzeta_3d)) THEN
4470 
4471  !Check dimension
4472  nset1=SIZE(wzeta_3d)
4473 
4474  IF(nset1 /= nzeta_3d) THEN
4475 
4476  !Reallocate toroidal weighting
4477  DEALLOCATE(wzeta_3d)
4478  ALLOCATE(wzeta_3d(nzeta_3d))
4479 
4480  wzeta_3d(:)=0
4481 
4482  !Set toroidal weights
4483  wzeta_3d(1)=dzeta_3d
4484 
4485  IF(nzeta_3d > 1) THEN
4486 
4487  !Non-axisymmetric plasma
4488  wzeta_3d(1)=1
4489  wzeta_3d(nzeta_3d)=1
4490 
4491  DO i=2,nzeta_3d-1 !Over toroidal nodes
4492 
4493  IF(mod(i,2) == 0) THEN
4494 
4495  !Even node
4496  wzeta_3d(i)=4
4497 
4498  ELSE
4499 
4500  !Odd mode
4501  wzeta_3d(i)=2
4502 
4503  ENDIF
4504 
4505  ENDDO !Over toroidal nodes
4506 
4507  wzeta_3d(:)=wzeta_3d(:)*nper_3d*dzeta_3d/3
4508 
4509  ENDIF
4510 
4511  ENDIF
4512 
4513 ELSE
4514 
4515  !Allocate toroidal weighting
4516  ALLOCATE(wzeta_3d(nzeta_3d))
4517 
4518  wzeta_3d(:)=0
4519 
4520  !Set toroidal weights
4521  wzeta_3d(1)=dzeta_3d
4522 
4523  IF(nzeta_3d > 1) THEN
4524 
4525  !Non-axisymmetric plasma
4526  wzeta_3d(1)=1
4527  wzeta_3d(nzeta_3d)=1
4528 
4529  DO i=2,nzeta_3d-1 !Over toroidal nodes
4530 
4531  IF(mod(i,2) == 0) THEN
4532 
4533  !Even node
4534  wzeta_3d(i)=4
4535 
4536  ELSE
4537 
4538  !Odd mode
4539  wzeta_3d(i)=2
4540 
4541  ENDIF
4542 
4543  ENDDO !Over toroidal nodes
4544 
4545  wzeta_3d(:)=wzeta_3d(:)*nper_3d*dzeta_3d/3
4546 
4547  ENDIF
4548 
4549 ENDIF
4550 
4551 !-------------------------------------------------------------------------------
4552 !Set logical switches for flux surface averaging
4553 !-------------------------------------------------------------------------------
4554 l_fluxavb_3d=.false.
4555 l_fluxavg_3d=.false.
4556 
4557 END SUBROUTINE ajax_init
4558 
4559 SUBROUTINE ajax_init_fluxav_b
4560 !-------------------------------------------------------------------------------
4561 !AJAX_INIT_FLUXAV_B initializes magnetic field arrays
4562 !
4563 !References:
4564 ! W.A.Houlberg, F90 free format 8/2004
4565 !-------------------------------------------------------------------------------
4566 
4567 !Declaration of local variables
4568 INTEGER :: &
4569  i,j,k,nset1,nset2,nset3
4570 
4571 REAL(KIND=rspec) :: &
4572  br,bz,bzeta,phiprm,r_flx(1:3)
4573 
4574 !-------------------------------------------------------------------------------
4575 !Load lambda derivatives for flux surface averaging
4576 !-------------------------------------------------------------------------------
4577 !Check allocation
4578 IF(ALLOCATED(eltheta_3d)) THEN
4579 
4580  !Check dimensions
4581  nset1=SIZE(eltheta_3d,1)
4582  nset2=SIZE(eltheta_3d,2)
4583  nset3=SIZE(eltheta_3d,3)
4584 
4585  !If storage requirements have changed, reallocate
4586  IF(nset1 /= nrho_3d .OR. &
4587  nset2 /= ntheta_3d .OR. &
4588  nset3 /= nzeta_3d) THEN
4589 
4590  !Reallocate lambda derivatives
4591  DEALLOCATE(eltheta_3d, &
4592  elzeta_3d)
4593  ALLOCATE(eltheta_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4594  elzeta_3d(nrho_3d,ntheta_3d,nzeta_3d))
4595 
4596  ENDIF
4597 
4598 ELSE
4599 
4600  !Allocate lambda derivatives
4601  ALLOCATE(eltheta_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4602  elzeta_3d(nrho_3d,ntheta_3d,nzeta_3d))
4603 
4604 ENDIF
4605 
4606 !Initialization
4607 r_flx(:)=0
4608 eltheta_3d(:,:,:)=0
4609 elzeta_3d(:,:,:)=0
4610 
4611 !Fill arrays
4612 DO i=2,nrho_3d !Over radial nodes
4613 
4614  r_flx(1)=rho_3d(i)
4615 
4616  DO j=1,ntheta_3d !Over poloidal nodes
4617 
4618  r_flx(2)=(j-1)*dtheta_3d
4619 
4620  DO k=1,nzeta_3d !Over toroidal nodes
4621 
4622  r_flx(3)=(k-1)*dzeta_3d
4623 
4624  CALL ajax_lambda(r_flx, &
4625  eltheta_3d(i,j,k),elzeta_3d(i,j,k))
4626 
4627  ENDDO !Over toroidal nodes
4628 
4629  ENDDO !Over poloidal nodes
4630 
4631 ENDDO !Over radial nodes
4632 
4633 !-------------------------------------------------------------------------------
4634 !Load B data for flux surface averaging
4635 !-------------------------------------------------------------------------------
4636 !Check allocation
4637 IF(ALLOCATED(b_3d)) THEN
4638 
4639  !Check dimensions
4640  nset1=SIZE(b_3d,1)
4641  nset2=SIZE(b_3d,2)
4642  nset3=SIZE(b_3d,3)
4643 
4644  !If storage requirements have changed, reallocate
4645  IF(nset1 /= nrho_3d .OR. &
4646  nset2 /= ntheta_3d .OR. &
4647  nset3 /= nzeta_3d) THEN
4648 
4649  !Reallocate B data
4650  DEALLOCATE(b_3d, &
4651  btheta_3d)
4652  ALLOCATE(b_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4653  btheta_3d(nrho_3d,ntheta_3d,nzeta_3d))
4654  ENDIF
4655 
4656 ELSE
4657 
4658  !Allocate B data
4659  ALLOCATE(b_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4660  btheta_3d(nrho_3d,ntheta_3d,nzeta_3d))
4661 
4662 ENDIF
4663 
4664 !Initialization
4665 btheta_3d(:,:,:)=0
4666 b_3d(:,:,:)=0
4667 
4668 !Evaluate 3D arrays
4669 DO i=2,nrho_3d !Over radial nodes
4670 
4671  phiprm=2*rho_3d(i)*phitot_3d/rhomax_3d**2
4672 
4673  DO j=1,ntheta_3d !Over poloidal nodes
4674 
4675  DO k=1,nzeta_3d !Over toroidal nodes
4676 
4677  btheta_3d(i,j,k)=(iotabar_3d(1,i)-elzeta_3d(i,j,k))
4678  bzeta=(1.0+eltheta_3d(i,j,k))
4679  br=gcyl_3d(2,i,j,k)*btheta_3d(i,j,k)+gcyl_3d(3,i,j,k)*bzeta
4680  bz=gcyl_3d(5,i,j,k)*btheta_3d(i,j,k)+gcyl_3d(6,i,j,k)*bzeta
4681  b_3d(i,j,k)=sqrt(br**2+bz**2+(rcyl_3d(i,j,k)*bzeta)**2)/gsqrt_3d(i,j,k)
4682  btheta_3d(i,j,k)=btheta_3d(i,j,k)/gsqrt_3d(i,j,k)
4683 
4684  ENDDO !Over toroidal nodes
4685 
4686  ENDDO !Over poloidal nodes
4687 
4688  btheta_3d(i,:,:)=phiprm*btheta_3d(i,:,:)
4689  b_3d(i,:,:)=abs(phiprm)*b_3d(i,:,:)
4690 
4691 ENDDO !Over radial nodes
4692 
4693 !Poloidal values at origin are linear extrapolation of averages at 2 and 3
4694 DO k=1,nzeta_3d
4695 
4696  btheta_3d(1,1:ntheta_3d,k)=(sum(btheta_3d(2,1:ntheta_3d-1,k))*rho_3d(3) &
4697  -sum(btheta_3d(3,1:ntheta_3d-1,k)) &
4698  *rho_3d(2))/(ntheta_3d-1)/(rho_3d(3)-rho_3d(2))
4699  b_3d(1,1:ntheta_3d,k)=(sum(b_3d(2,1:ntheta_3d-1,k))*rho_3d(3) &
4700  -sum(b_3d(3,1:ntheta_3d-1,k)) &
4701  *rho_3d(2))/(ntheta_3d-1)/(rho_3d(3)-rho_3d(2))
4702 
4703 ENDDO
4704 
4705 !Divide by 2*pi
4706 btheta_3d(:,:,:)=btheta_3d(:,:,:)/2/z_pi
4707 b_3d(:,:,:)=b_3d(:,:,:)/2/z_pi
4708 
4709 !-------------------------------------------------------------------------------
4710 !Set initialization flag
4711 !-------------------------------------------------------------------------------
4712 l_fluxavb_3d=.true.
4713 
4714 END SUBROUTINE ajax_init_fluxav_b
4715 
4716 SUBROUTINE ajax_init_fluxav_g(iflag,message)
4717 !-------------------------------------------------------------------------------
4718 !AJAX_INIT_FLUXAV_G initializes geometry arrays
4719 !
4720 !References:
4721 ! W.A.Houlberg, F90 free format 8/2004
4722 !-------------------------------------------------------------------------------
4723 
4724 !Declaration of output variables
4725 CHARACTER(LEN=1024), INTENT(OUT) :: &
4726  message !warning or error message [character]
4727 
4728 INTEGER, INTENT(OUT) :: &
4729  iflag !error and warning flag [-]
4730  !=-1 warning
4731  !=0 none
4732  !=1 error
4733 
4734 !-------------------------------------------------------------------------------
4735 !Declaration of local variables
4736 INTEGER :: &
4737  i,j,k,nset1,nset2,nset3
4738 
4739 REAL(KIND=rspec) :: &
4740  r_cyl(1:3),r_flx(1:3)
4741 
4742 !-------------------------------------------------------------------------------
4743 !Null output
4744 !-------------------------------------------------------------------------------
4745 !Error flag and message
4746 iflag=0
4747 message=''
4748 
4749 !-------------------------------------------------------------------------------
4750 !Load R,Z and other geometric data for flux surface averaging
4751 !-------------------------------------------------------------------------------
4752 !Check allocation
4753 IF(ALLOCATED(rcyl_3d)) THEN
4754 
4755  !Check dimensions
4756  nset1=SIZE(rcyl_3d,1)
4757  nset2=SIZE(rcyl_3d,2)
4758  nset3=SIZE(rcyl_3d,3)
4759 
4760  !If storage requirements have changed, reallocate
4761  IF(nset1 /= nrho_3d .OR. &
4762  nset2 /= ntheta_3d .OR. &
4763  nset3 /= nzeta_3d) THEN
4764 
4765  !Reallocate R,Z and other geometric data
4766  DEALLOCATE(rcyl_3d, &
4767  zcyl_3d, &
4768  gsqrt_3d, &
4769  gcyl_3d, &
4770  vp_3d, &
4771  gt_3d, &
4772  az_3d)
4773  ALLOCATE(rcyl_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4774  zcyl_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4775  gsqrt_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4776  gcyl_3d(6,nrho_3d,ntheta_3d,nzeta_3d), &
4777  vp_3d(nrho_3d), &
4778  gt_3d(ntheta_3d), &
4779  az_3d(nzeta_3d))
4780 
4781  ENDIF
4782 
4783 ELSE
4784 
4785  !Allocate R,Z and other geometric data
4786  ALLOCATE(rcyl_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4787  zcyl_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4788  gsqrt_3d(nrho_3d,ntheta_3d,nzeta_3d), &
4789  gcyl_3d(6,nrho_3d,ntheta_3d,nzeta_3d), &
4790  vp_3d(nrho_3d), &
4791  gt_3d(ntheta_3d), &
4792  az_3d(nzeta_3d))
4793 
4794 ENDIF
4795 
4796 !Initialization
4797 rcyl_3d(:,:,:)=0
4798 zcyl_3d(:,:,:)=0
4799 gsqrt_3d(:,:,:)=0
4800 gcyl_3d(:,:,:,:)=0
4801 vp_3d(:)=0
4802 gt_3d(:)=0
4803 az_3d(:)=0
4804 r_flx(:)=0
4805 r_cyl(:)=0
4806 
4807 !Evaluate 3D cylindrical coordinates, metrics, and Jacobian
4808 DO i=2,nrho_3d !Over radial nodes
4809 
4810  DO j=1,ntheta_3d !Over poloidal nodes
4811 
4812  DO k=1,nzeta_3d !Over toroidal nodes
4813 
4814  r_flx(1)=rho_3d(i)
4815  r_flx(2)=(j-1)*dtheta_3d
4816  r_flx(3)=(k-1)*dzeta_3d
4817  iflag=0
4818  message=''
4819  CALL ajax_flx2cyl(r_flx,r_cyl,iflag,message, &
4820  g_cyl=gcyl_3d(1:6,i,j,k), &
4821  gsqrt=gsqrt_3d(i,j,k))
4822 
4823  !Check messages
4824  IF(iflag /= 0) THEN
4825 
4826  message='AJAX_INIT_FLUXAV_G '// message
4827  IF(iflag > 0) GOTO 9999
4828 
4829  ENDIF
4830 
4831  rcyl_3d(i,j,k)=r_cyl(1)
4832  zcyl_3d(i,j,k)=r_cyl(3)
4833 
4834  ENDDO !Over toroidal nodes
4835 
4836  ENDDO !Over poloidal nodes
4837 
4838 ENDDO !Over radial nodes
4839 
4840 !Calculate V' on internal grid
4841 DO i=2,nrho_3d !Over radial nodes
4842 
4843  DO k=1,nzeta_3d !Over toroidal nodes
4844 
4845  gt_3d(1:ntheta_3d)=gsqrt_3d(i,1:ntheta_3d,k)
4846  az_3d(k)=sum(wtheta_3d*gt_3d) !Over poloidal nodes
4847 
4848  ENDDO !Over toroidal nodes
4849 
4850  vp_3d(i)=sum(wzeta_3d*az_3d) !Over toroidal nodes
4851 
4852 ENDDO !Over radial nodes
4853 
4854 !-------------------------------------------------------------------------------
4855 !Set logical switches for flux surface averaging
4856 !-------------------------------------------------------------------------------
4857 l_fluxavg_3d=.true.
4858 
4859 !-------------------------------------------------------------------------------
4860 !Cleanup and exit
4861 !-------------------------------------------------------------------------------
4862 9999 CONTINUE
4863 
4864 END SUBROUTINE ajax_init_fluxav_g
4865 
4866 SUBROUTINE ajax_init_lambda
4867 !-------------------------------------------------------------------------------
4868 !AJAX_INIT_LAMBDA calculates the magnetic stream function expansion coefficients
4869 ! for an axisymmetric plasma
4870 !
4871 !References:
4872 ! W.A.Houlberg, F90 free format 8/2004
4873 !-------------------------------------------------------------------------------
4874 
4875 !Declaration of local variables
4876 INTEGER :: &
4877  i,j,k,k_bc1=3,k_bcn=0
4878 
4879 REAL(KIND=rspec) :: &
4880  theta,g1(1:ntheta_3d),g2(1:ntheta_3d)
4881 
4882 !-------------------------------------------------------------------------------
4883 !Initialization
4884 !-------------------------------------------------------------------------------
4885 lam_3d(:,:,:)=0
4886 g1(:)=0
4887 g2(:)=0
4888 
4889 !-------------------------------------------------------------------------------
4890 !Calculate lambda values
4891 !-------------------------------------------------------------------------------
4892 !Loop over harmonics
4893 DO k=1,klam_3d !Over modes
4894 
4895  IF(k /= km0n0_3d) THEN
4896 
4897  !Loop over radial grid
4898  DO i=2,nrho_3d !Over radial nodes
4899 
4900  !Loop over theta grid
4901  DO j=1,ntheta_3d !Over poloidal nodes
4902 
4903  g1(j)=gsqrt_3d(i,j,1)/rcyl_3d(i,j,1)**2
4904  theta=(j-1)*dtheta_3d
4905  g2(j)=g1(j)*cos(m_3d(k)*theta)
4906 
4907  ENDDO !Over poloidal nodes
4908 
4909  !Theta averages to find lambda coefficients
4910  lam_3d(1,i,k)=2*sum(wtheta_3d*g2)/sum(wtheta_3d*g1)/m_3d(k) !Over poloidal nodes
4911 
4912  ENDDO !Over radial nodes
4913 
4914  lam_3d(1,2:nrho_3d,k)=lam_3d(1,2:nrho_3d,k)/rho_3d(2:nrho_3d)**mabs_3d(k)
4915 
4916  !Make a parabolic fit to axis
4917  lam_3d(1,1,k)=(lam_3d(1,2,k)*rho_3d(3)**2-lam_3d(1,3,k)*rho_3d(2)**2) &
4918  /(rho_3d(3)**2-rho_3d(2)**2)
4919 
4920  !Spline the Lmn coefficients for internal storage (not-a-knot edge BC)
4921  CALL spline1_fit(nrho_3d,rho_3d,lam_3d(:,:,k), &
4922  k_bc1=k_bc1, &
4923  k_bcn=k_bcn)
4924 
4925  ENDIF
4926 
4927 ENDDO !Over modes
4928 
4929 END SUBROUTINE ajax_init_lambda
4930 
4931 SUBROUTINE ajax_load_lambda(k_grid,nr_lam,nk_lam,rhorz,rho_lam,lam, &
4932  iflag,message)
4933 !-------------------------------------------------------------------------------
4934 !AJAX_LOAD_LAMBDA loads the magnetic stream function
4935 !
4936 !References:
4937 ! W.A.Houlberg, F90 free format 8/2004
4938 !
4939 !Comments:
4940 ! The radial grid is assumed to be the same as for the R,Z data, so the scale
4941 ! factor, rhorz, and grid type, k_grid are needed input
4942 !-------------------------------------------------------------------------------
4943 
4944 !Declaration of input variables
4945 INTEGER, INTENT(IN) :: &
4946  k_grid, & !option designating type of input radial grid [-]
4947  !=0 proportional to sqrt(toroidal flux)
4948  !=1 proportional to toroidal flux
4949  !=else not allowed
4950  nr_lam, & !no. of radial nodes in the input lambda [-]
4951  nk_lam !no. of poloidal & toroidal modes in the input lambda [-]
4952 
4953 REAL(KIND=rspec), INTENT(IN) :: &
4954  rhorz, & !max rho of the R,Z data [arb]
4955  rho_lam(:), & !radial nodes in the input lambda [arb]
4956  lam(:,:) !expansion coeffs for lambda [-]
4957 
4958 !Declaration of output variables
4959 CHARACTER(LEN=1024), INTENT(OUT) :: &
4960  message !warning or error message [character]
4961 
4962 INTEGER, INTENT(OUT) :: &
4963  iflag !error and warning flag [-]
4964  !=-1 warning
4965  !=0 none
4966  !=1 error
4967 
4968 !-------------------------------------------------------------------------------
4969 !Declaration of local variables
4970 LOGICAL :: &
4971  l_edge
4972 
4973 INTEGER :: &
4974  j,k,nset1,nset2,k_vopt(1:3)=(/1,0,0/),k_bc1=3,k_bcn=0
4975 
4976 REAL(KIND=rspec), ALLOCATABLE :: &
4977  rho(:),lmn(:,:),fspl(:,:),values(:,:)
4978 
4979 !-------------------------------------------------------------------------------
4980 !Initialization
4981 !-------------------------------------------------------------------------------
4982 !Null output
4983 iflag=0
4984 message=''
4985 
4986 !Stream function
4987 lam_3d(:,:,:)=0
4988 
4989 !-------------------------------------------------------------------------------
4990 !Load lambda expansion data
4991 !-------------------------------------------------------------------------------
4992 !Copy temporary radial grid and expansion coefficients
4993 nset2=nk_lam
4994 
4995 !Check whether inner boundary is at axis
4996 IF(rho_lam(1) > 10*z_precision*rhorz) THEN
4997 
4998  !Radial node needs to be added at axis, check whether boundary node is present
4999  IF(rho_lam(nr_lam) < (1.0+10*z_precision)*rhorz) THEN
5000 
5001  !Add radial nodes at center and edge
5002  nset1=nr_lam+2
5003  ALLOCATE(rho(nset1), &
5004  lmn(nset1,nset2))
5005 
5006  rho(:)=0
5007  lmn(:,:)=0
5008 
5009  rho(1)=0
5010  rho(2:nset1-1)=rho_lam(1:nr_lam)/rhorz
5011  rho(nset1)=1
5012  lmn(2:nset1-1,1:nset2)=lam(1:nr_lam,1:nset2)
5013  l_edge=.true.
5014 
5015  ELSE
5016 
5017  !Add radial node at center
5018  nset1=nr_lam+1
5019  ALLOCATE(rho(nset1), &
5020  lmn(nset1,nset2))
5021 
5022  rho(:)=0
5023  lmn(:,:)=0
5024 
5025  rho(1)=0
5026  rho(2:nset1)=rho_lam(1:nr_lam)/rhorz
5027  lmn(2:nset1,1:nset2)=lam(1:nr_lam,1:nset2)
5028  l_edge=.false.
5029 
5030  ENDIF
5031 
5032 ELSE
5033 
5034  !Radial node is present at axis
5035  !Check whether boundary node is present
5036  IF(rho_lam(nr_lam) < (1.0+10*z_precision)*rhorz) THEN
5037 
5038  !Add radial node at edge
5039  nset1=nr_lam+1
5040  ALLOCATE(rho(nset1), &
5041  lmn(nset1,nset2))
5042 
5043  rho(:)=0
5044  lmn(:,:)=0
5045 
5046  rho(1:nset1-1)=rho_lam(1:nset1-1)/rhorz
5047  rho(nset1)=1
5048  lmn(1:nset1-1,1:nset2)=lam(1:nset1-1,1:nset2)
5049  l_edge=.true.
5050 
5051  ELSE
5052 
5053  !Use input grid
5054  nset1=nr_lam
5055  ALLOCATE(rho(nset1), &
5056  lmn(nset1,nset2))
5057 
5058  rho(:)=0
5059  lmn(:,:)=0
5060 
5061  rho(1:nset1)=rho_lam(1:nset1)/rhorz
5062  lmn(1:nset1,1:nset2)=lam(1:nset1,1:nset2)
5063  l_edge=.false.
5064 
5065  ENDIF
5066 
5067 ENDIF
5068 
5069 !Convert rho to sqrt(toroidal flux) if necesssary and scale
5070 IF(k_grid == 1) THEN
5071 
5072  !~toroidal flux
5073  rho(:)=sqrt(rho(:))*rhomax_3d
5074 
5075 ELSE
5076 
5077  !~sqrt(toroidal flux)
5078  rho(:)=rho(:)*rhomax_3d
5079 
5080 ENDIF
5081 
5082 !Allocate temporary work arrays
5083 ALLOCATE(fspl(4,nset1), &
5084  values(3,nrho_3d))
5085 
5086  fspl(:,:)=0
5087  values(:,:)=0
5088 
5089 !Normalize the expansion coeffs to rho**m
5090 DO k=1,klam_3d !Over modes
5091 
5092  IF(l_edge) THEN
5093 
5094  !Extrapolate to edge
5095  DO j=2,nset1-1 !Over radial nodes
5096 
5097  lmn(j,k)=lmn(j,k)/rho(j)**mabs_3d(k)
5098 
5099  ENDDO !Over radial nodes
5100 
5101  lmn(nset1,k)=(lmn(nset1-1,k)*(rho(nset1)-rho(nset1-2)) &
5102  -lmn(nset1-2,k)*(rho(nset1)-rho(nset1-1))) &
5103  /(rho(nset1-1)-rho(nset1-2))
5104  ELSE
5105 
5106  DO j=2,nset1 !Over radial nodes
5107 
5108  lmn(j,k)=lmn(j,k)/rho(j)**mabs_3d(k)
5109 
5110  ENDDO !Over radial nodes
5111 
5112  ENDIF
5113 
5114  !Make a parabolic fit to axis
5115  lmn(1,k)=(lmn(2,k)*rho(3)**2-lmn(3,k)*rho(2)**2)/(rho(3)**2-rho(2)**2)
5116 
5117  !Map lambda_mn to internal radial grid
5118  fspl(1,1:nset1)=lmn(1:nset1,k)
5119  iflag=0
5120  message=''
5121  CALL spline1_interp(k_vopt,nset1,rho,fspl,nrho_3d,rho_3d,values, &
5122  iflag,message, &
5123  k_bc1=k_bc1, &
5124  k_bcn=k_bcn)
5125 
5126  !Check messages
5127  IF(iflag > 0) THEN
5128 
5129  message='AJAX_LOAD_LAM '// message
5130  GOTO 9999
5131 
5132  ENDIF
5133 
5134  !Respline the Lmn coefficients for internal storage (not-a-knot now)
5135  lam_3d(1,1:nrho_3d,k)=values(1,1:nrho_3d)
5136  CALL spline1_fit(nrho_3d,rho_3d,lam_3d(:,:,k), &
5137  k_bc1=k_bc1, &
5138  k_bcn=k_bcn)
5139 
5140 ENDDO !Over modes
5141 
5142 !-------------------------------------------------------------------------------
5143 !Cleanup and exit
5144 !-------------------------------------------------------------------------------
5145 9999 CONTINUE
5146 
5147 IF(ALLOCATED(rho)) THEN
5148 
5149  !Deallocate radial grid and lambda arrays
5150  DEALLOCATE(rho, &
5151  lmn)
5152 
5153 ENDIF
5154 
5155 IF(ALLOCATED(fspl)) THEN
5156 
5157  !Deallocate spline arrays
5158  DEALLOCATE(fspl, &
5159  values)
5160 
5161 ENDIF
5162 
5163 END SUBROUTINE ajax_load_lambda
5164 
5165 END MODULE ajax_mod