8 #include "sll_assert.h"
30 procedure :: find_cell => f_bsplines_non_uniform__find_cell
31 procedure :: eval_basis => s_bsplines_non_uniform__eval_basis
32 procedure :: eval_deriv => s_bsplines_non_uniform__eval_deriv
33 procedure :: eval_basis_and_n_derivs => s_bsplines_non_uniform__eval_basis_and_n_derivs
50 integer,
intent(in) :: degree
51 logical,
intent(in) :: periodic
52 real(wp),
intent(in) :: breaks(:)
59 self%periodic = periodic
60 self%uniform = .false.
61 self%ncells =
size(breaks) - 1
62 self%nbasis = merge(self%ncells, self%ncells + degree, periodic)
64 self%xmax = breaks(self%ncells + 1)
72 associate(npoints => self%ncells + 1)
74 allocate (self%knots(1 - degree:npoints + degree))
77 self%knots(i) = breaks(i)
82 period = breaks(npoints) - breaks(1)
84 self%knots(1 - i) = breaks(npoints - i) - period
85 self%knots(npoints + i) = breaks(i + 1) + period
89 self%knots(1 - i) = breaks(1)
90 self%knots(npoints + i) = breaks(npoints)
105 deallocate (self%knots)
115 sll_pure
function f_bsplines_non_uniform__find_cell(self, x)
result(icell)
117 real(wp),
intent(in) :: x
122 associate(npoints => self%ncells + 1)
125 if (x > self%knots(npoints)) then; icell = -1; return;
end if
126 if (x < self%knots(1)) then; icell = -1; return;
end if
129 if (x == self%knots(1)) then; icell = 1; return;
end if
130 if (x == self%knots(npoints)) then; icell = self%ncells; return;
end if
134 icell = (low + high)/2
135 do while (x < self%knots(icell) .or. x >= self%knots(icell + 1))
136 if (x < self%knots(icell))
then
141 icell = (low + high)/2
157 sll_pure
subroutine s_bsplines_non_uniform__eval_basis(self, x, values, jmin)
159 real(wp),
intent(in) :: x
160 real(wp),
intent(out) :: values(0:)
161 integer,
intent(out) :: jmin
170 real(wp) :: left(1:self%degree)
171 real(wp) :: right(1:self%degree)
174 sll_assert(x >= self%xmin)
175 sll_assert(x <= self%xmax)
176 sll_assert(
size(values) == 1 + self%degree)
180 icell = self%find_cell(x)
181 sll_assert(icell >= 1)
182 sll_assert(icell <= self%ncells)
183 sll_assert(self%knots(icell) <= x)
184 sll_assert(x <= self%knots(icell + 1))
191 do j = 1, self%degree
192 left(j) = x - self%knots(icell + 1 - j)
193 right(j) = self%knots(icell + j) - x
196 temp = values(r)/(right(r + 1) + left(j - r))
197 values(r) = saved + right(r + 1)*temp
198 saved = left(j - r)*temp
203 end subroutine s_bsplines_non_uniform__eval_basis
214 sll_pure
subroutine s_bsplines_non_uniform__eval_deriv(self, x, derivs, jmin)
216 real(wp),
intent(in) :: x
217 real(wp),
intent(out) :: derivs(0:)
218 integer,
intent(out) :: jmin
227 real(wp) :: left(1:self%degree)
228 real(wp) :: right(1:self%degree)
231 sll_assert(x >= self%xmin)
232 sll_assert(x <= self%xmax)
233 sll_assert(
size(derivs) == 1 + self%degree)
237 icell = self%find_cell(x)
238 sll_assert(icell >= 1)
239 sll_assert(icell <= self%ncells)
240 sll_assert(self%knots(icell) <= x)
241 sll_assert(x <= self%knots(icell + 1))
247 associate(degree => self%degree, degree_real => real(self%degree, wp))
254 left(j) = x - self%knots(icell + 1 - j)
255 right(j) = self%knots(icell + j) - x
259 temp = derivs(r)/(right(r + 1) + left(j - r))
260 derivs(r) = saved + right(r + 1)*temp
261 saved = left(j - r)*temp
271 saved = degree_real*derivs(0)/(self%knots(icell + 1) - self%knots(icell + 1 - degree))
275 saved = degree_real*derivs(j)/(self%knots(icell + j + 1) - self%knots(icell + j + 1 - degree))
276 derivs(j) = temp - saved
279 derivs(degree) = saved
283 end subroutine s_bsplines_non_uniform__eval_deriv
295 sll_pure
subroutine s_bsplines_non_uniform__eval_basis_and_n_derivs(self, x, n, derivs, jmin)
297 real(wp),
intent(in) :: x
298 integer,
intent(in) :: n
299 real(wp),
intent(out) :: derivs(0:, 0:)
300 integer,
intent(out) :: jmin
308 integer :: k, s1, s2, rk, pk, j1, j2
312 real(wp) :: left(1:self%degree)
313 real(wp) :: right(1:self%degree)
314 real(wp) :: ndu(0:self%degree, 0:self%degree)
315 real(wp) :: a(0:1, 0:self%degree)
318 sll_assert(x >= self%xmin)
319 sll_assert(x <= self%xmax)
321 sll_assert(n <= self%degree)
322 sll_assert(
size(derivs, 1) == 1 + n)
323 sll_assert(
size(derivs, 2) == 1 + self%degree)
327 icell = self%find_cell(x)
328 sll_assert(icell >= 1)
329 sll_assert(icell <= self%ncells)
330 sll_assert(self%knots(icell) <= x)
331 sll_assert(x <= self%knots(icell + 1))
342 associate(degree => self%degree)
346 left(j) = x - self%knots(icell + 1 - j)
347 right(j) = self%knots(icell + j) - x
351 ndu(j, r) = 1.0_wp/(right(r + 1) + left(j - r))
353 temp = ndu(r, j - 1)*ndu(j, r)
354 ndu(r, j) = saved + right(r + 1)*temp
355 saved = left(j - r)*temp
359 derivs(0, :) = ndu(:, degree)
370 a(s2, 0) = a(s1, 0)*ndu(pk + 1, rk)
371 d = a(s2, 0)*ndu(rk, pk)
378 if (r - 1 <= pk)
then
384 a(s2, j) = (a(s1, j) - a(s1, j - 1))*ndu(pk + 1, rk + j)
385 d = d + a(s2, j)*ndu(rk + j, pk)
388 a(s2, k) = -a(s1, k - 1)*ndu(pk + 1, r)
389 d = d + a(s2, k)*ndu(r, pk)
399 derivs(k, :) = derivs(k, :)*real(r, kind=wp)
405 end subroutine s_bsplines_non_uniform__eval_basis_and_n_derivs
Abstract class for B-splines of arbitrary degree.
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.