3 #include "sll_assert.h"
43 sll_pure
function i_fun_rhs(x)
result(rhs)
45 real(
wp),
intent(in) :: x(2)
47 end function i_fun_rhs
53 integer :: mm, n1, n2, ncells1, ncells2
65 real(
wp),
allocatable :: quad_points_eta1(:, :)
66 real(
wp),
allocatable :: quad_points_eta2(:, :)
69 real(
wp),
allocatable :: data_1d_eta1(:, :, :, :)
70 real(
wp),
allocatable :: data_1d_eta2(:, :, :, :)
73 real(
wp),
allocatable :: int_volume(:, :, :, :)
74 real(
wp),
allocatable :: inv_metric(:, :, :, :, :, :)
75 real(
wp),
allocatable :: data_2d_rhs(:, :, :, :)
78 real(
wp),
allocatable :: a(:, :)
79 real(
wp),
allocatable :: m(:, :)
80 real(
wp),
allocatable :: ap(:, :)
81 real(
wp),
allocatable :: mp(:, :)
84 real(
wp),
allocatable :: l(:, :)
87 real(
wp),
allocatable :: b(:)
88 real(
wp),
allocatable :: bp(:)
91 real(
wp),
allocatable :: x(:)
92 real(
wp),
allocatable :: xp(:)
108 real(
wp) :: tol = 1.0e-14_wp
109 logical :: verbose = .false.
119 generic :: solve => solve_1, solve_2
138 class(sll_c_bsplines),
target,
intent(in) :: bsplines_eta1
139 class(sll_c_bsplines),
target,
intent(in) :: bsplines_eta2
140 real(wp),
allocatable,
intent(in) :: breaks_eta1(:)
141 real(wp),
allocatable,
intent(in) :: breaks_eta2(:)
143 real(wp),
optional,
intent(in) :: tol
144 logical,
optional,
intent(in) :: verbose
150 real(wp),
allocatable :: quad_weights_eta1(:, :)
151 real(wp),
allocatable :: quad_weights_eta2(:, :)
154 integer :: i, j, k, idx, k1, k2, q1, q2, p1, p2
155 real(wp) :: cx, cy, jdet, eta(2), jmat(2, 2)
157 if (
present(tol)) self%tol = tol
158 if (
present(verbose)) self%verbose = verbose
161 self%mapping => mapping
164 call polar_bsplines%init(bsplines_eta1, bsplines_eta2, mapping)
167 self%n1 = bsplines_eta1%nbasis
168 self%n2 = bsplines_eta2%nbasis
175 self%Nk1 =
size(breaks_eta1) - 1
176 self%Nk2 =
size(breaks_eta2) - 1
179 p1 = bsplines_eta1%degree
180 p2 = bsplines_eta2%degree
186 associate(n1 => self%n1, &
188 nn => 3 + (self%n1 - 2)*self%n2, &
195 allocate (self%quad_points_eta1(nq1, nk1))
196 allocate (self%quad_points_eta2(nq2, nk2))
199 allocate (quad_weights_eta1(nq1, nk1))
200 allocate (quad_weights_eta2(nq2, nk2))
203 allocate (self%data_1d_eta1(nq1, 2, 1 + p1, nk1))
204 allocate (self%data_1d_eta2(nq2, 2, 1 + p2, nk2))
207 allocate (self%int_volume(nq1, nq2, nk1, nk2))
208 allocate (self%inv_metric(nq1, nq2, nk1, nk2, 2, 2))
209 allocate (self%data_2d_rhs(nq1, nq2, nk1, nk2))
212 allocate (self%L(2*n2, 3))
215 allocate (self%A(n1*n2, n1*n2))
216 allocate (self%M(n1*n2, n1*n2))
219 allocate (self%b(n1*n2))
222 allocate (self%x(n1*n2))
225 allocate (self%Ap(nn, nn))
226 allocate (self%Mp(nn, nn))
229 allocate (self%bp(nn))
232 allocate (self%xp(nn))
257 call bsplines_eta1%eval_basis_and_n_derivs( &
258 x=self%quad_points_eta1(q1, k1), &
260 derivs=self%data_1d_eta1(q1, :, :, k1), &
268 call bsplines_eta2%eval_basis_and_n_derivs( &
269 x=self%quad_points_eta2(q2, k2), &
271 derivs=self%data_1d_eta2(q2, :, :, k2), &
286 eta = [self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)]
288 jdet = mapping%jdet(eta)
289 jmat = mapping%jmat(eta)
292 self%int_volume(q1, q2, k1, k2) = abs(jdet)*quad_weights_eta1(q1, k1)*quad_weights_eta2(q2, k2)
295 self%inv_metric(q1, q2, k1, k2, 1, 1) = jmat(1, 2)**2 + jmat(2, 2)**2
296 self%inv_metric(q1, q2, k1, k2, 1, 2) = -jmat(1, 1)*jmat(1, 2) - jmat(2, 1)*jmat(2, 2)
297 self%inv_metric(q1, q2, k1, k2, 2, 1) = self%inv_metric(q1, q2, k1, k2, 1, 2)
298 self%inv_metric(q1, q2, k1, k2, 2, 2) = jmat(1, 1)**2 + jmat(2, 1)**2
299 self%inv_metric(q1, q2, k1, k2, :, :) = self%inv_metric(q1, q2, k1, k2, :, :)/jdet**2
314 k = modulo((i - 1), n2) + 1
316 cx = mapping%spline_2d_x1%bcoef(j, k)
317 cy = mapping%spline_2d_x2%bcoef(j, k)
319 self%L(i, 1) = polar_bsplines%eval_l0(cx, cy)
320 self%L(i, 2) = polar_bsplines%eval_l1(cx, cy)
321 self%L(i, 3) = polar_bsplines%eval_l2(cx, cy)
329 call self%assembler%init(n1, n2, self%weak_form)
330 call self%projector%init(n1, n2, self%L)
342 call self%assembler%add_element_mat( &
358 call self%projector%change_basis_matrix(self%A, self%Ap)
359 call self%projector%change_basis_matrix(self%M, self%Mp)
365 idx = 3 + (n1 - 3)*n2
368 call self%Ap_linop%init(idx, idx)
369 self%Ap_linop%A = self%Ap(:idx, :idx)
373 allocate (self%xp_vecsp%array(
size(self%xp(:idx))), source=self%xp(:idx))
376 call self%cjsolver%init( &
378 verbose=self%verbose, &
379 template_vector=self%xp_vecsp)
383 call polar_bsplines%free()
390 procedure(i_fun_rhs) :: rhs
391 type(sll_t_spline_2d),
intent(inout) :: sol
394 integer :: idx, k1, k2, q1, q2
395 real(wp) :: eta(2), x(2)
397 associate(n1 => self%n1, &
399 nn => 3 + (self%n1 - 2)*self%n2, &
411 eta = [self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)]
413 x = self%mapping%eval(eta)
415 self%data_2d_rhs(q1, q2, k1, k2) = rhs(x)
431 call self%assembler%add_element_rhs( &
446 call self%projector%change_basis_vector(self%b, self%bp)
452 idx = 3 + (n1 - 3)*n2
455 allocate (self%bp_vecsp%array(
size(self%bp(:idx))), source=self%bp(:idx))
458 call self%cjsolver%solve( &
464 self%xp(:idx) = self%xp_vecsp%array
470 call self%projector%change_basis_vector_inv(self%xp, self%x)
472 sol%bcoef = reshape(self%x, (/n2, n1/))
481 type(sll_t_spline_2d),
intent(in) :: rhs
482 type(sll_t_spline_2d),
intent(inout) :: sol
484 integer :: idx, i, i1, i2
486 associate(n1 => self%n1, n2 => self%n2)
492 self%b(i) = rhs%bcoef(i1, i2)
497 self%b = matmul(self%M, self%b)
500 call self%projector%change_basis_vector(self%b, self%bp)
506 idx = 3 + (n1 - 3)*n2
509 allocate (self%bp_vecsp%array(
size(self%bp(:idx))), source=self%bp(:idx))
512 call self%cjsolver%solve( &
518 self%xp(:idx) = self%xp_vecsp%array
524 call self%projector%change_basis_vector_inv(self%xp, self%x)
526 sol%bcoef = reshape(self%x, (/n2, n1/))
536 deallocate (self%quad_points_eta1)
537 deallocate (self%quad_points_eta2)
538 deallocate (self%data_1d_eta1)
539 deallocate (self%data_1d_eta2)
540 deallocate (self%int_volume)
541 deallocate (self%inv_metric)
550 call self%projector%free()
552 call self%cjsolver%free()
553 call self%Ap_linop%free()
554 deallocate (self%bp_vecsp%array)
555 deallocate (self%xp_vecsp%array)
Access point to B-splines of arbitrary degree providing factory function.
Gauss-Legendre integration.
real(kind=f64) function, dimension(1:npoints), public sll_f_gauss_legendre_points(npoints, a, b)
real(kind=f64) function, dimension(1:npoints), public sll_f_gauss_legendre_weights(npoints, a, b)
subroutine s_poisson_2d_fem_sps_dense__init(self, bsplines_eta1, bsplines_eta2, breaks_eta1, breaks_eta2, mapping, tol, verbose)
subroutine s_poisson_2d_fem_sps_dense__free(self)
subroutine s_poisson_2d_fem_sps_dense__solve_2(self, rhs, sol)
subroutine s_poisson_2d_fem_sps_dense__solve_1(self, rhs, sol)
Module for tensor-product 2D splines.
Vector space for wrapping 1D Fortran real arrays.
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
Type containing new 2D polar basis functions.
Concrete type, discrete singular mapping.
Vector space for wrapping 1D Fortran real arrays.