Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_maxwell_clamped_1d_fem_sm.F90
Go to the documentation of this file.
1 
6 
8  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
12 
13  use sll_m_collective, only: &
16 
19 
21 
24 
25  use sll_m_linear_solver_cg, only : &
27 
28  use sll_m_linear_solver_mgmres, only : &
30 
31  use sll_m_low_level_bsplines, only: &
32  sll_s_uniform_bsplines_eval_basis
33 
34  use sll_m_matrix_csr, only: &
36 
37  use sll_m_maxwell_1d_base, only: &
40 
41  use sll_m_spline_fem_utilities, only : &
44 
49 
53 
54  use sll_m_splines_pp, only: &
59 
60  implicit none
61 
62  public :: &
64 
65  private
66  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
67 
69 
70  type(sll_t_spline_pp_1d) :: spline0_pp
71  type(sll_t_spline_pp_1d) :: spline1_pp
72  sll_real64, allocatable :: work1(:)
73  sll_real64, allocatable :: work0(:)
74  sll_real64, allocatable :: work01(:)
75  type(sll_t_matrix_csr) :: mass0
76  type(sll_t_matrix_csr) :: mass1
77  type(sll_t_matrix_csr) :: mixed_mass
78  type(sll_t_linear_solver_cg) :: linear_solver_mass0
79  type(sll_t_linear_solver_cg) :: linear_solver_mass1
80 
82  type(sll_t_linear_solver_cg) :: poisson_solver
83 
84  type( sll_t_linear_operator_schur_eb_cl_1d ) :: linear_op_schur_eb
85  type( sll_t_linear_solver_mgmres ) :: linear_solver_schur_eb
86 
87  contains
88  procedure :: &
89  compute_e_from_b => sll_s_compute_e_from_b_1d_fem_sm
90  procedure :: &
91  compute_b_from_e => sll_s_compute_b_from_e_1d_fem_sm
92  procedure :: &
93  compute_curl_part => sll_s_compute_curl_part_1d_fem_sm
94  procedure :: &
95  compute_e_from_rho => sll_s_compute_e_from_rho_1d_fem_sm
96  procedure :: &
97  compute_rho_from_e => compute_rho_from_e_1d_fem_sm
98  procedure :: &
99  compute_e_from_j => compute_e_from_j_1d_fem_sm
100  procedure :: &
101  compute_phi_from_rho => compute_phi_from_rho_1d_fem_sm
102  procedure :: &
103  compute_phi_from_j => compute_phi_from_j_1d_fem_sm
104  procedure :: &
105  compute_rhs_from_function => sll_s_compute_rhs_fem_sm
106  procedure :: &
107  l2projection => l2projection_1d_fem_sm
108  procedure :: &
109  l2norm_squared => l2norm_squared_1d_fem_sm
110  procedure :: &
111  inner_product => inner_product_1d_fem_sm
112  procedure :: &
113  init => init_1d_fem_sm
114  procedure :: &
115  init_from_file => init_from_file_1d_fem_sm
116  procedure :: &
117  free => free_1d_fem_sm
118  procedure :: &
119  multiply_g
120  procedure :: &
122  procedure :: &
123  multiply_mass => multiply_mass_1d_fem_sm
124  procedure :: &
125  invert_mass => invert_mass_1d_fem_sm
126  procedure :: &
128 
129 
131 
132 contains
133 
134 
136  subroutine sll_s_compute_e_from_b_1d_fem_sm(self, delta_t, field_in, field_out)
137  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
138  sll_real64, intent(in) :: delta_t
139  sll_real64, intent(in) :: field_in(:)
140  sll_real64, intent(inout) :: field_out(:)
141 
142  ! Compute potential weak curl of Bz
143  call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
144  call self%multiply_gt( self%work1, self%work0 )
145  call self%invert_mass( self%work0, self%work01, self%s_deg_0 )
146 
147  ! Update Ey from self value
148  field_out = field_out + delta_t*self%work01
149 
150  end subroutine sll_s_compute_e_from_b_1d_fem_sm
151 
152 
155  subroutine sll_s_compute_b_from_e_1d_fem_sm(self, delta_t, field_in, field_out)
156  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
157  sll_real64, intent(in) :: delta_t
158  sll_real64, intent(in) :: field_in(:) ! Ey
159  sll_real64, intent(inout) :: field_out(:) ! Bz
160 
161  call self%multiply_g(field_in, self%work1)
162  ! Update Bz from self value
163  field_out = field_out - delta_t * self%work1
164 
165  end subroutine sll_s_compute_b_from_e_1d_fem_sm
166 
167 
169  subroutine sll_s_compute_curl_part_1d_fem_sm( self, delta_t, efield, bfield, betar )
170  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
171  sll_real64, intent(in) :: delta_t
172  sll_real64, intent(inout) :: efield(:)
173  sll_real64, intent(inout) :: bfield(:)
174  sll_real64, optional :: betar
175  !local variables
176  sll_real64 :: factor
177 
178  if( present(betar) ) then
179  factor = betar
180  else
181  factor = 1._f64
182  end if
183 
184  self%work1 = 0._f64
185  self%work0 = 0._f64
186  self%work01 = 0._f64
187 
188  ! Compute D^T M2 b
189  call self%multiply_mass( bfield, self%work1, self%s_deg_1 )
190  call self%multiply_gt( self%work1, self%work0 )
191 
192  self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
193  call self%linear_op_schur_eb%dot( efield, self%work01 )
194  self%work01 = self%work01 + delta_t*factor*self%work0
195 
196  ! Save efield dofs from previous time step for B field update
197  self%work0 = efield
198 
199  ! Invert Schur complement matrix
200  self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
201  call self%linear_solver_schur_eb%set_guess( efield )
202  call self%linear_solver_schur_eb%solve( self%work01, efield )
203 
204  ! Update B field
205  self%work0 = self%work0 + efield
206  call self%compute_B_from_E( delta_t*0.5_f64, self%work0, bfield )
207 
208  end subroutine sll_s_compute_curl_part_1d_fem_sm
209 
210 
212  subroutine sll_s_compute_e_from_rho_1d_fem_sm(self, field_in, field_out )
213  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
214  sll_real64, intent(in) :: field_in(:)
215  sll_real64, intent(out) :: field_out(:)
216 
217  call self%poisson_solver%solve( field_in, self%work0 )
218  call multiply_g( self, self%work0, field_out )
219  field_out = -field_out
220 
222 
223 
225  subroutine compute_rho_from_e_1d_fem_sm(self, field_in, field_out)
226  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
227  sll_real64, intent(in) :: field_in(:) ! E
228  sll_real64, intent(out) :: field_out(:) ! rho
229 
230  call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
231  call multiply_gt( self, self%work1, field_out )
232  field_out = - field_out
233 
234  end subroutine compute_rho_from_e_1d_fem_sm
235 
236 
238  subroutine compute_e_from_j_1d_fem_sm(self, current, component, E)
239  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
240  sll_real64,dimension(:),intent(in) :: current
241  sll_int32, intent(in) :: component
242  sll_real64,dimension(:),intent(inout) :: e
243 
244  ! Multiply by inverse mass matrix
245  if (component == 1) then
246  call self%invert_mass( current, self%work1, self%s_deg_1 )
247  ! Update the electric field and scale
248  e = e - self%work1
249  elseif (component == 2) then
250  call self%invert_mass( current, self%work0, self%s_deg_0 )
251  e = e - self%work0
252  else
253  print*, 'Component ', component, 'not implemented in compute_E_from_j_1d_fem_sm.'
254  end if
255 
256  end subroutine compute_e_from_j_1d_fem_sm
257 
258 
260  subroutine compute_phi_from_rho_1d_fem_sm( self, in, phi, efield )
261  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
262  sll_real64, intent(in) :: in(:)
263  sll_real64, intent(out) :: phi(:)
264  sll_real64, intent(out) :: efield(:)
265 
266  ! Compute phi by inverting the mass matrix
267  call self%invert_mass( in, phi, self%s_deg_0 )
268 
269  ! Compute the degrees of freedom of the electric field as -G phi
270  call multiply_g( self, phi, efield )
271  efield = -efield
272 
273  end subroutine compute_phi_from_rho_1d_fem_sm
274 
275 
277  subroutine compute_phi_from_j_1d_fem_sm( self, in, phi, efield )
278  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
279  sll_real64, intent(in) :: in(:)
280  sll_real64, intent(out) :: phi(:)
281  sll_real64, intent(out) :: efield(:)
282 
283  ! Compute divergence of the current (G^T current) (assuming a 1v model)
284  call multiply_gt( self, in, self%work01 )
285 
286  ! Compute phi by inverting the mass matrix
287  call self%invert_mass( self%work01, self%work0, self%s_deg_0 )
288 
289  phi = phi + self%work0
290 
291  ! Compute the degrees of freedom of the electric field as -G phi
292  call multiply_g( self, phi, efield )
293  efield = -efield
294 
295  end subroutine compute_phi_from_j_1d_fem_sm
296 
297 
300  subroutine sll_s_compute_rhs_fem_sm(self, func, degree, coefs_dofs)
301  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
302  procedure(sll_i_function_1d_real64) :: func
303  sll_int32, intent(in) :: degree
304  sll_real64, intent(out) :: coefs_dofs(:)
305  ! local variables
306  sll_int32 :: i,j,quad,q
307  sll_real64, allocatable :: xw_gauss(:,:)
308  sll_real64, allocatable :: bspl(:,:)
309 
310  q = 2*degree+1
311  allocate( xw_gauss(2,q) )
312  allocate( bspl(degree+1,q) )
313  ! rescale on [0,1] for compatibility with B-splines
314  xw_gauss = sll_f_gauss_legendre_points_and_weights(q, 0.0_f64, 1.0_f64)
315 
316  if( degree == self%s_deg_0 ) then
317  coefs_dofs = 0._f64
318  !first degree-1 cells are different
319  !loop over cells
320  do i = 1, degree-1
321  !loop over splines
322  do j = 1, degree+1
323  ! loop over Gauss points
324  do quad = 1, q
325  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
326  self%delta_x * xw_gauss(2,quad) * func( self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64)) ) *&
327  sll_f_spline_pp_horner_1d( degree, self%spline0_pp%poly_coeffs_boundary_left(:,:,i), xw_gauss(1,quad), j)
328  enddo
329  enddo
330  enddo
331  bspl=0._f64
332  ! Compute bsplines at gauss_points
333  do quad=1,q
334  do j=1, degree+1
335  bspl(j,quad) = sll_f_spline_pp_horner_1d( degree, self%spline0_pp%poly_coeffs, xw_gauss(1,quad), j)
336  end do
337  end do
338 
339  ! Compute coefs_dofs = int f(x)N_i(x)
340  !loop over cells
341  do i = degree, self%n_cells-degree+1
342  ! loop over splines
343  do j = 1, degree+1
344  ! loop over Gauss points
345  do quad = 1, q
346  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
347  self%delta_x * xw_gauss(2,quad) * func(self%delta_x * (xw_gauss(1,quad) + real(i - 1,f64)) ) * bspl(j,quad)
348  enddo
349  enddo
350  enddo
351 
352  !last degree-1 cells are different
353  !loop over cells
354  do i = self%n_cells-degree+2, self%n_cells
355  !loop over splines
356  do j = 1, degree+1
357  ! loop over Gauss points
358  do quad = 1, q
359  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
360  self%delta_x * xw_gauss(2,quad) * func( self%delta_x * (xw_gauss(1,quad)+real(i-1,f64)) ) *&
361  sll_f_spline_pp_horner_1d( degree, self%spline0_pp%poly_coeffs_boundary_right(:,:,i-self%n_cells+degree-1), xw_gauss(1,quad), j)
362  enddo
363  enddo
364  end do
365 
366  else if (degree == self%s_deg_1)then
367 
368  coefs_dofs = 0._f64
369  !first degree-1 cells are different
370  !loop over cells
371  do i = 1, degree-1
372  !loop over splines
373  do j = 1, degree+1
374  ! loop over Gauss points
375  do quad = 1, q
376  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
377  self%delta_x * xw_gauss(2,quad)*func( self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64)) ) *&
378  sll_f_spline_pp_horner_1d( degree, self%spline1_pp%poly_coeffs_boundary_left(:,:,i), xw_gauss(1,quad), j)
379  enddo
380  enddo
381  enddo
382 
383  bspl=0._f64
384  ! Compute bsplines at gauss_points
385  do quad=1, q
386  do j=1, degree+1
387  bspl(j,quad) = sll_f_spline_pp_horner_1d( degree, self%spline1_pp%poly_coeffs, xw_gauss(1,quad), j)
388  end do
389  end do
390 
391  ! Compute coefs_dofs = int f(x)N_i(x)
392  !loop over cells
393  do i = max(1,degree), min(self%n_cells,self%n_cells-degree+1)
394  !loop over splines
395  do j = 1, degree+1
396  ! loop over Gauss points
397  do quad = 1, q
398  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
399  self%delta_x * xw_gauss(2,quad)*func(self%delta_x * (xw_gauss(1,quad) + real(i - 1,f64)) ) * bspl(j,quad)
400  enddo
401  enddo
402  enddo
403 
404  !last degree-1 cells are different
405  !loop over cells
406  do i = self%n_cells-degree+2, self%n_cells
407  !loop over splines
408  do j = 1, degree+1
409  ! loop over Gauss points
410  do quad = 1, q
411  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
412  self%delta_x * xw_gauss(2,quad)*func( self%delta_x * (xw_gauss(1,quad)+real(i-1,f64)) ) *&
413  sll_f_spline_pp_horner_1d( degree, self%spline1_pp%poly_coeffs_boundary_right(:,:,i-self%n_cells+degree-1), xw_gauss(1,quad), j)
414  enddo
415  enddo
416  end do
417  end if
418 
419  end subroutine sll_s_compute_rhs_fem_sm
420 
421 
423  subroutine l2projection_1d_fem_sm(self, func, degree, coefs_dofs)
424  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
425  procedure(sll_i_function_1d_real64) :: func
426  sll_int32, intent(in) :: degree
427  sll_real64, intent(out) :: coefs_dofs(:) ! spline coefficients of projection
428 
429  ! Multiply by inverse mass matrix
430  if (degree == self%s_deg_0) then
431  ! Compute right-hand-side
432  call sll_s_compute_rhs_fem_sm(self, func, degree, self%work0)
433  call self%invert_mass( self%work0, coefs_dofs, degree )
434 
435  elseif (degree == self%s_deg_1) then
436  ! Compute right-hand-side
437  call sll_s_compute_rhs_fem_sm(self, func, degree, self%work1)
438  call self%invert_mass( self%work1, coefs_dofs, degree )
439  else
440  print*, 'degree ', degree, 'not availlable in maxwell_clamped_1d_fem_sm object'
441  endif
442 
443  end subroutine l2projection_1d_fem_sm
444 
445 
447  function l2norm_squared_1d_fem_sm(self, coefs_dofs, degree) result (r)
448  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
449  sll_real64 :: coefs_dofs(:)
450  sll_int32 :: degree
451  sll_real64 :: r
452 
453  ! Multiply coefficients by mass matrix
454  if (degree == self%s_deg_0 ) then
455  call self%multiply_mass( coefs_dofs, self%work0, self%s_deg_0 )
456  ! Multiply by the coefficients from the left (inner product)
457  r = sum(coefs_dofs*self%work0)
458  elseif (degree == self%s_deg_1) then
459  call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_1 )
460  ! Multiply by the coefficients from the left (inner product)
461  r = sum(coefs_dofs*self%work1)
462  end if
463 
464  end function l2norm_squared_1d_fem_sm
465 
466 
468  function inner_product_1d_fem_sm(self, coefs1_dofs, coefs2_dofs, degree, degree2) result (r)
469  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
470  sll_real64 :: coefs1_dofs(:)
471  sll_real64 :: coefs2_dofs(:)
472  sll_int32 :: degree
473  sll_int32, optional :: degree2
474  sll_real64 :: r
475 
476  ! Multiply coefficients by mass matrix (use diagonalization FFT and mass matrix eigenvalues)
477  if (present(degree2)) then
478  if (degree == degree2) then
479  if (degree == self%s_deg_0 ) then
480  call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
481  ! Multiply by the coefficients from the left (inner product)
482  r = sum(coefs1_dofs*self%work0)
483  elseif (degree == self%s_deg_1) then
484  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
485  ! Multiply by the coefficients from the left (inner product)
486  r = sum(coefs1_dofs*self%work1)
487  end if
488  else
489  if (degree == self%s_deg_0) then
490  call self%multiply_mass( coefs2_dofs, self%work01, 10 )
491  ! Multiply by the coefficients from the left (inner product)
492  r = sum(coefs1_dofs*self%work01)
493  else
494  call self%multiply_mass( coefs1_dofs, self%work01, 10 )
495  ! Multiply by the coefficients from the left (inner product)
496  r = sum(coefs2_dofs*self%work01)
497  end if
498  end if
499  else
500  if (degree == self%s_deg_0 ) then
501  call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
502  ! Multiply by the coefficients from the left (inner product)
503  r = sum(coefs1_dofs*self%work0)
504  elseif (degree == self%s_deg_1) then
505  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
506  ! Multiply by the coefficients from the left (inner product)
507  r = sum(coefs1_dofs*self%work1)
508  end if
509  end if
510 
511  end function inner_product_1d_fem_sm
512 
513 
515  subroutine init_1d_fem_sm( self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance )
516  class(sll_t_maxwell_clamped_1d_fem_sm), intent(out) :: self
517  sll_real64, intent(in) :: domain(2)
518  sll_int32, intent(in) :: n_cells
519  sll_int32, intent(in) :: s_deg_0
520  sll_int32, intent(in) :: boundary
521  sll_real64, intent(in), optional :: mass_tolerance
522  sll_real64, intent(in), optional :: poisson_tolerance
523  sll_real64, intent(in), optional :: solver_tolerance
524  ! local variables
525  sll_int32 :: ierr
526  sll_real64 :: mass_line_0(s_deg_0+1), mass_line_1(s_deg_0)
527  sll_real64 :: mass_line_b0((s_deg_0+1)*s_deg_0), mass_line_b1(s_deg_0*(s_deg_0-1))
528 
529  if (present( mass_tolerance) ) then
530  self%mass_solver_tolerance = mass_tolerance
531  else
532  self%mass_solver_tolerance = 1d-12
533  end if
534  if (present( poisson_tolerance) ) then
535  self%poisson_solver_tolerance = poisson_tolerance
536  else
537  self%poisson_solver_tolerance = 1d-12
538  end if
539 
540  if (present( solver_tolerance) ) then
541  self%solver_tolerance = solver_tolerance
542  else
543  self%solver_tolerance = 1d-12
544  end if
545 
546  self%n_cells = n_cells
547  self%n_dofs0 = n_cells+s_deg_0
548  self%n_dofs1 = n_cells+s_deg_0-1
549  self%Lx = domain(2) - domain(1)
550  self%delta_x = self%Lx /real(n_cells,f64)
551  self%s_deg_0 = s_deg_0
552  self%s_deg_1 = s_deg_0 - 1
553 
554  call sll_s_spline_pp_init_1d( self%spline0_pp, self%s_deg_0, n_cells, boundary)
555  call sll_s_spline_pp_init_1d( self%spline1_pp, self%s_deg_1, n_cells, boundary)
556 
557  sll_allocate(self%work1(self%n_dofs1),ierr)
558  sll_allocate(self%work0(self%n_dofs0),ierr)
559  sll_allocate(self%work01(self%n_dofs0),ierr)
560 
561 
562  ! Sparse matrices
563  call sll_s_spline_fem_mass_line ( self%s_deg_0, mass_line_0 )
564  call sll_s_spline_fem_mass_line_boundary ( self%s_deg_0, self%spline0_pp, mass_line_b0 )
565  !scale with delta_x=L/n_cells
566  mass_line_0= mass_line_0*self%delta_x
567  mass_line_b0= mass_line_b0*self%delta_x
568  call sll_s_spline_fem_mass1d_clamped( n_cells, self%s_deg_0, mass_line_0, mass_line_b0, self%mass0 )
569 
570  if(self%s_deg_1 > 0)then
571  call sll_s_spline_fem_mass_line ( self%s_deg_1, mass_line_1 )
572  call sll_s_spline_fem_mass_line_boundary ( self%s_deg_1, self%spline1_pp, mass_line_b1 )
573  !scale with delta_x=L/n_cells
574  mass_line_1= mass_line_1*self%delta_x
575  mass_line_b1= mass_line_b1*self%delta_x
576  call sll_s_spline_fem_mass1d_clamped( n_cells, self%s_deg_1, mass_line_1, mass_line_b1, self%mass1 )
577  else
578  call sll_s_spline_fem_mass_line ( self%s_deg_1, mass_line_1 )
579  mass_line_1 = mass_line_1*self%delta_x
580  call sll_s_spline_fem_mass1d( n_cells, self%s_deg_1, mass_line_1, self%mass1 )
581  end if
582  call self%linear_solver_mass0%create( self%mass0 )
583  call self%linear_solver_mass1%create( self%mass1 )
584  self%linear_solver_mass0%atol = self%mass_solver_tolerance
585  self%linear_solver_mass1%atol = self%mass_solver_tolerance
586  !self%linear_solver_mass0%verbose = .true.
587  !self%linear_solver_mass1%verbose = .true.
588 
589  call sll_s_spline_fem_mixedmass1d_clamped_full( n_cells, self%s_deg_0, self%s_deg_1, self%mixed_mass, profile_0, self%spline0_pp, self%spline1_pp )
590 
591  ! Poisson solver
592  call self%poisson_matrix%create( self%mass1, self%s_deg_0, self%n_dofs0, self%delta_x)
593  call self%poisson_solver%create( self%poisson_matrix )
594  self%poisson_solver%atol = self%poisson_solver_tolerance
595  !self%poisson_solver%verbose = .true.
596  !self%poisson_solver%n_maxiter=40000
597 
598  ! Only for Schur complement eb solver
599  call self%linear_op_schur_eb%create( self%mass0, self%mass1, self%n_dofs0, self%delta_x, self%s_deg_0 )
600  call self%linear_solver_schur_eb%create( self%linear_op_schur_eb )
601  self%linear_solver_schur_eb%atol = self%solver_tolerance
602  self%linear_solver_schur_eb%rtol = self%solver_tolerance
603  !self%linear_solver_schur_eb%verbose = .true.
604 
605  contains
606  function profile_0( x)
607  sll_real64 :: profile_0
608  sll_real64, intent(in) :: x
609 
610  profile_0 = self%Lx
611 
612  end function profile_0
613  end subroutine init_1d_fem_sm
614 
615 
617  subroutine init_from_file_1d_fem_sm( self, domain, n_cells, s_deg_0, boundary, nml_file)
618  class(sll_t_maxwell_clamped_1d_fem_sm), intent(out) :: self
619  sll_real64, intent(in) :: domain(2)
620  sll_int32, intent(in) :: n_cells
621  !sll_real64 :: delta_x ! cell size
622  sll_int32, intent(in) :: s_deg_0
623  sll_int32, intent(in) :: boundary
624  character(len=*) :: nml_file
625  ! local variables
626  character(len=256) :: file_prefix
627  sll_int32 :: input_file
628  sll_int32 :: io_stat, io_stat0, io_stat1, rank, file_id
629  sll_real64 :: mass_tolerance
630  sll_real64 :: poisson_tolerance
631  sll_real64 :: maxwell_tolerance
632 
633  namelist /output/ file_prefix
634  namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
635  namelist /time_solver/ maxwell_tolerance
636 
638 
639  ! Read in solver tolerance
640  open(newunit = input_file, file=nml_file, status='old',iostat=io_stat)
641  if (io_stat /= 0) then
642  if (rank == 0 ) then
643  print*, 'sll_m_maxwell_clamped_1d_fem_sm: Input file does not exist. Set default tolerance.'
644  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
645  write(file_id, *) 'mass solver tolerance:', 1d-12
646  write(file_id, *) 'poisson solver tolerance:', 1d-12
647  close(file_id)
648  end if
649  call self%init( domain, n_cells, s_deg_0, boundary )
650  else
651  read(input_file, output,iostat=io_stat0)
652  read(input_file, maxwell_solver,iostat=io_stat)
653  read(input_file, time_solver,iostat=io_stat1)
654  if (io_stat /= 0) then
655  if (rank == 0 ) then
656  print*, 'sll_m_maxwell_clamped_1d_fem_sm: Input parameter does not exist. Set default tolerance.'
657  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
658  write(file_id, *) 'mass solver tolerance:', 1d-12
659  write(file_id, *) 'poisson solver tolerance:', 1d-12
660  close(file_id)
661  end if
662  call self%init( domain, n_cells, s_deg_0, boundary )
663  else
664  if (rank == 0 ) then
665  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
666  write(file_id, *) 'mass solver tolerance:', mass_tolerance
667  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
668  close(file_id)
669  end if
670  call self%init( domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, maxwell_tolerance )
671  end if
672  close(input_file)
673  end if
674 
675  end subroutine init_from_file_1d_fem_sm
676 
677 
679  subroutine free_1d_fem_sm(self)
680  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
681 
682  deallocate(self%work1)
683  deallocate(self%work0)
684  deallocate(self%work01)
685  call self%linear_solver_mass0%free()
686  call self%linear_solver_mass1%free()
687  call self%poisson_solver%free()
688  call self%poisson_matrix%free()
689  call self%linear_solver_schur_eb%free()
690  call self%linear_op_schur_eb%free()
691 
692  call sll_s_spline_pp_free_1d( self%spline0_pp )
693  call sll_s_spline_pp_free_1d( self%spline1_pp )
694 
695  end subroutine free_1d_fem_sm
696 
697 
699  subroutine multiply_g( self, in, out)
700  class(sll_t_maxwell_clamped_1d_fem_sm), intent(in) :: self
701  sll_real64, intent(in) :: in(:)
702  sll_real64, intent(out) :: out(:)
703 
704  call sll_s_multiply_g_clamped_1d( self%n_dofs0, self%delta_x, self%s_deg_0, in, out)
705 
706  end subroutine multiply_g
707 
708 
710  subroutine multiply_gt( self, in, out)
711  class(sll_t_maxwell_clamped_1d_fem_sm), intent(in) :: self
712  sll_real64, intent(in) :: in(:)
713  sll_real64, intent(out) :: out(:)
714 
715  call sll_s_multiply_gt_clamped_1d( self%n_dofs0, self%delta_x, self%s_deg_0, in, out)
716 
717  end subroutine multiply_gt
718 
719 
721  subroutine multiply_mass_1d_fem_sm( self, in, out, degree)
722  class(sll_t_maxwell_clamped_1d_fem_sm), intent(inout) :: self
723  sll_real64, intent(in) :: in(:)
724  sll_real64, intent(out) :: out(:)
725  sll_int32, intent(in) :: degree
726 
727  ! Multiply coefficients by mass matrix
728  if (degree == self%s_deg_0 ) then
729  call self%mass0%dot ( in, out)
730  elseif (degree == self%s_deg_1) then
731  call self%mass1%dot ( in, out)
732  elseif(degree == 10) then
733  call self%mixed_mass%dot( in, out )
734  else
735  print*, 'maxwell_solver_clamped_1d_fem_sm: multiply mass for other form not yet implemented'
736  stop
737  end if
738 
739  end subroutine multiply_mass_1d_fem_sm
740 
741 
743  subroutine invert_mass_1d_fem_sm( self, in, out, degree)
744  class(sll_t_maxwell_clamped_1d_fem_sm), intent(inout) :: self
745  sll_real64, intent(in) :: in(:)
746  sll_real64, intent(out) :: out(:)
747  sll_int32, intent(in) :: degree
748 
749  ! Multiply coefficients by mass matrix
750  if (degree == self%s_deg_0 ) then
751 
752  call self%linear_solver_mass0%solve ( in, out)
753  !perfect conductor boundary
754  out(1) = 0._f64
755  out(self%n_dofs0) = 0._f64
756  elseif (degree == self%s_deg_1) then
757  call self%linear_solver_mass1%solve ( in, out)
758  else
759  print*, 'Invert mass for other form not yet implemented'
760  stop
761  end if
762 
763  end subroutine invert_mass_1d_fem_sm
764 
766  subroutine compute_field_energy( self, efield_dofs1, efield_dofs2, bfield_dofs, energy)
767  class(sll_t_maxwell_clamped_1d_fem_sm) :: self
768  sll_real64, intent( in ) :: efield_dofs1(:)
769  sll_real64, intent( in ) :: efield_dofs2(:)
770  sll_real64, intent( in ) :: bfield_dofs(:)
771  sll_real64, intent( out ) :: energy
772  !local variables
773  sll_real64 :: field_energy(3)
774 
775 
776  field_energy(1) = self%l2norm_squared &
777  ( efield_dofs1(1:self%n_dofs1), self%s_deg_1 )
778  field_energy(2) = self%l2norm_squared &
779  ( efield_dofs2(1:self%n_dofs0), self%s_deg_0 )
780  field_energy(3) =self%l2norm_squared &
781  ( bfield_dofs(1:self%n_dofs1), self%s_deg_1 )
782 
783  energy = 0.5_f64*sum(field_energy)
784 
785  end subroutine compute_field_energy
786 
787 
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 conjugate gradient method in pure form
module for a sequential gmres
Low level arbitrary degree splines.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations in 1D.
Solve Maxwell's equations with boundary conditions in 1D based on spline FEM, version based on sparse...
subroutine multiply_g(self, in, out)
Multiply by dicrete gradient matrix.
subroutine compute_rho_from_e_1d_fem_sm(self, field_in, field_out)
Compute rho from Gauss law for given efield.
subroutine multiply_gt(self, in, out)
Multiply by transpose of dicrete gradient matrix.
subroutine sll_s_compute_rhs_fem_sm(self, func, degree, coefs_dofs)
Compute the FEM right-hand-side for a given function f and clamped splines of given degree Its compon...
subroutine sll_s_compute_e_from_rho_1d_fem_sm(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 init_1d_fem_sm(self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance)
Initialization.
subroutine init_from_file_1d_fem_sm(self, domain, n_cells, s_deg_0, boundary, nml_file)
Initialization from nml file.
subroutine compute_field_energy(self, efield_dofs1, efield_dofs2, bfield_dofs, energy)
Compute the field energy.
subroutine compute_phi_from_rho_1d_fem_sm(self, in, phi, efield)
For model with adiabatic electrons.
subroutine sll_s_compute_curl_part_1d_fem_sm(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
real(kind=f64) function inner_product_1d_fem_sm(self, coefs1_dofs, coefs2_dofs, degree, degree2)
Compute inner product.
real(kind=f64) function l2norm_squared_1d_fem_sm(self, coefs_dofs, degree)
Compute square of the L2norm.
subroutine invert_mass_1d_fem_sm(self, in, out, degree)
Multiply by the inverse mass matrix.
subroutine sll_s_compute_e_from_b_1d_fem_sm(self, delta_t, field_in, field_out)
compute Ey from Bz using weak Ampere formulation
subroutine compute_e_from_j_1d_fem_sm(self, current, component, E)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation.
subroutine compute_phi_from_j_1d_fem_sm(self, in, phi, efield)
For model with adiabatic electrons.
subroutine multiply_mass_1d_fem_sm(self, in, out, degree)
Multiply by the mass matrix.
subroutine l2projection_1d_fem_sm(self, func, degree, coefs_dofs)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine sll_s_compute_b_from_e_1d_fem_sm(self, delta_t, field_in, field_out)
Compute Bz from Ey using strong 1D Faraday equation for spline coefficients $B_z^{new}(x_j) = B_z^{ol...
Utilites for Maxwell solver's with spline finite elements using sparse matrices.
subroutine, public sll_s_multiply_gt_clamped_1d(n_dofs, delta_x, s_deg_0, in, out)
Multiplication of the input vector in by the transposed clamped derivative matrix G^T.
subroutine, public sll_s_multiply_g_clamped_1d(n_dofs, delta_x, s_deg_0, in, out)
Multiplication of the input vector in by the clamped derivative matrix G.
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_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_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)
    Report Typos and Errors