Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_maxwell_1d_trafo.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_mapping_3d, only: &
40 
41  use sll_m_matrix_csr, only: &
43 
44  use sll_m_maxwell_1d_base, only: &
47 
48  use sll_m_spline_fem_utilities, only : &
51 
55 
56  implicit none
57 
58  public :: &
60 
61  private
62  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
63 
65 
66  sll_real64, allocatable :: work1(:)
67  sll_real64, allocatable :: work2(:)
68  type(sll_t_matrix_csr) :: mass0
69  type(sll_t_matrix_csr) :: mass1
70  type(sll_t_matrix_csr) :: mixed_mass
71  type(sll_t_linear_solver_cg) :: linear_solver_mass0
72  type(sll_t_linear_solver_cg) :: linear_solver_mass1
73 
74  type(sll_t_linear_operator_poisson_1d) :: poisson_matrix
75  type(sll_t_linear_operator_penalized) :: poisson_operator
76  type(sll_t_linear_solver_cg) :: poisson_solver
77  type( sll_t_linear_operator_schur_eb_1d ) :: linear_op_schur_eb
78  type( sll_t_linear_solver_mgmres ) :: linear_solver_schur_eb
79  type(sll_t_mapping_3d), pointer :: map
80  sll_real64 :: force_sign = 1._f64
81 
82  contains
83 
84  procedure :: &
85  compute_e_from_b => sll_s_compute_e_from_b_1d_trafo
86  procedure :: &
87  compute_b_from_e => sll_s_compute_b_from_e_1d_trafo
88  procedure :: &
89  compute_curl_part => sll_s_compute_curl_part_1d_trafo
90  procedure :: &
91  compute_e_from_rho => sll_s_compute_e_from_rho_1d_trafo
92  procedure :: &
93  compute_rho_from_e => compute_rho_from_e_1d_trafo
94  procedure :: &
95  compute_e_from_j => compute_e_from_j_1d_trafo
96  procedure :: &
97  compute_phi_from_rho => compute_phi_from_rho_1d_trafo
98  procedure :: &
99  compute_phi_from_j => compute_phi_from_j_1d_trafo
100 
101  procedure :: &
102  compute_rhs_from_function => sll_s_compute_rhs_trafo
103  procedure :: &
104  l2projection => l2projection_1d_trafo
105  procedure :: &
106  l2norm_squared => l2norm_squared_1d_trafo
107  procedure :: &
108  inner_product => inner_product_1d_trafo
109  procedure :: &
110  init => init_1d_trafo
111  procedure :: &
112  init_from_file => init_from_file_1d_trafo
113  procedure :: &
114  free => free_1d_trafo
115  procedure :: &
116  multiply_g
117  procedure :: &
119  procedure :: &
120  multiply_mass => multiply_mass_1d_trafo
121  procedure :: &
122  invert_mass => invert_mass_1d_trafo
123 
124  end type sll_t_maxwell_1d_trafo
125 
126 contains
127 
129  subroutine sll_s_compute_e_from_b_1d_trafo(self, delta_t, field_in, field_out)
130  class(sll_t_maxwell_1d_trafo) :: self
131  sll_real64, intent( in ) :: delta_t
132  sll_real64, intent( in ) :: field_in(:)
133  sll_real64, intent( inout ) :: field_out(:)
134 
135  call self%multiply_mass( field_in, self%work2, self%s_deg_1 )
136  call self%multiply_gt( self%work2, self%work1 )
137  self%work2=0._f64
138  call self%linear_solver_mass0%solve ( self%work1, self%work2 )
139  ! Update ey from self value
140  field_out = field_out + delta_t*self%work2
141 
142  end subroutine sll_s_compute_e_from_b_1d_trafo
143 
144 
147  subroutine sll_s_compute_b_from_e_1d_trafo(self, delta_t, field_in, field_out)
148  class(sll_t_maxwell_1d_trafo) :: self
149  sll_real64, intent( in ) :: delta_t
150  sll_real64, intent( in ) :: field_in(:) ! Ey
151  sll_real64, intent( inout ) :: field_out(:) ! Bz
152 
153  call self%multiply_g(field_in, self%work1)
154  ! Update Bz from self value
155  field_out = field_out - delta_t * self%work1
156 
157  end subroutine sll_s_compute_b_from_e_1d_trafo
158 
159 
161  subroutine sll_s_compute_curl_part_1d_trafo( self, delta_t, efield, bfield, betar )
162  class(sll_t_maxwell_1d_trafo) :: self
163  sll_real64, intent(in) :: delta_t
164  sll_real64, intent(inout) :: efield(:)
165  sll_real64, intent(inout) :: bfield(:)
166  sll_real64, optional :: betar
167  !local variables
168  sll_real64 :: factor
169 
170  if( present(betar) ) then
171  factor = betar
172  else
173  factor = 1._f64
174  end if
175 
176  self%work1 = 0._f64
177  self%work2 = 0._f64
178 
179  ! Compute D^T M2 b
180  call self%multiply_mass( bfield, self%work1, self%s_deg_1 )
181  call self%multiply_gt( self%work1, self%work2 )
182 
183  self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
184  call self%linear_op_schur_eb%dot( efield, self%work1 )
185  self%work1 = self%work1 + delta_t*factor*self%work2
186 
187  ! Save efield dofs from previous time step for B field update
188  self%work2 = efield
189 
190  ! Invert Schur complement matrix
191  self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
192  call self%linear_solver_schur_eb%set_guess( efield )
193  call self%linear_solver_schur_eb%solve( self%work1, efield )
194 
195  ! Update B field
196  self%work2 = self%work2 + efield
197  call self%compute_B_from_E( delta_t*0.5_f64, self%work2, bfield )
198 
199  end subroutine sll_s_compute_curl_part_1d_trafo
200 
201 
203  subroutine sll_s_compute_e_from_rho_1d_trafo(self, field_in, field_out )
204  class(sll_t_maxwell_1d_trafo) :: self
205  sll_real64, intent( in ) :: field_in(:)
206  sll_real64, intent( out ) :: field_out(:)
207 
208  call self%poisson_solver%solve( field_in, self%work1 )
209  call multiply_g( self, self%work1, field_out )
210  field_out = -field_out
211 
212  end subroutine sll_s_compute_e_from_rho_1d_trafo
213 
214 
216  subroutine compute_rho_from_e_1d_trafo(self, field_in, field_out)
217  class(sll_t_maxwell_1d_trafo) :: self
218  sll_real64, intent( in ) :: field_in(:)
219  sll_real64, intent( out ) :: field_out(:)
220 
221  call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
222  call multiply_gt( self, self%work1, field_out )
223  field_out = - self%force_sign * field_out
224 
225  end subroutine compute_rho_from_e_1d_trafo
226 
227 
229  subroutine compute_e_from_j_1d_trafo(self, current, component, E)
230  class(sll_t_maxwell_1d_trafo) :: self
231  sll_real64,dimension(:),intent(in) :: current
232  sll_int32, intent(in) :: component
233  sll_real64,dimension(:),intent(inout) :: e
234 
235  ! Multiply by inverse mass matrix using the eigenvalues of the circulant inverse matrix
236  if (component == 1) then
237  call self%linear_solver_mass1%solve( current, self%work1 )
238 
239  elseif (component == 2) then
240  call self%linear_solver_mass0%solve( current, self%work1 )
241  else
242  print*, 'Component ', component, 'not implemented in compute_E_from_j_1d_trafo.'
243  end if
244 
245  ! Update the electric field and scale
246  e = e - self%force_sign * self%work1
247 
248  end subroutine compute_e_from_j_1d_trafo
249 
250 
252  subroutine compute_phi_from_rho_1d_trafo( self, in, phi, efield )
253  class(sll_t_maxwell_1d_trafo) :: self
254  sll_real64, intent(in) :: in(:)
255  sll_real64, intent(out) :: phi(:)
256  sll_real64, intent(out) :: efield(:)
257 
258  ! Compute phi by inverting the mass matrix
259  call self%invert_mass( in, phi, self%s_deg_0 )
260 
261  ! Compute the degrees of freedom of the electric field as G phi
262  call multiply_g( self, phi, efield )
263  efield = -efield
264 
265  end subroutine compute_phi_from_rho_1d_trafo
266 
267 
269  subroutine compute_phi_from_j_1d_trafo( self, in, phi, efield )
270  class(sll_t_maxwell_1d_trafo) :: self
271  sll_real64, intent(in) :: in(:)
272  sll_real64, intent(out) :: phi(:)
273  sll_real64, intent(out) :: efield(:)
274 
275  ! Compute divergence of the current (G^T current) (assuming a 1v model)
276  call multiply_gt( self, in, self%work1 )
277 
278  ! Compute phi by inverting the mass matrix
279  call self%invert_mass( self%work1, self%work2, self%s_deg_0 )
280  phi = phi + self%work2
281 
282  ! Compute the degrees of freedom of the electric field as -G phi
283  call multiply_g( self, phi, efield )
284  efield = -efield
285 
286  end subroutine compute_phi_from_j_1d_trafo
287 
288 
291  subroutine sll_s_compute_rhs_trafo(self, func, degree, coefs_dofs)
292  class(sll_t_maxwell_1d_trafo) :: self
293  procedure(sll_i_function_1d_real64) :: func
294  sll_int32, intent( in ) :: degree
295  sll_real64, intent( out ) :: coefs_dofs(:)
296  ! local variables
297  sll_int32 :: i,j,k
298  sll_real64 :: coef, c
299  sll_real64, dimension(2,degree+1) :: xw_gauss
300  sll_real64, dimension(degree+1,degree+1) :: bspl
301  sll_real64 :: jacobian
302 
303  ! take enough Gauss points so that projection is exact for splines of degree deg
304  ! rescale on [0,1] for compatibility with B-splines
305  xw_gauss = sll_f_gauss_legendre_points_and_weights(degree+1, 0.0_f64, 1.0_f64)
306  ! Compute bsplines at gauss_points
307  do k=1,degree+1
308  call sll_s_uniform_bsplines_eval_basis(degree,xw_gauss(1,k), bspl(:,k))
309  end do
310 
311  if( degree == self%s_deg_0 ) then
312  ! Compute coefs_dofs = int f(x)N_i(x)
313  do i = 1, self%n_cells
314  coef=0.0_f64
315  ! loop over support of B spline
316  do j = 1, degree+1
317  ! loop over Gauss points
318  do k=1, degree+1
319  c = self%delta_x * (xw_gauss(1,k) + real(i + j - 2 - ((i + j - 2)/self%n_cells) * self%n_cells,f64))
320  jacobian= self%map%jacobian( [[c, 0.0_f64, 0._f64]])
321  coef = coef + xw_gauss(2,k)*func(self%map%get_x1( [c, 0._f64, 0._f64])) * bspl(degree+2-j,k)*abs(jacobian)
322  enddo
323  enddo
324  ! rescale by cell size
325  coefs_dofs(i) = coef*self%delta_x
326  enddo
327  else
328  ! Compute coefs_dofs = int f(x)N_i(x)
329  do i = 1, self%n_cells
330  coef=0.0_f64
331  ! loop over support of B spline
332  do j = 1, degree+1
333  ! loop over Gauss points
334  do k=1, degree+1
335  c = self%delta_x * (xw_gauss(1,k) + real(i + j - 2 - ((i + j - 2)/self%n_cells) * self%n_cells,f64))
336  coef = coef + xw_gauss(2,k)*func(self%map%get_x1( [c, 0._f64, 0._f64])) * bspl(degree+2-j,k)* sign( 1._f64, self%map%jacobian( [c, 0._f64, 0._f64] ) )
337  enddo
338  enddo
339  ! rescale by cell size
340  coefs_dofs(i) = coef*self%delta_x
341  enddo
342  endif
343 
344  end subroutine sll_s_compute_rhs_trafo
345 
346 
348  subroutine l2projection_1d_trafo(self, func, degree, coefs_dofs)
349  class(sll_t_maxwell_1d_trafo) :: self
350  procedure(sll_i_function_1d_real64) :: func
351  sll_int32, intent( in ) :: degree
352  sll_real64, intent( out ) :: coefs_dofs(:)
353 
354  ! Compute right-hand-side
355  call self%compute_rhs_from_function( func, degree, self%work1)
356 
357  ! Multiply by inverse mass matrix
358  if (degree == self%s_deg_0) then
359  call self%linear_solver_mass0%solve ( self%work1, coefs_dofs )
360 
361  elseif (degree == self%s_deg_1) then
362  call self%linear_solver_mass1%solve ( self%work1, coefs_dofs )
363  else
364  print*, 'degree ', degree, 'not availlable in maxwell_1d_trafo object'
365  endif
366  end subroutine l2projection_1d_trafo
367 
368 
370  function l2norm_squared_1d_trafo(self, coefs_dofs, degree) result (r)
371  class(sll_t_maxwell_1d_trafo) :: self
372  sll_real64 :: coefs_dofs(:)
373  sll_int32 :: degree
374  sll_real64 :: r
375 
376  ! Multiply coefficients by mass matrix (use diagonalization FFT and mass matrix eigenvalues)
377  if (degree == self%s_deg_0 ) then
378 
379  call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_0 )
380 
381  elseif (degree == self%s_deg_1) then
382 
383  call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_1 )
384 
385  end if
386  ! Multiply by the coefficients from the left (inner product)
387  r = sum(coefs_dofs*self%work1)
388 
389  end function l2norm_squared_1d_trafo
390 
391 
393  function inner_product_1d_trafo(self, coefs1_dofs, coefs2_dofs, degree, degree2) result (r)
394  class(sll_t_maxwell_1d_trafo) :: self
395  sll_real64 :: coefs1_dofs(:)
396  sll_real64 :: coefs2_dofs(:)
397  sll_int32 :: degree
398  sll_int32, optional :: degree2
399  sll_real64 :: r
400 
401  ! Multiply coefficients by mass matrix
402  if (present(degree2)) then
403  if (degree == degree2) then
404  if (degree == self%s_deg_0 ) then
405 
406  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_0 )
407 
408  elseif (degree == self%s_deg_1) then
409 
410  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
411 
412  end if
413  ! Multiply by the coefficients from the left (inner product)
414  r = sum(coefs1_dofs*self%work1)
415  else
416  if (degree == self%s_deg_0) then
417  call self%multiply_mass( coefs2_dofs, self%work1, 10 )
418  ! Multiply by the coefficients from the left (inner product)
419  r = sum(coefs1_dofs*self%work1)
420  else
421  call self%multiply_mass( coefs1_dofs, self%work1, 10 )
422  ! Multiply by the coefficients from the left (inner product)
423  r = sum(coefs2_dofs*self%work1)
424  end if
425  end if
426  else
427  if (degree == self%s_deg_0 ) then
428 
429  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_0 )
430 
431  elseif (degree == self%s_deg_1) then
432 
433  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
434 
435  end if
436  ! Multiply by the coefficients from the left (inner product)
437  r = sum(coefs1_dofs*self%work1)
438  end if
439  end function inner_product_1d_trafo
440 
441 
443  subroutine init_1d_trafo( self, domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance, force_sign )
444  class(sll_t_maxwell_1d_trafo), intent(out) :: self
445  sll_real64, intent(in) :: domain(2)
446  sll_int32, intent(in) :: n_dofs
447  sll_int32, intent(in) :: s_deg_0
448  type(sll_t_mapping_3d), target, intent(inout) :: map
449  sll_real64, intent(in), optional :: mass_tolerance
450  sll_real64, intent(in), optional :: poisson_tolerance
451  sll_real64, intent(in), optional :: solver_tolerance
452  sll_real64, intent(in), optional :: force_sign
453  ! local variables
454  sll_real64, allocatable :: nullspace(:,:)
455  sll_int32 :: ierr
456 
457  if (present( mass_tolerance) ) then
458  self%mass_solver_tolerance = mass_tolerance
459  else
460  self%mass_solver_tolerance = 1d-12
461  end if
462  if (present( poisson_tolerance) ) then
463  self%poisson_solver_tolerance = poisson_tolerance
464  else
465  self%poisson_solver_tolerance = 1d-12
466  end if
467 
468  if (present( solver_tolerance) ) then
469  self%solver_tolerance = solver_tolerance
470  else
471  self%solver_tolerance = 1d-12
472  end if
473 
474  if (present( force_sign) ) then
475  self%force_sign = force_sign
476  end if
477 
478  self%n_dofs0 = n_dofs
479  self%n_dofs1 = n_dofs
480  self%n_cells = n_dofs
481  self%Lx = map%params(1)
482  self%delta_x = 1._f64 / real(n_dofs,f64)
483  self%s_deg_0 = s_deg_0
484  self%s_deg_1 = s_deg_0 - 1
485  self%map=>map
486 
487  sll_allocate(self%work1(n_dofs),ierr)
488  sll_allocate(self%work2(n_dofs),ierr)
489 
490  ! Sparse matrices
491  call sll_s_spline_fem_mass1d_full ( n_dofs, self%s_deg_0, self%mass0, profile_0 )
492  call sll_s_spline_fem_mass1d_full ( n_dofs, self%s_deg_1, self%mass1, profile_1 )
493 
494  call self%linear_solver_mass0%create( self%mass0)
495  self%linear_solver_mass0%atol = self%mass_solver_tolerance
496 
497  call self%linear_solver_mass1%create( self%mass1)
498  self%linear_solver_mass1%atol = self%mass_solver_tolerance /self%Lx
499  !self%linear_solver_mass0%verbose = .true.
500  !self%linear_solver_mass1%verbose = .true.
501 
502  ! Penalized Poisson operator
503  allocate(nullspace(1,1:self%n_cells))
504  nullspace(1,:) = 1.0_f64
505  call self%poisson_matrix%create( self%mass1, self%n_cells, self%delta_x )
506  call self%poisson_operator%create( self%poisson_matrix, vecs=nullspace, &
507  n_dim_nullspace=1 )
508 
509  call self%poisson_solver%create( self%poisson_operator )
510  self%poisson_solver%null_space = .true.
511  self%poisson_solver%atol = self%poisson_solver_tolerance
512  !self%poisson_solver%verbose = .true.
513 
514  call sll_s_spline_fem_mixedmass1d_full( n_dofs, self%s_deg_0, self%s_deg_1, self%mixed_mass, profile_m0 )
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  contains
524  function profile_0(x)
525  sll_real64 :: profile_0
526  sll_real64, intent(in) :: x
527 
528  profile_0 = map%jacobian( [x, 0._f64, 0._f64] )
529 
530  end function profile_0
531 
532  function profile_1(x)
533  sll_real64 :: profile_1
534  sll_real64, intent(in) :: x
535 
536  profile_1 = 1._f64/map%jacobian( [x, 0._f64, 0._f64] )
537 
538  end function profile_1
539 
540  function profile_m0(x)
541  sll_real64 :: profile_m0
542  sll_real64, intent(in) :: x
543 
544  profile_m0 = 1._f64
545  end function profile_m0
546 
547  end subroutine init_1d_trafo
548 
549 
551  subroutine init_from_file_1d_trafo( self, domain, n_dofs, s_deg_0, map, nml_file, force_sign )
552  class(sll_t_maxwell_1d_trafo), intent(out) :: self
553  sll_real64, intent(in) :: domain(2)
554  sll_int32, intent(in) :: n_dofs
555  sll_int32, intent(in) :: s_deg_0
556  type(sll_t_mapping_3d), target, intent(inout) :: map
557  character(len=*), intent(in) :: nml_file
558  sll_real64, intent(in), optional :: force_sign
559  ! local variables
560  sll_int32 :: input_file
561  sll_int32 :: io_stat, io_stat0, io_stat1, rank, file_id
562  character(len=256) :: file_prefix
563  sll_real64 :: mass_tolerance
564  sll_real64 :: poisson_tolerance
565  sll_real64 :: maxwell_tolerance
566 
567  namelist /output/ file_prefix
568  namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
569  namelist /time_solver/ maxwell_tolerance
570 
572 
573  if (present( force_sign) ) then
574  self%force_sign = force_sign
575  end if
576 
577  ! Read in solver tolerance
578  open(newunit = input_file, file=nml_file, status='old',iostat=io_stat)
579  if (io_stat /= 0) then
580  if (rank == 0 ) then
581  print*, 'sll_m_maxwell_1d_trafo: Input file does not exist. Set default tolerance.'
582  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
583  write(file_id, *) 'mass solver tolerance:', 1d-12
584  write(file_id, *) 'poisson solver tolerance:', 1d-12
585  close(file_id)
586  end if
587  call self%init( domain, n_dofs, s_deg_0, map )
588  else
589  read(input_file, output,iostat=io_stat0)
590  read(input_file, maxwell_solver,iostat=io_stat)
591  read(input_file, time_solver,iostat=io_stat1)
592  if (io_stat /= 0 .and. io_stat1 /= 0) then
593  if (rank == 0 ) then
594  print*, 'sll_m_maxwell_1d_trafo: Input parameter does not exist. Set default tolerance.'
595  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
596  write(file_id, *) 'mass solver tolerance:', 1d-12
597  write(file_id, *) 'poisson solver tolerance:', 1d-12
598  close(file_id)
599  end if
600  call self%init( domain, n_dofs, s_deg_0, map )
601  else if (io_stat /= 0 .and. io_stat1 == 0) then
602  call self%init( domain, n_dofs, s_deg_0, map, solver_tolerance=maxwell_tolerance )
603  else if (io_stat == 0 .and. io_stat1 /= 0) then
604  if (rank == 0 ) then
605  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
606  write(file_id, *) 'mass solver tolerance:', mass_tolerance
607  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
608  close(file_id)
609  end if
610  call self%init( domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance )
611  else
612  if (rank == 0 ) then
613  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
614  write(file_id, *) 'mass solver tolerance:', mass_tolerance
615  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
616  close(file_id)
617  end if
618  call self%init( domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance=maxwell_tolerance )
619  end if
620  close(input_file)
621  end if
622 
623 
624  end subroutine init_from_file_1d_trafo
625 
626 
628  subroutine free_1d_trafo(self)
629  class(sll_t_maxwell_1d_trafo) :: self
630 
631  deallocate(self%work1)
632  deallocate(self%work2)
633  self%map=> null()
634  call self%linear_solver_mass0%free()
635  call self%linear_solver_mass1%free()
636  call self%poisson_solver%free()
637  call self%poisson_operator%free()
638  call self%poisson_matrix%free()
639  call self%linear_solver_schur_eb%free()
640  call self%linear_op_schur_eb%free()
641 
642  end subroutine free_1d_trafo
643 
644 
646  subroutine multiply_g( self, in, out)
647  class(sll_t_maxwell_1d_trafo), intent(in) :: self
648  sll_real64, intent(in) :: in(:)
649  sll_real64, intent(out) :: out(:)
650 
651  call sll_s_multiply_g_1d( self%n_cells, self%delta_x, in, out )
652 
653  end subroutine multiply_g
654 
655 
657  subroutine multiply_gt( self, in, out)
658  class(sll_t_maxwell_1d_trafo), intent(in) :: self
659  sll_real64, intent(in) :: in(:)
660  sll_real64, intent(out) :: out(:)
661 
662  call sll_s_multiply_gt_1d( self%n_cells, self%delta_x, in, out )
663 
664  end subroutine multiply_gt
665 
666 
668  subroutine multiply_mass_1d_trafo( self, in, out, degree)
669  class(sll_t_maxwell_1d_trafo), intent(inout) :: self
670  sll_real64, intent(in) :: in(:)
671  sll_real64, intent(out) :: out(:)
672  sll_int32, intent(in) :: degree
673 
674  if (degree == self%s_deg_0 ) then
675  call self%mass0%dot( in, out )
676  elseif (degree == self%s_deg_1) then
677  call self%mass1%dot( in, out )
678  elseif(degree == 10) then
679  call self%mixed_mass%dot( in, out )
680  else
681  print*, 'maxwell_solver_1d_trafo: multiply mass for other form not yet implemented'
682  stop
683  end if
684 
685  end subroutine multiply_mass_1d_trafo
686 
687 
689  subroutine invert_mass_1d_trafo( self, in, out, degree)
690  class(sll_t_maxwell_1d_trafo), intent(inout) :: self
691  sll_real64, intent(in) :: in(:)
692  sll_real64, intent(out) :: out(:)
693  sll_int32, intent(in) :: degree
694 
695  if (degree == self%s_deg_0 ) then
696  call self%linear_solver_mass0%solve( in, out )
697  elseif (degree == self%s_deg_1) then
698  call self%linear_solver_mass1%solve( in, out )
699  else
700  print*, 'Invert mass for other form not yet implemented'
701  stop
702  end if
703 
704  end subroutine invert_mass_1d_trafo
705 
706 
707 end module sll_m_maxwell_1d_trafo
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 interfaces for coordinate transformation.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations in 1D.
Solve Maxwell's equations in curvilinear coordinates in 1D based on spline FEM, version based on spar...
subroutine compute_rho_from_e_1d_trafo(self, field_in, field_out)
Compute rho from Gauss law for given efield.
subroutine init_from_file_1d_trafo(self, domain, n_dofs, s_deg_0, map, nml_file, force_sign)
Initialization from nml file.
subroutine multiply_gt(self, in, out)
Multiply by transpose of dicrete gradient matrix.
subroutine multiply_g(self, in, out)
Multiply by dicrete gradient matrix.
subroutine init_1d_trafo(self, domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance, force_sign)
Initialization.
real(kind=f64) function inner_product_1d_trafo(self, coefs1_dofs, coefs2_dofs, degree, degree2)
Compute inner product.
subroutine sll_s_compute_e_from_b_1d_trafo(self, delta_t, field_in, field_out)
compute Ey from Bz using weak Ampere formulation
subroutine multiply_mass_1d_trafo(self, in, out, degree)
Multiply by the mass matrix.
subroutine compute_phi_from_j_1d_trafo(self, in, phi, efield)
For model with adiabatic electrons.
subroutine invert_mass_1d_trafo(self, in, out, degree)
Multiply by the inverse mass matrix.
subroutine compute_phi_from_rho_1d_trafo(self, in, phi, efield)
For model with adiabatic electrons.
subroutine sll_s_compute_b_from_e_1d_trafo(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_trafo(self, current, component, E)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation.
subroutine sll_s_compute_curl_part_1d_trafo(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
subroutine sll_s_compute_rhs_trafo(self, func, degree, coefs_dofs)
Compute the FEM right-hand-side for a given function f and periodic splines of given degree Its compo...
real(kind=f64) function l2norm_squared_1d_trafo(self, coefs_dofs, degree)
Compute square of the L2norm.
subroutine l2projection_1d_trafo(self, func, degree, coefs_dofs)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine free_1d_trafo(self)
Finalization.
subroutine sll_s_compute_e_from_rho_1d_trafo(self, field_in, field_out)
compute e from rho using weak Poisson's equation ( rho = G^T M_1 G \phi, e = -G \phi )
Utilites for Maxwell solver's with spline finite elements using sparse matrix linear solvers.
subroutine, public sll_s_spline_fem_mixedmass1d_full(n_cells, deg1, deg2, matrix, profile)
subroutine, public sll_s_spline_fem_mass1d_full(n_cells, s_deg, matrix, profile)
Set up 1d mass matrix for specific spline degree and profile function.
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
real(kind=f64) function profile_0(x)
real(kind=f64) function profile_m0(x)
real(kind=f64) function profile_1(x)
type collecting functions for analytical coordinate mapping
    Report Typos and Errors