2015-11-18 17:34:33 +01:00
|
|
|
module equilibrium
|
|
|
|
use const_and_precisions, only : wp_
|
|
|
|
implicit none
|
|
|
|
|
|
|
|
real(wp_), save :: btaxis,rmaxis,zmaxis,sgnbphi
|
|
|
|
real(wp_), save :: btrcen ! used only for jcd_astra def.
|
|
|
|
real(wp_), save :: rcen ! computed as fpol(a)/btrcen
|
|
|
|
real(wp_), save :: rmnm,rmxm,zmnm,zmxm
|
|
|
|
real(wp_), save :: zbinf,zbsup
|
|
|
|
! real(wp_), save :: rup,zup,rlw,zlw
|
|
|
|
|
|
|
|
integer, parameter :: kspl=3,ksplp=kspl+1
|
|
|
|
|
|
|
|
! === 2d spline psi(r,z), normalization and derivatives ==========
|
|
|
|
integer, save :: nsr, nsz
|
2021-12-15 02:31:09 +01:00
|
|
|
real(wp_), save :: psia, psiant, psinop, psnbnd
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_), dimension(:), allocatable, save :: tr,tz
|
|
|
|
real(wp_), dimension(:), allocatable, save :: cceq, cceq01, cceq10, &
|
|
|
|
cceq20, cceq02, cceq11
|
|
|
|
|
|
|
|
! === 1d spline fpol(psi) ========================================
|
|
|
|
! integer, save :: npsiest
|
|
|
|
integer, save :: nsf
|
|
|
|
real(wp_), dimension(:), allocatable, save :: tfp, cfp
|
|
|
|
real(wp_), save :: fpolas
|
|
|
|
|
|
|
|
! === 1d spline rhot(rhop), rhop(rhot), q(psi) ===================
|
|
|
|
! computed on psinr,rhopnr [,rhotnr] arrays
|
|
|
|
integer, save :: nq,nrho
|
|
|
|
real(wp_), dimension(:), allocatable, save :: psinr,rhopr,rhotr
|
|
|
|
real(wp_), dimension(:,:), allocatable, save :: cq,crhop,crhot
|
|
|
|
real(wp_), save :: phitedge,aminor
|
|
|
|
real(wp_), save :: q0,qa,alq
|
|
|
|
|
|
|
|
contains
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
subroutine read_eqdsk(params, data, unit)
|
|
|
|
! Reads the MHD equilibrium `data` from a G-EQDSK file (params%filenm).
|
|
|
|
! If given, the file is opened in the `unit` number.
|
|
|
|
! For a description of the G-EQDSK, see the GRAY user manual.
|
2015-11-18 17:34:33 +01:00
|
|
|
use const_and_precisions, only : one
|
2021-12-15 02:31:09 +01:00
|
|
|
use gray_params, only : equilibrium_parameters, equilibrium_data
|
|
|
|
use utils, only : get_free_unit
|
2021-12-18 18:57:38 +01:00
|
|
|
use logger, only : log_error
|
2021-12-15 02:31:09 +01:00
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
type(equilibrium_parameters), intent(in) :: params
|
|
|
|
type(equilibrium_data), intent(out) :: data
|
|
|
|
integer, optional, intent(in) :: unit
|
|
|
|
|
|
|
|
! local variables
|
|
|
|
integer :: u, idum, i, j, nr, nz, nbnd, nlim
|
2015-11-18 17:34:33 +01:00
|
|
|
character(len=48) :: string
|
2021-12-15 02:31:09 +01:00
|
|
|
real(wp_) :: dr, dz, dps, rleft, zmid, zleft, psiedge, psiaxis
|
|
|
|
real(wp_) :: xdum ! dummy variable, used to discard data
|
2021-12-18 18:57:38 +01:00
|
|
|
integer :: err
|
2021-12-15 02:31:09 +01:00
|
|
|
|
2021-12-15 18:40:16 +01:00
|
|
|
u = get_free_unit(unit)
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Open the G-EQDSK file
|
2021-12-18 18:57:38 +01:00
|
|
|
open(file=params%filenm, status='old', action='read', unit=u, iostat=err)
|
|
|
|
if (err /= 0) then
|
|
|
|
call log_error('opening eqdsk file ('//trim(params%filenm)//') failed!', &
|
|
|
|
mod='equilibrium', proc='read_eqdsk')
|
|
|
|
call exit(1)
|
|
|
|
end if
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! get size of main arrays and allocate them
|
|
|
|
if (params%idesc == 1) then
|
2015-11-18 17:34:33 +01:00
|
|
|
read (u,'(a48,3i4)') string,idum,nr,nz
|
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
read (u,*) nr, nz
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
2021-12-15 02:31:09 +01:00
|
|
|
if (allocated(data%rv)) deallocate(data%rv)
|
|
|
|
if (allocated(data%zv)) deallocate(data%zv)
|
|
|
|
if (allocated(data%psin)) deallocate(data%psin)
|
|
|
|
if (allocated(data%psinr)) deallocate(data%psinr)
|
|
|
|
if (allocated(data%fpol)) deallocate(data%fpol)
|
|
|
|
if (allocated(data%qpsi)) deallocate(data%qpsi)
|
|
|
|
allocate(data%rv(nr), data%zv(nz), &
|
|
|
|
data%psin(nr, nz), &
|
|
|
|
data%psinr(nr), &
|
|
|
|
data%fpol(nr), &
|
|
|
|
data%qpsi(nr))
|
|
|
|
|
|
|
|
! Store 0D data and main arrays
|
|
|
|
if (params%ifreefmt==1) then
|
|
|
|
read (u, *) dr, dz, data%rvac, rleft, zmid
|
|
|
|
read (u, *) data%rax, data%zax, psiaxis, psiedge, xdum
|
|
|
|
read (u, *) xdum, xdum, xdum, xdum, xdum
|
|
|
|
read (u, *) xdum, xdum, xdum, xdum, xdum
|
|
|
|
read (u, *) (data%fpol(i), i=1,nr)
|
|
|
|
read (u, *) (xdum,i=1, nr)
|
|
|
|
read (u, *) (xdum,i=1, nr)
|
|
|
|
read (u, *) (xdum,i=1, nr)
|
|
|
|
read (u, *) ((data%psin(i,j), i=1,nr), j=1,nz)
|
|
|
|
read (u, *) (data%qpsi(i), i=1,nr)
|
2015-11-18 17:34:33 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
read (u, '(5e16.9)') dr,dz,data%rvac,rleft,zmid
|
|
|
|
read (u, '(5e16.9)') data%rax,data%zax,psiaxis,psiedge,xdum
|
|
|
|
read (u, '(5e16.9)') xdum,xdum,xdum,xdum,xdum
|
|
|
|
read (u, '(5e16.9)') xdum,xdum,xdum,xdum,xdum
|
|
|
|
read (u, '(5e16.9)') (data%fpol(i),i=1,nr)
|
|
|
|
read (u, '(5e16.9)') (xdum,i=1,nr)
|
|
|
|
read (u, '(5e16.9)') (xdum,i=1,nr)
|
|
|
|
read (u, '(5e16.9)') (xdum,i=1,nr)
|
|
|
|
read (u, '(5e16.9)') ((data%psin(i,j),i=1,nr),j=1,nz)
|
|
|
|
read (u, '(5e16.9)') (data%qpsi(i),i=1,nr)
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Get size of boundary and limiter arrays and allocate them
|
|
|
|
read (u,*) nbnd, nlim
|
|
|
|
if (allocated(data%rbnd)) deallocate(data%rbnd)
|
|
|
|
if (allocated(data%zbnd)) deallocate(data%zbnd)
|
|
|
|
if (allocated(data%rlim)) deallocate(data%rlim)
|
|
|
|
if (allocated(data%zlim)) deallocate(data%zlim)
|
|
|
|
|
|
|
|
! Load plasma boundary data
|
|
|
|
if(nbnd > 0) then
|
|
|
|
allocate(data%rbnd(nbnd), data%zbnd(nbnd))
|
|
|
|
if (params%ifreefmt == 1) then
|
|
|
|
read(u, *) (data%rbnd(i), data%zbnd(i), i=1,nbnd)
|
2015-11-18 17:34:33 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
read(u, '(5e16.9)') (data%rbnd(i), data%zbnd(i), i=1,nbnd)
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
end if
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! Load limiter data
|
|
|
|
if(nlim > 0) then
|
|
|
|
allocate(data%rlim(nlim), data%zlim(nlim))
|
|
|
|
if (params%ifreefmt == 1) then
|
|
|
|
read(u, *) (data%rlim(i), data%zlim(i), i=1,nlim)
|
2015-11-18 17:34:33 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
read(u, '(5e16.9)') (data%rlim(i), data%zlim(i), i=1,nlim)
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
end if
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! End of G-EQDSK file
|
2015-11-18 17:34:33 +01:00
|
|
|
close(u)
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Build rv,zv,psinr arrays
|
|
|
|
zleft = zmid-0.5_wp_*dz
|
|
|
|
dr = dr/(nr-1)
|
|
|
|
dz = dz/(nz-1)
|
|
|
|
dps = one/(nr-1)
|
2015-11-18 17:34:33 +01:00
|
|
|
do i=1,nr
|
2021-12-15 02:31:09 +01:00
|
|
|
data%psinr(i) = (i-1)*dps
|
|
|
|
data%rv(i) = rleft + (i-1)*dr
|
2015-11-18 17:34:33 +01:00
|
|
|
end do
|
|
|
|
do i=1,nz
|
2021-12-15 02:31:09 +01:00
|
|
|
data%zv(i) = zleft + (i-1)*dz
|
2015-11-18 17:34:33 +01:00
|
|
|
end do
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Normalize psin
|
|
|
|
data%psia = psiedge - psiaxis
|
|
|
|
if(params%ipsinorm == 0) data%psin = (data%psin - psiaxis)/data%psia
|
|
|
|
|
|
|
|
end subroutine read_eqdsk
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
subroutine read_equil_an(filenm, ipass, data, unit)
|
|
|
|
! Reads the MHD equilibrium `data` in the analytical format
|
|
|
|
! from params%filenm.
|
|
|
|
! If given, the file is opened in the `unit` number.
|
|
|
|
!
|
|
|
|
! TODO: add format description
|
|
|
|
use gray_params, only : equilibrium_data
|
|
|
|
use utils, only : get_free_unit
|
|
|
|
use logger, only : log_error
|
2021-12-18 18:57:38 +01:00
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2022-05-11 00:30:34 +02:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
character(len=*), intent(in) :: filenm
|
|
|
|
integer, intent(in) :: ipass
|
|
|
|
type(equilibrium_data), intent(out) :: data
|
|
|
|
integer, optional, intent(in) :: unit
|
|
|
|
|
|
|
|
! local variables
|
2019-03-26 15:21:22 +01:00
|
|
|
integer :: i, u, nlim
|
2021-12-18 18:57:38 +01:00
|
|
|
integer :: err
|
2022-05-11 00:30:34 +02:00
|
|
|
real(wp_) :: rr0m, zr0m, rpam, b0, q0, qa, alq
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 18:40:16 +01:00
|
|
|
u = get_free_unit(unit)
|
|
|
|
|
2021-12-18 18:57:38 +01:00
|
|
|
open(file=filenm, status='old', action='read', unit=u, iostat=err)
|
|
|
|
if (err /= 0) then
|
|
|
|
call log_error('opening equilibrium file ('//trim(filenm)//') failed!', &
|
|
|
|
mod='equilibrium', proc='read_equil_an')
|
|
|
|
call exit(1)
|
|
|
|
end if
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
read(u, *) rr0m, zr0m, rpam
|
|
|
|
read(u, *) b0
|
|
|
|
read(u, *) q0, qa, alq
|
|
|
|
|
|
|
|
if(allocated(data%rv)) deallocate(data%rv)
|
|
|
|
if(allocated(data%zv)) deallocate(data%zv)
|
|
|
|
if(allocated(data%fpol)) deallocate(data%fpol)
|
|
|
|
if(allocated(data%qpsi)) deallocate(data%qpsi)
|
|
|
|
allocate(data%rv(2), data%zv(1), data%fpol(1), data%qpsi(3))
|
|
|
|
|
|
|
|
data%rv = [rr0m, rpam]
|
|
|
|
data%zv = [zr0m]
|
|
|
|
data%fpol = [b0*rr0m]
|
|
|
|
data%qpsi = [q0, qa, alq]
|
|
|
|
|
|
|
|
if(ipass >= 2) then
|
|
|
|
! get size of boundary and limiter arrays and allocate them
|
2019-03-26 15:21:22 +01:00
|
|
|
read (u,*) nlim
|
2022-05-11 00:30:34 +02:00
|
|
|
if (allocated(data%rlim)) deallocate(data%rlim)
|
|
|
|
if (allocated(data%zlim)) deallocate(data%zlim)
|
2021-12-15 02:31:00 +01:00
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
! store boundary and limiter data
|
|
|
|
if(nlim > 0) then
|
|
|
|
allocate(data%rlim(nlim), data%zlim(nlim))
|
|
|
|
read(u,*) (data%rlim(i), data%zlim(i), i = 1, nlim)
|
|
|
|
end if
|
|
|
|
end if
|
2021-12-15 02:31:00 +01:00
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
close(u)
|
|
|
|
end subroutine read_equil_an
|
2022-05-11 00:30:34 +02:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
subroutine change_cocos(data, cocosin, cocosout, error)
|
|
|
|
! Convert the MHD equilibrium data from one coordinate convention
|
|
|
|
! (COCOS) to another. These are specified by `cocosin` and
|
|
|
|
! `cocosout`, respectively.
|
|
|
|
!
|
|
|
|
! For more information, see: https://doi.org/10.1016/j.cpc.2012.09.010
|
|
|
|
use const_and_precisions, only : zero, one, pi
|
|
|
|
use gray_params, only : equilibrium_data
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
type(equilibrium_data), intent(inout) :: data
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, intent(in) :: cocosin, cocosout
|
2021-12-15 02:31:09 +01:00
|
|
|
integer, intent(out), optional :: error
|
|
|
|
|
|
|
|
! local variables
|
|
|
|
real(wp_) :: isign, bsign
|
|
|
|
integer :: exp2pi, exp2piout
|
|
|
|
logical :: phiccw, psiincr, qpos, phiccwout, psiincrout, qposout
|
|
|
|
|
|
|
|
call decode_cocos(cocosin, exp2pi, phiccw, psiincr, qpos)
|
|
|
|
call decode_cocos(cocosout, exp2piout, phiccwout, psiincrout, qposout)
|
|
|
|
|
|
|
|
! Check sign consistency
|
|
|
|
isign = sign(one, data%psia)
|
|
|
|
if (.not.psiincr) isign = -isign
|
|
|
|
bsign = sign(one, data%fpol(size(data%fpol)))
|
|
|
|
if (qpos .neqv. isign * bsign * data%qpsi(size(data%qpsi)) > zero) then
|
|
|
|
! Warning: sign inconsistency found among q, Ipla and Bref
|
|
|
|
data%qpsi = -data%qpsi
|
|
|
|
if (present(error)) error = 1
|
2015-11-18 17:34:33 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
if (present(error)) error = 0
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Convert cocosin to cocosout
|
|
|
|
|
|
|
|
! Opposite direction of toroidal angle phi in cocosin and cocosout
|
|
|
|
if (phiccw .neqv. phiccwout) data%fpol = -data%fpol
|
|
|
|
|
|
|
|
! q has opposite sign for given sign of Bphi*Ip
|
|
|
|
if (qpos .neqv. qposout) data%qpsi = -data%qpsi
|
|
|
|
|
|
|
|
! psi and Ip signs don't change accordingly
|
|
|
|
if ((phiccw .eqv. phiccwout) .neqv. (psiincr .eqv. psiincrout)) &
|
|
|
|
data%psia = -data%psia
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Convert Wb to Wb/rad or viceversa
|
|
|
|
data%psia = data%psia * (2.0_wp_*pi)**(exp2piout - exp2pi)
|
2015-11-18 17:34:33 +01:00
|
|
|
end subroutine change_cocos
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
subroutine decode_cocos(cocos, exp2pi, phiccw, psiincr, qpos)
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
integer, intent(in) :: cocos
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, intent(out) :: exp2pi
|
2021-12-15 02:31:09 +01:00
|
|
|
logical, intent(out) :: phiccw, psiincr, qpos
|
|
|
|
|
|
|
|
! local variables
|
|
|
|
integer :: cmod10, cmod4
|
|
|
|
|
|
|
|
cmod10 = mod(cocos, 10)
|
|
|
|
cmod4 = mod(cmod10, 4)
|
|
|
|
|
|
|
|
! cocos>10 ψ in Wb, cocos<10 ψ in Wb/rad
|
|
|
|
exp2pi = (cocos - cmod10)/10
|
|
|
|
|
|
|
|
! cocos mod 10 = 1,3,5,7: toroidal angle φ increasing CCW
|
|
|
|
phiccw = (mod(cmod10, 2)== 1)
|
|
|
|
|
|
|
|
! cocos mod 10 = 1,2,5,6: ψ increasing with positive Ip
|
|
|
|
psiincr = (cmod4==1 .or. cmod4==2)
|
|
|
|
|
|
|
|
! cocos mod 10 = 1,2,7,8: q positive for positive Bφ*Ip
|
|
|
|
qpos = (cmod10<3 .or. cmod10>6)
|
2015-11-18 17:34:33 +01:00
|
|
|
end subroutine decode_cocos
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
subroutine eq_scal(params, data)
|
|
|
|
! Rescale the magnetic field (B) and the plasma current (I)
|
|
|
|
! and/or force their signs.
|
|
|
|
!
|
|
|
|
! Notes:
|
|
|
|
! 1. signi and signb are ignored on input if equal to 0.
|
|
|
|
! They are used to assign the direction of Bphi and Ipla BEFORE scaling.
|
|
|
|
! 2. cocos=3 assumed: CCW direction is >0
|
|
|
|
! 3. Bphi and Ipla scaled by the same factor factb to keep q unchanged
|
|
|
|
! 4. factb<0 reverses the directions of Bphi and Ipla
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
use const_and_precisions, only : one
|
2021-12-15 02:31:09 +01:00
|
|
|
use gray_params, only : equilibrium_parameters, equilibrium_data
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
type(equilibrium_parameters), intent(inout) :: params
|
|
|
|
type(equilibrium_data), intent(inout) :: data
|
|
|
|
|
|
|
|
! local variables
|
|
|
|
real(wp_) :: last_fpol
|
|
|
|
|
|
|
|
last_fpol = data%fpol(size(data%fpol))
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
if (params%sgni /=0) &
|
|
|
|
data%psia = sign(data%psia, real(-params%sgni, wp_))
|
|
|
|
if (params%sgnb /=0 .and. params%sgnb * last_fpol < 0) &
|
|
|
|
data%fpol = -data%fpol
|
|
|
|
|
|
|
|
data%psia = data%psia * params%factb
|
|
|
|
data%fpol = data%fpol * params%factb
|
|
|
|
params%sgni = int(sign(one, -data%psia))
|
|
|
|
params%sgnb = int(sign(one, last_fpol))
|
2015-11-18 17:34:33 +01:00
|
|
|
end subroutine eq_scal
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
subroutine set_equil_spline(params, data)
|
2021-12-15 02:31:09 +01:00
|
|
|
! Computes splines for the MHD equilibrium data and stores them
|
|
|
|
! in their respective global variables, see the top of this file.
|
|
|
|
use const_and_precisions, only : zero, one
|
|
|
|
use gray_params, only : equilibrium_parameters, equilibrium_data
|
|
|
|
use dierckx, only : regrid, coeff_parder, curfit, splev
|
|
|
|
use gray_params, only : iequil
|
|
|
|
use reflections, only : inside
|
|
|
|
use utils, only : vmaxmin, vmaxmini
|
2021-12-18 18:57:38 +01:00
|
|
|
use logger, only : log_info
|
2021-12-15 02:31:09 +01:00
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
type(equilibrium_parameters), intent(in) :: params
|
|
|
|
type(equilibrium_data), intent(in) :: data
|
|
|
|
|
|
|
|
! local constants
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, parameter :: iopt=0
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! local variables
|
2015-11-18 17:34:33 +01:00
|
|
|
integer :: liwrk,lwrk,lw10,lw01,lw20,lw02,lw11,lwrkf
|
|
|
|
integer :: nr,nz,nrest,nzest,npsest,nrz,npsi,nbnd,ibinf,ibsup
|
|
|
|
real(wp_) :: sspln,fp,rax0,zax0,psinoptmp,psinxptmp
|
|
|
|
real(wp_) :: rbmin,rbmax,rbinf,rbsup,r1,z1
|
2021-12-15 02:31:09 +01:00
|
|
|
real(wp_), dimension(size(data%psinr)) :: rhotn
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_), dimension(1) :: fpoli
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_), dimension(:), allocatable :: rv1d,zv1d,fvpsi,wf,wrk
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, dimension(:), allocatable :: iwrk
|
2015-11-23 18:55:27 +01:00
|
|
|
integer :: ier,ixploc,info,i,j,ij
|
2021-12-18 18:57:38 +01:00
|
|
|
character(256) :: msg ! for log messages formatting
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! compute array sizes and prepare working space arrays
|
|
|
|
nr=size(data%rv)
|
|
|
|
nz=size(data%zv)
|
2015-11-18 17:34:33 +01:00
|
|
|
nrz=nr*nz
|
|
|
|
nrest=nr+ksplp
|
|
|
|
nzest=nz+ksplp
|
|
|
|
lwrk=4+nrest*nz+(nrest+nzest)*(2*kspl+5)+(nr+nz)*ksplp+max(nz,nrest)
|
|
|
|
liwrk=nz+nr+nrest+nzest+kspl
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
npsi=size(data%psinr)
|
2015-11-18 17:34:33 +01:00
|
|
|
npsest=npsi+ksplp
|
|
|
|
lwrkf=npsi*ksplp+npsest*(7+3*kspl)
|
|
|
|
|
|
|
|
allocate(wrk(max(lwrk,lwrkf)),iwrk(max(liwrk,npsest)))
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! spline fitting/interpolation of data%psin(i,j) and derivatives
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! allocate knots and spline coefficients arrays
|
2015-11-23 18:55:27 +01:00
|
|
|
if (allocated(tr)) deallocate(tr)
|
|
|
|
if (allocated(tz)) deallocate(tz)
|
|
|
|
if (allocated(cceq)) deallocate(cceq)
|
|
|
|
allocate(tr(nrest),tz(nzest),cceq(nrz))
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! length in m !!!
|
|
|
|
rmnm=data%rv(1)
|
|
|
|
rmxm=data%rv(nr)
|
|
|
|
zmnm=data%zv(1)
|
|
|
|
zmxm=data%zv(nz)
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
if (iequil>2) then
|
2021-12-15 02:31:09 +01:00
|
|
|
! data valid only inside boundary (data%psin=0 outside), e.g. source==ESCO
|
|
|
|
! presence of boundary anticipated here to filter invalid data
|
|
|
|
nbnd = min(size(data%rbnd), size(data%zbnd))
|
|
|
|
|
|
|
|
! determine number of valid grid points
|
2015-11-23 18:55:27 +01:00
|
|
|
nrz=0
|
|
|
|
do j=1,nz
|
|
|
|
do i=1,nr
|
|
|
|
if (nbnd.gt.0) then
|
2021-12-15 02:31:09 +01:00
|
|
|
if(.not.inside(data%rbnd,data%zbnd,nbnd,data%rv(i),data%zv(j))) cycle
|
2015-11-23 18:55:27 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
if(data%psin(i,j).le.0.0d0) cycle
|
2015-11-23 18:55:27 +01:00
|
|
|
end if
|
|
|
|
nrz=nrz+1
|
|
|
|
end do
|
|
|
|
end do
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! store valid data
|
2015-11-23 18:55:27 +01:00
|
|
|
allocate(rv1d(nrz),zv1d(nrz),fvpsi(nrz),wf(nrz))
|
|
|
|
ij=0
|
|
|
|
do j=1,nz
|
|
|
|
do i=1,nr
|
|
|
|
if (nbnd.gt.0) then
|
2021-12-15 02:31:09 +01:00
|
|
|
if(.not.inside(data%rbnd,data%zbnd,nbnd,data%rv(i),data%zv(j))) cycle
|
2015-11-23 18:55:27 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
if(data%psin(i,j).le.0.0d0) cycle
|
2015-11-23 18:55:27 +01:00
|
|
|
end if
|
|
|
|
ij=ij+1
|
2021-12-15 02:31:09 +01:00
|
|
|
rv1d(ij)=data%rv(i)
|
|
|
|
zv1d(ij)=data%zv(j)
|
|
|
|
fvpsi(ij)=data%psin(i,j)
|
2015-11-23 18:55:27 +01:00
|
|
|
wf(ij)=1.0d0
|
|
|
|
end do
|
|
|
|
end do
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! fit as a scattered set of points
|
|
|
|
! use reduced number of knots to limit memory comsumption ?
|
2015-11-23 18:55:27 +01:00
|
|
|
nsr=nr/4+4
|
|
|
|
nsz=nz/4+4
|
2021-12-15 02:31:09 +01:00
|
|
|
sspln=params%ssplps
|
2015-11-23 18:55:27 +01:00
|
|
|
call scatterspl(rv1d,zv1d,fvpsi,wf,nrz,kspl,sspln, &
|
|
|
|
rmnm,rmxm,zmnm,zmxm,tr,nsr,tz,nsz,cceq,ier)
|
2021-12-15 02:31:09 +01:00
|
|
|
! if ier=-1 data are fitted using params%ssplps=0
|
2015-11-23 18:55:27 +01:00
|
|
|
if(ier.eq.-1) then
|
|
|
|
sspln=0.0_wp_
|
|
|
|
nsr=nr/4+4
|
|
|
|
nsz=nz/4+4
|
|
|
|
call scatterspl(rv1d,zv1d,fvpsi,wf,nrz,kspl,sspln, &
|
|
|
|
rmnm,rmxm,zmnm,zmxm,tr,nsr,tz,nsz,cceq,ier)
|
|
|
|
end if
|
|
|
|
deallocate(rv1d,zv1d,wf,fvpsi)
|
2021-12-15 02:31:09 +01:00
|
|
|
! reset nrz to the total number of grid points for next allocations
|
2015-11-23 18:55:27 +01:00
|
|
|
nrz=nr*nz
|
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
! iequil==2: data are valid on the full R,z grid
|
2015-11-23 18:55:27 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! reshape 2D psi array to 1D (transposed) array and compute spline coeffs
|
2015-11-23 18:55:27 +01:00
|
|
|
allocate(fvpsi(nrz))
|
2021-12-15 02:31:09 +01:00
|
|
|
fvpsi=reshape(transpose(data%psin),(/nrz/))
|
|
|
|
sspln=params%ssplps
|
|
|
|
call regrid(iopt,nr,data%rv,nz,data%zv,fvpsi,rmnm,rmxm,zmnm,zmxm, &
|
|
|
|
kspl,kspl,sspln,nrest,nzest,nsr,tr,nsz,tz,cceq,fp, &
|
2015-11-18 17:34:33 +01:00
|
|
|
wrk(1:lwrk),lwrk,iwrk(1:liwrk),liwrk,ier)
|
2021-12-15 02:31:09 +01:00
|
|
|
! if ier=-1 data are re-fitted using params%ssplps=0
|
2015-11-23 18:55:27 +01:00
|
|
|
if(ier==-1) then
|
|
|
|
sspln=0.0_wp_
|
2021-12-15 02:31:09 +01:00
|
|
|
call regrid(iopt,nr,data%rv,nz,data%zv,fvpsi,rmnm,rmxm,zmnm,zmxm, &
|
2015-11-23 18:55:27 +01:00
|
|
|
kspl,kspl,sspln,nrest,nzest,nsr,tr,nsz,tz,cceq,fp, &
|
|
|
|
wrk(1:lwrk),lwrk,iwrk(1:liwrk),liwrk,ier)
|
|
|
|
end if
|
|
|
|
deallocate(fvpsi)
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
2015-11-23 18:55:27 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! compute spline coefficients for psi partial derivatives
|
2015-11-18 17:34:33 +01:00
|
|
|
lw10 = nr*(ksplp-1) + nz*ksplp + nrz
|
|
|
|
lw01 = nr*ksplp + nz*(ksplp-1) + nrz
|
|
|
|
lw20 = nr*(ksplp-2) + nz*ksplp + nrz
|
|
|
|
lw02 = nr*ksplp + nz*(ksplp-2) + nrz
|
|
|
|
lw11 = nr*(ksplp-1) + nz*(ksplp-1) + nrz
|
|
|
|
if (allocated(cceq10)) deallocate(cceq10)
|
|
|
|
if (allocated(cceq01)) deallocate(cceq01)
|
|
|
|
if (allocated(cceq20)) deallocate(cceq20)
|
|
|
|
if (allocated(cceq02)) deallocate(cceq02)
|
|
|
|
if (allocated(cceq11)) deallocate(cceq11)
|
|
|
|
allocate(cceq10(lw10),cceq01(lw01),cceq20(lw20),cceq02(lw02),cceq11(lw11))
|
|
|
|
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,1,0,cceq10,lw10,ier)
|
|
|
|
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,0,1,cceq01,lw01,ier)
|
|
|
|
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,2,0,cceq20,lw20,ier)
|
|
|
|
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,0,2,cceq02,lw02,ier)
|
|
|
|
call coeff_parder(tr,nsr,tz,nsz,cceq,kspl,kspl,1,1,cceq11,lw11,ier)
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Spline interpolation of data%fpol(i)
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Allocate knots and spline coefficients arrays
|
2015-11-18 17:34:33 +01:00
|
|
|
if (allocated(tfp)) deallocate(tfp)
|
|
|
|
if (allocated(cfp)) deallocate(cfp)
|
|
|
|
allocate(tfp(npsest),cfp(npsest))
|
|
|
|
allocate(wf(npsi))
|
|
|
|
wf(1:npsi-1)=one
|
|
|
|
wf(npsi)=1.0e2_wp_
|
2021-12-15 02:31:09 +01:00
|
|
|
call curfit(iopt,npsi,data%psinr,data%fpol,wf,zero,one,kspl,params%ssplf,npsest,nsf, &
|
2015-11-18 17:34:33 +01:00
|
|
|
tfp,cfp,fp,wrk(1:lwrkf),lwrkf,iwrk(1:npsest),ier)
|
2021-12-15 02:31:09 +01:00
|
|
|
call splev(tfp,nsf,cfp,kspl,data%psinr(npsi:npsi),fpoli,1,ier)
|
|
|
|
! Set vacuum value used outside 0<=data%psin<=1 range
|
2015-11-18 17:34:33 +01:00
|
|
|
fpolas=fpoli(1)
|
|
|
|
sgnbphi=sign(one,fpolas)
|
2021-12-15 02:31:09 +01:00
|
|
|
! Free temporary arrays
|
2015-11-18 17:34:33 +01:00
|
|
|
deallocate(wrk,iwrk,wf)
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Re-normalize psi after spline computation
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Start with un-corrected psi
|
|
|
|
psia=data%psia
|
2015-11-18 17:34:33 +01:00
|
|
|
psinop=0.0_wp_
|
|
|
|
psiant=1.0_wp_
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Use provided boundary to set an initial guess
|
|
|
|
! for the search of O/X points
|
|
|
|
nbnd=min(size(data%rbnd), size(data%zbnd))
|
2015-11-18 17:34:33 +01:00
|
|
|
if (nbnd>0) then
|
2021-12-15 02:31:09 +01:00
|
|
|
call vmaxmini(data%zbnd,nbnd,zbinf,zbsup,ibinf,ibsup)
|
|
|
|
rbinf=data%rbnd(ibinf)
|
|
|
|
rbsup=data%rbnd(ibsup)
|
|
|
|
call vmaxmin(data%rbnd,nbnd,rbmin,rbmax)
|
2015-11-18 17:34:33 +01:00
|
|
|
else
|
2021-12-15 02:31:09 +01:00
|
|
|
zbinf=data%zv(2)
|
|
|
|
zbsup=data%zv(nz-1)
|
|
|
|
rbinf=data%rv((nr+1)/2)
|
2015-11-18 17:34:33 +01:00
|
|
|
rbsup=rbinf
|
2021-12-15 02:31:09 +01:00
|
|
|
rbmin=data%rv(2)
|
|
|
|
rbmax=data%rv(nr-1)
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Search for exact location of the magnetic axis
|
|
|
|
rax0=data%rax
|
|
|
|
zax0=data%zax
|
2015-11-18 17:34:33 +01:00
|
|
|
call points_ox(rax0,zax0,rmaxis,zmaxis,psinoptmp,info)
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
write (msg, '("O-point found:", 3(x,a,"=",g0.3))') &
|
|
|
|
'r', rmaxis, 'z', zmaxis, 'ψ', psinoptmp
|
2022-05-11 00:30:34 +02:00
|
|
|
call log_info(msg, mod='equilibrium', proc='set_equil_spline')
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! search for X-point if params%ixp /= 0
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
ixploc = params%ixp
|
2015-11-18 17:34:33 +01:00
|
|
|
if(ixploc/=0) then
|
|
|
|
if(ixploc<0) then
|
|
|
|
call points_ox(rbinf,zbinf,r1,z1,psinxptmp,info)
|
|
|
|
if(psinxptmp/=-1.0_wp_) then
|
2021-12-18 18:57:38 +01:00
|
|
|
write (msg, '("X-point found:", 3(x,a,"=",g0.3))') &
|
|
|
|
'r', r1, 'z', z1, 'ψ', psinxptmp
|
2022-05-11 00:30:34 +02:00
|
|
|
call log_info(msg, mod='equilibrium', proc='set_equil_spline')
|
2021-12-18 18:57:38 +01:00
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
zbinf=z1
|
|
|
|
psinop=psinoptmp
|
|
|
|
psiant=psinxptmp-psinop
|
|
|
|
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbsup),r1,z1,one,info)
|
|
|
|
zbsup=z1
|
|
|
|
else
|
|
|
|
ixploc=0
|
|
|
|
end if
|
|
|
|
else
|
|
|
|
call points_ox(rbsup,zbsup,r1,z1,psinxptmp,info)
|
|
|
|
if(psinxptmp.ne.-1.0_wp_) then
|
2021-12-18 18:57:38 +01:00
|
|
|
write (msg, '("X-point found:", 3(x,a,"=",g0.3))') &
|
|
|
|
'r', r1, 'z', z1, 'ψ', psinxptmp
|
2022-05-11 00:30:34 +02:00
|
|
|
call log_info(msg, mod='equilibrium', proc='set_equil_spline')
|
2021-12-18 18:57:38 +01:00
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
zbsup=z1
|
|
|
|
psinop=psinoptmp
|
|
|
|
psiant=psinxptmp-psinop
|
|
|
|
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbinf),r1,z1,one,info)
|
|
|
|
zbinf=z1
|
|
|
|
else
|
|
|
|
ixploc=0
|
|
|
|
end if
|
|
|
|
end if
|
|
|
|
end if
|
|
|
|
|
|
|
|
if (ixploc==0) then
|
|
|
|
psinop=psinoptmp
|
|
|
|
psiant=one-psinop
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! Find upper horizontal tangent point
|
2015-11-18 17:34:33 +01:00
|
|
|
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbsup),r1,z1,one,info)
|
|
|
|
zbsup=z1
|
|
|
|
rbsup=r1
|
2021-12-15 02:31:09 +01:00
|
|
|
|
|
|
|
! Find lower horizontal tangent point
|
2015-11-18 17:34:33 +01:00
|
|
|
call points_tgo(rmaxis,0.5_wp_*(zmaxis+zbinf),r1,z1,one,info)
|
|
|
|
zbinf=z1
|
|
|
|
rbinf=r1
|
2021-12-18 18:57:38 +01:00
|
|
|
write (msg, '("X-point not found in", 2(x,a,"∈[",g0.3,",",g0.3,"]"))') &
|
|
|
|
'r', rbinf, rbsup, 'z', zbinf, zbsup
|
2022-05-11 00:30:34 +02:00
|
|
|
call log_info(msg, mod='equilibrium', proc='set_equil_spline')
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Save Bt value on axis (required in flux_average and used in Jcd def)
|
|
|
|
! and vacuum value B0 at ref. radius data%rvac (used in Jcd_astra def)
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
call equinum_fpol(0.0_wp_,btaxis)
|
2021-12-15 02:31:09 +01:00
|
|
|
btaxis = btaxis/rmaxis
|
|
|
|
btrcen = fpolas/data%rvac
|
|
|
|
rcen = data%rvac
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
write (msg, '(2(a,g0.3))') 'Bt_center=', btrcen, ' Bt_axis=', btaxis
|
2022-05-11 00:30:34 +02:00
|
|
|
call log_info(msg, mod='equilibrium', proc='set_equil_spline')
|
2015-11-23 18:55:27 +01:00
|
|
|
|
2021-12-15 02:31:09 +01:00
|
|
|
! Compute rho_pol/rho_tor mapping based on input q profile
|
|
|
|
call setqphi_num(data%psinr,abs(data%qpsi),abs(psia),rhotn)
|
|
|
|
call set_rhospl(sqrt(data%psinr),rhotn)
|
2015-11-23 18:55:27 +01:00
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
end subroutine set_equil_spline
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
subroutine scatterspl(x,y,z,w,n,kspl,sspl,xmin,xmax,ymin,ymax, &
|
|
|
|
tx,nknt_x,ty,nknt_y,coeff,ierr)
|
|
|
|
use const_and_precisions, only : wp_, comp_eps
|
|
|
|
use dierckx, only : surfit
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2015-11-23 18:55:27 +01:00
|
|
|
! arguments
|
|
|
|
integer, intent(in) :: n
|
|
|
|
real(wp_), dimension(n), intent(in) :: x, y, z
|
|
|
|
real(wp_), dimension(n), intent(in) :: w
|
|
|
|
integer, intent(in) :: kspl
|
|
|
|
real(wp_), intent(in) :: sspl
|
|
|
|
real(wp_), intent(in) :: xmin, xmax, ymin, ymax
|
|
|
|
real(wp_), dimension(nknt_x), intent(inout) :: tx
|
|
|
|
real(wp_), dimension(nknt_y), intent(inout) :: ty
|
|
|
|
integer, intent(inout) :: nknt_x, nknt_y
|
|
|
|
real(wp_), dimension(nknt_x*nknt_y), intent(out) :: coeff
|
|
|
|
integer, intent(out) :: ierr
|
|
|
|
! local variables
|
|
|
|
integer :: iopt
|
|
|
|
real(wp_) :: resid
|
|
|
|
integer :: u,v,km,ne,b1,b2,lwrk1,lwrk2,kwrk,nxest,nyest
|
|
|
|
real(wp_), dimension(:), allocatable :: wrk1, wrk2
|
|
|
|
integer, dimension(:), allocatable :: iwrk
|
|
|
|
|
|
|
|
nxest=nknt_x
|
|
|
|
nyest=nknt_y
|
|
|
|
ne = max(nxest,nyest)
|
|
|
|
|
|
|
|
km = kspl+1
|
|
|
|
u = nxest-km
|
|
|
|
v = nyest-km
|
|
|
|
b1 = kspl*min(u,v)+kspl+1
|
|
|
|
b2 = (kspl+1)*min(u,v)+1
|
|
|
|
lwrk1 = u*v*(2+b1+b2)+2*(u+v+km*(n+ne)+ne-2*kspl)+b2+1
|
|
|
|
lwrk2 = u*v*(b2+1)+b2
|
|
|
|
kwrk = n+(nknt_x-2*kspl-1)*(nknt_y-2*kspl-1)
|
|
|
|
allocate(wrk1(lwrk1),wrk2(lwrk2),iwrk(kwrk))
|
|
|
|
|
|
|
|
iopt=0
|
|
|
|
call surfit(iopt,n,x,y,z,w,xmin,xmax,ymin,ymax,kspl,kspl, &
|
|
|
|
sspl,nxest,nyest,ne,comp_eps,nknt_x,tx,nknt_y,ty, &
|
|
|
|
coeff,resid,wrk1,lwrk1,wrk2,lwrk2,iwrk,kwrk,ierr)
|
|
|
|
|
|
|
|
deallocate(wrk1,wrk2,iwrk)
|
|
|
|
|
|
|
|
end subroutine scatterspl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subroutine setqphi_num(psinq,q,psia,rhotn)
|
|
|
|
use const_and_precisions, only : pi
|
|
|
|
use simplespline, only : difcs
|
|
|
|
implicit none
|
|
|
|
! arguments
|
|
|
|
real(wp_), dimension(:), intent(in) :: psinq,q
|
|
|
|
real(wp_), intent(in) :: psia
|
|
|
|
real(wp_), dimension(:), intent(out), optional :: rhotn
|
|
|
|
! local variables
|
|
|
|
real(wp_), dimension(size(q)) :: phit
|
|
|
|
real(wp_) :: dx
|
|
|
|
integer, parameter :: iopt=0
|
|
|
|
integer :: k,ier
|
|
|
|
|
|
|
|
nq=size(q)
|
|
|
|
if(allocated(psinr)) deallocate(psinr)
|
|
|
|
if(allocated(cq)) deallocate(cq)
|
|
|
|
allocate(psinr(nq),cq(nq,4))
|
|
|
|
|
|
|
|
psinr=psinq
|
|
|
|
call difcs(psinr,q,nq,iopt,cq,ier)
|
|
|
|
|
|
|
|
! Toroidal flux phi = 2*pi*Integral q dpsi
|
|
|
|
phit(1)=0.0_wp_
|
|
|
|
do k=1,nq-1
|
|
|
|
dx=psinr(k+1)-psinr(k)
|
|
|
|
phit(k+1)=phit(k) + dx*(cq(k,1) + dx*(cq(k,2)/2.0_wp_ + &
|
|
|
|
dx*(cq(k,3)/3.0_wp_ + dx* cq(k,4)/4.0_wp_) ) )
|
|
|
|
end do
|
|
|
|
phitedge=phit(nq)
|
|
|
|
if(present(rhotn)) rhotn(1:nq)=sqrt(phit/phitedge)
|
|
|
|
phitedge=2*pi*psia*phitedge
|
|
|
|
end subroutine setqphi_num
|
|
|
|
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
subroutine set_equil_an(data, n)
|
|
|
|
! Computes the analytical equilibrium data and stores them
|
|
|
|
! in their respective global variables, see the top of this file.
|
|
|
|
use const_and_precisions, only : pi, zero, one
|
|
|
|
use gray_params, only : equilibrium_data
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
implicit none
|
2022-05-11 00:30:34 +02:00
|
|
|
|
|
|
|
! subroutine arguments
|
|
|
|
type(equilibrium_data), intent(in) :: data
|
|
|
|
integer, optional, intent(in) :: n
|
|
|
|
|
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
integer, parameter :: nqdef=101
|
|
|
|
integer :: i
|
2022-05-11 00:30:34 +02:00
|
|
|
real(wp_) :: dr, fq0, fq1, qq, res, rn
|
|
|
|
real(wp_) :: rax, zax, a, bax, qax, q1, qexp
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_), dimension(:), allocatable :: rhotn,rhopn
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
rax = data%rv(1)
|
|
|
|
zax = data%zv(1)
|
|
|
|
a = data%rv(2)
|
|
|
|
bax = data%fpol(1) / rax
|
|
|
|
qax = data%qpsi(1)
|
|
|
|
q1 = data%qpsi(2)
|
|
|
|
qexp = data%qpsi(3)
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
btaxis=bax
|
|
|
|
rmaxis=rax
|
|
|
|
zmaxis=zax
|
|
|
|
btrcen=bax
|
|
|
|
rcen=rax
|
|
|
|
aminor=a
|
|
|
|
zbinf=zmaxis-a
|
|
|
|
zbsup=zmaxis+a
|
|
|
|
q0=qax
|
|
|
|
qa=q1
|
|
|
|
alq=qexp
|
|
|
|
sgnbphi=sign(one,bax)
|
|
|
|
|
|
|
|
rmxm=rmaxis+aminor
|
|
|
|
rmnm=rmaxis-aminor
|
|
|
|
zmxm=zbsup
|
|
|
|
zmnm=zbinf
|
|
|
|
|
|
|
|
if (present(n)) then
|
|
|
|
nq=n
|
|
|
|
else
|
|
|
|
nq=nqdef
|
|
|
|
end if
|
|
|
|
if (allocated(psinr)) deallocate(psinr)
|
|
|
|
allocate(psinr(nq),rhotn(nq),rhopn(nq))
|
|
|
|
|
|
|
|
dr=one/(nq-1)
|
|
|
|
rhotn(1)=zero
|
|
|
|
psinr(1)=zero
|
|
|
|
res=zero
|
|
|
|
fq0=zero
|
|
|
|
do i=2,nq
|
|
|
|
rn=(i-1)*dr
|
|
|
|
qq=q0+(q1-q0)*rn**qexp
|
|
|
|
fq1=rn/qq
|
|
|
|
res=res+0.5_wp_*(fq1+fq0)*dr
|
|
|
|
fq0=fq1
|
|
|
|
rhotn(i)=rn
|
|
|
|
psinr(i)=res
|
|
|
|
end do
|
|
|
|
|
|
|
|
phitedge=btaxis*aminor**2 ! temporary
|
|
|
|
psia=res*phitedge
|
|
|
|
phitedge=pi*phitedge ! final
|
|
|
|
psinr=psinr/res
|
|
|
|
rhopn=sqrt(psinr)
|
|
|
|
|
|
|
|
call set_rhospl(rhopn,rhotn)
|
2022-05-11 00:30:34 +02:00
|
|
|
end subroutine set_equil_an
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
subroutine set_rhospl(rhop,rhot)
|
|
|
|
use simplespline, only : difcs
|
|
|
|
implicit none
|
|
|
|
! arguments
|
|
|
|
real(wp_), dimension(:), intent(in) :: rhop, rhot
|
|
|
|
! local variables
|
|
|
|
integer, parameter :: iopt=0
|
|
|
|
integer :: ier
|
|
|
|
|
|
|
|
nrho=size(rhop)
|
|
|
|
|
|
|
|
if(allocated(rhopr)) deallocate(rhopr)
|
|
|
|
if(allocated(rhotr)) deallocate(rhotr)
|
|
|
|
if(allocated(crhop)) deallocate(crhop)
|
|
|
|
if(allocated(crhot)) deallocate(crhot)
|
|
|
|
allocate(rhopr(nrho),rhotr(nrho),crhop(nrho,4),crhot(nrho,4))
|
|
|
|
|
|
|
|
rhopr=rhop
|
|
|
|
rhotr=rhot
|
|
|
|
call difcs(rhotr,rhopr,nrho,iopt,crhop,ier)
|
|
|
|
call difcs(rhopr,rhotr,nrho,iopt,crhot,ier)
|
|
|
|
end subroutine set_rhospl
|
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
subroutine equinum_psi(rpsim,zpsim,psinv,dpsidr,dpsidz, &
|
|
|
|
ddpsidrr,ddpsidzz,ddpsidrz)
|
|
|
|
use dierckx, only : fpbisp
|
|
|
|
implicit none
|
|
|
|
! local constants
|
|
|
|
integer, parameter :: lwrk=8,liwrk=2
|
|
|
|
! arguments
|
|
|
|
real(wp_), intent(in) :: rpsim,zpsim
|
|
|
|
real(wp_), intent(out), optional :: psinv,dpsidr,dpsidz, &
|
|
|
|
ddpsidrr,ddpsidzz,ddpsidrz
|
|
|
|
|
|
|
|
! local variables
|
|
|
|
integer, dimension(liwrk) :: iwrk
|
|
|
|
real(wp_), dimension(1) :: rrs,zzs,ffspl
|
|
|
|
real(wp_), dimension(lwrk) :: wrk
|
|
|
|
|
|
|
|
! here lengths are measured in meters
|
|
|
|
|
|
|
|
if (rpsim.le.rmxm .and. rpsim.ge.rmnm .and. &
|
|
|
|
zpsim.le.zmxm .and. zpsim.ge.zmnm) then
|
|
|
|
|
|
|
|
if (present(psinv)) then
|
|
|
|
rrs(1)=rpsim
|
|
|
|
zzs(1)=zpsim
|
|
|
|
call fpbisp(tr,nsr,tz,nsz,cceq,3,3,rrs,1,zzs,1,ffspl, &
|
|
|
|
wrk(1),wrk(5),iwrk(1),iwrk(2))
|
|
|
|
psinv=(ffspl(1)-psinop)/psiant
|
|
|
|
end if
|
|
|
|
if (present(dpsidr)) then
|
|
|
|
call sub_derpsi(rpsim,zpsim,1,0,dpsidr,cceq10)
|
|
|
|
end if
|
|
|
|
if (present(dpsidz)) then
|
|
|
|
call sub_derpsi(rpsim,zpsim,0,1,dpsidz,cceq01)
|
|
|
|
end if
|
|
|
|
if (present(ddpsidrr)) then
|
|
|
|
call sub_derpsi(rpsim,zpsim,2,0,ddpsidrr,cceq20)
|
|
|
|
end if
|
|
|
|
if (present(ddpsidzz)) then
|
|
|
|
call sub_derpsi(rpsim,zpsim,0,2,ddpsidzz,cceq02)
|
|
|
|
end if
|
|
|
|
if (present(ddpsidrz)) then
|
|
|
|
call sub_derpsi(rpsim,zpsim,1,1,ddpsidrz,cceq11)
|
|
|
|
end if
|
|
|
|
else
|
|
|
|
if(present(psinv)) psinv=-1.0_wp_
|
|
|
|
if(present(dpsidr)) dpsidr=0.0_wp_
|
|
|
|
if(present(dpsidz)) dpsidz=0.0_wp_
|
|
|
|
if(present(ddpsidrr)) ddpsidrr=0.0_wp_
|
|
|
|
if(present(ddpsidzz)) ddpsidzz=0.0_wp_
|
|
|
|
if(present(ddpsidrz)) ddpsidrz=0.0_wp_
|
|
|
|
end if
|
|
|
|
end subroutine equinum_psi
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
subroutine sub_derpsi(rpsim,zpsim,nur,nuz,derpsi,cc)
|
|
|
|
use dierckx, only : fpbisp
|
|
|
|
implicit none
|
|
|
|
! arguments
|
|
|
|
real(wp_), intent(in) :: rpsim,zpsim
|
|
|
|
integer, intent(in) :: nur,nuz
|
|
|
|
real(wp_), intent(out) :: derpsi
|
|
|
|
real(wp_), dimension(:) :: cc
|
|
|
|
! local variables
|
|
|
|
integer, dimension(1) :: iwrkr,iwrkz
|
|
|
|
real(wp_), dimension(1) :: rrs,zzs,ffspl
|
|
|
|
real(wp_), dimension(1,ksplp) :: wrkr
|
|
|
|
real(wp_), dimension(1,ksplp) :: wrkz
|
|
|
|
|
|
|
|
rrs(1)=rpsim
|
|
|
|
zzs(1)=zpsim
|
|
|
|
call fpbisp(tr(nur+1),nsr-2*nur,tz(nuz+1),nsz-2*nuz,cc,kspl-nur,kspl-nuz, &
|
|
|
|
rrs,1,zzs,1,ffspl,wrkr,wrkz,iwrkr,iwrkz)
|
|
|
|
derpsi=ffspl(1)*psia
|
|
|
|
end subroutine sub_derpsi
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
subroutine equinum_fpol(psinv,fpolv,dfpv)
|
|
|
|
use dierckx, only : splev,splder
|
|
|
|
implicit none
|
|
|
|
! arguments
|
|
|
|
real(wp_), intent(in) :: psinv
|
|
|
|
real(wp_), intent(out) :: fpolv
|
|
|
|
real(wp_), intent(out), optional :: dfpv
|
|
|
|
! local variables
|
|
|
|
integer :: ier
|
|
|
|
real(wp_), dimension(1) :: rrs,ffspl
|
|
|
|
real(wp_), dimension(nsf) :: wrkfd
|
|
|
|
!
|
|
|
|
if(psinv.le.1.0_wp_.and.psinv.ge.0.0_wp_) then
|
|
|
|
rrs(1)=psinv
|
|
|
|
call splev(tfp,nsf,cfp,3,rrs,ffspl,1,ier)
|
|
|
|
fpolv=ffspl(1)
|
|
|
|
if(present(dfpv)) then
|
|
|
|
call splder(tfp,nsf,cfp,3,1,rrs,ffspl,1,wrkfd,ier)
|
|
|
|
dfpv=ffspl(1)/psia
|
|
|
|
end if
|
|
|
|
else
|
|
|
|
fpolv=fpolas
|
|
|
|
if (present(dfpv)) dfpv=0._wp_
|
|
|
|
end if
|
|
|
|
end subroutine equinum_fpol
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
subroutine equian(rrm,zzm,psinv,fpolv,dfpv,dpsidr,dpsidz, &
|
|
|
|
ddpsidrr,ddpsidzz,ddpsidrz)
|
|
|
|
use const_and_precisions, only : wp_
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
|
|
|
! arguments
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_), intent(in) :: rrm,zzm
|
|
|
|
real(wp_), intent(out), optional :: psinv,fpolv,dfpv,dpsidr,dpsidz, &
|
|
|
|
ddpsidrr,ddpsidzz,ddpsidrz
|
2015-11-18 17:34:33 +01:00
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: cst,dpsidrp,d2psidrp,dqq,qq,rn,rpm,snt,rhop,rhot,btaxqq
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
! simple model for equilibrium: large aspect ratio
|
|
|
|
! outside plasma: analytical continuation, not solution Maxwell eqs
|
|
|
|
|
|
|
|
rpm=sqrt((rrm-rmaxis)**2+(zzm-zmaxis)**2) !!! rpm==rho_tor[m], rn=rho_tor_norm
|
|
|
|
rn=rpm/aminor
|
|
|
|
|
|
|
|
snt=0.0_wp_
|
|
|
|
cst=1.0_wp_
|
|
|
|
if (rpm > 0.0_wp_) then
|
|
|
|
snt=(zzm-zmaxis)/rpm
|
|
|
|
cst=(rrm-rmaxis)/rpm
|
|
|
|
end if
|
|
|
|
|
|
|
|
if (present(psinv)) then
|
|
|
|
rhot=rn
|
|
|
|
if(rn <= 1.0_wp_) then
|
|
|
|
rhop=frhopol(rhot)
|
|
|
|
psinv=rhop**2
|
|
|
|
else
|
|
|
|
psinv=1.0_wp_+btaxis/(2.0_wp_*psia*qa)*(rpm**2-aminor**2)
|
|
|
|
rhop=sqrt(psinv)
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
end if
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
if(rn <= 1.0_wp_) then
|
|
|
|
qq=q0+(qa-q0)*rn**alq
|
|
|
|
btaxqq=btaxis/qq
|
|
|
|
dpsidrp=btaxqq*rpm
|
|
|
|
dqq=alq*(qa-q0)*rn**(alq-1.0_wp_)
|
|
|
|
d2psidrp=btaxqq*(1.0_wp_-rn*dqq/qq)
|
|
|
|
else
|
|
|
|
btaxqq=btaxis/qa
|
|
|
|
dpsidrp=btaxqq*rpm
|
|
|
|
d2psidrp=btaxqq
|
|
|
|
end if
|
|
|
|
|
|
|
|
if(present(fpolv)) fpolv=btaxis*rmaxis
|
|
|
|
if(present(dfpv)) dfpv=0.0_wp_
|
|
|
|
|
|
|
|
if(present(dpsidr)) dpsidr=dpsidrp*cst
|
|
|
|
if(present(dpsidz)) dpsidz=dpsidrp*snt
|
|
|
|
if(present(ddpsidrr)) ddpsidrr=btaxqq*snt**2+cst**2*d2psidrp
|
|
|
|
if(present(ddpsidrz)) ddpsidrz=cst*snt*(d2psidrp-btaxqq)
|
|
|
|
if(present(ddpsidzz)) ddpsidzz=btaxqq*cst**2+snt**2*d2psidrp
|
|
|
|
end subroutine equian
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function frhopol(rhot)
|
|
|
|
use utils, only : locate
|
|
|
|
use simplespline, only : spli
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
|
|
|
! arguments
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_), intent(in) :: rhot
|
|
|
|
real(wp_) :: frhopol
|
2015-11-18 17:34:33 +01:00
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
integer :: i
|
|
|
|
real(wp_) :: dr
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
call locate(rhotr,nrho,rhot,i)
|
|
|
|
i=min(max(1,i),nrho-1)
|
|
|
|
dr=rhot-rhotr(i)
|
|
|
|
frhopol=spli(crhop,nrho,i,dr)
|
|
|
|
end function frhopol
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
function frhopolv(rhot)
|
|
|
|
use utils, only : locate
|
|
|
|
use simplespline, only : spli
|
|
|
|
implicit none
|
|
|
|
! arguments
|
|
|
|
real(wp_), dimension(:), intent(in) :: rhot
|
|
|
|
real(wp_), dimension(size(rhot)) :: frhopolv
|
|
|
|
! local variables
|
|
|
|
integer :: i,i0,j
|
|
|
|
real(wp_) :: dr
|
|
|
|
|
|
|
|
i0=1
|
|
|
|
do j=1,size(rhot)
|
|
|
|
call locate(rhotr(i0:),nrho-i0+1,rhot(j),i)
|
|
|
|
i=min(max(1,i),nrho-i0)+i0-1
|
|
|
|
dr=rhot(j)-rhotr(i)
|
|
|
|
frhopolv(j)=spli(crhop,nrho,i,dr)
|
|
|
|
i0=i
|
2015-11-18 17:34:33 +01:00
|
|
|
end do
|
2015-11-23 18:55:27 +01:00
|
|
|
end function frhopolv
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
function frhotor(rhop)
|
|
|
|
use utils, only : locate
|
|
|
|
use simplespline, only : spli
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2015-11-23 18:55:27 +01:00
|
|
|
! arguments
|
|
|
|
real(wp_), intent(in) :: rhop
|
|
|
|
real(wp_) :: frhotor
|
|
|
|
! local variables
|
|
|
|
integer :: i
|
|
|
|
real(wp_) :: dr
|
|
|
|
|
|
|
|
call locate(rhopr,nrho,rhop,i)
|
|
|
|
i=min(max(1,i),nrho-1)
|
|
|
|
dr=rhop-rhopr(i)
|
|
|
|
frhotor=spli(crhot,nrho,i,dr)
|
|
|
|
end function frhotor
|
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
function fq(psin)
|
|
|
|
use const_and_precisions, only : wp_
|
|
|
|
use gray_params, only : iequil
|
|
|
|
use simplespline, only :spli
|
|
|
|
use utils, only : locate
|
|
|
|
implicit none
|
|
|
|
! arguments
|
|
|
|
real(wp_), intent(in) :: psin
|
|
|
|
real(wp_) :: fq
|
|
|
|
! local variables
|
|
|
|
integer :: i
|
|
|
|
real(wp_) :: dps,rn
|
|
|
|
|
|
|
|
if (iequil<2) then
|
|
|
|
rn=frhotor(sqrt(psin))
|
|
|
|
fq=q0+(qa-q0)*rn**alq
|
|
|
|
else
|
|
|
|
call locate(psinr,nq,psin,i)
|
|
|
|
i=min(max(1,i),nq-1)
|
|
|
|
dps=psin-psinr(i)
|
|
|
|
fq=spli(cq,nq,i,dps)
|
|
|
|
end if
|
|
|
|
end function fq
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
subroutine bfield(rpsim,zpsim,bphi,br,bz)
|
|
|
|
use gray_params, only : iequil
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
|
|
|
! arguments
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_), intent(in) :: rpsim,zpsim
|
|
|
|
real(wp_), intent(out), optional :: bphi,br,bz
|
2015-11-18 17:34:33 +01:00
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: psin,fpol
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
if (iequil < 2) then
|
|
|
|
call equian(rpsim,zpsim,fpolv=bphi,dpsidr=bz,dpsidz=br)
|
|
|
|
if (present(bphi)) bphi=bphi/rpsim
|
|
|
|
else
|
|
|
|
call equinum_psi(rpsim,zpsim,psinv=bphi,dpsidr=bz,dpsidz=br)
|
|
|
|
if (present(bphi)) then
|
|
|
|
psin=bphi
|
|
|
|
call equinum_fpol(psin,fpol)
|
|
|
|
bphi=fpol/rpsim
|
|
|
|
end if
|
|
|
|
end if
|
|
|
|
if (present(br)) br=-br/rpsim
|
|
|
|
if (present(bz)) bz= bz/rpsim
|
|
|
|
end subroutine bfield
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
subroutine tor_curr(rpsim,zpsim,ajphi)
|
|
|
|
use const_and_precisions, only : wp_,ccj=>mu0inv
|
|
|
|
use gray_params, only : iequil
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
|
|
|
! arguments
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: rpsim,zpsim,ajphi
|
2015-11-18 17:34:33 +01:00
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: bzz,dbvcdc13,dbvcdc31
|
|
|
|
real(wp_) :: dpsidr,ddpsidrr,ddpsidzz
|
|
|
|
|
|
|
|
if(iequil < 2) then
|
|
|
|
call equian(rpsim,zpsim,dpsidr=dpsidr, &
|
|
|
|
ddpsidrr=ddpsidrr,ddpsidzz=ddpsidzz)
|
|
|
|
else
|
|
|
|
call equinum_psi(rpsim,zpsim,dpsidr=dpsidr, &
|
|
|
|
ddpsidrr=ddpsidrr,ddpsidzz=ddpsidzz)
|
|
|
|
end if
|
|
|
|
bzz= dpsidr/rpsim
|
|
|
|
dbvcdc13=-ddpsidzz/rpsim
|
|
|
|
dbvcdc31= ddpsidrr/rpsim-bzz/rpsim
|
|
|
|
ajphi=ccj*(dbvcdc13-dbvcdc31)
|
|
|
|
end subroutine tor_curr
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
subroutine psi_raxis(psin,r1,r2)
|
|
|
|
use const_and_precisions, only : wp_
|
2021-12-18 18:57:38 +01:00
|
|
|
use gray_params, only : iequil
|
|
|
|
use dierckx, only : profil, sproota
|
|
|
|
use logger, only : log_error
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: psin,r1,r2
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! local constants
|
|
|
|
integer, parameter :: mest=4
|
|
|
|
|
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
integer :: iopt,ier,m
|
|
|
|
real(wp_) :: zc,val
|
|
|
|
real(wp_), dimension(mest) :: zeroc
|
|
|
|
real(wp_), dimension(nsr) :: czc
|
2021-12-18 18:57:38 +01:00
|
|
|
character(64) :: msg
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
if (iequil < 2) then
|
|
|
|
val=frhotor(sqrt(psin))
|
|
|
|
r1=rmaxis-val*aminor
|
|
|
|
r2=rmaxis+val*aminor
|
|
|
|
else
|
|
|
|
iopt=1
|
|
|
|
zc=zmaxis
|
|
|
|
call profil(iopt,tr,nsr,tz,nsz,cceq,kspl,kspl,zc,nsr,czc,ier)
|
2021-12-18 18:57:38 +01:00
|
|
|
if (ier > 0) then
|
|
|
|
write (msg, '("profil failed with error ",g0)') ier
|
|
|
|
call log_error(msg, mod='equilibrium', proc='psi_raxis')
|
|
|
|
end if
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
val=psin*psiant+psinop
|
|
|
|
call sproota(val,tr,nsr,czc,zeroc,mest,m,ier)
|
|
|
|
r1=zeroc(1)
|
|
|
|
r2=zeroc(2)
|
|
|
|
end if
|
|
|
|
end subroutine psi_raxis
|
2015-11-18 17:34:33 +01:00
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
subroutine tor_curr_psi(psin,ajphi)
|
|
|
|
use const_and_precisions, only : wp_
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
|
|
|
! arguments
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: psin,ajphi
|
2015-11-18 17:34:33 +01:00
|
|
|
! local variables
|
2015-11-23 18:55:27 +01:00
|
|
|
real(wp_) :: r1,r2
|
|
|
|
call psi_raxis(psin,r1,r2)
|
|
|
|
call tor_curr(r2,zmaxis,ajphi)
|
|
|
|
end subroutine tor_curr_psi
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
subroutine points_ox(rz,zz,rf,zf,psinvf,info)
|
|
|
|
use const_and_precisions, only : comp_eps
|
2021-12-18 18:57:38 +01:00
|
|
|
use minpack, only : hybrj1
|
|
|
|
use logger, only : log_error, log_debug
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! local constants
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, parameter :: n=2,ldfjac=n,lwa=(n*(n+13))/2
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! arguments
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_), intent(in) :: rz,zz
|
|
|
|
real(wp_), intent(out) :: rf,zf,psinvf
|
|
|
|
integer, intent(out) :: info
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! local variables
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_) :: tol
|
|
|
|
real(wp_), dimension(n) :: xvec,fvec
|
|
|
|
real(wp_), dimension(lwa) :: wa
|
|
|
|
real(wp_), dimension(ldfjac,n) :: fjac
|
2021-12-18 18:57:38 +01:00
|
|
|
character(256) :: msg
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
xvec(1)=rz
|
|
|
|
xvec(2)=zz
|
|
|
|
tol = sqrt(comp_eps)
|
|
|
|
call hybrj1(fcnox,n,xvec,fvec,fjac,ldfjac,tol,info,wa,lwa)
|
2021-12-18 18:57:38 +01:00
|
|
|
if(info /= 1) then
|
|
|
|
write (msg, '("O,X coordinates:",2(x,", ",g0.3))') xvec
|
|
|
|
call log_debug(msg, mod='equilibrium', proc='points_ox')
|
|
|
|
write (msg, '("hybrj1 failed with error ",g0)') info
|
|
|
|
call log_error(msg, mod='equilibrium', proc='points_ox')
|
|
|
|
end if
|
|
|
|
rf=xvec(1)
|
|
|
|
zf=xvec(2)
|
|
|
|
call equinum_psi(rf,zf,psinvf)
|
2015-11-18 17:34:33 +01:00
|
|
|
end subroutine points_ox
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
subroutine fcnox(n,x,fvec,fjac,ldfjac,iflag)
|
2021-12-18 18:57:38 +01:00
|
|
|
use logger, only : log_error
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, intent(in) :: n,iflag,ldfjac
|
|
|
|
real(wp_), dimension(n), intent(in) :: x
|
|
|
|
real(wp_), dimension(n), intent(inout) :: fvec
|
|
|
|
real(wp_), dimension(ldfjac,n), intent(inout) :: fjac
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! local variables
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_) :: dpsidr,dpsidz,ddpsidrr,ddpsidzz,ddpsidrz
|
2021-12-18 18:57:38 +01:00
|
|
|
character(64) :: msg
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
select case(iflag)
|
|
|
|
case(1)
|
|
|
|
call equinum_psi(x(1),x(2),dpsidr=dpsidr,dpsidz=dpsidz)
|
|
|
|
fvec(1) = dpsidr/psia
|
|
|
|
fvec(2) = dpsidz/psia
|
|
|
|
case(2)
|
|
|
|
call equinum_psi(x(1),x(2),ddpsidrr=ddpsidrr,ddpsidzz=ddpsidzz, &
|
|
|
|
ddpsidrz=ddpsidrz)
|
|
|
|
fjac(1,1) = ddpsidrr/psia
|
|
|
|
fjac(1,2) = ddpsidrz/psia
|
|
|
|
fjac(2,1) = ddpsidrz/psia
|
|
|
|
fjac(2,2) = ddpsidzz/psia
|
|
|
|
case default
|
2021-12-18 18:57:38 +01:00
|
|
|
write (msg, '("invalid iflag: ",g0)')
|
|
|
|
call log_error(msg, mod='equilibrium', proc='fcnox')
|
2015-11-18 17:34:33 +01:00
|
|
|
end select
|
|
|
|
end subroutine fcnox
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
subroutine points_tgo(rz,zz,rf,zf,psin0,info)
|
|
|
|
use const_and_precisions, only : comp_eps
|
2021-12-18 18:57:38 +01:00
|
|
|
use minpack, only : hybrj1mv
|
|
|
|
use logger, only : log_error, log_debug
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! local constants
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, parameter :: n=2,ldfjac=n,lwa=(n*(n+13))/2
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! arguments
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_), intent(in) :: rz,zz,psin0
|
|
|
|
real(wp_), intent(out) :: rf,zf
|
|
|
|
integer, intent(out) :: info
|
2021-12-18 18:57:38 +01:00
|
|
|
character(256) :: msg
|
|
|
|
|
|
|
|
! local variables
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_) :: tol
|
|
|
|
real(wp_), dimension(n) :: xvec,fvec,f0
|
|
|
|
real(wp_), dimension(lwa) :: wa
|
|
|
|
real(wp_), dimension(ldfjac,n) :: fjac
|
|
|
|
|
|
|
|
xvec(1)=rz
|
|
|
|
xvec(2)=zz
|
|
|
|
f0(1)=psin0
|
|
|
|
f0(2)=0.0_wp_
|
|
|
|
tol = sqrt(comp_eps)
|
|
|
|
call hybrj1mv(fcntgo,n,xvec,f0,fvec,fjac,ldfjac,tol,info,wa,lwa)
|
2021-12-18 18:57:38 +01:00
|
|
|
if(info /= 1) then
|
|
|
|
write (msg, '("R,z coordinates:",5(x,g0.3))') xvec, rz, zz, psin0
|
|
|
|
call log_debug(msg, mod='equilibrium', proc='points_tgo')
|
|
|
|
write (msg, '("hybrj1mv failed with error ",g0)') info
|
|
|
|
call log_error(msg, mod='equilibrium', proc='points_tgo')
|
2015-11-18 17:34:33 +01:00
|
|
|
end if
|
|
|
|
rf=xvec(1)
|
|
|
|
zf=xvec(2)
|
|
|
|
end
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
subroutine fcntgo(n,x,f0,fvec,fjac,ldfjac,iflag)
|
|
|
|
use const_and_precisions, only : wp_
|
2021-12-18 18:57:38 +01:00
|
|
|
use logger, only : log_error
|
|
|
|
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! subroutine arguments
|
2015-11-18 17:34:33 +01:00
|
|
|
integer, intent(in) :: n,ldfjac,iflag
|
|
|
|
real(wp_), dimension(n), intent(in) :: x,f0
|
|
|
|
real(wp_), dimension(n), intent(inout) :: fvec
|
|
|
|
real(wp_), dimension(ldfjac,n), intent(inout) :: fjac
|
2021-12-18 18:57:38 +01:00
|
|
|
|
|
|
|
! local variables
|
2015-11-18 17:34:33 +01:00
|
|
|
real(wp_) :: psinv,dpsidr,dpsidz,ddpsidrr,ddpsidrz
|
2021-12-18 18:57:38 +01:00
|
|
|
character(64) :: msg
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
select case(iflag)
|
|
|
|
case(1)
|
|
|
|
call equinum_psi(x(1),x(2),psinv,dpsidr)
|
|
|
|
fvec(1) = psinv-f0(1)
|
|
|
|
fvec(2) = dpsidr/psia-f0(2)
|
|
|
|
case(2)
|
|
|
|
call equinum_psi(x(1),x(2),dpsidr=dpsidr,dpsidz=dpsidz, &
|
|
|
|
ddpsidrr=ddpsidrr,ddpsidrz=ddpsidrz)
|
|
|
|
fjac(1,1) = dpsidr/psia
|
|
|
|
fjac(1,2) = dpsidz/psia
|
|
|
|
fjac(2,1) = ddpsidrr/psia
|
|
|
|
fjac(2,2) = ddpsidrz/psia
|
|
|
|
case default
|
2021-12-18 18:57:38 +01:00
|
|
|
write (msg, '("invalid iflag: ",g0)')
|
|
|
|
call log_error(msg, mod='equilibrium', proc='fcntgo')
|
2015-11-18 17:34:33 +01:00
|
|
|
end select
|
|
|
|
end subroutine fcntgo
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
subroutine unset_equil_spline
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2022-05-11 00:30:34 +02:00
|
|
|
|
|
|
|
if (allocated(tr)) deallocate(tr)
|
|
|
|
if (allocated(tz)) deallocate(tz)
|
|
|
|
if (allocated(tfp)) deallocate(tfp)
|
|
|
|
if (allocated(cfp)) deallocate(cfp)
|
|
|
|
if (allocated(cceq)) deallocate(cceq)
|
|
|
|
if (allocated(cceq01)) deallocate(cceq01)
|
|
|
|
if (allocated(cceq10)) deallocate(cceq10)
|
|
|
|
if (allocated(cceq02)) deallocate(cceq02)
|
|
|
|
if (allocated(cceq20)) deallocate(cceq20)
|
|
|
|
if (allocated(cceq11)) deallocate(cceq11)
|
|
|
|
nsr = 0
|
|
|
|
nsz = 0
|
|
|
|
nsf = 0
|
|
|
|
end subroutine unset_equil_spline
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2015-11-23 18:55:27 +01:00
|
|
|
subroutine unset_q
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
if (allocated(psinr)) deallocate(psinr)
|
|
|
|
if (allocated(cq)) deallocate(cq)
|
|
|
|
nq = 0
|
2015-11-23 18:55:27 +01:00
|
|
|
end subroutine unset_q
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2022-05-11 00:30:34 +02:00
|
|
|
subroutine unset_rho_spline
|
2015-11-18 17:34:33 +01:00
|
|
|
implicit none
|
2015-11-23 18:55:27 +01:00
|
|
|
|
|
|
|
if(allocated(rhopr)) deallocate(rhopr)
|
|
|
|
if(allocated(rhotr)) deallocate(rhotr)
|
|
|
|
if(allocated(crhop)) deallocate(crhop)
|
|
|
|
if(allocated(crhot)) deallocate(crhot)
|
|
|
|
nrho=0
|
2022-05-11 00:30:34 +02:00
|
|
|
end subroutine unset_rho_spline
|
2015-11-18 17:34:33 +01:00
|
|
|
|
|
|
|
end module equilibrium
|