9 #include "sll_assert.h"
10 #include "sll_errors.h"
23 sll_c_spline_matrix, &
39 integer,
parameter :: &
40 allowed_bcs(1:3) = [sll_p_periodic, sll_p_hermite, sll_p_greville]
49 integer,
private :: bc_xmin
50 integer,
private :: bc_xmax
51 integer,
private :: nbc_xmin
52 integer,
private :: nbc_xmax
53 integer,
private :: odd
54 integer,
private :: offset
55 real(
wp),
private :: dx
56 real(
wp),
allocatable,
private :: tau(:)
57 class(sll_c_spline_matrix),
allocatable,
private :: matrix
91 integer,
intent(in) :: degree
92 integer,
intent(in) :: bc_xmin
93 integer,
intent(in) :: bc_xmax
94 integer,
intent(in) :: nipts
95 integer,
intent(out) :: ncells
98 sll_assert(degree > 0)
102 if (any([bc_xmin, bc_xmax] == sll_p_periodic) .and. bc_xmin /= bc_xmax)
then
103 sll_error(
"sll_s_spline_1d_compute_num_cells",
"Incompatible BCs")
106 if (bc_xmin == sll_p_periodic)
then
109 associate(nbc_xmin => merge(degree/2, 0, bc_xmin == sll_p_hermite), &
110 nbc_xmax => merge(degree/2, 0, bc_xmax == sll_p_hermite))
111 ncells = nipts + nbc_xmin + nbc_xmax - degree
127 class(sll_c_bsplines),
target,
intent(in) :: bspl
128 integer,
intent(in) :: bc_xmin
129 integer,
intent(in) :: bc_xmax
132 character(len=32) :: matrix_type
137 if (bspl%periodic)
then
138 sll_assert(bc_xmin == sll_p_periodic)
139 sll_assert(bc_xmax == sll_p_periodic)
143 sll_assert(.not. bspl%radial)
150 self%bc_xmin = bc_xmin
151 self%bc_xmax = bc_xmax
152 self%nbc_xmin = merge(bspl%degree/2, 0, bc_xmin == sll_p_hermite)
153 self%nbc_xmax = merge(bspl%degree/2, 0, bc_xmax == sll_p_hermite)
154 self%odd = modulo(bspl%degree, 2)
155 self%offset = merge(bspl%degree/2, 0, bspl%periodic)
158 self%dx = (bspl%xmax - bspl%xmin)/real(bspl%ncells, f64)
161 if (bspl%uniform)
then
171 if (self%bspl%degree == 1)
return
174 associate(nbasis => self%bspl%nbasis)
176 if (bc_xmin == sll_p_periodic)
then
177 if (kl + 1 + ku >= nbasis)
then
178 matrix_type =
"dense"
180 matrix_type =
"periodic_banded"
183 matrix_type =
"banded"
186 call sll_s_spline_matrix_new(self%matrix, matrix_type, nbasis, kl, ku)
194 call self%matrix%factorize()
207 deallocate (self%tau)
209 if (
allocated(self%matrix))
then
210 call self%matrix%free()
211 deallocate (self%matrix)
224 real(wp),
allocatable,
intent(out) :: tau(:)
226 sll_assert(
allocated(self%tau))
227 allocate (tau(
size(self%tau)), source=self%tau)
244 spline, gtau, derivs_xmin, derivs_xmax)
247 type(sll_t_spline_1d),
intent(inout) :: spline
248 real(wp),
intent(in) :: gtau(:)
249 real(wp),
optional,
intent(in) :: derivs_xmin(:)
250 real(wp),
optional,
intent(in) :: derivs_xmax(:)
252 character(len=*),
parameter :: &
253 this_sub_name =
"sll_t_spline_interpolator_1d % compute_interpolant"
257 sll_assert(
size(gtau) == self%bspl%nbasis - self%nbc_xmin - self%nbc_xmax)
258 sll_assert(spline%belongs_to_space(self%bspl))
260 associate(nbasis => self%bspl%nbasis, &
261 degree => self%bspl%degree, &
262 nbc_xmin => self%nbc_xmin, &
263 nbc_xmax => self%nbc_xmax, &
265 bcoef => spline%bcoef)
268 if (degree == 1)
then
269 bcoef(1:nbasis) = gtau(1:nbasis)
271 if (self%bspl%periodic)
then
272 bcoef(nbasis + 1) = bcoef(1)
280 if (self%bc_xmin == sll_p_hermite)
then
281 if (
present(derivs_xmin))
then
282 bcoef(1:nbc_xmin) = &
283 [(derivs_xmin(i)*self%dx**(i + self%odd - 1), i=nbc_xmin, 1, -1)]
285 sll_error(this_sub_name,
"Hermite BC at xmin requires derivatives")
290 bcoef(nbc_xmin + 1 + g:nbasis - nbc_xmax + g) = gtau(:)
295 if (self%bc_xmax == sll_p_hermite)
then
296 if (
present(derivs_xmax))
then
297 bcoef(nbasis - nbc_xmax + 1:nbasis) = &
298 [(derivs_xmax(i)*self%dx**(i + self%odd - 1), i=1, nbc_xmax)]
300 sll_error(this_sub_name,
"Hermite BC at xmax requires derivatives")
305 call self%matrix%solve_inplace(bcoef(1 + g:nbasis + g))
308 if (self%bc_xmin == sll_p_periodic)
then
309 bcoef(1:g) = bcoef(nbasis + 1:nbasis + g)
310 bcoef(nbasis + 1 + g:nbasis + degree) = bcoef(1 + g:degree)
333 class(sll_c_spline_matrix),
intent(inout) :: matrix
335 integer :: i, j, d, s
339 real(wp) :: values(self%bspl%degree + 1)
340 real(wp),
allocatable :: derivs(:, :)
345 associate(nbasis => self%bspl%nbasis, &
346 degree => self%bspl%degree, &
347 nbc_xmin => self%nbc_xmin, &
348 nbc_xmax => self%nbc_xmax)
350 if (any([self%bc_xmin, self%bc_xmax] == sll_p_hermite))
then
351 allocate (derivs(0:degree/2, 1:degree + 1))
355 if (self%bc_xmin == sll_p_hermite)
then
357 call self%bspl%eval_basis_and_n_derivs(x, nbc_xmin, derivs, jmin)
362 associate(h => [(self%dx**i, i=1, ubound(derivs, 1))])
363 do j = lbound(derivs, 2), ubound(derivs, 2)
364 derivs(1:, j) = derivs(1:, j)*h(1:)
370 order = nbc_xmin - i + self%odd
372 call matrix%set_element(i, j, derivs(order, j))
379 do i = nbc_xmin + 1, nbasis - nbc_xmax
380 x = self%tau(i - nbc_xmin)
381 call self%bspl%eval_basis(x, values, jmin)
383 j = modulo(jmin - self%offset + s - 2, nbasis) + 1
384 call matrix%set_element(i, j, values(s))
389 if (self%bc_xmax == sll_p_hermite)
then
391 call self%bspl%eval_basis_and_n_derivs(x, nbc_xmax, derivs, jmin)
395 associate(h => [(self%dx**i, i=1, ubound(derivs, 1))])
396 do j = lbound(derivs, 2), ubound(derivs, 2)
397 derivs(1:, j) = derivs(1:, j)*h(1:)
401 do i = nbasis - nbc_xmax + 1, nbasis
402 order = i - (nbasis - nbc_xmax + 1) + self%odd
408 call matrix%set_element(i, j, derivs(order, d))
414 if (
allocated(derivs))
deallocate (derivs)
429 real(wp),
allocatable,
intent(out) :: tau(:)
431 integer :: i, ntau, isum
432 integer,
allocatable :: iknots(:)
434 associate(nbasis => self%bspl%nbasis, &
435 ncells => self%bspl%ncells, &
436 degree => self%bspl%degree, &
437 xmin => self%bspl%xmin, &
438 xmax => self%bspl%xmax, &
440 bc_xmin => self%bc_xmin, &
441 bc_xmax => self%bc_xmax, &
442 nbc_xmin => self%nbc_xmin, &
443 nbc_xmax => self%nbc_xmax)
446 ntau = nbasis - nbc_xmin - nbc_xmax
447 allocate (tau(1:ntau))
449 if (bc_xmin == sll_p_periodic)
then
454 associate(shift => merge(0.5_wp, 0.0_wp, self%odd == 0))
455 tau = [(xmin + (real(i - 1, wp) + shift)*dx, i=1, ntau)]
463 allocate (iknots(2 - degree:ntau))
466 associate(r => 2 - degree, s => -nbc_xmin)
467 select case (bc_xmin)
468 case (sll_p_greville); iknots(r:s) = 0
469 case (sll_p_hermite); iknots(r:s) = [(i, i=r - s - 1, -1)]
474 associate(r => -nbc_xmin + 1, s => -nbc_xmin + 1 + ncells)
475 iknots(r:s) = [(i, i=0, ncells)]
479 associate(r => -nbc_xmin + 1 + ncells + 1, s => ntau)
480 select case (bc_xmax)
481 case (sll_p_greville); iknots(r:s) = ncells
482 case (sll_p_hermite); iknots(r:s) = [(i, i=ncells + 1, ncells + 1 + s - r)]
487 associate(inv_deg => 1.0_wp/real(degree,
wp))
489 isum = sum(iknots(i + 1 - degree:i))
490 if (modulo(isum, degree) == 0)
then
491 tau(i) = xmin + real(isum/degree,
wp)*dx
493 tau(i) = xmin + real(isum,
wp)*inv_deg*dx
499 if (self%odd == 1)
then
515 integer,
intent(out) :: kl
516 integer,
intent(out) :: ku
518 associate(degree => self%bspl%degree)
523 select case (self%bc_xmin)
524 case (sll_p_periodic); ku = (degree + 1)/2
525 case (sll_p_hermite); ku = max((degree + 1)/2, degree - 1)
526 case (sll_p_greville); ku = degree
529 select case (self%bc_xmax)
530 case (sll_p_periodic); kl = (degree + 1)/2
531 case (sll_p_hermite); kl = max((degree + 1)/2, degree - 1)
532 case (sll_p_greville); kl = degree
548 real(wp),
allocatable,
intent(out) :: tau(:)
551 real(wp),
allocatable :: temp_knots(:)
553 associate(nbasis => self%bspl%nbasis, &
554 ncells => self%bspl%ncells, &
555 degree => self%bspl%degree, &
556 xmin => self%bspl%xmin, &
557 xmax => self%bspl%xmax, &
559 bc_xmin => self%bc_xmin, &
560 bc_xmax => self%bc_xmax, &
561 nbc_xmin => self%nbc_xmin, &
562 nbc_xmax => self%nbc_xmax)
564 associate(breaks => self%bspl%knots(1:ncells + 1))
567 ntau = nbasis - nbc_xmin - nbc_xmax
568 allocate (tau(1:ntau))
572 allocate (temp_knots(2 - degree:ntau))
574 if (bc_xmin == sll_p_periodic)
then
576 associate(k => degree/2)
577 temp_knots(:) = self%bspl%knots(2 - degree + k:ntau + k)
582 associate(r => 2 - degree, s => -nbc_xmin)
583 select case (bc_xmin)
584 case (sll_p_greville); temp_knots(r:s) = breaks(1)
585 case (sll_p_hermite); temp_knots(r:s) = 2.0_wp*breaks(1) - breaks(2 + s - r:2:-1)
589 associate(r => -nbc_xmin + 1, s => -nbc_xmin + 1 + ncells)
590 temp_knots(r:s) = breaks(:)
593 associate(r => -nbc_xmin + 1 + ncells + 1, s => ntau)
594 select case (bc_xmax)
595 case (sll_p_greville)
596 temp_knots(r:s) = breaks(ncells + 1)
598 temp_knots(r:s) = 2.0_wp*breaks(ncells + 1) - breaks(ncells:ncells + r - s:-1)
605 associate(inv_deg => 1.0_wp/real(degree,
wp))
607 tau(i) = sum(temp_knots(i + 1 - degree:i))*inv_deg
612 if (bc_xmin == sll_p_periodic)
then
613 tau(:) = modulo(tau(:) - xmin, xmax - xmin) + xmin
616 else if (self%odd == 1)
then
629 integer,
intent(out) :: kl
630 integer,
intent(out) :: ku
632 integer :: i, j, s, d, icell
638 associate(nbasis => self%bspl%nbasis, &
639 degree => self%bspl%degree, &
640 offset => self%offset, &
641 nbc_xmin => self%nbc_xmin, &
642 nbc_xmax => self%nbc_xmax)
644 if (self%bc_xmin == sll_p_periodic)
then
648 icell = self%bspl%find_cell(x)
650 j = modulo(icell - offset - 2 + s, nbasis) + 1
652 if (d > nbasis/2) then; d = d - nbasis;
else &
653 if (d < -nbasis/2) then; d = d + nbasis;
end if
661 do i = nbc_xmin + 1, nbasis - nbc_xmax
662 x = self%tau(i - nbc_xmin)
663 icell = self%bspl%find_cell(x)
Describe different boundary conditions.
Abstract class for B-splines of arbitrary degree.
Module for 1D splines, linear combination of B-spline functions.
Interpolator for 1D splines of arbitrary degree, on uniform and non-uniform grids.
subroutine s_build_system(self, matrix)
Private subroutine for assembling and factorizing linear system for any kind of boundary conditions a...
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.
integer, dimension(1:3), parameter allowed_bcs
Allowed boundary conditions.
subroutine s_spline_interpolator_1d__free(self)
Destroy local objects and free allocated memory.
integer, parameter wp
Working precision.
subroutine s_compute_num_diags_uniform(self, kl, ku)
subroutine s_spline_interpolator_1d__compute_interpolant(self, spline, gtau, derivs_xmin, derivs_xmax)
Compute interpolating 1D spline.
subroutine s_spline_interpolator_1d__get_interp_points(self, tau)
Get coordinates of interpolation points (1D grid)
subroutine s_compute_interpolation_points_non_uniform(self, tau)
subroutine s_spline_interpolator_1d__init(self, bspl, bc_xmin, bc_xmax)
Initialize a 1D spline interpolator object.
subroutine s_compute_num_diags_non_uniform(self, kl, ku)
subroutine s_compute_interpolation_points_uniform(self, tau)
Access point to matrix class providing factory function.
subroutine, public sll_s_spline_matrix_new(matrix, matrix_type, n, kl, ku)
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
Abstract type, B-splines.