Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_maxwell_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 
22 
25 
28 
29  use sll_m_linear_solver_cg, only : &
31 
32  use sll_m_linear_solver_mgmres, only : &
34 
35  use sll_m_low_level_bsplines, only: &
36  sll_s_uniform_bsplines_eval_basis
37 
38  use sll_m_matrix_csr, only: &
40 
41  use sll_m_maxwell_1d_base, only: &
44 
45  use sll_m_spline_fem_utilities, only : &
50 
54 
55 
56  implicit none
57 
58  public :: &
60 
61  private
62  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
65 
66  type( sll_t_linear_operator_schur_eb_1d ) :: linear_op_schur_eb
67  type( sll_t_linear_solver_mgmres ) :: linear_solver_schur_eb
68 
69  sll_real64, allocatable :: wsave(:)
70  sll_real64, allocatable :: work(:)
71  sll_real64, allocatable :: work2(:)
72  type(sll_t_matrix_csr) :: mass0
73  type(sll_t_matrix_csr) :: mass1
74  type(sll_t_matrix_csr) :: mixed_mass
75  type(sll_t_linear_solver_cg) :: linear_solver_mass0
76  type(sll_t_linear_solver_cg) :: linear_solver_mass1
77 
78  type(sll_t_linear_operator_poisson_1d) :: poisson_matrix
79  type(sll_t_linear_operator_penalized) :: poisson_operator
80  type(sll_t_linear_solver_cg) :: poisson_solver
81  sll_real64 :: force_sign = 1._f64
82  logical :: adiabatic_electrons
83 
84  contains
85  procedure :: &
86  compute_e_from_b => sll_s_compute_e_from_b_1d_fem_sm
87  procedure :: &
88  compute_b_from_e => sll_s_compute_b_from_e_1d_fem_sm
89  procedure :: &
90  compute_curl_part => sll_s_compute_curl_part_1d_fem_sm
91  procedure :: &
92  compute_e_from_rho => sll_s_compute_e_from_rho_1d_fem_sm
93  procedure :: &
94  compute_rho_from_e => compute_rho_from_e_1d_fem_sm
95  procedure :: &
96  compute_e_from_j => compute_e_from_j_1d_fem_sm
97  procedure :: &
98  compute_phi_from_rho => compute_phi_from_rho_1d_fem_sm
99  procedure :: &
100  compute_phi_from_j => compute_phi_from_j_1d_fem_sm
101  procedure :: &
102  compute_rhs_from_function => sll_s_compute_rhs_fem_sm
103  procedure :: &
104  l2projection => l2projection_1d_fem_sm
105  procedure :: &
106  l2norm_squared => l2norm_squared_1d_fem_sm
107  procedure :: &
108  inner_product => inner_product_1d_fem_sm
109  procedure :: &
110  init => init_1d_fem_sm
111  procedure :: &
112  init_from_file => init_from_file_1d_fem_sm
113  procedure :: &
114  free => free_1d_fem_sm
115  procedure :: &
116  multiply_g
117  procedure :: &
119  procedure :: &
120  multiply_mass => multiply_mass_1d_fem_sm
121  procedure :: &
122  invert_mass => invert_mass_1d_fem_sm
123 
124 
125  end type sll_t_maxwell_1d_fem_sm
126 
127 contains
128 
129 
131  subroutine sll_s_compute_e_from_b_1d_fem_sm(self, delta_t, field_in, field_out)
132  class(sll_t_maxwell_1d_fem_sm) :: self
133  sll_real64, intent(in) :: delta_t
134  sll_real64, intent(in) :: field_in(:)
135  sll_real64, intent(inout) :: field_out(:)
136 
137  call self%multiply_mass( field_in, self%work2, self%s_deg_1 )
138  call self%multiply_gt( self%work2, self%work )
139  self%work2=0._f64
140  !call self%linear_solver_mass0%set_guess( field_in )
141  call self%linear_solver_mass0%solve ( self%work, self%work2 )
142  ! Update bz from self value
143  field_out = field_out + delta_t*self%work2
144  end subroutine sll_s_compute_e_from_b_1d_fem_sm
145 
146 
149  subroutine sll_s_compute_b_from_e_1d_fem_sm(self, delta_t, field_in, field_out)
150  class(sll_t_maxwell_1d_fem_sm) :: self
151  sll_real64, intent(in) :: delta_t
152  sll_real64, intent(in) :: field_in(:) ! ey
153  sll_real64, intent(inout) :: field_out(:) ! bz
154 
155  call self%multiply_g(field_in, self%work)
156  ! Update Bz from self value
157  field_out = field_out - delta_t * self%work
158 
159  end subroutine sll_s_compute_b_from_e_1d_fem_sm
160 
161 
163  subroutine sll_s_compute_curl_part_1d_fem_sm( self, delta_t, efield, bfield, betar )
164  class(sll_t_maxwell_1d_fem_sm) :: self
165  sll_real64, intent(in) :: delta_t
166  sll_real64, intent(inout) :: efield(:)
167  sll_real64, intent(inout) :: bfield(:)
168  sll_real64, optional :: betar
169  !local variables
170  sll_real64 :: factor
171 
172  if( present(betar) ) then
173  factor = betar
174  else
175  factor = 1._f64
176  end if
177 
178  self%work = 0._f64
179  self%work2 = 0._f64
180 
181  ! Compute D^T M2 b
182  call self%multiply_mass( bfield, self%work, self%s_deg_1 )
183  call self%multiply_gt( self%work, self%work2 )
184 
185  self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
186  call self%linear_op_schur_eb%dot( efield, self%work )
187  self%work = self%work + delta_t*factor*self%work2
188 
189  ! Save efield dofs from previous time step for B field update
190  self%work2 = efield
191 
192  ! Invert Schur complement matrix
193  self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
194  call self%linear_solver_schur_eb%set_guess( efield )
195  call self%linear_solver_schur_eb%solve( self%work, efield )
196 
197  ! Update B field
198  self%work2 = self%work2 + efield
199  call self%compute_B_from_E( delta_t*0.5_f64, self%work2, bfield )
200 
201 
202  end subroutine sll_s_compute_curl_part_1d_fem_sm
203 
204 
206  subroutine sll_s_compute_e_from_rho_1d_fem_sm(self, field_in, field_out )
207  class(sll_t_maxwell_1d_fem_sm) :: self
208  sll_real64, intent(in) :: field_in(:)
209  sll_real64, intent(out) :: field_out(:)
210 
211  self%wsave = self%force_sign * field_in
212  call self%poisson_solver%solve( self%wsave, self%work )
213  call multiply_g( self, self%work, field_out )
214  field_out = -field_out
215 
217 
218 
220  subroutine compute_rho_from_e_1d_fem_sm(self, field_in, field_out)
221  class(sll_t_maxwell_1d_fem_sm) :: self
222  sll_real64, intent(in) :: field_in(:)
223  sll_real64, intent(out) :: field_out(:)
224 
225  call self%multiply_mass( field_in, self%work, self%s_deg_1 )
226  call multiply_gt( self, self%work, field_out )
227  field_out = - self%force_sign * field_out
228 
229  end subroutine compute_rho_from_e_1d_fem_sm
230 
231 
233  subroutine compute_e_from_j_1d_fem_sm(self, current, component, E)
234  class(sll_t_maxwell_1d_fem_sm) :: self
235  sll_real64,dimension(:),intent(in) :: current
236  sll_int32, intent(in) :: component
237  sll_real64,dimension(:),intent(inout) :: e
238 
239  ! Multiply by inverse mass matrix using the eigenvalues of the circulant inverse matrix
240  if (component == 1) then
241  call self%linear_solver_mass1%solve( current, self%work )
242 
243  elseif (component == 2) then
244  call self%linear_solver_mass0%solve( current, self%work )
245  else
246  print*, 'Component ', component, 'not implemented in compute_E_from_j_1d_fem_sm.'
247  end if
248 
249  ! Update the electric field and scale
250  e = e - self%force_sign * self%work
251  end subroutine compute_e_from_j_1d_fem_sm
252 
253 
255  subroutine compute_phi_from_rho_1d_fem_sm( self, in, phi, efield )
256  class(sll_t_maxwell_1d_fem_sm) :: self
257  sll_real64, intent(in) :: in(:)
258  sll_real64, intent(out) :: phi(:)
259  sll_real64, intent(out) :: efield(:)
260 
261  ! Compute phi by inverting the mass matrix
262  call self%invert_mass( in, phi, self%s_deg_0 )
263 
264  ! Compute the degrees of freedom of the electric field as -G phi
265  call multiply_g( self, phi, efield )
266  efield = -efield
267 
268  end subroutine compute_phi_from_rho_1d_fem_sm
269 
270 
272  subroutine compute_phi_from_j_1d_fem_sm( self, in, phi, efield )
273  class(sll_t_maxwell_1d_fem_sm) :: self
274  sll_real64, intent(in) :: in(:)
275  sll_real64, intent(out) :: phi(:)
276  sll_real64, intent(out) :: efield(:)
277 
278  ! Compute divergence of the current (G^T current) (assuming a 1v model)
279  call multiply_gt( self, in, self%work )
280 
281  ! Compute phi by inverting the mass matrix
282  call self%invert_mass( self%work, self%wsave, self%s_deg_0 )
283  phi = phi + self%wsave
284 
285  ! Compute the degrees of freedom of the electric field as -G phi
286  call multiply_g( self, phi, efield )
287  efield = -efield
288 
289  end subroutine compute_phi_from_j_1d_fem_sm
290 
291 
294  subroutine sll_s_compute_rhs_fem_sm(self, func, degree, coefs_dofs)
295  class(sll_t_maxwell_1d_fem_sm) :: self
296  procedure(sll_i_function_1d_real64) :: func
297  sll_int32, intent(in) :: degree
298  sll_real64, intent(out) :: coefs_dofs(:)
299  ! local variables
300  sll_int32 :: i,j,k
301  sll_real64 :: coef
302  sll_real64, dimension(2,degree+1) :: xw_gauss
303  sll_real64, dimension(degree+1,degree+1) :: bspl
304 
305  ! take enough Gauss points so that projection is exact for splines of degree deg
306  ! rescale on [0,1] for compatibility with B-splines
307  xw_gauss = sll_f_gauss_legendre_points_and_weights(degree+1, 0.0_f64, 1.0_f64)
308  ! Compute bsplines at gauss_points
309  do k=1,degree+1
310  call sll_s_uniform_bsplines_eval_basis(degree,xw_gauss(1,k), bspl(:,k))
311  !print*, 'bs', bspl(k,:)
312  end do
313 
314  ! Compute coefs_dofs = int f(x)N_i(x)
315  do i = 1, self%n_cells
316  coef=0.0_f64
317  ! loop over support of B spline
318  do j = 1, degree+1
319  ! loop over Gauss points
320  do k=1, degree+1
321  coef = coef + xw_gauss(2,k)*func(self%delta_x * (xw_gauss(1,k) + real(i + j - 2 - ((i + j - 2)/self%n_cells) * self%n_cells,f64))) * bspl(degree+2-j,k)
322  end do
323  end do
324  ! rescale by cell size
325  coefs_dofs(i) = coef*self%delta_x
326  end do
327 
328  end subroutine sll_s_compute_rhs_fem_sm
329 
330 
332  subroutine l2projection_1d_fem_sm(self, func, degree, coefs_dofs)
333  class(sll_t_maxwell_1d_fem_sm) :: self
334  procedure(sll_i_function_1d_real64) :: func
335  sll_int32, intent(in) :: degree
336  sll_real64, intent(out) :: coefs_dofs(:)
337 
338  ! Compute right-hand-side
339  call sll_s_compute_rhs_fem_sm(self, func, degree, self%work)
340 
341  ! Multiply by inverse mass matrix (! complex numbers stored in real array with fftpack ordering)
342  if (degree == self%s_deg_0) then
343  call self%linear_solver_mass0%solve ( self%work, coefs_dofs )
344 
345  elseif (degree == self%s_deg_0-1) then
346  call self%linear_solver_mass1%solve ( self%work, coefs_dofs )
347  else
348  print*, 'degree ', degree, 'not availlable in maxwell_1d_fem_sm object'
349  endif
350 
351  end subroutine l2projection_1d_fem_sm
352 
353 
355  function l2norm_squared_1d_fem_sm(self, coefs_dofs, degree) result (r)
356  class(sll_t_maxwell_1d_fem_sm) :: self
357  sll_real64 :: coefs_dofs(:)
358  sll_int32 :: degree
359  sll_real64 :: r
360 
361  ! Multiply coefficients by mass matrix
362  if (degree == self%s_deg_0 ) then
363  call self%multiply_mass( coefs_dofs, self%work, self%s_deg_0 )
364 
365  elseif (degree == self%s_deg_1) then
366  call self%multiply_mass( coefs_dofs, self%work, self%s_deg_1 )
367 
368  end if
369  ! Multiply by the coefficients from the left (inner product)
370  r = sum(coefs_dofs*self%work)
371  end function l2norm_squared_1d_fem_sm
372 
373 
375  function inner_product_1d_fem_sm(self, coefs1_dofs, coefs2_dofs, degree, degree2) result (r)
376  class(sll_t_maxwell_1d_fem_sm) :: self
377  sll_real64 :: coefs1_dofs(:)
378  sll_real64 :: coefs2_dofs(:)
379  sll_int32 :: degree
380  sll_int32, optional :: degree2
381  sll_real64 :: r
382 
383  if (present(degree2)) then
384  if (degree == degree2) then
385  if (degree == self%s_deg_0 ) then
386 
387  !call self%mass0%dot ( coefs2_dofs, self%work )
388  call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_0 )
389 
390  elseif (degree == self%s_deg_1) then
391 
392  call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_1 )
393  !call self%mass1%dot ( coefs2_dofs, self%work )
394 
395  end if
396 
397  ! Multiply by the coefficients from the left (inner product)
398  r = sum(coefs1_dofs*self%work)
399  else
400  if (degree == self%s_deg_0) then
401  call self%multiply_mass( coefs2_dofs, self%work, 10 )
402  ! Multiply by the coefficients from the left (inner product)
403  r = sum(coefs1_dofs*self%work)
404  else
405  call self%multiply_mass( coefs1_dofs, self%work, 10 )
406  ! Multiply by the coefficients from the left (inner product)
407  r = sum(coefs2_dofs*self%work)
408  end if
409  end if
410  else
411  if (degree == self%s_deg_0 ) then
412  call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_0 )
413 
414  elseif (degree == self%s_deg_1) then
415  call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_1 )
416 
417  end if
418  ! Multiply by the coefficients from the left (inner product)
419  r = sum(coefs1_dofs*self%work)
420  end if
421  end function inner_product_1d_fem_sm
422 
423 
425  subroutine init_1d_fem_sm( self, domain, n_dofs, s_deg_0, delta_t, mass_tolerance, poisson_tolerance, solver_tolerance, force_sign, adiabatic_electrons )
426  class(sll_t_maxwell_1d_fem_sm), intent(out) :: self
427  sll_real64, intent(in) :: domain(2)
428  sll_int32, intent(in) :: n_dofs
429  !sll_real64 :: delta_x ! cell size
430  sll_int32, intent(in) :: s_deg_0
431  sll_real64, intent(in) :: delta_t
432  sll_real64, intent(in), optional :: mass_tolerance
433  sll_real64, intent(in), optional :: poisson_tolerance
434  sll_real64, intent(in), optional :: solver_tolerance
435  sll_real64, intent(in), optional :: force_sign
436  logical, intent(in), optional :: adiabatic_electrons
437  ! local variables
438  sll_int32 :: ierr
439  sll_real64 :: mass_line_0(s_deg_0+1), mass_line_1(s_deg_0), mass_line_mixed(s_deg_0*2)
440  sll_real64, allocatable :: nullspace(:,:)
441  sll_real64 :: t_e = 10000._f64
442 
443  if (present( mass_tolerance) ) then
444  self%mass_solver_tolerance = mass_tolerance
445  else
446  self%mass_solver_tolerance = 1d-12
447  end if
448  if (present( poisson_tolerance) ) then
449  self%poisson_solver_tolerance = poisson_tolerance
450  else
451  self%poisson_solver_tolerance = 1d-12
452  end if
453 
454  if (present( solver_tolerance) ) then
455  self%solver_tolerance = solver_tolerance
456  else
457  self%solver_tolerance = 1d-12
458  end if
459 
460  if (present( force_sign) ) then
461  self%force_sign = force_sign
462  end if
463 
464  if (present( adiabatic_electrons) ) then
465  self%adiabatic_electrons = adiabatic_electrons
466  end if
467 
468  self%n_dofs0 = n_dofs
469  self%n_dofs1 = n_dofs
470  self%n_cells = n_dofs
471  self%Lx = domain(2) - domain(1)
472  self%delta_x = self%Lx /real(n_dofs,f64)
473  self%s_deg_0 = s_deg_0
474  self%s_deg_1 = s_deg_0 - 1
475 
476 
477  sll_allocate(self%work(n_dofs),ierr)
478  sll_allocate(self%work2(n_dofs),ierr)
479  sll_allocate(self%wsave(n_dofs),ierr)
480 
481  ! Sparse matrices
482  call sll_s_spline_fem_mass_line ( self%s_deg_0, mass_line_0 )
483  call sll_s_spline_fem_mass_line ( self%s_deg_1, mass_line_1 )
484  !scale with delta_x=L/n_dofs
485  if(self%adiabatic_electrons) then
486  mass_line_0= mass_line_0*self%delta_x/t_e
487  else
488  mass_line_0= mass_line_0*self%delta_x
489  end if
490  mass_line_1= mass_line_1*self%delta_x
491  call sll_s_spline_fem_mass1d( n_dofs, self%s_deg_0, mass_line_0, self%mass0 )
492  call sll_s_spline_fem_mass1d( n_dofs, self%s_deg_1, mass_line_1, self%mass1 )
493  call self%linear_solver_mass0%create( self%mass0)
494  call self%linear_solver_mass1%create( self%mass1)
495  self%linear_solver_mass0%atol = self%mass_solver_tolerance
496  self%linear_solver_mass1%atol = self%mass_solver_tolerance
497  !self%linear_solver_mass0%verbose = .true.
498  !self%linear_solver_mass1%verbose = .true.
499 
500  ! Penalized Poisson operator
501  allocate(nullspace(1,1:self%n_cells))
502  nullspace(1,:) = 1.0_f64
503  call self%poisson_matrix%create( self%mass1, self%n_cells, self%delta_x )
504  call self%poisson_operator%create( self%poisson_matrix, vecs=nullspace, &
505  n_dim_nullspace=1 )
506  call self%poisson_solver%create( self%poisson_operator )
507  self%poisson_solver%null_space = .true.
508  self%poisson_solver%atol = self%poisson_solver_tolerance
509  !self%poisson_solver%verbose = .true.
510 
511 
512  call sll_s_spline_fem_mixedmass_line( self%s_deg_0, mass_line_mixed)
513  mass_line_mixed=mass_line_mixed*self%delta_x
514  call sll_s_spline_fem_mixedmass1d( n_dofs, self%s_deg_0, mass_line_mixed, self%mixed_mass )
515 
516  ! Only for Schur complement eb solver
517  call self%linear_op_schur_eb%create( self%mass0, self%mass1, self%n_cells, self%delta_x )
518  call self%linear_solver_schur_eb%create( self%linear_op_schur_eb )
519  self%linear_solver_schur_eb%atol = self%solver_tolerance
520  self%linear_solver_schur_eb%rtol = self%solver_tolerance
521  !self%linear_solver_schur_eb%verbose = .true.
522 
523  end subroutine init_1d_fem_sm
524 
525 
527  subroutine init_from_file_1d_fem_sm( self, domain, n_dofs, s_deg_0, nml_file, force_sign, adiabatic_electrons )
528  class(sll_t_maxwell_1d_fem_sm), intent(out) :: self
529  sll_real64, intent(in) :: domain(2)
530  sll_int32, intent(in) :: n_dofs
531  sll_int32, intent(in) :: s_deg_0
532  character(len=*) :: nml_file
533  sll_real64, intent(in), optional :: force_sign
534  logical, intent(in), optional :: adiabatic_electrons
535  ! local variables
536  sll_int32 :: input_file, rank
537  sll_int32 :: io_stat, io_stat0, io_stat1, file_id
538  character(len=256) :: file_prefix
539  logical :: output_fields = .false.
540  logical :: output_particles = .false.
541  sll_real64 :: mass_tolerance
542  sll_real64 :: poisson_tolerance
543  sll_real64 :: maxwell_tolerance
544  sll_real64 :: delta_t = 0._f64
545  sll_int32 :: n_time_steps
546  sll_real64 :: beta
547  character(len=256) :: initial_distrib
548  character(len=256) :: initial_bfield
549  sll_real64 :: charge
550 
551  namelist /sim_params/ delta_t, n_time_steps, beta, initial_distrib, initial_bfield, charge
552  namelist /output/ file_prefix, output_fields, output_particles
553  namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
554  namelist /time_solver/ maxwell_tolerance
555 
557 
558  if( present(force_sign) ) then
559  self%force_sign = force_sign
560  end if
561 
562  if (present( adiabatic_electrons) ) then
563  self%adiabatic_electrons = adiabatic_electrons
564  end if
565 
566  ! Read in solver tolerance
567  open(newunit = input_file, file=nml_file, status='old',iostat=io_stat)
568  if (io_stat /= 0) then
569  if (rank == 0 ) then
570  print*, 'sll_m_maxwell_1d_fem_sm: Input file does not exist. Set default tolerance.'
571  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
572  write(file_id, *) 'mass solver tolerance:', 1d-12
573  write(file_id, *) 'poisson solver tolerance:', 1d-12
574  close(file_id)
575  end if
576  call self%init( domain, n_dofs, s_deg_0, delta_t*0.5_f64 )
577 
578  else
579  read(input_file, output,iostat=io_stat0)
580  read(input_file, maxwell_solver,iostat=io_stat)
581  read(input_file, time_solver,iostat=io_stat1)
582  if (io_stat /= 0) then
583  if (rank == 0 ) then
584  print*, 'sll_m_maxwell_1d_fem_sm: Tolerance not given. Set default tolerance.'
585  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
586  write(file_id, *) 'mass solver tolerance:', 1d-12
587  write(file_id, *) 'poisson solver tolerance:', 1d-12
588  close(file_id)
589  end if
590  call self%init( domain, n_dofs, s_deg_0, delta_t*0.5_f64 )
591  else
592  if (rank == 0 ) then
593  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
594  write(file_id, *) 'mass solver tolerance:', mass_tolerance
595  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
596  close(file_id)
597  end if
598  call self%init( domain, n_dofs, s_deg_0, delta_t*0.5_f64, mass_tolerance, poisson_tolerance, solver_tolerance=maxwell_tolerance )
599  end if
600  close(input_file)
601  end if
602 
603 
604  end subroutine init_from_file_1d_fem_sm
605 
606 
608  subroutine free_1d_fem_sm(self)
609  class(sll_t_maxwell_1d_fem_sm) :: self
610 
611  deallocate(self%wsave)
612  deallocate(self%work)
613  call self%linear_solver_schur_eb%free()
614  call self%linear_op_schur_eb%free()
615 
616  end subroutine free_1d_fem_sm
617 
618 
620  subroutine multiply_g( self, in, out)
621  class(sll_t_maxwell_1d_fem_sm), intent(in) :: self
622  sll_real64, intent(in) :: in(:)
623  sll_real64, intent(out) :: out(:)
624 
625  call sll_s_multiply_g_1d( self%n_cells, self%delta_x, in, out )
626 
627  end subroutine multiply_g
628 
629 
631  subroutine multiply_gt( self, in, out)
632  class(sll_t_maxwell_1d_fem_sm), intent(in) :: self
633  sll_real64, intent(in) :: in(:)
634  sll_real64, intent(out) :: out(:)
635 
636  call sll_s_multiply_gt_1d( self%n_cells, self%delta_x, in, out )
637 
638  end subroutine multiply_gt
639 
640 
642  subroutine multiply_mass_1d_fem_sm( self, in, out, degree)
643  class(sll_t_maxwell_1d_fem_sm), intent(inout) :: self
644  sll_real64, intent(in) :: in(:)
645  sll_real64, intent(out) :: out(:)
646  sll_int32, intent(in) :: degree
647 
648  ! Multiply coefficients by mass matrix
649  if (degree == self%s_deg_0 ) then
650  call self%mass0%dot ( in, out)
651  elseif (degree == self%s_deg_1) then
652  call self%mass1%dot ( in, out)
653  elseif(degree == 10) then
654  call self%mixed_mass%dot( in, out )
655  else
656  print*, 'maxwell_solver_1d_fem_sm: multiply mass for other form not yet implemented'
657  stop
658  end if
659 
660  end subroutine multiply_mass_1d_fem_sm
661 
662 
664  subroutine invert_mass_1d_fem_sm( self, in, out, degree)
665  class(sll_t_maxwell_1d_fem_sm), intent(inout) :: self
666  sll_real64, intent(in) :: in(:)
667  sll_real64, intent(out) :: out(:)
668  sll_int32, intent(in) :: degree
669 
670  ! Multiply coefficients by mass matrix
671  if (degree == self%s_deg_0 ) then
672 
673  call self%linear_solver_mass0%solve( in, out)
674 
675  elseif (degree == self%s_deg_1) then
676 
677  call self%linear_solver_mass1%solve ( in, out)
678  else
679  print*, 'Invert mass for other form not yet implemented'
680  stop
681  end if
682 
683  end subroutine invert_mass_1d_fem_sm
684 
685 end module sll_m_maxwell_1d_fem_sm
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 penalized linear operator
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 in 1D based on spline FEM, version based on sparse matrices.
subroutine compute_phi_from_rho_1d_fem_sm(self, in, phi, efield)
For model with adiabatic electrons.
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_rhs_fem_sm(self, func, degree, coefs_dofs)
Compute the FEM right-hand-side for a given function f and periodic splines of given degree Its compo...
subroutine compute_rho_from_e_1d_fem_sm(self, field_in, field_out)
Compute rho from Gauss law for given efield.
real(kind=f64) function inner_product_1d_fem_sm(self, coefs1_dofs, coefs2_dofs, degree, degree2)
Compute inner product.
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 compute_phi_from_j_1d_fem_sm(self, in, phi, efield)
For model with adiabatic electrons.
subroutine init_1d_fem_sm(self, domain, n_dofs, s_deg_0, delta_t, mass_tolerance, poisson_tolerance, solver_tolerance, force_sign, adiabatic_electrons)
Initialization.
real(kind=f64) function l2norm_squared_1d_fem_sm(self, coefs_dofs, degree)
Compute square of the L2norm.
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 init_from_file_1d_fem_sm(self, domain, n_dofs, s_deg_0, nml_file, force_sign, adiabatic_electrons)
Initialization from nml file.
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...
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 multiply_mass_1d_fem_sm(self, in, out, degree)
Multiply by the mass matrix.
subroutine free_1d_fem_sm(self)
Finalization.
subroutine invert_mass_1d_fem_sm(self, in, out, degree)
Multiply by the inverse mass matrix.
subroutine multiply_g(self, in, out)
Multiply by dicrete gradient matrix.
subroutine sll_s_compute_curl_part_1d_fem_sm(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
subroutine multiply_gt(self, in, out)
Multiply by transpose of dicrete gradient matrix.
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(n_cells, s_deg, mass_line, matrix)
Utilites for Maxwell solver's with spline finite elements.
subroutine, public sll_s_multiply_g_1d(n_dofs, delta_x, in, out)
Multiplication of the input vector in by the derivative matrix G.
subroutine, public sll_s_multiply_gt_1d(n_dofs, delta_x, in, out)
Multiplication of the input vector in by the transposed derivative matrix G^T
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.
Maxwell solver class for spline FEM with sparse matrix solvers.
    Report Typos and Errors