Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_spline_interpolator_2d.F90
Go to the documentation of this file.
1 
6 
8 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 #include "sll_assert.h"
10 #include "sll_errors.h"
11 
12  use sll_m_working_precision, only: f64
13 
15  sll_p_periodic, &
16  sll_p_hermite, &
17  sll_p_greville
18 
22 
23  use sll_m_spline_interpolator_1d, only: &
26 
27  implicit none
28 
29  public :: &
33 
34  private
35 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
36 
38  integer, parameter :: wp = f64
39 
40  !-----------------------------------------------------------------------------
56  !-----------------------------------------------------------------------------
58  real(wp), allocatable :: derivs_x1_min(:, :)
59  real(wp), allocatable :: derivs_x1_max(:, :)
60  real(wp), allocatable :: derivs_x2_min(:, :)
61  real(wp), allocatable :: derivs_x2_max(:, :)
62  real(wp), allocatable :: mixed_derivs_a(:, :)
63  real(wp), allocatable :: mixed_derivs_b(:, :)
64  real(wp), allocatable :: mixed_derivs_c(:, :)
65  real(wp), allocatable :: mixed_derivs_d(:, :)
67 
68  !-----------------------------------------------------------------------------
70  !-----------------------------------------------------------------------------
72 
73  ! Private attributes
74  class(sll_c_bsplines), pointer, private :: bspl1 => null()
75  class(sll_c_bsplines), pointer, private :: bspl2 => null()
76  integer, private :: bc_xmin(2)
77  integer, private :: bc_xmax(2)
78  integer, private :: nbc_xmin(2)
79  integer, private :: nbc_xmax(2)
80  type(sll_t_spline_1d), private :: spline1
81  type(sll_t_spline_1d), private :: spline2
82  type(sll_t_spline_interpolator_1d), private :: interp1
83  type(sll_t_spline_interpolator_1d), private :: interp2
84  real(wp), allocatable, private :: bwork(:, :)
85 
86  contains
87 
88  procedure :: init => s_spline_interpolator_2d__init
89  procedure :: free => s_spline_interpolator_2d__free
90  procedure :: get_interp_points => s_spline_interpolator_2d__get_interp_points
91  procedure :: compute_interpolant => s_spline_interpolator_2d__compute_interpolant
92 
94 
95 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
96 contains
97 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
98 
99  !-----------------------------------------------------------------------------
110  !-----------------------------------------------------------------------------
112  degree, &
113  bc_xmin, &
114  bc_xmax, &
115  nipts, &
116  ncells)
117 
118  integer, intent(in) :: degree(2)
119  integer, intent(in) :: bc_xmin(2)
120  integer, intent(in) :: bc_xmax(2)
121  integer, intent(in) :: nipts(2)
122  integer, intent(out) :: ncells(2)
123 
124  integer :: i
125 
126  do i = 1, 2
128  degree(i), bc_xmin(i), bc_xmax(i), nipts(i), ncells(i))
129  end do
130 
131  end subroutine sll_s_spline_2d_compute_num_cells
132 
133  !-----------------------------------------------------------------------------
140  !-----------------------------------------------------------------------------
142  self, &
143  bspl1, &
144  bspl2, &
145  bc_xmin, &
146  bc_xmax)
147 
148  class(sll_t_spline_interpolator_2d), intent(out) :: self
149  class(sll_c_bsplines), target, intent(in) :: bspl1
150  class(sll_c_bsplines), target, intent(in) :: bspl2
151  integer, intent(in) :: bc_xmin(2)
152  integer, intent(in) :: bc_xmax(2)
153 
154  ! Save pointers to B-splines
155  ! (later needed to verify 2D spline input to 'compute_interpolant')
156  self%bspl1 => bspl1
157  self%bspl2 => bspl2
158 
159  ! Initialize 1D splines along x1 and x2
160  call self%spline1%init(bspl1)
161  call self%spline2%init(bspl2)
162 
163  ! Initialize 1D interpolators along x1 and x2
164  call self%interp1%init(bspl1, bc_xmin(1), bc_xmax(1))
165  call self%interp2%init(bspl2, bc_xmin(2), bc_xmax(2))
166 
167  associate(n1 => bspl1%ncells, &
168  n2 => bspl2%ncells, &
169  p1 => bspl1%degree, &
170  p2 => bspl2%degree)
171 
172  ! Save data into type
173  self%bc_xmin = bc_xmin
174  self%bc_xmax = bc_xmax
175 
176  ! Allocate work array for interpolation: in case of periodic BCs, the last
177  ! p coefficients are a periodic copy of the first p ones (p=p1,p2)
178  allocate (self%bwork(1:n2 + p2, 1:n1 + p1))
179  self%bwork = 0.0_f64
180 
181  ! Calculate number of additional boundary data on each side of domain
182  ! (i.e. derivatives for Hermite BC)
183  self%nbc_xmin = merge([p1, p2]/2, 0, bc_xmin == sll_p_hermite)
184  self%nbc_xmax = merge([p1, p2]/2, 0, bc_xmax == sll_p_hermite)
185 
186  end associate
187 
188  end subroutine s_spline_interpolator_2d__init
189 
190  !-----------------------------------------------------------------------------
193  !-----------------------------------------------------------------------------
195 
196  class(sll_t_spline_interpolator_2d), intent(inout) :: self
197 
198  ! Detach pointers to B-splines
199  nullify (self%bspl1)
200  nullify (self%bspl2)
201 
202  ! Destroy local objects: 1D splines and interpolators along x1 and x2
203  call self%spline1%free()
204  call self%spline2%free()
205  call self%interp1%free()
206  call self%interp2%free()
207 
208  ! Deallocate 2D work array
209  deallocate (self%bwork)
210 
211  end subroutine s_spline_interpolator_2d__free
212 
213  !-----------------------------------------------------------------------------
218  !-----------------------------------------------------------------------------
219  subroutine s_spline_interpolator_2d__get_interp_points(self, tau1, tau2)
220 
221  class(sll_t_spline_interpolator_2d), intent(in) :: self
222  real(wp), allocatable, intent(out) :: tau1(:)
223  real(wp), allocatable, intent(out) :: tau2(:)
224 
225  call self%interp1%get_interp_points(tau1)
226  call self%interp2%get_interp_points(tau2)
227 
229 
230  !-----------------------------------------------------------------------------
240  !-----------------------------------------------------------------------------
242  spline, gtau, boundary_data)
243 
244  class(sll_t_spline_interpolator_2d), intent(inout) :: self
245  type(sll_t_spline_2d), intent(inout) :: spline
246  real(wp), intent(in) :: gtau(:, :)
247  type(sll_t_spline_2d_boundary_data), intent(in), optional :: boundary_data
248 
249  character(len=*), parameter :: &
250  this_sub_name = "sll_t_spline_interpolator_2d % compute_interpolant"
251 
252  integer :: i1, i2
253 
254  ! User must provide derivatives at boundary in case of Hermite BC
255  if (.not. present(boundary_data)) then
256  if (self%bc_xmin(1) == sll_p_hermite) then
257  sll_error(this_sub_name, "Hermite BC at x1_min requires derivatives")
258  else if (self%bc_xmax(1) == sll_p_hermite) then
259  sll_error(this_sub_name, "Hermite BC at x1_max requires derivatives")
260  else if (self%bc_xmin(2) == sll_p_hermite) then
261  sll_error(this_sub_name, "Hermite BC at x2_min requires derivatives")
262  else if (self%bc_xmax(2) == sll_p_hermite) then
263  sll_error(this_sub_name, "Hermite BC at x2_max requires derivatives")
264  end if
265  end if
266 
267  associate(w => spline%bcoef, &
268  wt => self%bwork, &
269  n1 => self%bspl1%nbasis, &
270  n2 => self%bspl2%nbasis, &
271  a1 => self%nbc_xmin(1), &
272  a2 => self%nbc_xmin(2), &
273  b1 => self%nbc_xmax(1), &
274  b2 => self%nbc_xmax(2), &
275  p1 => self%bspl1%degree, &
276  p2 => self%bspl2%degree)
277 
278  sll_assert(all(shape(gtau) == [n1 - a1 - b1, n2 - a2 - b2]))
279  sll_assert(spline%belongs_to_space(self%bspl1, self%bspl2))
280 
281  ! DEBUG mode, Hermite boundary conditions:
282  ! Verify that required arrays are passed and allocated with correct shape
283  if (a1 > 0) then
284  sll_assert(present(boundary_data))
285  sll_assert(allocated(boundary_data%derivs_x1_min))
286  sll_assert(size(boundary_data%derivs_x1_min, 1) == a1)
287  sll_assert(size(boundary_data%derivs_x1_min, 2) == n2 - a2 - b2)
288  end if
289 
290  if (b1 > 0) then
291  sll_assert(present(boundary_data))
292  sll_assert(allocated(boundary_data%derivs_x1_max))
293  sll_assert(size(boundary_data%derivs_x1_max, 1) == b1)
294  sll_assert(size(boundary_data%derivs_x1_max, 2) == n2 - a2 - b2)
295  end if
296 
297  if (a2 > 0) then
298  sll_assert(present(boundary_data))
299  sll_assert(allocated(boundary_data%derivs_x2_min))
300  sll_assert(size(boundary_data%derivs_x2_min, 1) == a2)
301  sll_assert(size(boundary_data%derivs_x2_min, 2) == n1 - a1 - b1)
302  end if
303 
304  if (b2 > 0) then
305  sll_assert(present(boundary_data))
306  sll_assert(allocated(boundary_data%derivs_x2_max))
307  sll_assert(size(boundary_data%derivs_x2_max, 1) == b2)
308  sll_assert(size(boundary_data%derivs_x2_max, 2) == n1 - a1 - b1)
309  end if
310 
311  if (a1 > 0 .and. a2 > 0) then
312  sll_assert(allocated(boundary_data%mixed_derivs_a))
313  sll_assert(size(boundary_data%mixed_derivs_a, 1) == a1)
314  sll_assert(size(boundary_data%mixed_derivs_a, 2) == a2)
315  end if
316 
317  if (b1 > 0 .and. a2 > 0) then
318  sll_assert(allocated(boundary_data%mixed_derivs_b))
319  sll_assert(size(boundary_data%mixed_derivs_b, 1) == b1)
320  sll_assert(size(boundary_data%mixed_derivs_b, 2) == a2)
321  end if
322 
323  if (a1 > 0 .and. b2 > 0) then
324  sll_assert(allocated(boundary_data%mixed_derivs_c))
325  sll_assert(size(boundary_data%mixed_derivs_c, 1) == a1)
326  sll_assert(size(boundary_data%mixed_derivs_c, 2) == b2)
327  end if
328 
329  if (b1 > 0 .and. b2 > 0) then
330  sll_assert(allocated(boundary_data%mixed_derivs_d))
331  sll_assert(size(boundary_data%mixed_derivs_d, 1) == b1)
332  sll_assert(size(boundary_data%mixed_derivs_d, 2) == b2)
333  end if
334 
335  ! Copy interpolation data onto w array
336  w(1 + a1:n1 - b1, 1 + a2:n2 - b2) = gtau(:, :)
337 
338  ! Hermite BCs: store boundary data in appropriate chunk of w array
339  if (present(boundary_data)) then
340 
341  if (a1 > 0) w(1:a1, 1 + a2:n2 - b2) = boundary_data%derivs_x1_min(1:a1, :)
342  if (b1 > 0) w(n1 - b1 + 1:n1, 1 + a2:n2 - b2) = boundary_data%derivs_x1_max(1:b1, :)
343 
344  if (a2 > 0) w(1 + a1:n1 - b1, 1:a2) = transpose(boundary_data%derivs_x2_min(1:a2, :))
345  if (b2 > 0) w(1 + a1:n1 - b1, n2 - b2 + 1:n2) = transpose(boundary_data%derivs_x2_max(1:b2, :))
346 
347  if (a1 > 0 .and. a2 > 0) w(1:a1, 1:a2) = boundary_data%mixed_derivs_a(:, :)
348  if (b1 > 0 .and. a2 > 0) w(n1 - b1 + 1:n1, 1:a2) = boundary_data%mixed_derivs_b(:, :)
349  if (a1 > 0 .and. b2 > 0) w(1:a1, n2 - b2 + 1:n2) = boundary_data%mixed_derivs_c(:, :)
350  if (b1 > 0 .and. b2 > 0) w(n1 - b1 + 1:n1, n2 - b2 + 1:n2) = boundary_data%mixed_derivs_d(:, :)
351 
352  end if
353 
354  ! Cycle over x2 position (or order of x2-derivative at boundary)
355  ! and interpolate f along x1 direction. Store coefficients in bwork
356  do i2 = 1, n2
357 
358  call self%interp1%compute_interpolant( &
359  spline=self%spline1, &
360  gtau=w(1 + a1:n1 - b1, i2), &
361  derivs_xmin=w(1:a1, i2), &
362  derivs_xmax=w(n1 - b1 + 1:n1, i2))
363 
364  w(1:n1, i2) = self%spline1%bcoef(1:n1)
365 
366  end do
367 
368  wt = transpose(w)
369 
370  ! Cycle over x1 position (or order of x1-derivative at boundary)
371  ! and interpolate w along x2 direction. Store coefficients in bcoef
372  do i1 = 1, n1
373 
374  call self%interp2%compute_interpolant( &
375  spline=self%spline2, &
376  gtau=wt(1 + a2:n2 - b2, i1), &
377  derivs_xmin=wt(1:a2, i1), &
378  derivs_xmax=wt(n2 - b2 + 1:n2, i1))
379 
380  wt(1:n2, i1) = self%spline2%bcoef(1:n2)
381 
382  end do
383 
384  ! x1-periodic only: "wrap around" coefficients onto extended array
385  if (self%bc_xmin(1) == sll_p_periodic) then
386  wt(:, n1 + 1:n1 + p1) = wt(:, 1:p1)
387  end if
388 
389  w = transpose(wt)
390 
391  ! x2-periodic only: "wrap around" coefficients onto extended array
392  if (self%bc_xmin(2) == sll_p_periodic) then
393  w(:, n2 + 1:n2 + p2) = w(:, 1:p2)
394  end if
395 
396  end associate
397 
399 
Abstract class for B-splines of arbitrary degree.
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.
subroutine s_spline_interpolator_2d__compute_interpolant(self, spline, gtau, boundary_data)
Compute interpolating 2D spline.
integer, parameter wp
Working precision.
subroutine s_spline_interpolator_2d__init(self, bspl1, bspl2, bc_xmin, bc_xmax)
Initialize a 2D tensor-product spline interpolator object.
subroutine s_spline_interpolator_2d__free(self)
Destroy local objects and free allocated memory.
subroutine s_spline_interpolator_2d__get_interp_points(self, tau1, tau2)
Get coordinates of interpolation points (2D tensor grid)
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