Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_singular_mapping_base.F90
Go to the documentation of this file.
2 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 #include "sll_assert.h"
4 #include "sll_errors.h"
5 
7 
9 
11 
12  implicit none
13 
14  public :: sll_c_singular_mapping
15 
16  private
17 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
18 
20  integer, parameter :: wp = f64
21 
23  type, abstract :: sll_c_singular_mapping
24 
25  contains
26 
27  ! Deferred procedures
28  procedure(i_fun_eval), deferred :: eval
29  procedure(i_fun_jmat), deferred :: jmat ! Jacobian matrix
30  procedure(i_sub_store_data), deferred :: store_data
31 
32  ! Non-deferred procedures
33  procedure :: jdet => f_singular_mapping__jdet ! Jacobian determinant
34  procedure :: eval_inverse => f_singular_mapping__eval_inverse ! inverse mapping (Newton method)
35 
36  end type sll_c_singular_mapping
37 
38  ! Interfaces for deferred procedures
39  abstract interface
40 
41  sll_pure function i_fun_eval(self, eta) result(x)
43  class(sll_c_singular_mapping), intent(in) :: self
44  real(wp), intent(in) :: eta(2)
45  real(wp) :: x(2)
46  end function i_fun_eval
47 
48  sll_pure function i_fun_jmat(self, eta) result(jmat)
50  class(sll_c_singular_mapping), intent(in) :: self
51  real(wp), intent(in) :: eta(2)
52  real(wp) :: jmat(2, 2)
53  end function i_fun_jmat
54 
55  subroutine i_sub_store_data(self, n1, n2, file_id)
57  class(sll_c_singular_mapping), intent(in) :: self
58  integer, intent(in) :: n1
59  integer, intent(in) :: n2
60  type(sll_t_hdf5_ser_handle), intent(in) :: file_id
61  end subroutine i_sub_store_data
62 
63  end interface
64 
65 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66 contains
67 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
68 
69  sll_pure function f_singular_mapping__jdet(self, eta) result(jdet)
70  class(sll_c_singular_mapping), intent(in) :: self
71  real(wp), intent(in) :: eta(2)
72  real(wp) :: jdet
73 
74  real(wp) :: jmat(2, 2)
75 
76  jmat = self%jmat(eta)
77 
78  jdet = jmat(1, 1)*jmat(2, 2) - jmat(1, 2)*jmat(2, 1)
79 
80  end function f_singular_mapping__jdet
81 
82  !-----------------------------------------------------------------------------
83  function f_singular_mapping__eval_inverse(self, x, eta0, tol, maxiter) result(eta)
84  class(sll_c_singular_mapping), intent(in) :: self
85  real(wp), intent(in) :: x(2)
86  real(wp), intent(in) :: eta0(2)
87  real(wp), intent(in) :: tol
88  integer, intent(in) :: maxiter
89  real(wp) :: eta(2)
90 
91  real(wp) :: jdet
92  real(wp) :: eta_new(2), x_new(2), temp(2), delx(2)
93  real(wp) :: jmat(2, 2)
94  integer :: i
95 
96  ! To handle error
97  character(len=*), parameter :: this_fun_name = "sll_c_singular_mapping % eval_inverse"
98  character(len=64) :: err_msg
99 
100  ! First guess:
101  ! - use circle inverse mapping for pole of singularity
102  ! - use given coordinates for all other points in domain
103  if (abs(eta0(1)) < 1.0e-14_wp) then
104  eta_new(1) = sqrt(x(1)**2 + x(2)**2)
105  eta_new(2) = modulo(atan2(x(2), x(1)), sll_p_twopi)
106  else
107  eta_new = eta0
108  end if
109 
110  ! Newton method
111  do i = 1, maxiter
112 
113  ! Function to be inverted
114  temp = self%eval(eta_new) - x
115 
116  ! Jacobian matrix
117  jmat = self%jmat(eta_new)
118 
119  ! Jacobian determinant (needed for inverse of Jacobian matrix)
120  jdet = self%jdet(eta_new)
121 
122  ! Apply inverse of Jacobian matrix
123  delx(1) = (jmat(2, 2)*temp(1) - jmat(1, 2)*temp(2))/jdet
124  delx(2) = (-jmat(2, 1)*temp(1) + jmat(1, 1)*temp(2))/jdet
125 
126  ! New guess
127  eta = eta_new - delx
128 
129  ! Apply periodicity for eta2
130  eta(2) = modulo(eta(2), sll_p_twopi)
131 
132  ! Deal with points out of domain
133  if (eta(1) < 0.0_wp) then; eta(1) = 1.0e-14_wp; end if
134  if (eta(1) > 1.0_wp) then; eta(1) = 1.0_wp; return; end if
135 
136  ! Check convergence using Euclidean distance
137  x_new = self%eval(eta)
138  if (norm2(x_new - x) < tol) return
139 
140  eta_new = eta
141 
142  end do
143 
144  ! Newton method did not converge
145  write (err_msg, '(a,i0,a)') "Newton method did not converge after ", maxiter, " iterations"
146  sll_error(this_fun_name, err_msg)
147 
149 
Fortran module where set some physical and mathematical constants.
real(kind=f64), parameter, public sll_p_twopi
Implements the functions to write hdf5 file to store heavy data.
integer, parameter wp
Working precision.
real(wp) function, dimension(2) f_singular_mapping__eval_inverse(self, x, eta0, tol, maxiter)
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
    Report Typos and Errors