29 #include "sll_assert.h"
30 #include "sll_errors.h"
47 sll_s_bsplines_eval_basis, &
48 sll_s_bsplines_eval_deriv, &
49 sll_s_bsplines_eval_basis_and_deriv, &
50 sll_s_bsplines_eval_basis_and_n_derivs, &
54 sll_s_bsplines_eval_basis_mm, &
55 sll_s_bsplines_eval_basis_and_deriv_mm, &
57 sll_s_uniform_bsplines_eval_basis, &
58 sll_s_uniform_bsplines_eval_deriv, &
59 sll_s_uniform_bsplines_eval_basis_and_deriv, &
60 sll_s_uniform_bsplines_eval_basis_and_n_derivs, &
62 sll_s_eval_uniform_periodic_spline_curve, &
63 sll_s_eval_uniform_periodic_spline_curve_with_zero
72 integer,
parameter ::
allowed_bcs(1:3) = [sll_p_periodic, sll_p_open, sll_p_mirror]
81 real(
wp),
allocatable :: knots(:)
153 integer,
intent(in) :: degree
154 real(
wp),
intent(in) :: grid(:)
155 integer,
intent(in) :: bc_xmin
156 integer,
intent(in) :: bc_xmax
158 character(len=*),
parameter :: this_sub_name =
"sll_s_bsplines_init_from_grid"
159 character(len=256) :: err_msg
164 real(
wp) :: min_cell_width
168 write (err_msg,
"('Minimum degree = 1, given ',i0,' instead.')") degree
169 sll_error(this_sub_name, trim(err_msg))
174 if (num_pts < 2)
then
175 write (err_msg,
"('Minimum size(grid) = 2, given ',i0,' instead.')") num_pts
176 sll_error(this_sub_name, trim(err_msg))
180 min_cell_width = grid(2) - grid(1)
182 min_cell_width = min(min_cell_width, grid(i) - grid(i - 1))
184 if (min_cell_width <= 0.0_wp)
then
185 err_msg =
"Grid points must be in strictly increasing order."
186 sll_error(this_sub_name, trim(err_msg))
187 else if (min_cell_width < 1.e-10_wp)
then
188 err_msg =
"Length of grid cells must be >= 1e-10."
189 sll_error(this_sub_name, trim(err_msg))
194 err_msg =
"Unrecognized boundary condition at xmin: "// &
195 "possible values are [sll_p_periodic, sll_p_open, sll_p_mirror]."
196 sll_error(this_sub_name, trim(err_msg))
199 err_msg =
"Unrecognized boundary condition at xmax: "// &
200 "possible values are [sll_p_periodic, sll_p_open, sll_p_mirror]."
201 sll_error(this_sub_name, trim(err_msg))
203 if (any([bc_xmin, bc_xmax] == sll_p_periodic) .and. bc_xmin /= bc_xmax)
then
204 err_msg =
"Periodic boundary conditions mismatch: bc_xmin /= bc_xmax."
205 sll_error(this_sub_name, trim(err_msg))
209 if (any([bc_xmin, bc_xmax] == sll_p_periodic) .and. num_pts < 2 + degree)
then
210 err_msg =
"Insufficient number of grid points for periodic spline: "// &
211 "condition num_pts >= 2+degree not satisfied."
212 sll_error(this_sub_name, trim(err_msg))
215 basis%num_pts = num_pts
218 basis%xmax = grid(num_pts)
221 period = grid(num_pts) - grid(1)
229 allocate (basis%knots(1 - degree:num_pts + degree))
231 basis%knots(i) = grid(i)
235 if (bc_xmin == sll_p_periodic)
then
236 basis%n = num_pts - 1
238 basis%n = num_pts + degree - 1
245 select case (bc_xmin)
246 case (sll_p_periodic)
248 basis%knots(1 - i) = grid(num_pts - i) - period
252 basis%knots(1 - i) = grid(1)
256 basis%knots(1 - i) = 2*grid(1) - grid(1 + i)
261 select case (bc_xmax)
262 case (sll_p_periodic)
264 basis%knots(num_pts + i) = grid(i + 1) + period
268 basis%knots(num_pts + i) = grid(num_pts)
272 basis%knots(num_pts + i) = 2*grid(num_pts) - grid(num_pts - i)
292 integer,
intent(in) :: degree
293 integer,
intent(in) :: n
294 real(
wp),
intent(in) :: knots(:)
300 sll_assert(
size(knots) == n + 2*degree)
302 print *,
'ERROR. sll_s_bsplines_init_from_knots: ', &
303 'only strictly positive integer values for degree are allowed, ', &
307 knotmin = knots(2) - knots(1)
308 do i = 2, n + 2*degree
309 knotmin = min(knotmin, knots(i) - knots(i - 1))
311 if (knotmin < 0.0_wp)
then
312 print *,
'ERROR. sll_s_bsplines_init_from_knots: ', &
313 ' we require that knots are in non decreasing.'
319 basis%num_pts = n - degree + 1
320 basis%xmin = knots(degree + 1)
321 basis%xmax = knots(n + 1)
326 allocate (basis%knots(1 - degree:n + 1))
327 basis%knots(1 - degree:n + 1) = knots
342 real(
wp),
intent(in) :: x
352 if (x > basis%knots(n))
then
356 if (x < basis%knots(1))
then
362 if (x == basis%knots(1))
then
368 if (x == basis%knots(n))
then
375 icell = (low + high)/2
376 do while (x < basis%knots(icell) &
377 .or. x >= basis%knots(icell + 1))
378 if (x < basis%knots(icell))
then
383 icell = (low + high)/2
417 sll_pure
subroutine sll_s_bsplines_eval_basis(basis, icell, x, splines_at_x)
420 integer,
intent(in) :: icell
421 real(
wp),
intent(in) :: x
422 real(
wp),
intent(out) :: splines_at_x(0:basis%deg)
430 real(
wp) :: left(1:basis%deg)
431 real(
wp) :: right(1:basis%deg)
434 sll_assert(x > basis%xmin - 1.0d-14)
435 sll_assert(x < basis%xmax + 1.0d-14)
436 sll_assert(icell >= 1)
437 sll_assert(icell <= basis%num_pts - 1)
438 sll_assert(basis%knots(icell) <= x .and. x <= basis%knots(icell + 1))
440 splines_at_x(0) = 1.0_wp
442 left(j) = x - basis%knots(icell + 1 - j)
443 right(j) = basis%knots(icell + j) - x
446 temp = splines_at_x(r)/(right(r + 1) + left(j - r))
447 splines_at_x(r) = saved + right(r + 1)*temp
448 saved = left(j - r)*temp
450 splines_at_x(j) = saved
453 end subroutine sll_s_bsplines_eval_basis
470 sll_pure
subroutine sll_s_bsplines_eval_deriv(basis, icell, x, bsdx)
473 integer,
intent(in) :: icell
474 real(
wp),
intent(in) :: x
475 real(
wp),
intent(out) :: bsdx(0:basis%deg)
486 real(
wp) :: left(1:basis%deg)
487 real(
wp) :: right(1:basis%deg)
490 sll_assert(
allocated(basis%knots))
491 sll_assert(x > basis%xmin - 1.0d-14)
492 sll_assert(x < basis%xmax + 1.0d-14)
493 sll_assert(icell >= 1)
494 sll_assert(icell <= basis%num_pts - 1)
495 sll_assert(basis%knots(icell) <= x .and. x <= basis%knots(icell + 1))
499 num_pts = basis%num_pts
506 left(j) = x - basis%knots(icell + 1 - j)
507 right(j) = basis%knots(icell + j) - x
511 temp = bsdx(r)/(right(r + 1) + left(j - r))
512 bsdx(r) = saved + right(r + 1)*temp
513 saved = left(j - r)*temp
523 saved = rdeg*bsdx(0)/(basis%knots(icell + 1) - basis%knots(icell + 1 - deg))
527 saved = rdeg*bsdx(j)/(basis%knots(icell + j + 1) - basis%knots(icell + j + 1 - deg))
528 bsdx(j) = temp - saved
533 end subroutine sll_s_bsplines_eval_deriv
542 sll_pure
subroutine sll_s_bsplines_eval_basis_and_deriv(basis, icell, x, bsdx)
545 integer,
intent(in) :: icell
546 real(
wp),
intent(in) :: x
547 real(
wp),
intent(out) :: bsdx(2, 0:basis%deg)
558 real(
wp) :: left(1:basis%deg)
559 real(
wp) :: right(1:basis%deg)
562 sll_assert(
allocated(basis%knots))
563 sll_assert(x > basis%xmin - 1.0d-14)
564 sll_assert(x < basis%xmax + 1.0d-14)
565 sll_assert(icell >= 1)
566 sll_assert(icell <= basis%num_pts - 1)
567 sll_assert(basis%knots(icell) <= x .and. x <= basis%knots(icell + 1))
570 num_pts = basis%num_pts
578 left(j) = x - basis%knots(icell + 1 - j)
579 right(j) = basis%knots(icell + j) - x
583 temp = bsdx(1, r)/(right(r + 1) + left(j - r))
584 bsdx(1, r) = saved + right(r + 1)*temp
585 saved = left(j - r)*temp
595 saved = rdeg*bsdx(1, 0)/ &
596 (basis%knots(icell + 1) - basis%knots(icell + 1 - deg))
600 saved = rdeg*bsdx(1, j)/ &
601 (basis%knots(icell + j + 1) - basis%knots(icell + j + 1 - deg))
602 bsdx(2, j) = temp - saved
610 left(j) = x - basis%knots(icell + 1 - j)
611 right(j) = basis%knots(icell + j) - x
615 temp = bsdx(1, r)/(right(r + 1) + left(j - r))
616 bsdx(1, r) = saved + right(r + 1)*temp
617 saved = left(j - r)*temp
621 end subroutine sll_s_bsplines_eval_basis_and_deriv
636 sll_pure
subroutine sll_s_bsplines_eval_basis_and_n_derivs(basis, icell, x, n, bsdx)
639 integer,
intent(in) :: icell
640 real(
wp),
intent(in) :: x
641 integer,
intent(in) :: n
642 real(
wp),
intent(out) :: bsdx(0:n, 0:basis%deg)
661 real(
wp) :: left(1:basis%deg)
662 real(
wp) :: right(1:basis%deg)
663 real(
wp) :: ndu(0:basis%deg, 0:basis%deg)
664 real(
wp) :: a(0:1, 0:basis%deg)
667 sll_assert(
allocated(basis%knots))
668 sll_assert(x > basis%xmin - 1.0d-14)
669 sll_assert(x < basis%xmax + 1.0d-14)
670 sll_assert(icell >= 1)
671 sll_assert(icell <= basis%num_pts - 1)
673 sll_assert(n <= basis%deg)
674 sll_assert(basis%knots(icell) <= x .and. x <= basis%knots(icell + 1))
677 num_pts = basis%num_pts
689 left(j) = x - basis%knots(icell + 1 - j)
690 right(j) = basis%knots(icell + j) - x
694 ndu(j, r) = 1.0_wp/(right(r + 1) + left(j - r))
696 temp = ndu(r, j - 1)*ndu(j, r)
697 ndu(r, j) = saved + right(r + 1)*temp
698 saved = left(j - r)*temp
702 bsdx(0, :) = ndu(:, deg)
713 a(s2, 0) = a(s1, 0)*ndu(pk + 1, rk)
714 d = a(s2, 0)*ndu(rk, pk)
721 if (r - 1 <= pk)
then
727 a(s2, j) = (a(s1, j) - a(s1, j - 1))*ndu(pk + 1, rk + j)
728 d = d + a(s2, j)*ndu(rk + j, pk)
731 a(s2, k) = -a(s1, k - 1)*ndu(pk + 1, r)
732 d = d + a(s2, k)*ndu(r, pk)
742 bsdx(k, :) = bsdx(k, :)*real(r,
f64)
746 end subroutine sll_s_bsplines_eval_basis_and_n_derivs
757 sll_pure
subroutine sll_s_bsplines_eval_basis_mm( &
764 integer,
intent(in) :: degree
765 real(
wp),
intent(in) :: knots(1 - degree:)
766 integer,
intent(in) :: cell
767 real(
wp),
intent(in) :: x
768 real(
wp),
intent(out) :: out(:)
777 tmp1 = (x - knots(cell + 1 - ell))/(knots(cell + 1) - knots(cell + 1 - ell))*out(1)
778 out(1) = out(1) - tmp1
780 tmp2 = (x - knots(cell + k - ell))/(knots(cell + k) - knots(cell + k - ell))*out(k)
781 out(k) = out(k) + tmp1 - tmp2
787 end subroutine sll_s_bsplines_eval_basis_mm
798 sll_pure
subroutine sll_s_bsplines_eval_basis_and_deriv_mm( &
805 integer,
intent(in) :: degree
806 real(
wp),
intent(in) :: knots(1 - degree:)
807 integer,
intent(in) :: cell
808 real(
wp),
intent(in) :: x
809 real(
wp),
intent(out) :: out(:, :)
818 tmp1 = (x - knots(cell + 1 - ell))/(knots(cell + 1) - knots(cell + 1 - ell))*out(1, 1)
819 out(1, 1) = out(1, 1) - tmp1
821 tmp2 = (x - knots(cell + k - ell))/(knots(cell + k) - knots(cell + k - ell))*out(1, k)
822 out(1, k) = out(1, k) + tmp1 - tmp2
825 out(2, ell + 1) = tmp1
826 if (ell == degree - 1)
then
828 tmp1 = real(degree,
wp)/(knots(cell + 1) - knots(cell + 1 - degree))*out(1, 1)
832 tmp1 = real(degree,
wp)/(knots(cell + k) - knots(cell + k - degree))*out(2, k)
833 out(2, k) = out(2, k) - tmp1
835 out(2, degree + 1) = tmp1
839 end subroutine sll_s_bsplines_eval_basis_and_deriv_mm
846 character(len=*),
parameter :: this_sub_name =
"sll_s_bsplines_free()"
848 if (.not.
allocated(spline%knots))
then
849 sll_error(this_sub_name,
'knots array is not allocated.')
851 deallocate (spline%knots)
880 sll_pure
subroutine sll_s_uniform_bsplines_eval_basis( &
885 integer,
intent(in) :: spline_degree
886 real(
wp),
intent(in) :: normalized_offset
887 real(
wp),
intent(out) :: bspl(0:spline_degree)
896 sll_assert(spline_degree >= 0)
897 sll_assert(normalized_offset >= 0.0_wp)
898 sll_assert(normalized_offset <= 1.0_wp)
901 do j = 1, spline_degree
902 xx = -normalized_offset
904 inv_j = 1.0_wp/j_real
909 bspl(r) = saved + xx*temp
910 saved = (j_real - xx)*temp
915 end subroutine sll_s_uniform_bsplines_eval_basis
927 sll_pure
subroutine sll_s_uniform_bsplines_eval_deriv( &
932 integer,
intent(in) :: spline_degree
933 real(
wp),
intent(in) :: normalized_offset
934 real(
wp),
intent(out) :: bspl(0:spline_degree)
944 sll_assert(spline_degree >= 0)
945 sll_assert(normalized_offset >= 0.0_wp)
946 sll_assert(normalized_offset <= 1.0_wp)
948 x = normalized_offset
952 do j = 1, spline_degree - 1
955 inv_j = 1.0_wp/j_real
960 bspl(r) = saved + xx*temp
961 saved = (j_real - xx)*temp
970 do j = 1, spline_degree - 1
975 bspl(spline_degree) = bj
977 end subroutine sll_s_uniform_bsplines_eval_deriv
989 sll_pure
subroutine sll_s_uniform_bsplines_eval_basis_and_deriv( &
994 integer,
intent(in) :: degree
995 real(
wp),
intent(in) :: normalized_offset
996 real(
wp),
intent(out) :: bspl(2, 0:degree)
1005 sll_assert(degree >= 0)
1006 sll_assert(normalized_offset >= 0.0_wp)
1007 sll_assert(normalized_offset <= 1.0_wp)
1011 do j = 1, degree - 1
1013 j_real = real(j,
wp)
1014 inv_j = 1.0_wp/j_real
1015 xx = -normalized_offset
1018 temp = bspl(1, r)*inv_j
1019 bspl(1, r) = saved + xx*temp
1020 saved = (j_real - xx)*temp
1026 bspl(2, 0) = -bspl(1, 0)
1027 do j = 1, degree - 1
1028 bspl(2, j) = bspl(1, j - 1) - bspl(1, j)
1030 bspl(2, degree) = bspl(1, degree - 1)
1035 j_real = real(j,
wp)
1036 inv_j = 1.0_wp/j_real
1037 xx = -normalized_offset
1040 temp = bspl(1, r)*inv_j
1041 bspl(1, r) = saved + xx*temp
1042 saved = (j_real - xx)*temp
1046 end subroutine sll_s_uniform_bsplines_eval_basis_and_deriv
1050 sll_pure
subroutine sll_s_uniform_bsplines_eval_basis_and_n_derivs( &
1052 normalized_offset, &
1056 integer,
intent(in) :: spline_degree
1057 real(
wp),
intent(in) :: normalized_offset
1058 integer,
intent(in) :: n
1059 real(
wp),
intent(out) :: bspl(0:n, 0:spline_degree)
1067 integer :: k, s1, s2, rk, pk, j1, j2
1071 real(
wp) :: ndu(0:spline_degree, 0:spline_degree)
1072 real(
wp) :: a(0:1, 0:spline_degree)
1075 real(
wp),
parameter :: inv_idx(1:32) = [(1.0_wp/real(j,
wp), j=1, 32)]
1077 sll_assert(spline_degree >= 0)
1079 sll_assert(normalized_offset >= 0.0_wp)
1080 sll_assert(normalized_offset <= 1.0_wp)
1084 do j = 1, spline_degree
1085 xx = -normalized_offset
1086 j_real = real(j,
wp)
1090 temp = ndu(r, j - 1)*inv_idx(j)
1091 ndu(r, j) = saved + xx*temp
1092 saved = (j_real - xx)*temp
1096 bspl(0, :) = ndu(:, spline_degree)
1099 associate(deg => spline_degree, bsdx => bspl)
1110 a(s2, 0) = a(s1, 0)*inv_idx(pk + 1)
1111 d = a(s2, 0)*ndu(rk, pk)
1118 if (r - 1 <= pk)
then
1124 a(s2, j) = (a(s1, j) - a(s1, j - 1))*inv_idx(pk + 1)
1125 d = d + a(s2, j)*ndu(rk + j, pk)
1128 a(s2, k) = -a(s1, k - 1)*inv_idx(pk + 1)
1129 d = d + a(s2, k)*ndu(r, pk)
1142 bsdx(k, :) = bsdx(k, :)*real(r,
f64)
1148 end subroutine sll_s_uniform_bsplines_eval_basis_and_n_derivs
1155 sll_pure
subroutine sll_s_eval_uniform_periodic_spline_curve(degree, scoef, sval)
1157 integer,
intent(in) :: degree
1158 real(
wp),
intent(in) :: scoef(:)
1159 real(
wp),
intent(out) :: sval(:)
1161 real(
wp) :: bspl(degree + 1)
1163 integer :: i, j, imj, n
1166 call sll_s_uniform_bsplines_eval_basis(degree, 0.0_wp, bspl)
1171 imj = mod(i - 1 - j + n, n) + 1
1172 val = val + bspl(j)*scoef(imj)
1178 end subroutine sll_s_eval_uniform_periodic_spline_curve
1181 sll_pure
subroutine sll_s_eval_uniform_periodic_spline_curve_with_zero(degree, scoef, sval)
1183 integer,
intent(in) :: degree
1184 real(
wp),
intent(in) :: scoef(:)
1185 real(
wp),
intent(out) :: sval(:)
1187 if (degree == 0)
then
1190 call sll_s_eval_uniform_periodic_spline_curve(degree, scoef, sval)
1193 end subroutine sll_s_eval_uniform_periodic_spline_curve_with_zero
Describe different boundary conditions.
Low level arbitrary degree splines.
integer, dimension(1:3), parameter allowed_bcs
List of allowed boundary conditions.
integer, parameter wp
Working precision.
subroutine, public sll_s_bsplines_init_from_grid(basis, degree, grid, bc_xmin, bc_xmax)
Build new sll_t_bsplines object based on a on a grid of strictly increasing points including the last...
subroutine, public sll_s_bsplines_free(spline)
Evaluates B-spline values at a point x in a given cell.
subroutine, public sll_s_bsplines_init_from_knots(basis, degree, n, knots)
Build new sll_t_bsplines object.
pure integer function, public sll_f_find_cell(basis, x)
return index i of grid cell such that: basisknots(i) <= x <= basisknots(i+1).
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
Information for evaluation of B-splines on non-uniform grid.