3 #include "sll_assert.h"
4 #include "sll_errors.h"
50 sll_pure
function i_fun_rhs(x)
result(rhs)
52 real(
wp),
intent(in) :: x(2)
54 end function i_fun_rhs
60 integer :: mm, n1, n2, ncells1, ncells2, p1, p2
62 class(sll_c_bsplines),
pointer :: bsplines_eta1 => null()
63 class(sll_c_bsplines),
pointer :: bsplines_eta2 => null()
75 real(
wp),
allocatable :: quad_points_eta1(:, :)
76 real(
wp),
allocatable :: quad_points_eta2(:, :)
79 real(
wp),
allocatable :: data_1d_eta1(:, :, :, :)
80 real(
wp),
allocatable :: data_1d_eta2(:, :, :, :)
83 real(
wp),
allocatable :: int_volume(:, :, :, :)
84 real(
wp),
allocatable :: inv_metric(:, :, :, :, :, :)
85 real(
wp),
allocatable :: data_2d_rhs(:, :, :, :)
92 real(
wp),
allocatable :: l(:, :, :)
99 real(
wp),
allocatable :: x(:)
102 real(
wp),
allocatable :: bspl1(:)
103 real(
wp),
allocatable :: bspl2(:)
116 real(
wp) :: tol = 1.0e-14_wp
117 logical :: verbose = .false.
137 generic :: accumulate_charge => accumulate_charge_1, accumulate_charge_2, accumulate_charge_3
156 class(sll_c_bsplines),
target,
intent(in) :: bsplines_eta1
157 class(sll_c_bsplines),
target,
intent(in) :: bsplines_eta2
158 real(wp),
allocatable,
intent(in) :: breaks_eta1(:)
159 real(wp),
allocatable,
intent(in) :: breaks_eta2(:)
161 real(wp),
optional,
intent(in) :: tol
162 logical,
optional,
intent(in) :: verbose
168 real(wp),
allocatable :: quad_weights_eta1(:, :)
169 real(wp),
allocatable :: quad_weights_eta2(:, :)
172 integer :: i, j, k, i1, i2, k1, k2, q1, q2
173 real(wp) :: cx, cy, jdet, eta(2), jmat(2, 2)
175 if (
present(tol)) self%tol = tol
176 if (
present(verbose)) self%verbose = verbose
179 self%bsplines_eta1 => bsplines_eta1
180 self%bsplines_eta2 => bsplines_eta2
183 self%mapping => mapping
186 call polar_bsplines%init(bsplines_eta1, bsplines_eta2, mapping)
189 self%n1 = bsplines_eta1%nbasis
190 self%n2 = bsplines_eta2%nbasis
197 self%Nk1 =
size(breaks_eta1) - 1
198 self%Nk2 =
size(breaks_eta2) - 1
201 self%p1 = bsplines_eta1%degree
202 self%p2 = bsplines_eta2%degree
205 self%Nq1 = 1 + self%p1
206 self%Nq2 = 1 + self%p2
208 associate(n1 => self%n1, &
212 nn => 3 + (self%n1 - 2)*self%n2, &
219 allocate (self%quad_points_eta1(nq1, nk1))
220 allocate (self%quad_points_eta2(nq2, nk2))
223 allocate (quad_weights_eta1(nq1, nk1))
224 allocate (quad_weights_eta2(nq2, nk2))
227 allocate (self%data_1d_eta1(nq1, 2, 1 + p1, nk1))
228 allocate (self%data_1d_eta2(nq2, 2, 1 + p2, nk2))
231 allocate (self%int_volume(nq1, nq2, nk1, nk2))
232 allocate (self%inv_metric(nq1, nq2, nk1, nk2, 2, 2))
233 allocate (self%data_2d_rhs(nq1, nq2, nk1, nk2))
236 allocate (self%L(2, n2, 3))
239 allocate (self%bs%array(1 - p1:n1 + p1, 1 - p2:n2 + p2))
240 allocate (self%bs_tmp%array(1 - p1:n1 + p1, 1 - p2:n2 + p2))
243 allocate (self%x(n1*n2))
246 allocate (self%bspl1(1 + p1))
247 allocate (self%bspl2(1 + p2))
272 call bsplines_eta1%eval_basis_and_n_derivs( &
273 x=self%quad_points_eta1(q1, k1), &
275 derivs=self%data_1d_eta1(q1, :, :, k1), &
283 call bsplines_eta2%eval_basis_and_n_derivs( &
284 x=self%quad_points_eta2(q2, k2), &
286 derivs=self%data_1d_eta2(q2, :, :, k2), &
301 eta = [self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)]
303 jdet = mapping%jdet(eta)
304 jmat = mapping%jmat(eta)
307 self%int_volume(q1, q2, k1, k2) = abs(jdet)*quad_weights_eta1(q1, k1)*quad_weights_eta2(q2, k2)
310 self%inv_metric(q1, q2, k1, k2, 1, 1) = jmat(1, 2)**2 + jmat(2, 2)**2
311 self%inv_metric(q1, q2, k1, k2, 1, 2) = -jmat(1, 1)*jmat(1, 2) - jmat(2, 1)*jmat(2, 2)
312 self%inv_metric(q1, q2, k1, k2, 2, 1) = self%inv_metric(q1, q2, k1, k2, 1, 2)
313 self%inv_metric(q1, q2, k1, k2, 2, 2) = jmat(1, 1)**2 + jmat(2, 1)**2
314 self%inv_metric(q1, q2, k1, k2, :, :) = self%inv_metric(q1, q2, k1, k2, :, :)/jdet**2
331 k = modulo((i - 1), n2) + 1
333 cx = mapping%spline_2d_x1%bcoef(j, k)
334 cy = mapping%spline_2d_x2%bcoef(j, k)
336 self%L(i1, i2, 1) = polar_bsplines%eval_l0(cx, cy)
337 self%L(i1, i2, 2) = polar_bsplines%eval_l1(cx, cy)
338 self%L(i1, i2, 3) = polar_bsplines%eval_l2(cx, cy)
347 call self%assembler%init(n1, n2, p1, p2, self%weak_form)
348 call self%projector%init(n1, n2, p1, p2, self%L)
355 call self%A_linop_stencil%init(n1, n2, p1, p2)
356 call self%M_linop_stencil%init(n1, n2, p1, p2)
361 call self%assembler%add_element_mat( &
368 self%A_linop_stencil%A, &
369 self%M_linop_stencil%A)
379 call self%Ap_linop_c1_block%init(n1, n2, p1, p2)
380 call self%Mp_linop_c1_block%init(n1, n2, p1, p2)
386 call self%projector%change_basis_matrix(self%A_linop_stencil, self%Ap_linop_c1_block)
387 call self%projector%change_basis_matrix(self%M_linop_stencil, self%Mp_linop_c1_block)
391 call self%xp_vecsp_c1_block%init(n1 - 2, n2, p1, p2)
393 allocate (self%xp_vecsp_c1_block%vd%array(1:3))
394 allocate (self%xp_vecsp_c1_block%vs%array(1 - p1:(n1 - 2) + p1, 1 - p2:n2 + p2))
395 self%xp_vecsp_c1_block%vd%array(:) = 0.0_wp
396 self%xp_vecsp_c1_block%vs%array(:, :) = 0.0_wp
399 call self%cjsolver%init( &
401 verbose=self%verbose, &
402 template_vector=self%xp_vecsp_c1_block)
405 call self%bp_vecsp_c1_block%init(n1 - 2, n2, p1, p2)
406 allocate (self%bp_vecsp_c1_block%vd%array(1:3))
407 allocate (self%bp_vecsp_c1_block%vs%array(1 - p1:(n1 - 2) + p1, 1 - p2:n2 + p2))
411 call polar_bsplines%free()
418 integer,
intent(in) :: bc
420 integer :: i, j, i1, i2, j1, j2, k1, k2, nb
422 character(len=*),
parameter :: this_sub_name =
"sll_t_poisson_2d_fem_sps_stencil_new % set_boundary_conditions"
424 if (bc == sll_p_dirichlet)
then
426 associate(n1 => self%n1, &
439 j2 = modulo(i2 - 1 + k2, n2) + 1
443 if (i > nb - n2 .or. j > nb - n2) &
444 self%Ap_linop_c1_block%block4%A(k1, k2, i1, i2) = 0.0_wp
453 sll_error(this_sub_name,
"Boundary conditions not implemented")
462 self%bs%array(:, :) = 0.0_wp
469 procedure(i_fun_rhs) :: rhs
472 integer :: k1, k2, q1, q2
473 real(wp) :: eta(2), x(2)
475 associate(n1 => self%n1, &
487 eta = (/self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)/)
488 x = self%mapping%eval(eta)
489 self%data_2d_rhs(q1, q2, k1, k2) = rhs(x)
498 call self%assembler%add_element_rhs( &
505 self%bs%array(1:n1, 1:n2))
516 type(sll_t_spline_2d),
intent(in) :: rhs
518 associate(n1 => self%n1, n2 => self%n2)
521 self%bs_tmp%array(:, :) = 0.0_wp
522 self%bs_tmp%array(1:n1, 1:n2) = rhs%bcoef(1:n1, 1:n2)
524 call self%M_linop_stencil%dot_incr(self%bs_tmp, self%bs)
533 real(wp),
intent(in) :: intensity
534 real(wp),
intent(in) :: location(2)
536 integer :: i1, i2, j1, j2, jmin1, jmin2
538 associate(n1 => self%n1, &
546 call self%bsplines_eta1%eval_basis(sc, self%bspl1(:), jmin1)
547 call self%bsplines_eta2%eval_basis(tc, self%bspl2(:), jmin2)
550 do j2 = jmin2, jmin2 + p2
552 do j1 = jmin1, jmin1 + p1
553 self%bs%array(j1, j2) = self%bs%array(j1, j2) + qc*self%bspl1(i1)*self%bspl2(i2)
566 type(sll_t_spline_2d),
intent(inout) :: sol
568 integer :: j2, i1, i2, i
570 associate(n1 => self%n1, &
576 call self%projector%change_basis_vector(self%bs%array(1:n1, 1:n2), self%bp_vecsp_c1_block)
580 self%bp_vecsp_c1_block%vs%array(n1 - 2, j2) = 0.0_wp
584 self%bp_vecsp_c1_block%vs%array(1 - p1:0, :) = 0.0_wp
585 self%bp_vecsp_c1_block%vs%array((n1 - 2) + 1:(n1 - 2) + p1, :) = 0.0_wp
586 self%bp_vecsp_c1_block%vs%array(:, 1 - p2:0) = self%bp_vecsp_c1_block%vs%array(:, n2 - p2 + 1:n2)
587 self%bp_vecsp_c1_block%vs%array(:, n2 + 1:n2 + p2) = self%bp_vecsp_c1_block%vs%array(:, 1:p2)
590 self%xp_vecsp_c1_block%vs%array(:, :) = 0.0_wp
591 self%xp_vecsp_c1_block%vd%array(:) = 0.0_wp
594 call self%cjsolver%solve( &
595 a=self%Ap_linop_c1_block, &
596 b=self%bp_vecsp_c1_block, &
597 x=self%xp_vecsp_c1_block)
600 call self%projector%change_basis_vector_inv(self%xp_vecsp_c1_block, self%x)
605 sol%bcoef(i1, i2) = self%x(i)
608 sol%bcoef(:, n2 + 1:n2 + p2) = sol%bcoef(:, 1:p2)
618 deallocate (self%quad_points_eta1)
619 deallocate (self%quad_points_eta2)
620 deallocate (self%data_1d_eta1)
621 deallocate (self%data_1d_eta2)
622 deallocate (self%int_volume)
623 deallocate (self%inv_metric)
626 deallocate (self%bs%array)
627 deallocate (self%bs_tmp%array)
629 call self%Ap_linop_c1_block%free()
630 call self%Mp_linop_c1_block%free()
631 deallocate (self%bp_vecsp_c1_block%vd%array)
632 deallocate (self%bp_vecsp_c1_block%vs%array)
633 deallocate (self%xp_vecsp_c1_block%vd%array)
634 deallocate (self%xp_vecsp_c1_block%vs%array)
636 call self%projector%free()
638 call self%cjsolver%free()
Describe different boundary conditions.
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_stencil_new__init(self, bsplines_eta1, bsplines_eta2, breaks_eta1, breaks_eta2, mapping, tol, verbose)
subroutine s_poisson_2d_fem_sps_stencil_new__reset_charge(self)
subroutine s_poisson_2d_fem_sps_stencil_new__solve(self, sol)
subroutine s_poisson_2d_fem_sps_stencil_new__accumulate_charge_2(self, rhs)
subroutine s_poisson_2d_fem_sps_stencil_new__accumulate_charge_1(self, rhs)
subroutine s_poisson_2d_fem_sps_stencil_new__set_boundary_conditions(self, bc)
subroutine s_poisson_2d_fem_sps_stencil_new__accumulate_charge_3(self, intensity, location)
subroutine s_poisson_2d_fem_sps_stencil_new__free(self)
Module for tensor-product 2D splines.
Vector space for wrapping 2D Fortran real arrays.
Vector space for wrapping 2D 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 2D Fortran real arrays.