3 #include "sll_assert.h"
4 #include "sll_errors.h"
55 sll_pure
function i_fun_rhs(x)
result(rhs)
57 real(
wp),
intent(in) :: x(2)
59 end function i_fun_rhs
65 integer :: mm, n1, n2, ncells1, ncells2, p1, p2
67 class(sll_c_bsplines),
pointer :: bsplines_eta1 => null()
68 class(sll_c_bsplines),
pointer :: bsplines_eta2 => null()
80 real(
wp),
allocatable :: quad_points_eta1(:, :)
81 real(
wp),
allocatable :: quad_points_eta2(:, :)
84 real(
wp),
allocatable :: data_1d_eta1(:, :, :, :)
85 real(
wp),
allocatable :: data_1d_eta2(:, :, :, :)
88 real(
wp),
allocatable :: int_volume(:, :, :, :)
89 real(
wp),
allocatable :: inv_metric(:, :, :, :, :, :)
90 real(
wp),
allocatable :: data_2d_rhs(:, :, :, :)
93 real(
wp),
allocatable :: coeffs1(:, :, :, :)
94 real(
wp),
allocatable :: coeffs2(:, :, :, :)
104 real(
wp),
allocatable :: l(:, :, :)
111 real(
wp),
allocatable :: x(:)
114 real(
wp),
allocatable :: bspl1(:)
115 real(
wp),
allocatable :: bspl2(:)
128 real(
wp) :: tol = 1.0e-14_wp
129 logical :: verbose = .false.
149 generic :: accumulate_charge => accumulate_charge_1, accumulate_charge_2, accumulate_charge_3
170 class(sll_c_bsplines),
target,
intent(in) :: bsplines_eta1
171 class(sll_c_bsplines),
target,
intent(in) :: bsplines_eta2
172 real(wp),
allocatable,
intent(in) :: breaks_eta1(:)
173 real(wp),
allocatable,
intent(in) :: breaks_eta2(:)
175 real(wp),
allocatable,
intent(in) :: coeffs1(:, :)
176 real(wp),
allocatable,
intent(in) :: coeffs2(:, :)
177 real(wp),
optional,
intent(in) :: tol
178 logical,
optional,
intent(in) :: verbose
184 real(wp),
allocatable :: quad_weights_eta1(:, :)
185 real(wp),
allocatable :: quad_weights_eta2(:, :)
188 integer :: i, j, k, i1, i2, k1, k2, q1, q2
189 real(wp) :: cx, cy, jdet, eta(2), jmat(2, 2)
191 if (
present(tol)) self%tol = tol
192 if (
present(verbose)) self%verbose = verbose
195 self%bsplines_eta1 => bsplines_eta1
196 self%bsplines_eta2 => bsplines_eta2
199 self%mapping => mapping
202 call polar_bsplines%init(bsplines_eta1, bsplines_eta2, mapping)
205 self%n1 = bsplines_eta1%nbasis
206 self%n2 = bsplines_eta2%nbasis
209 call self%spline_2d_coeffs1%init(bsplines_eta1, bsplines_eta2)
210 call self%spline_2d_coeffs2%init(bsplines_eta1, bsplines_eta2)
213 call self%spline_interp_2d%init( &
216 [sll_p_greville, sll_p_periodic], &
217 [sll_p_greville, sll_p_periodic])
224 self%Nk1 =
size(breaks_eta1) - 1
225 self%Nk2 =
size(breaks_eta2) - 1
228 self%p1 = bsplines_eta1%degree
229 self%p2 = bsplines_eta2%degree
232 self%Nq1 = 1 + self%p1
233 self%Nq2 = 1 + self%p2
235 associate(n1 => self%n1, &
239 nn => 3 + (self%n1 - 2)*self%n2, &
246 allocate (self%quad_points_eta1(nq1, nk1))
247 allocate (self%quad_points_eta2(nq2, nk2))
250 allocate (quad_weights_eta1(nq1, nk1))
251 allocate (quad_weights_eta2(nq2, nk2))
254 allocate (self%data_1d_eta1(nq1, 2, 1 + p1, nk1))
255 allocate (self%data_1d_eta2(nq2, 2, 1 + p2, nk2))
258 allocate (self%int_volume(nq1, nq2, nk1, nk2))
259 allocate (self%inv_metric(nq1, nq2, nk1, nk2, 2, 2))
260 allocate (self%data_2d_rhs(nq1, nq2, nk1, nk2))
261 allocate (self%coeffs1(nq1, nq2, nk1, nk2))
262 allocate (self%coeffs2(nq1, nq2, nk1, nk2))
265 allocate (self%L(2, n2, 3))
268 allocate (self%bs%array(1 - p1:n1 + p1, 1 - p2:n2 + p2))
269 allocate (self%bs_tmp%array(1 - p1:n1 + p1, 1 - p2:n2 + p2))
272 allocate (self%x(n1*n2))
275 allocate (self%bspl1(1 + p1))
276 allocate (self%bspl2(1 + p2))
301 call bsplines_eta1%eval_basis_and_n_derivs( &
302 x=self%quad_points_eta1(q1, k1), &
304 derivs=self%data_1d_eta1(q1, :, :, k1), &
312 call bsplines_eta2%eval_basis_and_n_derivs( &
313 x=self%quad_points_eta2(q2, k2), &
315 derivs=self%data_1d_eta2(q2, :, :, k2), &
325 call self%spline_interp_2d%compute_interpolant(self%spline_2d_coeffs1, coeffs1)
326 call self%spline_interp_2d%compute_interpolant(self%spline_2d_coeffs2, coeffs2)
334 eta = [self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)]
336 jdet = mapping%jdet(eta)
337 jmat = mapping%jmat(eta)
340 self%int_volume(q1, q2, k1, k2) = abs(jdet)*quad_weights_eta1(q1, k1)*quad_weights_eta2(q2, k2)
343 self%inv_metric(q1, q2, k1, k2, 1, 1) = jmat(1, 2)**2 + jmat(2, 2)**2
344 self%inv_metric(q1, q2, k1, k2, 1, 2) = -jmat(1, 1)*jmat(1, 2) - jmat(2, 1)*jmat(2, 2)
345 self%inv_metric(q1, q2, k1, k2, 2, 1) = self%inv_metric(q1, q2, k1, k2, 1, 2)
346 self%inv_metric(q1, q2, k1, k2, 2, 2) = jmat(1, 1)**2 + jmat(2, 1)**2
347 self%inv_metric(q1, q2, k1, k2, :, :) = self%inv_metric(q1, q2, k1, k2, :, :)/jdet**2
349 self%coeffs1(q1, q2, k1, k2) = self%spline_2d_coeffs1%eval(eta(1), eta(2))
350 self%coeffs2(q1, q2, k1, k2) = self%spline_2d_coeffs2%eval(eta(1), eta(2))
367 k = modulo((i - 1), n2) + 1
369 cx = mapping%spline_2d_x1%bcoef(j, k)
370 cy = mapping%spline_2d_x2%bcoef(j, k)
372 self%L(i1, i2, 1) = polar_bsplines%eval_l0(cx, cy)
373 self%L(i1, i2, 2) = polar_bsplines%eval_l1(cx, cy)
374 self%L(i1, i2, 3) = polar_bsplines%eval_l2(cx, cy)
383 call self%assembler%init(n1, n2, p1, p2, self%weak_form)
384 call self%projector%init(n1, n2, p1, p2, self%L)
391 call self%A_linop_stencil%init(n1, n2, p1, p2)
392 call self%M_linop_stencil%init(n1, n2, p1, p2)
397 call self%assembler%add_element_mat( &
406 self%A_linop_stencil%A, &
407 self%M_linop_stencil%A)
417 call self%Ap_linop_c1_block%init(n1, n2, p1, p2)
418 call self%Mp_linop_c1_block%init(n1, n2, p1, p2)
424 call self%projector%change_basis_matrix(self%A_linop_stencil, self%Ap_linop_c1_block)
425 call self%projector%change_basis_matrix(self%M_linop_stencil, self%Mp_linop_c1_block)
429 call self%xp_vecsp_c1_block%init(n1 - 2, n2, p1, p2)
431 allocate (self%xp_vecsp_c1_block%vd%array(1:3))
432 allocate (self%xp_vecsp_c1_block%vs%array(1 - p1:(n1 - 2) + p1, 1 - p2:n2 + p2))
433 self%xp_vecsp_c1_block%vd%array(:) = 0.0_wp
434 self%xp_vecsp_c1_block%vs%array(:, :) = 0.0_wp
437 call self%cjsolver%init( &
439 verbose=self%verbose, &
440 template_vector=self%xp_vecsp_c1_block)
443 call self%bp_vecsp_c1_block%init(n1 - 2, n2, p1, p2)
444 allocate (self%bp_vecsp_c1_block%vd%array(1:3))
445 allocate (self%bp_vecsp_c1_block%vs%array(1 - p1:(n1 - 2) + p1, 1 - p2:n2 + p2))
449 call polar_bsplines%free()
456 integer,
intent(in) :: bc
458 integer :: i, j, i1, i2, j1, j2, k1, k2, nb
460 character(len=*),
parameter :: this_sub_name =
"sll_t_qn_solver_2d_fem_sps_stencil_new % set_boundary_conditions"
462 if (bc == sll_p_dirichlet)
then
464 associate(n1 => self%n1, &
477 j2 = modulo(i2 - 1 + k2, n2) + 1
481 if (i > nb - n2 .or. j > nb - n2) &
482 self%Ap_linop_c1_block%block4%A(k1, k2, i1, i2) = 0.0_wp
491 sll_error(this_sub_name,
"Boundary conditions not implemented")
500 self%bs%array(:, :) = 0.0_wp
507 procedure(i_fun_rhs) :: rhs
510 integer :: k1, k2, q1, q2
511 real(wp) :: eta(2), x(2)
513 associate(n1 => self%n1, &
525 eta = (/self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)/)
526 x = self%mapping%eval(eta)
527 self%data_2d_rhs(q1, q2, k1, k2) = rhs(x)
536 call self%assembler%add_element_rhs( &
543 self%bs%array(1:n1, 1:n2))
554 type(sll_t_spline_2d),
intent(in) :: rhs
556 associate(n1 => self%n1, n2 => self%n2)
559 self%bs_tmp%array(:, :) = 0.0_wp
560 self%bs_tmp%array(1:n1, 1:n2) = rhs%bcoef(1:n1, 1:n2)
562 call self%M_linop_stencil%dot_incr(self%bs_tmp, self%bs)
571 real(wp),
intent(in) :: intensity
572 real(wp),
intent(in) :: location(2)
574 integer :: i1, i2, j1, j2, jmin1, jmin2
576 associate(n1 => self%n1, &
584 call self%bsplines_eta1%eval_basis(sc, self%bspl1(:), jmin1)
585 call self%bsplines_eta2%eval_basis(tc, self%bspl2(:), jmin2)
588 do j2 = jmin2, jmin2 + p2
590 do j1 = jmin1, jmin1 + p1
591 self%bs%array(j1, j2) = self%bs%array(j1, j2) + qc*self%bspl1(i1)*self%bspl2(i2)
604 type(sll_t_spline_2d),
intent(inout) :: sol
606 integer :: j2, i1, i2, i
608 associate(n1 => self%n1, &
614 call self%projector%change_basis_vector(self%bs%array(1:n1, 1:n2), self%bp_vecsp_c1_block)
618 self%bp_vecsp_c1_block%vs%array(n1 - 2, j2) = 0.0_wp
622 self%bp_vecsp_c1_block%vs%array(1 - p1:0, :) = 0.0_wp
623 self%bp_vecsp_c1_block%vs%array((n1 - 2) + 1:(n1 - 2) + p1, :) = 0.0_wp
624 self%bp_vecsp_c1_block%vs%array(:, 1 - p2:0) = self%bp_vecsp_c1_block%vs%array(:, n2 - p2 + 1:n2)
625 self%bp_vecsp_c1_block%vs%array(:, n2 + 1:n2 + p2) = self%bp_vecsp_c1_block%vs%array(:, 1:p2)
628 self%xp_vecsp_c1_block%vs%array(:, :) = 0.0_wp
629 self%xp_vecsp_c1_block%vd%array(:) = 0.0_wp
632 call self%cjsolver%solve( &
633 a=self%Ap_linop_c1_block, &
634 b=self%bp_vecsp_c1_block, &
635 x=self%xp_vecsp_c1_block)
638 call self%projector%change_basis_vector_inv(self%xp_vecsp_c1_block, self%x)
643 sol%bcoef(i1, i2) = self%x(i)
646 sol%bcoef(:, n2 + 1:n2 + p2) = sol%bcoef(:, 1:p2)
656 deallocate (self%quad_points_eta1)
657 deallocate (self%quad_points_eta2)
658 deallocate (self%data_1d_eta1)
659 deallocate (self%data_1d_eta2)
660 deallocate (self%int_volume)
661 deallocate (self%inv_metric)
664 deallocate (self%bs%array)
665 deallocate (self%bs_tmp%array)
667 call self%Ap_linop_c1_block%free()
668 call self%Mp_linop_c1_block%free()
669 deallocate (self%bp_vecsp_c1_block%vd%array)
670 deallocate (self%bp_vecsp_c1_block%vs%array)
671 deallocate (self%xp_vecsp_c1_block%vd%array)
672 deallocate (self%xp_vecsp_c1_block%vs%array)
674 call self%projector%free()
676 call self%cjsolver%free()
678 call self%spline_2d_coeffs1%free()
679 call self%spline_2d_coeffs2%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_qn_solver_2d_fem_sps_stencil_new__reset_charge(self)
subroutine s_qn_solver_2d_fem_sps_stencil_new__free(self)
subroutine s_qn_solver_2d_fem_sps_stencil_new__accumulate_charge_1(self, rhs)
subroutine s_qn_solver_2d_fem_sps_stencil_new__init(self, bsplines_eta1, bsplines_eta2, breaks_eta1, breaks_eta2, mapping, coeffs1, coeffs2, tol, verbose)
subroutine s_qn_solver_2d_fem_sps_stencil_new__set_boundary_conditions(self, bc)
subroutine s_qn_solver_2d_fem_sps_stencil_new__solve(self, sol)
subroutine s_qn_solver_2d_fem_sps_stencil_new__accumulate_charge_2(self, rhs)
subroutine s_qn_solver_2d_fem_sps_stencil_new__accumulate_charge_3(self, intensity, location)
Module for tensor-product 2D splines.
Interpolator for 2D tensor-product splines of arbitrary degree, on uniform and non-uniform grids (dir...
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.
2D tensor-product spline interpolator
Vector space for wrapping 2D Fortran real arrays.