Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_ellipt_2d_cartesian_gradient.F90
Go to the documentation of this file.
2 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 #include "sll_assert.h"
4 
6 
7  use sll_m_constants, only: sll_p_pi
8 
10 
12 
13  implicit none
14 
16 
17  private
18 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 
20  ! Working precision
21  integer, parameter :: wp = f64
22 
24 
25  ! Can be overwritten at initialization
26  real(wp) :: eps = 1.0e-12_wp
27 
28  type(sll_t_singular_mapping_discrete), pointer :: mapping_discrete => null()
29  type(sll_t_spline_2d), pointer :: spline_2d_phi => null()
30 
31  contains
32 
34  procedure :: eval => s_ellipt_2d_cartesian_gradient__eval
36 
38 
39 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
40 contains
41 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
42 
43  subroutine s_ellipt_2d_cartesian_gradient__init(self, mapping_discrete, spline_2d_phi, eps)
44  class(sll_t_ellipt_2d_cartesian_gradient), intent(inout) :: self
45  type(sll_t_singular_mapping_discrete), target, intent(in) :: mapping_discrete
46  type(sll_t_spline_2d), target, intent(in) :: spline_2d_phi
47  real(wp), optional, intent(in) :: eps
48 
49  self%mapping_discrete => mapping_discrete
50 
51  self%spline_2d_phi => spline_2d_phi
52 
53  if (present(eps)) self%eps = eps
54 
56 
57  !-----------------------------------------------------------------------------
58  ! Implements strategy described in section 5.4 of https://doi.org/10.1016/j.jcp.2019.108889
59  !-----------------------------------------------------------------------------
60  sll_pure function s_ellipt_2d_cartesian_gradient__eval(self, eta) result(gradient)
61  class(sll_t_ellipt_2d_cartesian_gradient), intent(in) :: self
62  real(wp), intent(in) :: eta(2)
63  real(wp) :: gradient(2)
64 
65  real(wp) :: jdet, d1, d2, d3, d4, d5, d6, th1, th2, eps, grad_0(2), grad_eps(2), jmat(2, 2)
66 
67  eps = self%eps
68 
69  if (eta(1) == 0.0_wp) then
70 
71  th1 = 0.0_wp
72  th2 = 0.5_wp*sll_p_pi
73 
74  d1 = self%spline_2d_phi%eval_deriv_x1(eta(1), th1) ! dphi/ds(0,theta_1)
75  d2 = self%spline_2d_phi%eval_deriv_x1(eta(1), th2) ! dphi/ds(0,theta_2)
76 
77  jmat = self%mapping_discrete%jmat((/eta(1), th1/))
78 
79  d3 = jmat(1, 1) ! dx/ds(0,theta_1)
80  d4 = jmat(2, 1) ! dy/ds(0,theta_1)
81 
82  jmat = self%mapping_discrete%jmat((/eta(1), th2/))
83 
84  d5 = jmat(1, 1) ! dx/ds(0,theta_2)
85  d6 = jmat(2, 1) ! dy/ds(0,theta_2)
86 
87  gradient(1) = (d4*d2 - d1*d6)/(d4*d5 - d3*d6)
88  gradient(2) = (d1*d5 - d3*d2)/(d4*d5 - d3*d6)
89 
90  ! Implements last equation of section 5.4 of https://doi.org/10.1016/j.jcp.2019.108889
91  else if (0.0_wp < eta(1) .and. eta(1) < eps) then
92 
93  th1 = 0.0_wp
94  th2 = 0.5_wp*sll_p_pi
95 
96  d1 = self%spline_2d_phi%eval_deriv_x1(0.0_wp, th1) ! dphi/ds(0,theta_1)
97  d2 = self%spline_2d_phi%eval_deriv_x1(0.0_wp, th2) ! dphi/ds(0,theta_2)
98 
99  jmat = self%mapping_discrete%jmat((/0.0_wp, th1/))
100 
101  d3 = jmat(1, 1) ! dx/ds(0,theta_1)
102  d4 = jmat(2, 1) ! dy/ds(0,theta_1)
103 
104  jmat = self%mapping_discrete%jmat((/0.0_wp, th2/))
105 
106  d5 = jmat(1, 1) ! dx/ds(0,theta_2)
107  d6 = jmat(2, 1) ! dy/ds(0,theta_2)
108 
109  ! E(0,theta)
110  grad_0(1) = (d4*d2 - d1*d6)/(d4*d5 - d3*d6)
111  grad_0(2) = (d1*d5 - d3*d2)/(d4*d5 - d3*d6)
112 
113  jmat = self%mapping_discrete%jmat((/eps, eta(2)/))
114  jdet = self%mapping_discrete%jdet((/eps, eta(2)/))
115 
116  ! E(eps,theta): J^(-T) times 'logical' gradient
117  grad_eps(1) = (jmat(2, 2)*self%spline_2d_phi%eval_deriv_x1(eps, eta(2)) &
118  - jmat(2, 1)*self%spline_2d_phi%eval_deriv_x2(eps, eta(2)))/jdet
119  grad_eps(2) = (-jmat(1, 2)*self%spline_2d_phi%eval_deriv_x1(eps, eta(2)) &
120  + jmat(1, 1)*self%spline_2d_phi%eval_deriv_x2(eps, eta(2)))/jdet
121 
122  ! Linear interpolation between 0 and eps
123  gradient(1) = (1.0_wp - eta(1)/eps)*grad_0(1) + eta(1)/eps*grad_eps(1)
124  gradient(2) = (1.0_wp - eta(1)/eps)*grad_0(2) + eta(1)/eps*grad_eps(2)
125 
126  ! Implements equation (29) of https://doi.org/10.1016/j.jcp.2019.108889
127  else if (eps <= eta(1)) then
128 
129  jmat = self%mapping_discrete%jmat(eta)
130  jdet = self%mapping_discrete%jdet(eta)
131 
132  ! J^(-T) times 'logical' gradient
133  gradient(1) = (jmat(2, 2)*self%spline_2d_phi%eval_deriv_x1(eta(1), eta(2)) &
134  - jmat(2, 1)*self%spline_2d_phi%eval_deriv_x2(eta(1), eta(2)))/jdet
135  gradient(2) = (-jmat(1, 2)*self%spline_2d_phi%eval_deriv_x1(eta(1), eta(2)) &
136  + jmat(1, 1)*self%spline_2d_phi%eval_deriv_x2(eta(1), eta(2)))/jdet
137 
138  end if
139 
140  end function s_ellipt_2d_cartesian_gradient__eval
141 
142  !-----------------------------------------------------------------------------
144  class(sll_t_ellipt_2d_cartesian_gradient), intent(inout) :: self
145 
146  nullify (self%mapping_discrete)
147 
148  nullify (self%spline_2d_phi)
149 
151 
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_pi
subroutine s_ellipt_2d_cartesian_gradient__init(self, mapping_discrete, spline_2d_phi, eps)
Module for tensor-product 2D splines.
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
2D tensor-product spline
    Report Typos and Errors