Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_polar_spline_interpolator_2d.F90
Go to the documentation of this file.
1 
5 
7 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 #include "sll_assert.h"
9 #include "sll_errors.h"
10 
11  use sll_m_working_precision, only: f64
12 
14  sll_p_periodic, &
15  sll_p_hermite, &
16  sll_p_greville
17 
18  use sll_m_bsplines, only: &
19  sll_c_bsplines, &
21 
24 
25  use sll_m_spline_interpolator_1d, only: &
28 
29  use sll_m_spline_interpolator_2d, only: &
33 
34  implicit none
35 
36  public :: &
39 
40  private
41 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
42 
44  integer, parameter :: wp = f64
45 
46  !-----------------------------------------------------------------------------
48  !-----------------------------------------------------------------------------
50 
51  private
52 
53  class(sll_c_bsplines), pointer :: bspl1 => null()
54  class(sll_c_bsplines), pointer :: bspl2 => null()
55 
56  integer :: nbc_rmax
57  integer :: nipts(2)
58  integer :: i1_start
59  integer :: even_deg1
60  real(wp), allocatable :: ext_gtau(:, :)
61  type(sll_t_spline_2d) :: ext_spline
62  type(sll_t_spline_interpolator_2d) :: ext_interp
63  class(sll_c_bsplines), allocatable :: ext_bspl1
64 
65  contains
66 
69  procedure :: get_interp_points => s_polar_spline_interpolator_2d__get_interp_points
70  procedure :: compute_interpolant => s_polar_spline_interpolator_2d__compute_interpolant
71 
73 
74 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
75 contains
76 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
77 
78  !-----------------------------------------------------------------------------
89  !-----------------------------------------------------------------------------
91  degree, &
92  bc_rmax, &
93  nipts, &
94  ncells)
95 
96  integer, intent(in) :: degree(2)
97  integer, intent(in) :: bc_rmax
98  integer, intent(in) :: nipts(2)
99  integer, intent(out) :: ncells(2)
100 
101  ! Along radial direction r, on extended domain [-R,R]
102  !
103  ! Option 1: breakpoint at r=0
104 ! call sll_s_spline_1d_compute_num_cells( &
105 ! degree(1), bc_rmax, bc_rmax, 2*nipts(1)-1, ncells(1) )
106  !
107  ! Option 2: no breakpoint at r=0
108 ! call sll_s_spline_1d_compute_num_cells( &
109 ! degree(1), bc_rmax, bc_rmax, 2*nipts(1), ncells(1) )
110  !
111  ! Option 3: no breakpoint at r=0, and use radial basis
113  degree(1), bc_rmax, bc_rmax, 2*nipts(1), ncells(1))
114  ncells(1) = (ncells(1) + 1)/2
115 
116  ! Along angular direction theta
118  degree(2), sll_p_periodic, sll_p_periodic, nipts(2), ncells(2))
119 
121 
122  !-----------------------------------------------------------------------------
129  !-----------------------------------------------------------------------------
131  self, &
132  bspl1, &
133  bspl2, &
134  bc_rmax)
135 
136  class(sll_t_polar_spline_interpolator_2d), intent(out) :: self
137  class(sll_c_bsplines), target, intent(in) :: bspl1
138  class(sll_c_bsplines), target, intent(in) :: bspl2
139  integer, intent(in) :: bc_rmax
140 
141  ! Check requirements on radial basis
142  sll_assert(bspl1%radial)
143  sll_assert(.not. bspl1%periodic)
144 
145  ! Check requirements on angular basis
146  sll_assert(bspl2%periodic)
147  sll_assert(modulo(bspl2%ncells, 2) == 0)
148 
149  ! Check boundary condition
150  sll_assert(any(bc_rmax == [sll_p_greville, sll_p_hermite]))
151 
152  ! Store pointers to B-splines
153  self%bspl1 => bspl1
154  self%bspl2 => bspl2
155 
156  ! Create B-spline on extended radial domain [-R,R]
157  call sll_s_bsplines_new_mirror_copy(self%bspl1, self%ext_bspl1)
158 
159  ! Initialize 2D spline with polar base
160  call self%ext_spline%init(self%ext_bspl1, self%bspl2)
161 
162  ! Initialize 2D interpolator on extended domain [-R,R] X [0,2\pi]
163  call self%ext_interp%init( &
164  self%ext_bspl1, &
165  self%bspl2, &
166  bc_xmin=[bc_rmax, sll_p_periodic], &
167  bc_xmax=[bc_rmax, sll_p_periodic])
168 
169  ! Determine number of additional boundary conditions at r=r_max (Hermite)
170  self%nbc_rmax = merge(self%bspl1%degree/2, 0, bc_rmax == sll_p_hermite)
171 
172  ! Allocate extended radial array of function values
173  associate(n1 => self%ext_bspl1%nbasis, &
174  n2 => self%bspl2%nbasis, &
175  a1 => self%nbc_rmax)
176 
177  allocate (self%ext_gtau(n1 - 2*a1, n2))
178 
179  end associate
180 
181  ! Determine size of 2D grid of interpolation points in physical domain
182  self%nipts(1) = (size(self%ext_gtau, 1) + 1)/2
183  self%nipts(2) = size(self%ext_gtau, 2)
184 
185  ! Determine first physical point in extended radial domain
186  self%i1_start = size(self%ext_gtau, 1) - self%nipts(1) + 1
187 
188  ! Store info about whether spline degree along r is even or odd
189  self%even_deg1 = 1 - modulo(self%bspl1%degree, 2)
190 
192 
193  !-----------------------------------------------------------------------------
196  !-----------------------------------------------------------------------------
198 
199  class(sll_t_polar_spline_interpolator_2d), intent(inout) :: self
200 
201  ! Destroy local objects: 1D splines and interpolators along x1 and x2
202  call self%ext_interp%free()
203  call self%ext_bspl1%free()
204 
205  ! Deallocate 2D array of interpolation points
206  deallocate (self%ext_gtau)
207 
209 
210  !-----------------------------------------------------------------------------
215  !-----------------------------------------------------------------------------
217 
218  class(sll_t_polar_spline_interpolator_2d), intent(in) :: self
219  real(wp), allocatable, intent(out) :: tau1(:)
220  real(wp), allocatable, intent(out) :: tau2(:)
221 
222  real(wp), allocatable :: ext_tau1(:)
223  real(wp), allocatable :: ext_tau2(:)
224 
225  ! Obtain interpolation points on extended domain
226  call self%ext_interp%get_interp_points(ext_tau1, ext_tau2)
227 
228  ! Determine interpolation points on physical domain
229  associate(n1 => self%nipts(1), &
230  n2 => self%nipts(2), &
231  first => self%i1_start)
232 
233  allocate (tau1(n1), source=ext_tau1(first:))
234  allocate (tau2(n2), source=ext_tau2(:))
235 
236  end associate
237 
239 
240  !-----------------------------------------------------------------------------
250  !-----------------------------------------------------------------------------
252  spline, gtau, derivs_rmax)
253 
254  class(sll_t_polar_spline_interpolator_2d), intent(inout) :: self
255  type(sll_t_spline_2d), intent(inout) :: spline
256  real(wp), intent(in) :: gtau(:, :)
257  real(wp), intent(in), optional :: derivs_rmax(:, :)
258 
259  character(len=*), parameter :: &
260  this_sub_name = "sll_t_polar_spline_interpolator_2d % compute_interpolant"
261 
262  class(sll_t_spline_2d_boundary_data), allocatable :: boundary_data
263  integer :: i1, i2, j1, j2, k, shift
264 
265  sll_assert(spline%belongs_to_space(self%bspl1, self%bspl2))
266  sll_assert(size(gtau, 1) == self%nipts(1))
267  sll_assert(size(gtau, 2) == self%nipts(2))
268 
269  ! Copy physical domain
270  self%ext_gtau(self%i1_start:, :) = gtau(:, :)
271 
272  shift = self%nipts(2)/2
273 
274  ! Fill in r<0 region with mirrored data
275  do i2 = 1, self%nipts(2)
276  j2 = 1 + modulo(i2 - 1 + shift, self%nipts(2))
277  do j1 = 1, self%i1_start - 1
278  i1 = self%i1_start - j1
279  self%ext_gtau(j1, j2) = gtau(i1, i2)
280  end do
281  end do
282 
283  ! Boundary data
284  ! TODO: allocate in init()
285  if (present(derivs_rmax)) then
286  sll_assert(size(derivs_rmax, 1) == self%nbc_rmax)
287  sll_assert(size(derivs_rmax, 2) == self%nipts(2))
288 
289  allocate (boundary_data)
290  allocate (boundary_data%derivs_x1_min(self%nbc_rmax, self%nipts(2)))
291  allocate (boundary_data%derivs_x1_max(self%nbc_rmax, self%nipts(2)))
292 
293  ! Derivatives at r=r_max
294  boundary_data%derivs_x1_max(:, :) = derivs_rmax(:, :)
295 
296  ! Derivatives at r=r_min: must apply shift in theta and change sign if odd
297  do i2 = 1, self%nipts(2)
298  j2 = 1 + modulo(i2 - 1 + shift, self%nipts(2))
299  do k = 1, self%nbc_rmax
300  boundary_data%derivs_x1_min(k, j2) = (-1)**(k - self%even_deg1)*derivs_rmax(k, i2)
301  end do
302  end do
303  end if
304 
305  ! Compute interpolant on extended domain
306  call self%ext_interp%compute_interpolant(self%ext_spline, self%ext_gtau, boundary_data)
307 
308  ! Copy data back onto 2D polar spline
309  associate(start => 1 + size(self%ext_spline%bcoef, 1) - size(spline%bcoef, 1))
310 
311  spline%bcoef(:, :) = self%ext_spline%bcoef(start:, :)
312 
313  end associate
314 
316 
Access point to B-splines of arbitrary degree providing factory function.
subroutine, public sll_s_bsplines_new_mirror_copy(radial_basis, extended_basis)
Create B-splines by mirroring radial basis onto extended domain [-R,R].
Interpolator for 2D polar splines of arbitrary degree, on uniform and non-uniform grids (directions a...
subroutine s_polar_spline_interpolator_2d__init(self, bspl1, bspl2, bc_rmax)
Initialize a 2D tensor-product spline interpolator object.
subroutine s_polar_spline_interpolator_2d__get_interp_points(self, tau1, tau2)
Get coordinates of interpolation points (2D tensor grid)
subroutine, public sll_s_polar_spline_2d_compute_num_cells(degree, bc_rmax, nipts, ncells)
Calculate number of cells from number of interpolation points.
subroutine s_polar_spline_interpolator_2d__compute_interpolant(self, spline, gtau, derivs_rmax)
Compute interpolating 2D spline.
subroutine s_polar_spline_interpolator_2d__free(self)
Destroy local objects and free allocated memory.
Module for 1D splines, linear combination of B-spline functions.
Module for tensor-product 2D splines.
Interpolator for 1D splines of arbitrary degree, on uniform and non-uniform grids.
subroutine, public sll_s_spline_1d_compute_num_cells(degree, bc_xmin, bc_xmax, nipts, ncells)
Calculate number of cells from number of interpolation points.
Interpolator for 2D tensor-product splines of arbitrary degree, on uniform and non-uniform grids (dir...
subroutine, public sll_s_spline_2d_compute_num_cells(degree, bc_xmin, bc_xmax, nipts, ncells)
Calculate number of cells from number of interpolation points.
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
Container for 2D boundary condition data: . x1-derivatives at x1_min and x1_max, for all values of x2...
    Report Typos and Errors