Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_maxwell_clamped_3d_fem.F90
Go to the documentation of this file.
1 
9 
11  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 #include "sll_assert.h"
13 #include "sll_errors.h"
14 #include "sll_memory.h"
15 #include "sll_working_precision.h"
16 
17  use sll_m_collective, only: &
20 
23 
24  use sll_m_linear_operator_block, only : &
26 
27  use sll_m_linear_operator_kron, only : &
29 
32 
35 
36  use sll_m_linear_solver_cg, only : &
38 
39  use sll_m_linear_solver_kron, only : &
41 
42  use sll_m_low_level_bsplines, only: &
43  sll_s_uniform_bsplines_eval_basis
44 
45  use sll_m_matrix_csr, only: &
47 
48  use sll_m_maxwell_3d_base, only: &
51 
52  use sll_m_preconditioner_fft, only : &
54 
55  use sll_m_preconditioner_singular, only : &
57 
58  use sll_m_profile_functions, only: &
60 
61  use sll_m_spline_fem_utilities, only : &
65 
71 
74 
81 
82  use sll_m_splines_pp, only: &
87 
88  implicit none
89 
90 
91  public :: &
93 
94  private
95  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
96 
98 
99  type(sll_t_spline_pp_1d), pointer :: spline0_pp
100  type(sll_t_spline_pp_1d), pointer :: spline1_pp
101  sll_real64, allocatable :: work0(:)
102  sll_real64, allocatable :: work01(:)
103  sll_real64, allocatable :: work1(:)
104  sll_real64, allocatable :: work12(:)
105  sll_real64, allocatable :: work2(:)
106  sll_real64, allocatable :: work22(:)
107 
108  sll_real64, allocatable :: work3d(:,:,:)
109  sll_real64, allocatable :: work_d1(:)
110  sll_real64, allocatable :: work_d2_in(:)
111  sll_real64, allocatable :: work_d2_out(:)
112  sll_real64, allocatable :: work_d3_in(:)
113  sll_real64, allocatable :: work_d3_out(:)
114  type(sll_t_matrix_csr) :: mass1d(3,3)
115  type(sll_t_matrix_csr) :: mass0
116 
117  type(sll_t_linear_operator_kron) :: mass1(3)
118  type(sll_t_linear_operator_kron) :: mass2(3)
119  type(sll_t_linear_solver_cg) :: mass1d_solver(2,3)
120  type(sll_t_linear_solver_kron) :: mass_1_solver(3)
121  type(sll_t_linear_solver_kron) :: mass_2_solver(3)
122  type(sll_t_linear_operator_block) :: mass1_operator
123  type(sll_t_linear_operator_block) :: mass2_operator
124  type(sll_t_linear_solver_cg) :: mass0_solver
125  type(sll_t_linear_solver_cg) :: mass1_solver
126  type(sll_t_linear_solver_cg) :: mass2_solver
127  type(sll_t_preconditioner_fft) :: preconditioner_fft
128  type(sll_t_preconditioner_singular) :: preconditioner1
129  type(sll_t_preconditioner_singular) :: preconditioner2
130 
131 
133  type(sll_t_linear_solver_cg) :: poisson_solver
134 
135  type( sll_t_linear_operator_schur_eb_cl_3d ) :: linear_op_schur_eb
136  type( sll_t_linear_solver_cg ) :: linear_solver_schur_eb
137  logical :: adiabatic_electrons = .false.
138 
139  contains
140  procedure :: &
141  compute_e_from_b => sll_s_compute_e_from_b_3d_fem
142  procedure :: &
143  compute_b_from_e => sll_s_compute_b_from_e_3d_fem
144  procedure :: &
145  compute_curl_part => sll_s_compute_curl_part_3d_fem
146  procedure :: &
147  compute_e_from_rho => sll_s_compute_e_from_rho_3d_fem
148  procedure :: &
149  compute_rho_from_e => sll_s_compute_rho_from_e_3d_fem
150  procedure :: &
151  compute_e_from_j => sll_s_compute_e_from_j_3d_fem
152  procedure :: &
153  compute_phi_from_rho => sll_s_compute_phi_from_rho_3d_fem
154  procedure :: &
155  compute_phi_from_j => sll_s_compute_phi_from_j_3d_fem
156  procedure :: &
157  compute_rhs_from_function => sll_s_compute_rhs_fem
158  procedure :: &
159  l2projection => l2projection_3d_fem
160  procedure :: &
161  l2norm_squared => l2norm_squared_3d_fem
162  procedure :: &
164  procedure :: &
165  init => init_3d_fem
166  procedure :: &
167  init_from_file => init_from_file_3d_fem
168  procedure :: &
169  free => free_3d_fem
170  procedure :: &
171  multiply_g
172  procedure :: &
174  procedure :: &
175  multiply_c
176  procedure :: &
178  procedure :: &
180  procedure :: &
182  procedure :: &
184 
186 
187 contains
188 
189 
191  subroutine sll_s_compute_e_from_b_3d_fem(self, delta_t, field_in, field_out)
192  class(sll_t_maxwell_clamped_3d_fem) :: self
193  sll_real64, intent(in) :: delta_t
194  sll_real64, intent(in) :: field_in(:)
195  sll_real64, intent(inout) :: field_out(:)
196 
197  !call self%mass2_operator%dot( field_in, self%work2 )
198  call self%multiply_mass( [2], field_in, self%work2 )
199  call self%multiply_ct( self%work2, self%work1 )
200 
201  call self%multiply_mass_inverse( 1, self%work1, self%work12 )
202 
203  ! Update E from self value
204  field_out = field_out + delta_t*self%work12
205 
206  end subroutine sll_s_compute_e_from_b_3d_fem
207 
208 
210  subroutine sll_s_compute_b_from_e_3d_fem(self, delta_t, field_in, field_out)
211  class(sll_t_maxwell_clamped_3d_fem) :: self
212  sll_real64, intent(in) :: delta_t
213  sll_real64, intent(in) :: field_in(:) ! E
214  sll_real64, intent(inout) :: field_out(:) ! B
215 
216  call self%multiply_c( field_in, self%work2 )
217  ! Update Bz from self value
218  field_out = field_out - delta_t * self%work2
219 
220  end subroutine sll_s_compute_b_from_e_3d_fem
221 
222 
224  subroutine sll_s_compute_curl_part_3d_fem( self, delta_t, efield, bfield, betar )
225  class(sll_t_maxwell_clamped_3d_fem) :: self
226  sll_real64, intent(in) :: delta_t
227  sll_real64, intent(inout) :: efield(:)
228  sll_real64, intent(inout) :: bfield(:)
229  sll_real64, optional :: betar
230  !local variables
231  sll_real64 :: factor
232 
233  if( present(betar) ) then
234  factor = betar
235  else
236  factor = 1._f64
237  end if
238 
239  self%work0 = 0._f64
240  self%work1 = 0._f64
241  self%work12 = 0._f64
242  self%work2 = 0._f64
243 
244  ! Compute C^T M2 b
245  call self%multiply_mass( [2], bfield, self%work2 )
246  call self%multiply_ct( self%work2, self%work1 )
247 
248 
249  self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
250  call self%linear_op_schur_eb%dot( efield, self%work12 )
251  self%work12 = self%work12 + delta_t*factor*self%work1
252 
253  ! Save efield dofs from previous time step for B field update
254  self%work1 = efield
255 
256  ! Invert Schur complement matrix
257  self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
258  call self%linear_solver_schur_eb%set_guess( efield )
259  call self%linear_solver_schur_eb%solve( self%work12, efield)
260 
261  ! Update B field
262  self%work1 = self%work1 + efield
263  call self%compute_B_from_E( delta_t*0.5_f64, self%work1, bfield)
264 
265  end subroutine sll_s_compute_curl_part_3d_fem
266 
267 
269  subroutine sll_s_compute_e_from_rho_3d_fem( self, field_in, field_out )
270  class(sll_t_maxwell_clamped_3d_fem) :: self
271  sll_real64, intent( in ) :: field_in(:)
272  sll_real64, intent( out ) :: field_out(:)
273 
274  call self%poisson_solver%solve( field_in, self%work0 )
275 
276  call self%multiply_g( self%work0, field_out )
277  field_out = -field_out
278 
279 
280  end subroutine sll_s_compute_e_from_rho_3d_fem
281 
282 
284  subroutine sll_s_compute_rho_from_e_3d_fem( self, field_in, field_out )
285  class(sll_t_maxwell_clamped_3d_fem) :: self
286  sll_real64, intent( in ) :: field_in(:)
287  sll_real64, intent( out ) :: field_out(:)
288 
289  call self%multiply_mass( [1], field_in, self%work1 )
290  call self%multiply_gt( self%work1, field_out )
291  field_out = - field_out
292 
293  end subroutine sll_s_compute_rho_from_e_3d_fem
294 
295 
297  subroutine sll_s_compute_e_from_j_3d_fem( self, current, E, component )
298  class(sll_t_maxwell_clamped_3d_fem) :: self
299  sll_real64, intent( in ) :: current(:)
300  sll_real64, intent( inout ) :: e(:)
301  sll_int32, intent( in ), optional :: component
302  !local variable
303  sll_int32 :: i
304 
305  if( present(component) )then
306  if (component == 1) then
307  call self%mass_1_solver(component)%solve( current, self%work01 )
308  e = e - self%work01
309  else
310  call self%mass_1_solver(component)%solve( current, self%work0 )
311  do i = 1, self%n_dofs(2)*self%n_dofs(3)
312  self%work0(1+(i-1)*self%n_dofs(1)) = 0._f64
313  self%work0(i*self%n_dofs(1)) = 0._f64
314  end do
315  e = e - self%work0
316 
317  end if
318  else
319  call self%multiply_mass_inverse( 1, current, self%work1 )
320  e = e - self%work1
321  end if
322 
323  end subroutine sll_s_compute_e_from_j_3d_fem
324 
325 
327  subroutine sll_s_compute_phi_from_rho_3d_fem( self, field_in, field_out, efield_dofs )
328  class(sll_t_maxwell_clamped_3d_fem) :: self
329  sll_real64, intent( in ) :: field_in(:)
330  sll_real64, intent( inout ) :: field_out(:)
331  sll_real64, intent( out ) :: efield_dofs(:)
332 
333  call self%multiply_mass_inverse( 0, field_in, field_out )
334  call self%multiply_g( field_out, efield_dofs )
335  efield_dofs = -efield_dofs
336 
337  end subroutine sll_s_compute_phi_from_rho_3d_fem
338 
339 
341  subroutine sll_s_compute_phi_from_j_3d_fem( self, field_in, field_out, efield_dofs )
342  class(sll_t_maxwell_clamped_3d_fem) :: self
343  sll_real64, intent( in ) :: field_in(:)
344  sll_real64, intent( inout ) :: field_out(:)
345  sll_real64, intent( out ) :: efield_dofs(:)
346 
347  call self%multiply_gt( field_in, self%work0 )
348  call self%multiply_mass_inverse( 0, self%work0, self%work1(1:self%n_total0) )
349  field_out = field_out + self%work1(1:self%n_total0)
350 
351  call self%multiply_g( field_out, efield_dofs )
352  efield_dofs = -efield_dofs
353 
354  end subroutine sll_s_compute_phi_from_j_3d_fem
355 
356 
359  subroutine sll_s_compute_rhs_fem(self, form, component, coefs_dofs, func1, func2, func3)
360  class(sll_t_maxwell_clamped_3d_fem) :: self
361  sll_int32, intent( in ) :: form
362  sll_int32, intent( in ) :: component
363  sll_real64, intent( out ) :: coefs_dofs(:)
364  procedure(sll_i_function_3d_real64) :: func1
365  procedure(sll_i_function_3d_real64), optional :: func2
366  procedure(sll_i_function_3d_real64), optional :: func3
367  ! local variables
368  sll_int32 :: i1, i2, i3, j1, j2, j3, k1, k2, k3
369  sll_int32 :: degree(3), q(3), index1d
370  sll_real64, allocatable :: xw_gauss_d1(:,:), xw_gauss_d2(:,:), xw_gauss_d3(:,:)
371  sll_real64, allocatable :: bspl_d1(:,:), bspl_d2(:,:), bspl_d3(:,:)
372 
373  q= 2*self%s_deg_0+1
374 
375  ! Define the spline degree in the 3 dimensions, depending on form and component of the form
376  if ( form == 0 ) then
377  degree = self%s_deg_0
378  elseif (form == 1 ) then
379  degree = self%s_deg_0
380  degree(component) = self%s_deg_1(component)
381  elseif( form == 2) then
382  degree = self%s_deg_1
383  degree(component) = self%s_deg_0(component)
384  elseif( form == 3) then
385  degree = self%s_deg_1
386  else
387  print*, 'Wrong form.'
388  end if
389 
390  allocate(xw_gauss_d3(2,q(3)))
391  allocate(bspl_d3(degree(3)+1, q(3)))
392  xw_gauss_d3 = sll_f_gauss_legendre_points_and_weights(q(3), 0.0_f64, 1.0_f64)
393  ! Compute bsplines at gauss_points
394  do k3=1, q(3)
395  call sll_s_uniform_bsplines_eval_basis(degree(3),xw_gauss_d3(1,k3), bspl_d3(:,k3))
396  end do
397 
398 
399  allocate(xw_gauss_d2(2, q(2)))
400  allocate(bspl_d2(degree(2)+1, q(2)))
401  xw_gauss_d2 = sll_f_gauss_legendre_points_and_weights(q(2), 0.0_f64, 1.0_f64)
402  ! Compute bsplines at gauss_points
403  do k2=1, q(2)
404  call sll_s_uniform_bsplines_eval_basis(degree(2),xw_gauss_d2(1,k2), bspl_d2(:,k2))
405  end do
406 
407  ! rescale on [0,1] for compatibility with B-splines
408  allocate(xw_gauss_d1(2,q(1)))
409  allocate(bspl_d1(degree(1)+1, q(1)))
410  xw_gauss_d1 = sll_f_gauss_legendre_points_and_weights(q(1), 0.0_f64, 1.0_f64)
411 
412  if( degree(1) == self%s_deg_0(1) ) then
413  ! Compute bsplines at gauss_points
414  bspl_d1 = 0._f64
415  do k1=1, q(1)
416  do j1=1, degree(1)+1
417  bspl_d1(j1,k1) = sll_f_spline_pp_horner_1d( degree(1), self%spline0_pp%poly_coeffs, xw_gauss_d1(1,k1), j1)
418  end do
419  end do
420  coefs_dofs = 0._f64
421  ! Compute coefs_dofs = int f(x)N_i(x)
422  !loop over cells
423  do i3 = 1, self%n_cells(3)
424  do i2 = 1, self%n_cells(2)
425  !! divide in i1=1, degree-1, degree,n_cells-degree+1,
426  do i1 = 1, degree(1)-1
427  ! loop over support of B spline
428  do j3 = 1, degree(3)+1
429  do j2 = 1, degree(2)+1
430  do j1 = 1, degree(1)+1
431  index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*self%n_dofs(1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*self%n_dofs(1)*self%n_cells(2)
432  ! loop over Gauss points
433  do k3=1, q(3)
434  do k2=1, q(2)
435  do k1=1, q(1)
436  coefs_dofs(index1d) = coefs_dofs(index1d) + &
437  self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
438  xw_gauss_d3(2,k3) *&
439  func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
440  sll_f_spline_pp_horner_1d( degree(1), self%spline0_pp%poly_coeffs_boundary_left(:,:,i1), xw_gauss_d1(1,k1), j1)*&
441  bspl_d2(j2,k2)*&
442  bspl_d3(j3,k3)
443 
444  enddo
445  enddo
446  end do
447  end do
448  end do
449  end do
450  enddo
451  do i1 = degree(1), self%n_cells(1)+1-degree(1)
452  ! loop over support of B spline
453  do j3 = 1, degree(3)+1
454  do j2 = 1, degree(2)+1
455  do j1 = 1, degree(1)+1
456  index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*self%n_dofs(1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*self%n_dofs(1)*self%n_cells(2)
457  ! loop over Gauss points
458  do k3=1, q(3)
459  do k2=1, q(2)
460  do k1=1, q(1)
461  coefs_dofs(index1d) = coefs_dofs(index1d) + &
462  self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
463  xw_gauss_d3(2,k3) *&
464  func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
465  bspl_d1(j1,k1)*&
466  bspl_d2(j2,k2)*&
467  bspl_d3(j3,k3)
468 
469  enddo
470  enddo
471  end do
472  end do
473  end do
474  end do
475  enddo
476  do i1 = self%n_cells(1)-degree(1)+2, self%n_cells(1)
477  ! loop over support of B spline
478  do j3 = 1, degree(3)+1
479  do j2 = 1, degree(2)+1
480  do j1 = 1, degree(1)+1
481  index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*self%n_dofs(1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*self%n_dofs(1)*self%n_cells(2)
482  ! loop over Gauss points
483  do k3=1, q(3)
484  do k2=1, q(2)
485  do k1=1, q(1)
486  coefs_dofs(index1d) = coefs_dofs(index1d) + &
487  self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
488  xw_gauss_d3(2,k3) *&
489  func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
490  sll_f_spline_pp_horner_1d( degree(1), self%spline0_pp%poly_coeffs_boundary_right(:,:,i1-self%n_cells(1)+degree(1)-1), xw_gauss_d1(1,k1), j1)*&
491  bspl_d2(j2,k2)*&
492  bspl_d3(j3,k3)
493 
494  enddo
495  enddo
496  end do
497  end do
498  end do
499  end do
500  enddo
501  end do
502  end do
503 
504  else if (degree(1) == self%s_deg_1(1))then
505  bspl_d1 = 0._f64
506  ! Compute bsplines at gauss_points
507  do k1=1, q(1)
508  do j1=1, degree(1)+1
509  bspl_d1(j1,k1) = sll_f_spline_pp_horner_1d( degree(1), self%spline1_pp%poly_coeffs, xw_gauss_d1(1,k1), j1)
510  end do
511  end do
512  coefs_dofs = 0._f64
513  ! Compute coefs_dofs = int f(x)N_i(x)
514  !loop over cells
515  do i3 = 1, self%n_cells(3)
516  do i2 = 1, self%n_cells(2)
517  !! divide in i1=1, degree-1, degree,n_cells-degree+1,
518  do i1 = 1, degree(1)-1
519  ! loop over support of B spline
520  do j3 = 1, degree(3)+1
521  do j2 = 1, degree(2)+1
522  do j1 = 1, degree(1)+1
523  index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*(self%n_dofs(1)-1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*(self%n_dofs(1)-1)*self%n_cells(2)
524  ! loop over Gauss points
525  do k3=1, q(3)
526  do k2=1, q(2)
527  do k1=1, q(1)
528  coefs_dofs(index1d) = coefs_dofs(index1d) + &
529  self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
530  xw_gauss_d3(2,k3) *&
531  func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
532  sll_f_spline_pp_horner_1d( degree(1), self%spline1_pp%poly_coeffs_boundary_left(:,:,i1), xw_gauss_d1(1,k1), j1)*&
533  bspl_d2(j2,k2)*&
534  bspl_d3(j3,k3)
535 
536  enddo
537  enddo
538  end do
539  end do
540  end do
541  end do
542  enddo
543  do i1 = degree(1), self%n_cells(1)+1-degree(1)
544  ! loop over support of B spline
545  do j3 = 1, degree(3)+1
546  do j2 = 1, degree(2)+1
547  do j1 = 1, degree(1)+1
548  index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*(self%n_dofs(1)-1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*(self%n_dofs(1)-1)*self%n_cells(2)
549  ! loop over Gauss points
550  do k3=1, q(3)
551  do k2=1, q(2)
552  do k1=1, q(1)
553  coefs_dofs(index1d) = coefs_dofs(index1d) + &
554  self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
555  xw_gauss_d3(2,k3) *&
556  func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
557  bspl_d1(j1,k1)*&
558  bspl_d2(j2,k2)*&
559  bspl_d3(j3,k3)
560 
561  enddo
562  enddo
563  end do
564  end do
565  end do
566  end do
567  enddo
568  do i1 = self%n_cells(1)-degree(1)+2, self%n_cells(1)
569  ! loop over support of B spline
570  do j3 = 1, degree(3)+1
571  do j2 = 1, degree(2)+1
572  do j1 = 1, degree(1)+1
573  index1d=i1+j1-1+modulo(i2-degree(2)+j2-2,self%n_cells(2))*(self%n_dofs(1)-1)+modulo(i3-degree(3)+j3-2,self%n_cells(3))*(self%n_dofs(1)-1)*self%n_cells(2)
574  ! loop over Gauss points
575  do k3=1, q(3)
576  do k2=1, q(2)
577  do k1=1, q(1)
578  coefs_dofs(index1d) = coefs_dofs(index1d) + &
579  self%volume * xw_gauss_d1(2,k1)* xw_gauss_d2(2,k2)* &
580  xw_gauss_d3(2,k3) *&
581  func1([ self%delta_x(1)*(xw_gauss_d1(1,k1)+ real(i1 - 1,f64)), self%delta_x(2)*(xw_gauss_d2(1,k2) + real(i2-1,f64)), self%delta_x(3)*(xw_gauss_d3(1,k3) + real(i3-1,f64))] ) * &
582  sll_f_spline_pp_horner_1d( degree(1), self%spline1_pp%poly_coeffs_boundary_right(:,:,i1-self%n_cells(1)+degree(1)-1), xw_gauss_d1(1,k1), j1)*&
583  bspl_d2(j2,k2)*&
584  bspl_d3(j3,k3)
585 
586  enddo
587  enddo
588  end do
589  end do
590  end do
591  end do
592  enddo
593  end do
594  end do
595  else
596  print*, "error in compute rhs"
597  end if
598 
599  end subroutine sll_s_compute_rhs_fem
600 
601 
603  subroutine l2projection_3d_fem(self, form, component, coefs_dofs, func1, func2, func3 )
604  class(sll_t_maxwell_clamped_3d_fem) :: self
605  sll_int32, intent( in ) :: form
606  sll_int32, intent( in ) :: component
607  sll_real64, intent( out ) :: coefs_dofs(:)
608  procedure(sll_i_function_3d_real64) :: func1
609  procedure(sll_i_function_3d_real64), optional :: func2
610  procedure(sll_i_function_3d_real64), optional :: func3
611  !local variables
612  sll_int32 :: j
613 
614  if( present(func2) .and. present(func3) ) then
615  select case( form )
616  case( 1 )
617  ! Compute right-hand-side
618  call sll_s_compute_rhs_fem( self, 1, 1, self%work1(1:self%n_total1), func1 )
619  call sll_s_compute_rhs_fem( self, 1, 2, self%work1(1+self%n_total1:self%n_total1+self%n_total0), func2 )
620  call sll_s_compute_rhs_fem( self, 1, 3, self%work1(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0), func3 )
621  call self%multiply_mass_inverse( 1, self%work1, coefs_dofs )
622  case( 2 )
623  ! Compute right-hand-side
624  call sll_s_compute_rhs_fem( self, 2, 1, self%work2(1:self%n_total0), func1 )
625  call sll_s_compute_rhs_fem( self, 2, 2, self%work2(1+self%n_total0:self%n_total0+self%n_total1), func2 )
626  call sll_s_compute_rhs_fem( self, 2, 3, self%work2(1+self%n_total0+self%n_total1:self%n_total0+2*self%n_total1), func3 )
627  call self%multiply_mass_inverse( 2, self%work2, coefs_dofs )
628  case default
629  print*, 'L2projection for', form, '-form not implemented.'
630  stop
631  end select
632  else
633  select case( form )
634  case( 0 )
635  ! Compute right-hand-side
636  call sll_s_compute_rhs_fem( self, form, 0, self%work0, func1 )
637  call self%multiply_mass_inverse( 0, self%work0, coefs_dofs )
638  case( 1 )
639  if( component == 1)then
640  ! Compute right-hand-side
641  call sll_s_compute_rhs_fem( self, form, component, self%work01, func1 )
642  call self%mass_1_solver(component)%solve( self%work01, coefs_dofs )
643  else
644  ! Compute right-hand-side
645  call sll_s_compute_rhs_fem( self, form, component, self%work0, func1 )
646  call self%mass_1_solver(component)%solve( self%work0, coefs_dofs )
647  do j = 1, self%n_dofs(2)*self%n_dofs(3)
648  coefs_dofs(1+(j-1)*self%n_dofs(1)) = 0._f64
649  coefs_dofs(j*self%n_dofs(1)) = 0._f64
650  end do
651  end if
652  case( 2 )
653  if( component == 1)then
654  ! Compute right-hand-side
655  call sll_s_compute_rhs_fem( self, form, component, self%work0, func1 )
656  call self%mass_2_solver(component)%solve( self%work0, coefs_dofs )
657  do j = 1, self%n_dofs(2)*self%n_dofs(3)
658  coefs_dofs(1+(j-1)*self%n_dofs(1)) = 0._f64
659  coefs_dofs(j*self%n_dofs(1)) = 0._f64
660  end do
661  else
662  ! Compute right-hand-side
663  call sll_s_compute_rhs_fem( self, form, component, self%work01, func1 )
664  call self%mass_2_solver(component)%solve( self%work01, coefs_dofs )
665  end if
666  case default
667  print*, 'L2projection for', form, '-form not implemented.'
668  stop
669  end select
670  end if
671 
672 
673  end subroutine l2projection_3d_fem
674 
675 
677  function l2norm_squared_3d_fem( self, coefs, form, component) result (r)
678  class(sll_t_maxwell_clamped_3d_fem) :: self
679  sll_real64 :: coefs(:)
680  sll_int32 :: form
681  sll_int32 :: component
682 
683  sll_real64 :: r
684 
685  r = inner_product_3d_fem(self, coefs, coefs, form, component)
686 
687  end function l2norm_squared_3d_fem
688 
689 
691  function inner_product_3d_fem( self, coefs1, coefs2, form, component ) result ( r )
692  class(sll_t_maxwell_clamped_3d_fem) :: self
693  sll_real64 :: coefs1(:)
694  sll_real64 :: coefs2(:)
695  sll_int32 :: form
696  sll_int32, optional :: component
697  sll_real64 :: r
698  !local variables
699  sll_int32 :: deg(3)
700 
701  if ( form == 0 ) then
702  call self%multiply_mass( [0], coefs2, self%work0 )
703  r = sum(coefs1*self%work0)
704  elseif (form == 1 ) then
705  deg = 1
706  deg(component) = 2
707  if( component == 1)then
708  call multiply_mass_3dkron( self, deg, coefs2, self%work01 )
709  r = sum(coefs1*self%work01)
710  else
711  call multiply_mass_3dkron( self, deg, coefs2, self%work0 )
712  r = sum(coefs1*self%work0)
713  end if
714  elseif( form == 2) then
715  deg = 2
716  deg(component) = 1
717  if( component == 1)then
718  call multiply_mass_3dkron( self, deg, coefs2, self%work0 )
719  r = sum(coefs1*self%work0)
720  else
721  call multiply_mass_3dkron( self, deg, coefs2, self%work01 )
722  r = sum(coefs1*self%work01)
723  end if
724  elseif( form == 3) then
725  deg = 2
726  call multiply_mass_3dkron( self, deg, coefs2, self%work0 )
727  r = sum(coefs1*self%work0)
728  else
729  print*, 'Wrong form.'
730  end if
731 
732  end function inner_product_3d_fem
733 
734 
736  subroutine init_3d_fem( self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile )
737  class(sll_t_maxwell_clamped_3d_fem), intent(inout) :: self
738  sll_real64, intent(in) :: domain(3,2)
739  sll_int32, intent(in) :: n_cells(3)
740  sll_int32, intent(in) :: s_deg_0(3)
741  sll_int32, intent( in ) :: boundary(3)
742  sll_real64, intent(in), optional :: mass_tolerance
743  sll_real64, intent(in), optional :: poisson_tolerance
744  sll_real64, intent(in), optional :: solver_tolerance
745  logical, intent(in), optional :: adiabatic_electrons
746  type(sll_t_profile_functions), intent(in), optional :: profile
747  ! local variables
748  sll_int32 :: j,k, deg(3)
749  sll_real64 :: mass_line_b0((s_deg_0(1)+1)*s_deg_0(1)), mass_line_b1(s_deg_0(1)*(s_deg_0(1)-1))
750  sll_real64, allocatable :: mass_line_0(:), mass_line_1(:), mass_line_mixed(:)
751 
752  if( present( mass_tolerance) ) then
753  self%mass_solver_tolerance = mass_tolerance
754  else
755  self%mass_solver_tolerance = 1d-12
756  end if
757  if( present( poisson_tolerance) ) then
758  self%poisson_solver_tolerance = poisson_tolerance
759  else
760  self%poisson_solver_tolerance = 1d-12
761  end if
762  if (present( solver_tolerance) ) then
763  self%solver_tolerance = solver_tolerance
764  else
765  self%solver_tolerance = 1d-12
766  end if
767 
768  if( present( adiabatic_electrons ) ) then
769  self%adiabatic_electrons = adiabatic_electrons
770  end if
771 
772  if( present( profile ) ) then
773  self%profile = profile
774  end if
775 
776  self%n_cells = n_cells
777  self%n_dofs = n_cells
778  self%n_dofs(1) = n_cells(1)+s_deg_0(1)
779  self%n_total = product(n_cells)
780  self%n_total0 = product(self%n_dofs)
781  self%n_total1 = (self%n_dofs(1)-1)*n_cells(2)*n_cells(3)
782  self%Lx = domain(:,2) - domain(:,1)
783  self%delta_x = self%Lx / real(n_cells, f64)
784  self%s_deg_0 = s_deg_0
785  self%s_deg_1 = s_deg_0 - 1
786  self%volume = product(self%delta_x)
787 
788  allocate( self%spline0_pp )
789  allocate( self%spline1_pp )
790  call sll_s_spline_pp_init_1d( self%spline0_pp, s_deg_0(1), self%n_cells(1), boundary(1))
791  call sll_s_spline_pp_init_1d( self%spline1_pp, s_deg_0(1)-1, self%n_cells(1), boundary(1))
792 
793 
794  ! Allocate scratch data
795  allocate(self%work0(1:self%n_total0))
796  allocate(self%work01(1:self%n_total1))
797  allocate(self%work1(1:self%n_total1+2*self%n_total0))
798  allocate(self%work12(1:self%n_total1+2*self%n_total0))
799  allocate(self%work2(1:self%n_total0+2*self%n_total1))
800  allocate(self%work22(1:self%n_total0+2*self%n_total1))
801  allocate( self%work_d2_in( n_cells(2) ) )
802  allocate( self%work_d2_out( n_cells(2) ) )
803  allocate( self%work_d3_in( n_cells(3) ) )
804  allocate( self%work_d3_out( n_cells(3) ) )
805 
806  ! Sparse matrices
807  ! Assemble the mass matrices
808  ! First assemble a mass line for both degrees
809  ! Next put together the 1d parts of the 3d Kronecker product
810  !clamped splines for first direction
811  allocate( mass_line_0(s_deg_0(1)+1) )
812  allocate( mass_line_1(s_deg_0(1)) )
813  call sll_s_spline_fem_mass_line ( self%s_deg_0(1), mass_line_0 )
814  call sll_s_spline_fem_mass_line_boundary ( self%s_deg_0(1), self%spline0_pp, mass_line_b0 )
815  call sll_s_spline_fem_mass_line ( self%s_deg_1(1), mass_line_1 )
816  call sll_s_spline_fem_mass_line_boundary ( self%s_deg_1(1), self%spline1_pp, mass_line_b1 )
817 
818 
819  call sll_s_spline_fem_mass1d_clamped( n_cells(1), self%s_deg_0(1), mass_line_0, mass_line_b0, self%mass1d(1,1) )
820  call sll_s_spline_fem_mass1d_clamped( n_cells(1), self%s_deg_1(1), mass_line_1, mass_line_b1, self%mass1d(2,1) )
821  self%mass1d(1,1)%arr_a = self%mass1d(1,1)%arr_a*self%delta_x(1)
822  self%mass1d(2,1)%arr_a = self%mass1d(2,1)%arr_a*self%delta_x(1)
823  call self%mass1d_solver(1,1)%create( self%mass1d(1,1) )
824  call self%mass1d_solver(2,1)%create( self%mass1d(2,1) )
825 
826  deallocate( mass_line_0 )
827  deallocate( mass_line_1 )
828 
829  call sll_s_spline_fem_mixedmass1d_clamped_full( n_cells(1), self%s_deg_0(1), self%s_deg_1(1), self%mass1d(3,1), profile_mix, self%spline0_pp, self%spline1_pp )
830 
831  do j = 2, 3
832  allocate( mass_line_0(s_deg_0(j)+1) )
833  allocate( mass_line_1(s_deg_0(j)) )
834  allocate( mass_line_mixed(s_deg_0(j)*2) )
835  call sll_s_spline_fem_mass_line ( self%s_deg_0(j), mass_line_0 )
836  call sll_s_spline_fem_mass_line ( self%s_deg_1(j), mass_line_1 )
837 
838  call sll_s_spline_fem_mass1d( n_cells(j), self%s_deg_0(j), mass_line_0, self%mass1d(1,j) )
839  call sll_s_spline_fem_mass1d( n_cells(j), self%s_deg_1(j), mass_line_1, self%mass1d(2,j) )
840  self%mass1d(1,j)%arr_a = self%mass1d(1,j)%arr_a*self%delta_x(j)
841  self%mass1d(2,j)%arr_a = self%mass1d(2,j)%arr_a*self%delta_x(j)
842  call self%mass1d_solver(1,j)%create( self%mass1d(1,j) )
843  call self%mass1d_solver(2,j)%create( self%mass1d(2,j) )
844 
845  call sll_s_spline_fem_mixedmass_line ( self%s_deg_0(j), mass_line_mixed )
846  call sll_s_spline_fem_mixedmass1d( self%n_dofs(j), self%s_deg_0(j), mass_line_mixed*self%delta_x(j), &
847  self%mass1d(3,j) )
848 
849 
850  deallocate( mass_line_0 )
851  deallocate( mass_line_1 )
852  deallocate( mass_line_mixed )
853  end do
854 
855  do j=1,3
856  do k=1,2
857  self%mass1d_solver(k,j)%atol = self%mass_solver_tolerance
858  !self%mass1d_solver(k,j)%verbose = .true.
859  end do
860  end do
861 
862  ! Put together the componentwise matrices as Kronecker products
863  call self%mass1(1)%create( linop_a=self%mass1d(1,3), &
864  linop_b=self%mass1d(1,2), &
865  linop_c=self%mass1d(2,1) )
866  call self%mass1(2)%create( linop_a=self%mass1d(1,3), &
867  linop_b=self%mass1d(2,2), &
868  linop_c=self%mass1d(1,1) )
869  call self%mass1(3)%create( linop_a=self%mass1d(2,3), &
870  linop_b=self%mass1d(1,2), &
871  linop_c=self%mass1d(1,1))
872  call self%mass2(1)%create( linop_a=self%mass1d(2,3), &
873  linop_b=self%mass1d(2,2), &
874  linop_c=self%mass1d(1,1) )
875  call self%mass2(2)%create( linop_a=self%mass1d(2,3), &
876  linop_b=self%mass1d(1,2), &
877  linop_c=self%mass1d(2,1) )
878  call self%mass2(3)%create( linop_a=self%mass1d(1,3), &
879  linop_b=self%mass1d(2,2), &
880  linop_c=self%mass1d(2,1) )
881 
882  deg = self%s_deg_0
883  if(self%adiabatic_electrons) then
884  call sll_s_spline_fem_mass3d_clamped( self%n_cells, deg, -1, self%mass0, profile_m0, self%spline0_pp )
885  else
886  call sll_s_spline_fem_mass3d_clamped( self%n_cells, deg, 0, self%mass0, profile_0, self%spline0_pp )
887  end if
888 
889  call self%mass0_solver%create( self%mass0 )
890  self%mass0_solver%atol = self%mass_solver_tolerance
891  !self%mass0_solver%verbose = .true.
892 
893  call self%mass1_operator%create( 3, 3 )
894  call self%mass2_operator%create( 3, 3 )
895 
896  do j= 1, 3
897  call self%mass1_operator%set( j, j, self%mass1(j) )
898  call self%mass2_operator%set( j, j, self%mass2(j) )
899  end do
900 
901  call self%preconditioner_fft%init( self%Lx, n_cells, s_deg_0, .true. )
902 
903  self%work12 = 1._f64
904  call self%mass1_operator%dot(self%work12, self%work1)
905  do j = 1, self%n_dofs(2)*self%n_dofs(3)
906  self%work1(self%n_total1+1+(j-1)*self%n_dofs(1)) = 1._f64
907  self%work1(self%n_total1+j*self%n_dofs(1)) = 1._f64
908  self%work1(self%n_total1+self%n_total0+1+(j-1)*self%n_dofs(1)) = 1._f64
909  self%work1(self%n_total1+self%n_total0+j*self%n_dofs(1)) = 1._f64
910  end do
911  self%work1 = 1._f64/sqrt(self%work1)
912 
913  self%work22 = 1._f64
914  call self%mass2_operator%dot(self%work22, self%work2)
915  do j = 1, self%n_dofs(2)*self%n_dofs(3)
916  self%work2(1+(j-1)*self%n_dofs(1)) = 1._f64
917  self%work2(j*self%n_dofs(1)) = 1._f64
918  end do
919  self%work2 = 1._f64/sqrt(self%work2)
920 
921  call self%preconditioner1%create( self%preconditioner_fft%inverse_mass1_3d, self%work1, 2*self%n_total0+self%n_total1 )
922  call self%preconditioner2%create( self%preconditioner_fft%inverse_mass2_3d, self%work2, 2*self%n_total1+self%n_total0 )
923 
924  self%work1 = 0._f64
925  self%work12 = 0._f64
926  self%work2 = 0._f64
927  self%work22 = 0._f64
928 
929  call self%mass1_solver%create( self%mass1_operator, self%preconditioner1)
930  call self%mass2_solver%create( self%mass2_operator, self%preconditioner2)
931  self%mass1_solver%atol = self%mass_solver_tolerance
932  self%mass2_solver%atol = self%mass_solver_tolerance
933  !self%mass1_solver%verbose = .true.
934  !self%mass2_solver%verbose = .true.
935 
936  ! Put together the componentwise matrices as Kronecker products
937  call self%mass_1_solver(1)%create( linear_solver_a=self%mass1d_solver(2,1), &
938  linear_solver_b=self%mass1d_solver(1,2), &
939  linear_solver_c=self%mass1d_solver(1,3) )
940  call self%mass_1_solver(2)%create( linear_solver_a=self%mass1d_solver(1,1), &
941  linear_solver_b=self%mass1d_solver(2,2), &
942  linear_solver_c=self%mass1d_solver(1,3) )
943  call self%mass_1_solver(3)%create( linear_solver_a=self%mass1d_solver(1,1), &
944  linear_solver_b=self%mass1d_solver(1,2), &
945  linear_solver_c=self%mass1d_solver(2,3))
946  call self%mass_2_solver(1)%create( linear_solver_a=self%mass1d_solver(1,1), &
947  linear_solver_b=self%mass1d_solver(2,2), &
948  linear_solver_c=self%mass1d_solver(2,3) )
949  call self%mass_2_solver(2)%create( linear_solver_a=self%mass1d_solver(2,1), &
950  linear_solver_b=self%mass1d_solver(1,2), &
951  linear_solver_c=self%mass1d_solver(2,3) )
952  call self%mass_2_solver(3)%create( linear_solver_a=self%mass1d_solver(2,1), &
953  linear_solver_b=self%mass1d_solver(2,2), &
954  linear_solver_c=self%mass1d_solver(1,3) )
955 
956 
957 
958  ! Only for Schur complement eb solver
959  call self%linear_op_schur_eb%create( self%mass1_operator, self%mass2_operator, self%n_dofs, self%delta_x, self%s_deg_0 )
960  call self%linear_solver_schur_eb%create( self%linear_op_schur_eb, self%preconditioner1 )
961  self%linear_solver_schur_eb%atol = self%solver_tolerance
962  !self%linear_solver_schur_eb%verbose = .true.
963  !self%linear_solver_schur_eb%n_maxiter = 2000
964 
965  ! Poisson solver
966  call self%poisson_matrix%create( self%mass1_operator, self%s_deg_0, self%n_dofs, self%delta_x)
967  call self%poisson_solver%create( self%poisson_matrix)
968  self%poisson_solver%atol = self%poisson_solver_tolerance
969  !self%poisson_solver%verbose = .true.
970 
971 
972  contains
973  function profile_m0( x, component)
974  sll_real64 :: profile_m0
975  sll_real64, intent(in) :: x(3)
976  sll_int32, optional, intent(in) :: component(:)
977 
978  profile_m0 = product(self%Lx) * self%profile%rho_0( x(1) )/ self%profile%T_e( x(1) )
979 
980  end function profile_m0
981 
982  function profile_0( x, component)
983  sll_real64 :: profile_0
984  sll_real64, intent(in) :: x(3)
985  sll_int32, optional, intent(in) :: component(:)
986 
987  profile_0 = product(self%Lx)
988 
989  end function profile_0
990 
991  function profile_mix( x)
992  sll_real64 :: profile_mix
993  sll_real64, intent(in) :: x
994 
995  profile_mix = product(self%Lx)
996 
997  end function profile_mix
998 
999  end subroutine init_3d_fem
1000 
1001 
1003  subroutine init_from_file_3d_fem( self, domain, n_cells, s_deg_0, boundary, nml_file, adiabatic_electrons, profile )
1004  class(sll_t_maxwell_clamped_3d_fem), intent(inout) :: self
1005  sll_real64, intent(in) :: domain(3,2)
1006  sll_int32, intent(in) :: n_cells(3)
1007  sll_int32, intent(in) :: s_deg_0(3)
1008  sll_int32, intent( in ) :: boundary(3)
1009  character(len=*), intent(in) :: nml_file
1010  logical, intent(in), optional :: adiabatic_electrons
1011  type(sll_t_profile_functions), intent(in), optional :: profile
1012  ! local variables
1013  character(len=256) :: file_prefix
1014  sll_int32 :: input_file
1015  sll_int32 :: io_stat, io_stat0, io_stat1, rank, file_id
1016  sll_real64 :: mass_tolerance
1017  sll_real64 :: poisson_tolerance
1018  sll_real64 :: maxwell_tolerance
1019 
1020  namelist /output/ file_prefix
1021  namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
1022  namelist /time_solver/ maxwell_tolerance
1023 
1025 
1026  if( present( adiabatic_electrons) ) then
1027  self%adiabatic_electrons = adiabatic_electrons
1028  end if
1029 
1030  if( present( profile ) ) then
1031  self%profile = profile
1032  end if
1033 
1034  ! Read in solver tolerance
1035  open(newunit = input_file, file=nml_file, status='old',iostat=io_stat)
1036  if (io_stat /= 0) then
1037  if (rank == 0 ) then
1038  print*, 'sll_m_maxwell_cl_3d_fem: Input file does not exist. Set default tolerance.'
1039  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
1040  write(file_id, *) 'mass solver tolerance:', 1d-12
1041  write(file_id, *) 'poisson solver tolerance:', 1d-12
1042  close(file_id)
1043  end if
1044  call self%init( domain, n_cells, s_deg_0, boundary )
1045  else
1046  read(input_file, output,iostat=io_stat0)
1047  read(input_file, maxwell_solver,iostat=io_stat)
1048  read(input_file, time_solver,iostat=io_stat1)
1049  if (io_stat /= 0 .and. io_stat1 /= 0) then
1050  if (rank == 0 ) then
1051  print*, 'sll_m_maxwell_cl_3d_fem: Input parameter does not exist. Set default tolerance.'
1052  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
1053  write(file_id, *) 'mass solver tolerance:', 1d-12
1054  write(file_id, *) 'poisson solver tolerance:', 1d-12
1055  close(file_id)
1056  end if
1057  call self%init( domain, n_cells, s_deg_0, boundary )
1058  else if (io_stat /= 0 .and. io_stat1 == 0) then
1059  call self%init( domain, n_cells, s_deg_0, boundary, solver_tolerance=maxwell_tolerance )
1060  else if (io_stat == 0 .and. io_stat1 /= 0) then
1061  if (rank == 0 ) then
1062  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
1063  write(file_id, *) 'mass solver tolerance:', mass_tolerance
1064  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
1065  close(file_id)
1066  end if
1067  call self%init( domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance )
1068  else
1069  if (rank == 0 ) then
1070  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
1071  write(file_id, *) 'mass solver tolerance:', mass_tolerance
1072  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
1073  close(file_id)
1074  end if
1075  call self%init( domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, maxwell_tolerance )
1076  end if
1077  close(input_file)
1078  end if
1079 
1080  end subroutine init_from_file_3d_fem
1081 
1083  subroutine free_3d_fem(self)
1084  class(sll_t_maxwell_clamped_3d_fem) :: self
1085 
1086  call self%mass0_solver%free()
1087  call self%mass1_solver%free()
1088  call self%mass2_solver%free()
1089  call self%mass1_operator%free()
1090  call self%mass2_operator%free()
1091  call self%poisson_solver%free()
1092  call self%poisson_matrix%free()
1093  call self%linear_solver_schur_eb%free()
1094  call self%linear_op_schur_eb%free()
1095 
1096  call sll_s_spline_pp_free_1d( self%spline0_pp )
1097  call sll_s_spline_pp_free_1d( self%spline1_pp )
1098 
1099  deallocate(self%work0)
1100  deallocate(self%work01)
1101  deallocate(self%work1)
1102  deallocate(self%work12)
1103  deallocate(self%work2)
1104  deallocate(self%work22)
1105 
1106  end subroutine free_3d_fem
1107 
1108 
1110  subroutine multiply_g( self, field_in, field_out )
1111  class(sll_t_maxwell_clamped_3d_fem) :: self
1112  sll_real64, intent( in ) :: field_in(:)
1113  sll_real64, intent( out ) :: field_out(:)
1114 
1115  call sll_s_multiply_g_clamped(self%n_dofs, self%delta_x, self%s_deg_0, field_in, field_out)
1116 
1117  end subroutine multiply_g
1118 
1119 
1121  subroutine multiply_gt(self, field_in, field_out)
1122  class(sll_t_maxwell_clamped_3d_fem) :: self
1123  sll_real64, intent( in ) :: field_in(:)
1124  sll_real64, intent( out ) :: field_out(:)
1125 
1126  call sll_s_multiply_gt_clamped(self%n_dofs, self%delta_x, self%s_deg_0, field_in, field_out)
1127 
1128  end subroutine multiply_gt
1129 
1130 
1132  subroutine multiply_c(self, field_in, field_out)
1133  class(sll_t_maxwell_clamped_3d_fem) :: self
1134  sll_real64, intent( in ) :: field_in(:)
1135  sll_real64, intent( out ) :: field_out(:)
1136 
1137  call sll_s_multiply_c_clamped(self%n_dofs, self%delta_x, self%s_deg_0, field_in, field_out)
1138 
1139  end subroutine multiply_c
1140 
1141 
1143  subroutine multiply_ct(self, field_in, field_out)
1144  class(sll_t_maxwell_clamped_3d_fem) :: self
1145  sll_real64, intent( in ) :: field_in(:)
1146  sll_real64, intent( out ) :: field_out(:)
1147 
1148  call sll_s_multiply_ct_clamped(self%n_dofs, self%delta_x, self%s_deg_0, field_in, field_out)
1149 
1150  end subroutine multiply_ct
1151 
1152 
1154  subroutine multiply_mass_3d_fem( self, deg, coefs_in, coefs_out )
1155  class(sll_t_maxwell_clamped_3d_fem) :: self
1156  sll_int32, intent( in ) :: deg(:)
1157  sll_real64, intent( in ) :: coefs_in(:)
1158  sll_real64, intent( out ) :: coefs_out(:)
1159 
1160 
1161  if( size(deg) == 1 )then
1162  select case(deg(1))
1163  case(0)
1164  call self%mass0%dot( coefs_in, coefs_out )
1165  case(1)
1166  call self%mass1_operator%dot( coefs_in, coefs_out )
1167  case(2)
1168  call self%mass2_operator%dot( coefs_in, coefs_out )
1169  case default
1170  print*, 'multiply mass for other form not yet implemented'
1171  stop
1172  end select
1173  else if( size(deg) == 3 ) then
1174  call multiply_mass_3dkron( self, deg, coefs_in, coefs_out )
1175  end if
1176 
1177  end subroutine multiply_mass_3d_fem
1178 
1179 
1181  subroutine multiply_mass_3dkron( self, deg, coefs_in, coefs_out )
1182  class(sll_t_maxwell_clamped_3d_fem) :: self
1183  sll_int32, intent( in ) :: deg(:)
1184  sll_real64, intent( in ) :: coefs_in(:)
1185  sll_real64, intent( out ) :: coefs_out(:)
1186  ! Local variables
1187  sll_int32 :: i,j,k,istart,iend
1188 
1189  if(deg(1) == 1)then
1190  allocate( self%work3d(self%n_dofs(1), self%n_cells(2), self%n_cells(3)) )
1191  allocate( self%work_d1( self%n_dofs(1) ) )
1192  istart = 1
1193  iend = self%n_dofs(1)
1194  do k = 1, self%n_cells(3)
1195  do j = 1, self%n_cells(2)
1196  call self%mass1d(deg(1),1)%dot( coefs_in(istart:iend), self%work_d1 )
1197  self%work3d(:,j,k) = self%work_d1
1198  istart = iend+1
1199  iend = iend + self%n_dofs(1)
1200  end do
1201  end do
1202 
1203  do k = 1, self%n_cells(3)
1204  do i = 1, self%n_dofs(1)
1205  self%work_d2_in = self%work3d(i,:,k)
1206  call self%mass1d(deg(2),2)%dot( self%work_d2_in, self%work_d2_out )
1207  self%work3d(i,:,k) = self%work_d2_out
1208  end do
1209  end do
1210 
1211  istart = 1
1212  do j = 1, self%n_cells(2)
1213  do i = 1, self%n_dofs(1)
1214  self%work_d3_in = self%work3d(i,j,:)
1215  call self%mass1d(deg(3),3)%dot( self%work_d3_in, self%work_d3_out )
1216  do k = 1, self%n_cells(3)
1217  coefs_out(istart+(k-1)*self%n_dofs(1)*self%n_cells(2)) = self%work_d3_out(k)
1218  end do
1219  istart = istart +1
1220  end do
1221  end do
1222  else if (deg(1) == 2)then
1223  allocate( self%work3d(self%n_dofs(1)-1, self%n_cells(2), self%n_cells(3)) )
1224  allocate( self%work_d1( self%n_dofs(1)-1 ) )
1225  istart = 1
1226  iend = self%n_dofs(1)-1
1227  do k = 1, self%n_cells(3)
1228  do j = 1, self%n_cells(2)
1229  call self%mass1d(deg(1),1)%dot( coefs_in(istart:iend), self%work_d1 )
1230  self%work3d(:,j,k) = self%work_d1
1231  istart = iend+1
1232  iend = iend + self%n_dofs(1)-1
1233  end do
1234  end do
1235 
1236  do k = 1, self%n_cells(3)
1237  do i = 1, self%n_dofs(1)-1
1238  self%work_d2_in = self%work3d(i,:,k)
1239  call self%mass1d(deg(2),2)%dot( self%work_d2_in, self%work_d2_out )
1240  self%work3d(i,:,k) = self%work_d2_out
1241  end do
1242  end do
1243 
1244  istart = 1
1245  do j = 1, self%n_cells(2)
1246  do i = 1, self%n_dofs(1)-1
1247  self%work_d3_in = self%work3d(i,j,:)
1248  call self%mass1d(deg(3),3)%dot( self%work_d3_in, self%work_d3_out )
1249  do k = 1, self%n_cells(3)
1250  coefs_out(istart+(k-1)*(self%n_dofs(1)-1)*self%n_cells(2)) = self%work_d3_out(k)
1251  end do
1252  istart = istart +1
1253  end do
1254  end do
1255  else if(deg(1) == 3) then
1256  allocate( self%work3d(self%n_dofs(1), self%n_cells(2), self%n_cells(3)) )
1257  allocate( self%work_d1( self%n_dofs(1) ) )
1258  istart = 1
1259  iend = self%n_dofs(1)-1
1260  do k = 1, self%n_cells(3)
1261  do j = 1, self%n_cells(2)
1262  call self%mass1d(deg(1),1)%dot( coefs_in(istart:iend), self%work_d1 )
1263  self%work3d(:,j,k) = self%work_d1
1264  istart = iend+1
1265  iend = iend + self%n_dofs(1)-1
1266  end do
1267  end do
1268 
1269  do k = 1, self%n_cells(3)
1270  do i = 1, self%n_dofs(1)
1271  self%work_d2_in = self%work3d(i,:,k)
1272  call self%mass1d(deg(2),2)%dot( self%work_d2_in, self%work_d2_out )
1273  self%work3d(i,:,k) = self%work_d2_out
1274  end do
1275  end do
1276 
1277  istart = 1
1278  do j = 1, self%n_cells(2)
1279  do i = 1, self%n_dofs(1)
1280  self%work_d3_in = self%work3d(i,j,:)
1281  call self%mass1d(deg(3),3)%dot( self%work_d3_in, self%work_d3_out )
1282  do k = 1, self%n_cells(3)
1283  coefs_out(istart+(k-1)*self%n_dofs(1)*self%n_cells(2)) = self%work_d3_out(k)
1284  end do
1285  istart = istart +1
1286  end do
1287  end do
1288  end if
1289  deallocate( self%work3d )
1290  deallocate( self%work_d1 )
1291 
1292  end subroutine multiply_mass_3dkron
1293 
1294 
1296  subroutine multiply_mass_inverse_3d_fem( self, form, coefs_in, coefs_out )
1297  class(sll_t_maxwell_clamped_3d_fem) :: self
1298  sll_int32, intent( in ) :: form
1299  sll_real64, intent( in ) :: coefs_in(:)
1300  sll_real64, intent( out ) :: coefs_out(:)
1301  !local variables
1302  sll_int32 :: j
1303 
1304  sll_assert(form>=0 .and. form<=3)
1305  select case(form)
1306  case(0)
1307  call self%mass0_solver%solve( coefs_in, coefs_out )
1308  do j = 1, self%n_dofs(2)*self%n_dofs(3)
1309  coefs_out(1+(j-1)*self%n_dofs(1)) = 0._f64
1310  coefs_out(j*self%n_dofs(1)) = 0._f64
1311  end do
1312  case(1)
1313  call self%mass1_solver%solve( coefs_in, coefs_out )
1314  do j = 1, self%n_dofs(2)*self%n_dofs(3)
1315  coefs_out(self%n_total1+1+(j-1)*self%n_dofs(1)) = 0._f64
1316  coefs_out(self%n_total1+j*self%n_dofs(1)) = 0._f64
1317  coefs_out(self%n_total1+self%n_total0+1+(j-1)*self%n_dofs(1)) = 0._f64
1318  coefs_out(self%n_total1+self%n_total0+j*self%n_dofs(1)) = 0._f64
1319  end do
1320  case(2)
1321  call self%mass2_solver%solve( coefs_in, coefs_out )
1322  do j = 1, self%n_dofs(2)*self%n_dofs(3)
1323  coefs_out(1+(j-1)*self%n_dofs(1)) = 0._f64
1324  coefs_out(j*self%n_dofs(1)) = 0._f64
1325  end do
1326  case default
1327  print*, 'multiply inverse mass for other form not yet implemented'
1328  stop
1329  end select
1330  end subroutine multiply_mass_inverse_3d_fem
1331 
1332 
1334  subroutine compute_field_energy( self, efield_dofs, bfield_dofs, energy)
1335  class(sll_t_maxwell_clamped_3d_fem) :: self
1336  sll_real64, intent( in ) :: efield_dofs(:)
1337  sll_real64, intent( in ) :: bfield_dofs(:)
1338  sll_real64, intent( out ) :: energy
1339  !local variables
1340  sll_real64 :: field_energy(6)
1341 
1342  field_energy(1) = self%l2norm_squared &
1343  ( efield_dofs(1:self%n_total1), 1, 1 )
1344  field_energy(2) = self%l2norm_squared &
1345  ( efield_dofs(self%n_total1+1:self%n_total1+self%n_total0), 1, 2 )
1346  field_energy(3) = self%l2norm_squared &
1347  ( efield_dofs(self%n_total1+self%n_total0+1:self%n_total1+self%n_total0*2), 1, 3 )
1348  field_energy(4) = self%l2norm_squared &
1349  ( bfield_dofs(1:self%n_total0), 2, 1 )
1350  field_energy(5) = self%l2norm_squared &
1351  ( bfield_dofs(self%n_total0+1:self%n_total0+self%n_total1), 2, 2 )
1352  field_energy(6) =self%l2norm_squared &
1353  ( bfield_dofs(self%n_total0+self%n_total1+1:self%n_total0+self%n_total1*2), 2, 3 )
1354 
1355  energy = 0.5_f64*sum(field_energy)
1356 
1357  end subroutine compute_field_energy
1358 
1359 
Parallelizing facility.
integer(kind=i32) function, public sll_f_get_collective_rank(col)
Determines the rank of the calling process in the communicator.
type(sll_t_collective_t), pointer, public sll_v_world_collective
Control of subset assignment. Processes with the same color are in the same new communicator.
real(kind=f64) function, dimension(2, 1:npoints), public sll_f_gauss_legendre_points_and_weights(npoints, a, b)
Returns a 2d array of size (2,npoints) containing gauss-legendre points and weights in the interval [...
module for a block linear operator
module for a linear operator of kronecker solver
module for conjugate gradient method in pure form
module for kronecker linear solver
Low level arbitrary degree splines.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations in 3D.
Module interface to solve Maxwell's equations in 3D The linear systems are solved using PLAF.
subroutine multiply_c(self, field_in, field_out)
Multiply by discrete curl matrix.
subroutine l2projection_3d_fem(self, form, component, coefs_dofs, func1, func2, func3)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine multiply_gt(self, field_in, field_out)
Multiply by transpose of dicrete gradient matrix.
real(kind=f64) function inner_product_3d_fem(self, coefs1, coefs2, form, component)
Compute inner product.
subroutine compute_field_energy(self, efield_dofs, bfield_dofs, energy)
Compute field energy.
subroutine sll_s_compute_phi_from_rho_3d_fem(self, field_in, field_out, efield_dofs)
Compute phi from rho_i integrated over the time interval.
subroutine multiply_mass_3d_fem(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
subroutine sll_s_compute_curl_part_3d_fem(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
subroutine sll_s_compute_e_from_j_3d_fem(self, current, E, component)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation,...
subroutine multiply_mass_inverse_3d_fem(self, form, coefs_in, coefs_out)
Multiply by the inverse mass matrix.
subroutine free_3d_fem(self)
Finalization.
subroutine sll_s_compute_e_from_b_3d_fem(self, delta_t, field_in, field_out)
compute E from B using weak Ampere formulation
subroutine multiply_mass_3dkron(self, deg, coefs_in, coefs_out)
Multiply by the mass matrix.
real(kind=f64) function l2norm_squared_3d_fem(self, coefs, form, component)
Compute square of the L2norm.
subroutine sll_s_compute_phi_from_j_3d_fem(self, field_in, field_out, efield_dofs)
Compute phi from j_i integrated over the time interval, delta_t is already included.
subroutine init_from_file_3d_fem(self, domain, n_cells, s_deg_0, boundary, nml_file, adiabatic_electrons, profile)
Initialization from nml file.
subroutine sll_s_compute_b_from_e_3d_fem(self, delta_t, field_in, field_out)
Compute B from E using strong 3D Faraday equation for spline coefficients.
subroutine multiply_g(self, field_in, field_out)
Multiply by dicrete gradient matrix.
subroutine sll_s_compute_rhs_fem(self, form, component, coefs_dofs, func1, func2, func3)
Compute the FEM right-hand-side for a given function f and periodic splines of given degree Its compo...
subroutine multiply_ct(self, field_in, field_out)
Multiply by transpose of discrete curl matrix.
subroutine init_3d_fem(self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile)
Initialization.
subroutine sll_s_compute_e_from_rho_3d_fem(self, field_in, field_out)
compute e from rho using weak Poisson's equation ( rho = G^T M_1 G \phi, e = G \phi )
subroutine sll_s_compute_rho_from_e_3d_fem(self, field_in, field_out)
compute rho from e using weak Gauss law ( rho = G^T M_1 e )
Module interface to solve Maxwell's equations with coordinate transformation in 3D The linear systems...
Module interface to solve Maxwell's equations with coordinate transformation in 3D The linear systems...
functions for initial profile of the particle distribution function
Utilites for Maxwell solver's with spline finite elements using sparse matrices.
subroutine, public sll_s_multiply_ct_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by transpose of discrete curl matrix.
subroutine, public sll_s_spline_fem_mass3d_clamped(n_cells, deg, component, matrix, profile, spline, n_cells_min, n_cells_max)
Set up 3d clamped mass matrix for specific spline degrees and profile function.
subroutine, public sll_s_multiply_g_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by dicrete gradient matrix.
subroutine, public sll_s_multiply_c_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by discrete curl matrix.
subroutine, public sll_s_multiply_gt_clamped(n_dofs, delta_x, s_deg_0, field_in, field_out)
Multiply by transpose of dicrete gradient matrix.
Utilites for 3D Maxwell solvers with spline finite elements.
subroutine, public sll_s_spline_fem_mass3d(n_cells, deg, component, matrix, profile, n_cells_min, n_cells_max)
Set up 3d mass matrix for specific spline degrees and profile function.
Utilites for Maxwell solver's with spline finite elements using sparse matrix linear solvers.
subroutine, public sll_s_spline_fem_mass1d(n_cells, s_deg, mass_line, matrix)
Set up 1d mass matrix (sparsity pattern and values)
subroutine, public sll_s_spline_fem_mixedmass1d_clamped_full(n_cells, deg1, deg2, matrix, profile, spline1, spline2)
Set up 1d mixed mass matrix for specific spline degrees and profile function.
subroutine, public sll_s_spline_fem_mixedmass1d(n_cells, s_deg, mass_line, matrix)
subroutine, public sll_s_spline_fem_mass1d_clamped(n_cells, s_deg, mass_line, mass_line_b, matrix)
Set up 1d mass matrix (sparsity pattern and values)
Utilites for Maxwell solver's with spline finite elements.
subroutine, public sll_s_spline_fem_mass_line_boundary(degree, spline, mass_line)
Function computing the boundary part for a mass matrix with clamped splines of degree.
subroutine, public sll_s_spline_fem_mixedmass_line(deg, mass_line)
Helper function to find line of mass matrix ( N_i^p N_j^{p-1}))
subroutine, public sll_s_spline_fem_mass_line(degree, mass_line)
Computes the mass line for a mass matrix with degree splines.
Splines in pp form.
subroutine, public sll_s_spline_pp_init_1d(self, degree, n_cells, boundary)
Initialize sll_t_spline_pp_1d object (Set poly_coeffs depending on degree)
subroutine, public sll_s_spline_pp_free_1d(self)
Destructor 1d.
real(kind=f64) function, public sll_f_spline_pp_horner_1d(degree, pp_coeffs, x, index)
Perform a 1d hornerschema on the pp_coeffs at index.
real(kind=f64) function profile_0(x)
real(kind=f64) function profile_m0(x)
real(kind=f64) function profile_mix(x)
    Report Typos and Errors