Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_qn_solver_2d_fem_sps_stencil_new.F90
Go to the documentation of this file.
2 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 #include "sll_assert.h"
4 #include "sll_errors.h"
5 
7 
8  use sll_m_bsplines, only: sll_c_bsplines
9 
11 
13 
15 
17 
19 
21 
23 
25 
27 
29 
31 
33 
37 
39  sll_p_dirichlet, &
40  sll_p_periodic, &
41  sll_p_greville
42 
43  implicit none
44 
46 
47  private
48 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
49 
50  ! Working precision
51  integer, parameter :: wp = f64
52 
53  ! Abstract interface for right hand side
54  abstract interface
55  sll_pure function i_fun_rhs(x) result(rhs)
56  import wp
57  real(wp), intent(in) :: x(2)
58  real(wp) :: rhs
59  end function i_fun_rhs
60  end interface
61 
63 
64  ! To initialize B-splines
65  integer :: mm, n1, n2, ncells1, ncells2, p1, p2
66 
67  class(sll_c_bsplines), pointer :: bsplines_eta1 => null()
68  class(sll_c_bsplines), pointer :: bsplines_eta2 => null()
69 
70  ! Analytical and discrete mappings
71  type(sll_t_singular_mapping_discrete), pointer :: mapping
72 
73  ! Number of finite elements
74  integer :: nk1, nk2
75 
76  ! Number of Gauss-Legendre quadrature points
77  integer :: nq1, nq2
78 
79  ! Quadrature points
80  real(wp), allocatable :: quad_points_eta1(:, :)
81  real(wp), allocatable :: quad_points_eta2(:, :)
82 
83  ! 1D data (B-splines values and derivatives)
84  real(wp), allocatable :: data_1d_eta1(:, :, :, :)
85  real(wp), allocatable :: data_1d_eta2(:, :, :, :)
86 
87  ! 2D data (inverse metric tensor, integral volume, right hand side)
88  real(wp), allocatable :: int_volume(:, :, :, :)
89  real(wp), allocatable :: inv_metric(:, :, :, :, :, :)
90  real(wp), allocatable :: data_2d_rhs(:, :, :, :)
91 
92  ! Additional 2D coefficients for quasi-neutrality equation
93  real(wp), allocatable :: coeffs1(:, :, :, :)
94  real(wp), allocatable :: coeffs2(:, :, :, :)
95  type(sll_t_spline_2d) :: spline_2d_coeffs1
96  type(sll_t_spline_2d) :: spline_2d_coeffs2
97  type(sll_t_spline_interpolator_2d) :: spline_interp_2d
98 
99  ! Stiffness and mass matrices and C1 projections
102 
103  ! Matrix for barycentric coordinates
104  real(wp), allocatable :: l(:, :, :)
105 
106  ! Right hand side vector and C1 projection
109 
110  ! Solution and C1 projection
111  real(wp), allocatable :: x(:)
112 
113  ! Allocatables for accumulation of point charge density
114  real(wp), allocatable :: bspl1(:)
115  real(wp), allocatable :: bspl2(:)
116 
117  ! Weak form
119 
120  ! Assembler
122 
123  ! C1 projector
125 
126  ! Linear solver
127  type(sll_t_conjugate_gradient) :: cjsolver
128  real(wp) :: tol = 1.0e-14_wp ! default value, can be overwritten from init method
129  logical :: verbose = .false. ! default value, can be overwritten from init method
130 
131  ! New C1 block format
132  type(sll_t_linear_operator_matrix_c1_block_new) :: ap_linop_c1_block
133  type(sll_t_linear_operator_matrix_c1_block_new) :: mp_linop_c1_block
134  type(sll_t_vector_space_c1_block) :: xp_vecsp_c1_block
135  type(sll_t_vector_space_c1_block) :: bp_vecsp_c1_block
136 
137  contains
138 
140  procedure :: set_boundary_conditions => s_qn_solver_2d_fem_sps_stencil_new__set_boundary_conditions
144 
145  ! Accumulate charge: generic procedure with multiple implementations
149  generic :: accumulate_charge => accumulate_charge_1, accumulate_charge_2, accumulate_charge_3
150 
152 
153 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
154 contains
155 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
156 
157  ! Initializer
159  self, &
160  bsplines_eta1, &
161  bsplines_eta2, &
162  breaks_eta1, &
163  breaks_eta2, &
164  mapping, &
165  coeffs1, &
166  coeffs2, &
167  tol, &
168  verbose)
169  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
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(:)
174  type(sll_t_singular_mapping_discrete), target, intent(in) :: mapping
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
179 
180  ! Polar B-splines
181  type(sll_t_polar_bsplines_2d) :: polar_bsplines
182 
183  ! Quadrature weights
184  real(wp), allocatable :: quad_weights_eta1(:, :)
185  real(wp), allocatable :: quad_weights_eta2(:, :)
186 
187  ! Auxiliary variables
188  integer :: i, j, k, i1, i2, k1, k2, q1, q2
189  real(wp) :: cx, cy, jdet, eta(2), jmat(2, 2)
190 
191  if (present(tol)) self%tol = tol
192  if (present(verbose)) self%verbose = verbose
193 
194  ! B-splines
195  self%bsplines_eta1 => bsplines_eta1
196  self%bsplines_eta2 => bsplines_eta2
197 
198  ! Smooth spline mapping
199  self%mapping => mapping
200 
201  ! Polar B-splines
202  call polar_bsplines%init(bsplines_eta1, bsplines_eta2, mapping)
203 
204  ! Number of degrees of freedom and spline degrees
205  self%n1 = bsplines_eta1%nbasis
206  self%n2 = bsplines_eta2%nbasis
207 
208  ! Initialize 2D splines for coefficients
209  call self%spline_2d_coeffs1%init(bsplines_eta1, bsplines_eta2)
210  call self%spline_2d_coeffs2%init(bsplines_eta1, bsplines_eta2)
211 
212  ! Initialize 2D spline interpolator
213  call self%spline_interp_2d%init( &
214  bsplines_eta1, &
215  bsplines_eta2, &
216  [sll_p_greville, sll_p_periodic], &
217  [sll_p_greville, sll_p_periodic])
218 
219  !---------------------------------------------------------------------------
220  ! Allocations
221  !---------------------------------------------------------------------------
222 
223  ! Number of finite elements
224  self%Nk1 = size(breaks_eta1) - 1
225  self%Nk2 = size(breaks_eta2) - 1
226 
227  ! Spline degrees
228  self%p1 = bsplines_eta1%degree
229  self%p2 = bsplines_eta2%degree
230 
231  ! Number of Gauss-Legendre quadrature points
232  self%Nq1 = 1 + self%p1
233  self%Nq2 = 1 + self%p2
234 
235  associate(n1 => self%n1, &
236  n2 => self%n2, &
237  p1 => self%p1, &
238  p2 => self%p2, &
239  nn => 3 + (self%n1 - 2)*self%n2, &
240  nk1 => self%Nk1, &
241  nk2 => self%Nk2, &
242  nq1 => self%Nq1, &
243  nq2 => self%Nq2)
244 
245  ! Quadrature points
246  allocate (self%quad_points_eta1(nq1, nk1))
247  allocate (self%quad_points_eta2(nq2, nk2))
248 
249  ! Quadrature weights
250  allocate (quad_weights_eta1(nq1, nk1))
251  allocate (quad_weights_eta2(nq2, nk2))
252 
253  ! 1D data
254  allocate (self%data_1d_eta1(nq1, 2, 1 + p1, nk1))
255  allocate (self%data_1d_eta2(nq2, 2, 1 + p2, nk2))
256 
257  ! 2D data
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))
263 
264  ! Barycentric coordinates
265  allocate (self%L(2, n2, 3))
266 
267  ! Right hand side
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))
270 
271  ! Solution
272  allocate (self%x(n1*n2))
273 
274  ! Allocatables for accumulation of point charge density
275  allocate (self%bspl1(1 + p1))
276  allocate (self%bspl2(1 + p2))
277 
278  !-------------------------------------------------------------------------
279  ! Initialize quadrature points and weights
280  !-------------------------------------------------------------------------
281 
282  ! Quadrature points and weights along s
283  do k1 = 1, nk1
284  self%quad_points_eta1(:, k1) = sll_f_gauss_legendre_points(nq1, breaks_eta1(k1), breaks_eta1(k1 + 1))
285  quad_weights_eta1(:, k1) = sll_f_gauss_legendre_weights(nq1, breaks_eta1(k1), breaks_eta1(k1 + 1))
286  end do
287 
288  ! Quadrature points and weights along theta
289  do k2 = 1, nk2
290  self%quad_points_eta2(:, k2) = sll_f_gauss_legendre_points(nq2, breaks_eta2(k2), breaks_eta2(k2 + 1))
291  quad_weights_eta2(:, k2) = sll_f_gauss_legendre_weights(nq2, breaks_eta2(k2), breaks_eta2(k2 + 1))
292  end do
293 
294  !-------------------------------------------------------------------------
295  ! Fill in 1D data
296  !-------------------------------------------------------------------------
297 
298  ! 1D data along s
299  do k1 = 1, nk1
300  do q1 = 1, nq1
301  call bsplines_eta1%eval_basis_and_n_derivs( &
302  x=self%quad_points_eta1(q1, k1), &
303  n=1, &
304  derivs=self%data_1d_eta1(q1, :, :, k1), &
305  jmin=i)
306  end do
307  end do
308 
309  ! 1D data along theta
310  do k2 = 1, nk2
311  do q2 = 1, nq2
312  call bsplines_eta2%eval_basis_and_n_derivs( &
313  x=self%quad_points_eta2(q2, k2), &
314  n=1, &
315  derivs=self%data_1d_eta2(q2, :, :, k2), &
316  jmin=i)
317  end do
318  end do
319 
320  !-------------------------------------------------------------------------
321  ! Fill in 2D data
322  !-------------------------------------------------------------------------
323 
324  ! Compute interpolant splines for 2D coefficients
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)
327 
328  ! 2D data
329  do k2 = 1, nk2
330  do k1 = 1, nk1
331  do q2 = 1, nq2
332  do q1 = 1, nq1
333 
334  eta = [self%quad_points_eta1(q1, k1), self%quad_points_eta2(q2, k2)]
335 
336  jdet = mapping%jdet(eta)
337  jmat = mapping%jmat(eta)
338 
339  ! Area associated to each quadrature point
340  self%int_volume(q1, q2, k1, k2) = abs(jdet)*quad_weights_eta1(q1, k1)*quad_weights_eta2(q2, k2)
341 
342  ! Inverse metric tensor
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) ! symmetry
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
348 
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))
351 
352  end do
353  end do
354  end do
355  end do
356 
357  !-------------------------------------------------------------------------
358  ! Matrix of barycentric coordinates
359  !-------------------------------------------------------------------------
360 
361  do i2 = 1, n2
362  do i1 = 1, 2
363 
364  ! Indices to access control points
365  i = (i1 - 1)*n2 + i2
366  j = (i - 1)/n2 + 1
367  k = modulo((i - 1), n2) + 1
368 
369  cx = mapping%spline_2d_x1%bcoef(j, k)
370  cy = mapping%spline_2d_x2%bcoef(j, k)
371 
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)
375 
376  end do
377  end do
378 
379  !-------------------------------------------------------------------------
380  ! Initialize assembler and projector
381  !-------------------------------------------------------------------------
382 
383  call self%assembler%init(n1, n2, p1, p2, self%weak_form)
384  call self%projector%init(n1, n2, p1, p2, self%L)
385 
386  !-------------------------------------------------------------------------
387  ! Fill in stiffness and mass matrices
388  !-------------------------------------------------------------------------
389 
390  ! Construct stencil linear operators
391  call self%A_linop_stencil%init(n1, n2, p1, p2)
392  call self%M_linop_stencil%init(n1, n2, p1, p2)
393 
394  ! Cycle over finite elements
395  do k2 = 1, nk2
396  do k1 = 1, nk1
397  call self%assembler%add_element_mat( &
398  k1, &
399  k2, &
400  self%data_1d_eta1, &
401  self%data_1d_eta2, &
402  self%int_volume, &
403  self%inv_metric, &
404  self%coeffs1, &
405  self%coeffs2, &
406  self%A_linop_stencil%A, &
407  self%M_linop_stencil%A)
408  end do
409  end do
410 
411  !-------------------------------------------------------------------------
412  ! Initialize linear system
413  !-------------------------------------------------------------------------
414 
415  ! Construct C1 block linear operators
416 
417  call self%Ap_linop_c1_block%init(n1, n2, p1, p2)
418  call self%Mp_linop_c1_block%init(n1, n2, p1, p2)
419 
420  !-------------------------------------------------------------------------
421  ! Compute C1 projections of stiffness and mass matrices
422  !-------------------------------------------------------------------------
423 
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)
426 
427  ! Construct C1 block vector space from vector xp
428 
429  call self%xp_vecsp_c1_block%init(n1 - 2, n2, p1, p2)
430 
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
435 
436  ! Initialize conjugate gradient solver
437  call self%cjsolver%init( &
438  tol=self%tol, &
439  verbose=self%verbose, &
440  template_vector=self%xp_vecsp_c1_block)
441 
442  ! Construct C1 block vector space for right hand side
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))
446 
447  end associate
448 
449  call polar_bsplines%free()
450 
452 
453  ! Set boundary conditions
455  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
456  integer, intent(in) :: bc
457 
458  integer :: i, j, i1, i2, j1, j2, k1, k2, nb
459 
460  character(len=*), parameter :: this_sub_name = "sll_t_qn_solver_2d_fem_sps_stencil_new % set_boundary_conditions"
461 
462  if (bc == sll_p_dirichlet) then
463 
464  associate(n1 => self%n1, &
465  n2 => self%n2, &
466  p1 => self%p1, &
467  p2 => self%p2)
468 
469  nb = (n1 - 2)*n2
470 
471  ! Homogeneous Dirichlet boundary conditions
472  do i2 = 1, n2
473  do i1 = 1, n1 - 2
474  do k2 = -p2, p2
475  do k1 = -p1, p1
476  j1 = i1 + k1
477  j2 = modulo(i2 - 1 + k2, n2) + 1
478  i = (i1 - 1)*n2 + i2
479  j = (j1 - 1)*n2 + j2
480  ! Check range of indices i and j
481  if (i > nb - n2 .or. j > nb - n2) &
482  self%Ap_linop_c1_block%block4%A(k1, k2, i1, i2) = 0.0_wp
483  end do
484  end do
485  end do
486  end do
487 
488  end associate
489 
490  else
491  sll_error(this_sub_name, "Boundary conditions not implemented")
492 
493  end if
494 
496 
498  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
499 
500  self%bs%array(:, :) = 0.0_wp
501 
503 
504  ! Accumulate charge: signature #1
506  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
507  procedure(i_fun_rhs) :: rhs
508 
509  ! Auxiliary variables
510  integer :: k1, k2, q1, q2
511  real(wp) :: eta(2), x(2)
512 
513  associate(n1 => self%n1, &
514  n2 => self%n2, &
515  nk1 => self%Nk1, &
516  nk2 => self%Nk2, &
517  nq1 => self%Nq1, &
518  nq2 => self%Nq2)
519 
520  ! 2D discrete RHS
521  do k2 = 1, nk2
522  do k1 = 1, nk1
523  do q2 = 1, nq2
524  do q1 = 1, nq1
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)
528  end do
529  end do
530  end do
531  end do
532 
533  ! Cycle over finite elements
534  do k2 = 1, nk2
535  do k1 = 1, nk1
536  call self%assembler%add_element_rhs( &
537  k1, &
538  k2, &
539  self%data_1d_eta1, &
540  self%data_1d_eta2, &
541  self%data_2d_rhs, &
542  self%int_volume, &
543  self%bs%array(1:n1, 1:n2))
544  end do
545  end do
546 
547  end associate
548 
550 
551  ! Accumulate charge: signature #2
553  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
554  type(sll_t_spline_2d), intent(in) :: rhs
555 
556  associate(n1 => self%n1, n2 => self%n2)
557 
558  ! Store temporarily spline coefficients of right hand side into self % b
559  self%bs_tmp%array(:, :) = 0.0_wp
560  self%bs_tmp%array(1:n1, 1:n2) = rhs%bcoef(1:n1, 1:n2)
561 
562  call self%M_linop_stencil%dot_incr(self%bs_tmp, self%bs)
563 
564  end associate
565 
567 
568  ! Accumulate charge: signature #3
569  subroutine s_qn_solver_2d_fem_sps_stencil_new__accumulate_charge_3(self, intensity, location)
570  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
571  real(wp), intent(in) :: intensity
572  real(wp), intent(in) :: location(2)
573 
574  integer :: i1, i2, j1, j2, jmin1, jmin2
575 
576  associate(n1 => self%n1, &
577  n2 => self%n2, &
578  p1 => self%p1, &
579  p2 => self%p2, &
580  qc => intensity, &
581  sc => location(1), &
582  tc => location(2))
583 
584  call self%bsplines_eta1%eval_basis(sc, self%bspl1(:), jmin1)
585  call self%bsplines_eta2%eval_basis(tc, self%bspl2(:), jmin2)
586 
587  i2 = 1
588  do j2 = jmin2, jmin2 + p2
589  i1 = 1
590  do j1 = jmin1, jmin1 + p1
591  self%bs%array(j1, j2) = self%bs%array(j1, j2) + qc*self%bspl1(i1)*self%bspl2(i2)
592  i1 = i1 + 1
593  end do
594  i2 = i2 + 1
595  end do
596 
597  end associate
598 
600 
601  ! Solver
603  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
604  type(sll_t_spline_2d), intent(inout) :: sol
605 
606  integer :: j2, i1, i2, i
607 
608  associate(n1 => self%n1, &
609  n2 => self%n2, &
610  p1 => self%p1, &
611  p2 => self%p2)
612 
613  ! Compute C1 projection of right hand side
614  call self%projector%change_basis_vector(self%bs%array(1:n1, 1:n2), self%bp_vecsp_c1_block)
615 
616  ! Homogeneous Dirichlet boundary conditions
617  do j2 = 1, n2
618  self%bp_vecsp_c1_block%vs%array(n1 - 2, j2) = 0.0_wp
619  end do
620 
621  ! Update buffer regions
622  self%bp_vecsp_c1_block%vs%array(1 - p1:0, :) = 0.0_wp ! no periodicity
623  self%bp_vecsp_c1_block%vs%array((n1 - 2) + 1:(n1 - 2) + p1, :) = 0.0_wp ! no periodicity
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)
626 
627  ! Set output vector (and first guess) to zero (no garbage)
628  self%xp_vecsp_c1_block%vs%array(:, :) = 0.0_wp
629  self%xp_vecsp_c1_block%vd%array(:) = 0.0_wp
630 
631  ! Solve linear system Ap*xp=bp
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)
636 
637  ! Compute solution in tensor-product space
638  call self%projector%change_basis_vector_inv(self%xp_vecsp_c1_block, self%x)
639 
640  do i2 = 1, n2
641  do i1 = 1, n1
642  i = (i1 - 1)*n2 + i2
643  sol%bcoef(i1, i2) = self%x(i)
644  end do
645  end do
646  sol%bcoef(:, n2 + 1:n2 + p2) = sol%bcoef(:, 1:p2)
647 
648  end associate
649 
651 
652  ! Free
654  class(sll_t_qn_solver_2d_fem_sps_stencil_new), intent(inout) :: self
655 
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)
662  deallocate (self%L)
663  deallocate (self%x)
664  deallocate (self%bs%array)
665  deallocate (self%bs_tmp%array)
666 
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)
673 
674  call self%projector%free()
675 
676  call self%cjsolver%free()
677 
678  call self%spline_2d_coeffs1%free()
679  call self%spline_2d_coeffs2%free()
680 
682 
Access point to B-splines of arbitrary degree providing factory function.
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__init(self, bsplines_eta1, bsplines_eta2, breaks_eta1, breaks_eta2, mapping, coeffs1, coeffs2, tol, verbose)
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.
2D tensor-product spline
    Report Typos and Errors