src/equilibrium.f90: give the poloidal flux a definition domain
This change limits the evaluation of the poloidal flux spline ψ(R,z) to a particular domain where ψ(R,z) is strictly monotonic. This choice ensures that ψ_n < 1 only inside the plasma boundary; so plasma parameters like q(ψ), Te(ψ), etc. can be mapped to the physical space without ambiguities. Before this change, anywhere ψ_n happened to decrease below 1 (either as a result of a physical current or simply from the spline extrapolation), Gray would effectively create a spurious plasma region. This behavior is seriously problematic because it completely invalidates the simulation: it can alter the ray directions, the power disribution and total power if the beam enters one such region. The domain is computed by applying a transformation to the contour of the plasma boundary: for each contour point we cast a ray from the magnetic axis to that point and extend the ray until the restriction of ψ(R,z) on the ray starts decreasing or reach a maximum scaling factor. The endpoint of the ray is then taken as the new point. If ψ(R,z) is globally monotonic, the transformation is a homotety wrt the magnetic axis, so the domain will be an enlarged boundary; otherwise the shape will be more irregular (an intersection of the enlarged boundary and several level curves of ψ). Finally, each `pol_flux(r, z)` call is now guarded behind a check `inside(psi_domain, r, z)`. For points outside the domain the subroutine returns, as usual, -1 for ψ and 0 for derivatives.
This commit is contained in:
parent
6fad08ed7c
commit
26976a31dd
@ -22,6 +22,12 @@ module equilibrium
|
|||||||
real(wp_) :: B0 ! Magnetic field at the magnetic axis (T)
|
real(wp_) :: B0 ! Magnetic field at the magnetic axis (T)
|
||||||
end type
|
end type
|
||||||
|
|
||||||
|
! A 2D contour in the (R,z) plane
|
||||||
|
type contour
|
||||||
|
real(wp_), allocatable :: R(:)
|
||||||
|
real(wp_), allocatable :: z(:)
|
||||||
|
end type
|
||||||
|
|
||||||
! Order of the splines
|
! Order of the splines
|
||||||
integer, parameter :: kspl=3, ksplp=kspl + 1
|
integer, parameter :: kspl=3, ksplp=kspl + 1
|
||||||
|
|
||||||
@ -36,6 +42,11 @@ module equilibrium
|
|||||||
! Analytic model
|
! Analytic model
|
||||||
type(analytic_model), save :: model
|
type(analytic_model), save :: model
|
||||||
|
|
||||||
|
! Contour of the region where the ψ(R,z) spline is monotonically
|
||||||
|
! increasing. The mapping from ψ to other plasma parameters is
|
||||||
|
! physically meaningful only inside this domain.
|
||||||
|
type(contour), save :: psi_domain
|
||||||
|
|
||||||
! More parameters
|
! More parameters
|
||||||
real(wp_), save :: fpolas ! Poloidal current at the edge (r=a), F_a
|
real(wp_), save :: fpolas ! Poloidal current at the edge (r=a), F_a
|
||||||
real(wp_), save :: psia ! Poloidal flux at the edge (r=a), ψ_a
|
real(wp_), save :: psia ! Poloidal flux at the edge (r=a), ψ_a
|
||||||
@ -45,8 +56,8 @@ module equilibrium
|
|||||||
real(wp_), save :: sgnbphi ! Sign of B_φ (>0 means CCW)
|
real(wp_), save :: sgnbphi ! Sign of B_φ (>0 means CCW)
|
||||||
real(wp_), save :: btrcen ! used only for jcd_astra def.
|
real(wp_), save :: btrcen ! used only for jcd_astra def.
|
||||||
real(wp_), save :: rcen ! Major radius R₀, computed as fpolas/btrcen
|
real(wp_), save :: rcen ! Major radius R₀, computed as fpolas/btrcen
|
||||||
real(wp_), save :: rmnm, rmxm ! R interval of the equilibrium definition
|
real(wp_), save :: rmnm, rmxm ! R interval of the equilibrium grid
|
||||||
real(wp_), save :: zmnm, zmxm ! z interval of the equilibrium definition
|
real(wp_), save :: zmnm, zmxm ! z interval of the equilibrium grid
|
||||||
real(wp_), save :: zbinf, zbsup ! z interval of the plasma boundary
|
real(wp_), save :: zbinf, zbsup ! z interval of the plasma boundary
|
||||||
|
|
||||||
private
|
private
|
||||||
@ -538,6 +549,13 @@ contains
|
|||||||
call psi_spline%init_deriv(nr, nz, 2, 0) ! ∂²ψ/∂R²
|
call psi_spline%init_deriv(nr, nz, 2, 0) ! ∂²ψ/∂R²
|
||||||
call psi_spline%init_deriv(nr, nz, 0, 2) ! ∂²ψ/∂z²
|
call psi_spline%init_deriv(nr, nz, 0, 2) ! ∂²ψ/∂z²
|
||||||
|
|
||||||
|
! set the initial ψ(R,z) domain to the grid boundary
|
||||||
|
!
|
||||||
|
! Note: this is required to bootstrap `flux_pol` calls
|
||||||
|
! within this very subroutine.
|
||||||
|
psi_domain%R = [rmnm, rmnm, rmxm, rmxm]
|
||||||
|
psi_domain%z = [zmnm, zmxm, zmxm, zmnm]
|
||||||
|
|
||||||
! Spline interpolation of F(ψ)
|
! Spline interpolation of F(ψ)
|
||||||
|
|
||||||
! give a small weight to the last point
|
! give a small weight to the last point
|
||||||
@ -672,9 +690,67 @@ contains
|
|||||||
call setqphi_num(data%psinr, abs(data%qpsi), abs(psia), rhotn)
|
call setqphi_num(data%psinr, abs(data%qpsi), abs(psia), rhotn)
|
||||||
call set_rho_spline(sqrt(data%psinr), rhotn)
|
call set_rho_spline(sqrt(data%psinr), rhotn)
|
||||||
|
|
||||||
|
! Compute the domain of the ψ mapping
|
||||||
|
psi_domain%R = data%rbnd
|
||||||
|
psi_domain%z = data%zbnd
|
||||||
|
call rescale_boundary(psi_domain, O=[rmaxis, zmaxis], t0=1.5_wp_)
|
||||||
|
|
||||||
end subroutine set_equil_spline
|
end subroutine set_equil_spline
|
||||||
|
|
||||||
|
|
||||||
|
subroutine rescale_boundary(cont, O, t0)
|
||||||
|
! Given the plasma boundary contour `cont`, the position of the
|
||||||
|
! magnetic axis `O`, and a scaling factor `t0`; this subroutine
|
||||||
|
! rescales the contour by `t0` about `O` while ensuring the
|
||||||
|
! psi_spline stays monotonic within the new boundary.
|
||||||
|
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
! subroutine arguments
|
||||||
|
type(contour), intent(inout) :: cont ! (R,z) contour
|
||||||
|
real(wp_), intent(in) :: O(2) ! center point
|
||||||
|
real(wp_), intent(in) :: t0 ! scaling factor
|
||||||
|
|
||||||
|
! subroutine variables
|
||||||
|
integer :: i
|
||||||
|
real(wp_) :: t
|
||||||
|
real(wp_), parameter :: dt = 0.05
|
||||||
|
real(wp_) :: P(2), N(2)
|
||||||
|
|
||||||
|
do i = 1, size(cont%R)
|
||||||
|
! For each point on the contour compute:
|
||||||
|
P = [cont%R(i), cont%z(i)] ! point on the contour
|
||||||
|
N = P - O ! direction of the line from O to P
|
||||||
|
|
||||||
|
! Find the max t: s(t) = ψ(O + tN) is monotonic in [1, t]
|
||||||
|
t = 1
|
||||||
|
do while (t < t0)
|
||||||
|
if (s(t + dt) < s(t)) exit
|
||||||
|
t = t + dt
|
||||||
|
end do
|
||||||
|
|
||||||
|
! The final point is thus O + tN
|
||||||
|
P = O + t * N
|
||||||
|
cont%R(i) = P(1)
|
||||||
|
cont%z(i) = P(2)
|
||||||
|
end do
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
function s(t)
|
||||||
|
! Rescriction of ψ(R, z) on the line Q(t) = O + tN
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
real(wp_), intent(in) :: t
|
||||||
|
real(wp_) :: s, Q(2)
|
||||||
|
|
||||||
|
Q = O + t * N
|
||||||
|
s = psi_spline%eval(Q(1), Q(2))
|
||||||
|
end function
|
||||||
|
|
||||||
|
end subroutine rescale_boundary
|
||||||
|
|
||||||
|
|
||||||
subroutine scatterspl(x,y,z,w,n,kspl,sspl,xmin,xmax,ymin,ymax, &
|
subroutine scatterspl(x,y,z,w,n,kspl,sspl,xmin,xmax,ymin,ymax, &
|
||||||
tx,nknt_x,ty,nknt_y,coeff,ierr)
|
tx,nknt_x,ty,nknt_y,coeff,ierr)
|
||||||
! Computes the spline interpolation of a surface when
|
! Computes the spline interpolation of a surface when
|
||||||
@ -834,6 +910,7 @@ contains
|
|||||||
!
|
!
|
||||||
! Note: all output arguments are optional.
|
! Note: all output arguments are optional.
|
||||||
use gray_params, only : iequil
|
use gray_params, only : iequil
|
||||||
|
use reflections, only : inside
|
||||||
use const_and_precisions, only : one, pi
|
use const_and_precisions, only : one, pi
|
||||||
|
|
||||||
implicit none
|
implicit none
|
||||||
@ -960,8 +1037,7 @@ contains
|
|||||||
if (present(ddpsidrz)) ddpsidrz = ddpsidphidr * dphidz + dpsidphi * ddphidrdz
|
if (present(ddpsidrz)) ddpsidrz = ddpsidphidr * dphidz + dpsidphi * ddphidrdz
|
||||||
else
|
else
|
||||||
! Numerical data
|
! Numerical data
|
||||||
if (R <= rmxm .and. R >= rmnm .and. &
|
if (inside(psi_domain%R, psi_domain%z, psi_domain%npoints, R, z)) then
|
||||||
z <= zmxm .and. z >= zmnm) then
|
|
||||||
! Within the interpolation range
|
! Within the interpolation range
|
||||||
if (present(psi_n)) psi_n = psi_spline%eval(R, z)
|
if (present(psi_n)) psi_n = psi_spline%eval(R, z)
|
||||||
if (present(dpsidr)) dpsidr = psi_spline%deriv(R, z, 1, 0)
|
if (present(dpsidr)) dpsidr = psi_spline%deriv(R, z, 1, 0)
|
||||||
@ -1431,6 +1507,9 @@ contains
|
|||||||
call q_spline%deinit
|
call q_spline%deinit
|
||||||
call rhop_spline%deinit
|
call rhop_spline%deinit
|
||||||
call rhot_spline%deinit
|
call rhot_spline%deinit
|
||||||
|
|
||||||
|
if (allocated(psi_domain%R)) deallocate(psi_domain%R, psi_domain%z)
|
||||||
|
|
||||||
end subroutine unset_equil_spline
|
end subroutine unset_equil_spline
|
||||||
|
|
||||||
end module equilibrium
|
end module equilibrium
|
||||||
|
Loading…
Reference in New Issue
Block a user