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_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 
26  use sll_m_linear_solver_cg, only : &
28 
29  use sll_m_linear_solver_mgmres, only : &
31 
32  use sll_m_low_level_bsplines, only: &
33  sll_s_uniform_bsplines_eval_basis
34 
35  use sll_m_mapping_3d, only: &
37 
38  use sll_m_matrix_csr, only: &
40 
41  use sll_m_maxwell_1d_base, only: &
44 
48 
52 
53  use sll_m_splines_pp, only: &
58 
59  implicit none
60 
61  public :: &
63 
64  private
65  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
66 
68 
69  type(sll_t_spline_pp_1d) :: spline0_pp
70  type(sll_t_spline_pp_1d) :: spline1_pp
71  sll_real64, allocatable :: work1(:)
72  sll_real64, allocatable :: work0(:)
73  sll_real64, allocatable :: work01(:)
74  type(sll_t_matrix_csr) :: mass0
75  type(sll_t_matrix_csr) :: mass1
76  type(sll_t_matrix_csr) :: mixed_mass
77  type(sll_t_linear_solver_cg) :: linear_solver_mass0
78  type(sll_t_linear_solver_cg) :: linear_solver_mass1
79 
81  type(sll_t_linear_solver_cg) :: poisson_solver
82  type( sll_t_linear_operator_schur_eb_cl_1d ) :: linear_op_schur_eb
83  type( sll_t_linear_solver_mgmres ) :: linear_solver_schur_eb
84  type(sll_t_mapping_3d), pointer :: map
85 
86  contains
87 
88  procedure :: &
89  compute_e_from_b => sll_s_compute_e_from_b_1d_trafo
90  procedure :: &
91  compute_b_from_e => sll_s_compute_b_from_e_1d_trafo
92  procedure :: &
93  compute_curl_part => sll_s_compute_curl_part_1d_trafo
94  procedure :: &
95  compute_e_from_rho => sll_s_compute_e_from_rho_1d_trafo
96  procedure :: &
97  compute_rho_from_e => compute_rho_from_e_1d_trafo
98  procedure :: &
99  compute_e_from_j => compute_e_from_j_1d_trafo
100  procedure :: &
101  compute_phi_from_rho => compute_phi_from_rho_1d_trafo
102  procedure :: &
103  compute_phi_from_j => compute_phi_from_j_1d_trafo
104  procedure :: &
105  compute_rhs_from_function => sll_s_compute_rhs_trafo
106  procedure :: &
107  l2projection => l2projection_1d_trafo
108  procedure :: &
109  l2norm_squared => l2norm_squared_1d_trafo
110  procedure :: &
111  inner_product => inner_product_1d_trafo
112  procedure :: &
113  init => init_1d_trafo
114  procedure :: &
115  init_from_file => init_from_file_1d_trafo
116  procedure :: &
117  free => free_1d_trafo
118  procedure :: &
119  multiply_g
120  procedure :: &
122  procedure :: &
123  multiply_mass => multiply_mass_1d_trafo
124  procedure :: &
125  invert_mass => invert_mass_1d_trafo
126 
128 
129 contains
130 
131 
133  subroutine sll_s_compute_e_from_b_1d_trafo(self, delta_t, field_in, field_out)
134  class(sll_t_maxwell_clamped_1d_trafo) :: self
135  sll_real64, intent( in ) :: delta_t
136  sll_real64, intent( in ) :: field_in(:)
137  sll_real64, intent( inout ) :: field_out(:)
138 
139  call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
140  call self%multiply_gt( self%work1, self%work0 )
141 
142  call self%invert_mass( self%work0, self%work01, self%s_deg_0 )
143  ! Update Ey from self value
144  field_out = field_out + delta_t*self%work01
145 
146  end subroutine sll_s_compute_e_from_b_1d_trafo
147 
148 
151  subroutine sll_s_compute_b_from_e_1d_trafo(self, delta_t, field_in, field_out)
152  class(sll_t_maxwell_clamped_1d_trafo) :: self
153  sll_real64, intent( in ) :: delta_t
154  sll_real64, intent( in ) :: field_in(:) ! Ey
155  sll_real64, intent( inout ) :: field_out(:) ! Bz
156 
157  call self%multiply_g(field_in, self%work1)
158  ! Update Bz from self value
159  field_out = field_out - delta_t * self%work1
160 
161  end subroutine sll_s_compute_b_from_e_1d_trafo
162 
163 
165  subroutine sll_s_compute_curl_part_1d_trafo( self, delta_t, efield, bfield, betar )
166  class(sll_t_maxwell_clamped_1d_trafo) :: self
167  sll_real64, intent(in) :: delta_t
168  sll_real64, intent(inout) :: efield(:)
169  sll_real64, intent(inout) :: bfield(:)
170  sll_real64, optional :: betar
171  !local variables
172  sll_real64 :: factor
173 
174  if( present(betar) ) then
175  factor = betar
176  else
177  factor = 1._f64
178  end if
179 
180  self%work1 = 0._f64
181  self%work0 = 0._f64
182  self%work01 = 0._f64
183 
184  ! Compute D^T M2 b
185  call self%multiply_mass( bfield, self%work1, self%s_deg_1 )
186  call self%multiply_gt( self%work1, self%work0 )
187 
188  self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
189  call self%linear_op_schur_eb%dot( efield, self%work01 )
190  self%work01 = self%work01 + delta_t*factor*self%work0
191 
192  ! Save efield dofs from previous time step for B field update
193  self%work0 = efield
194 
195  ! Invert Schur complement matrix
196  self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
197  call self%linear_solver_schur_eb%set_guess( efield )
198  call self%linear_solver_schur_eb%solve( self%work01, efield )
199 
200  ! Update B field
201  self%work0 = self%work0 + efield
202  call self%compute_B_from_E( delta_t*0.5_f64, self%work0, bfield )
203 
204  end subroutine sll_s_compute_curl_part_1d_trafo
205 
206 
208  subroutine sll_s_compute_e_from_rho_1d_trafo(self, field_in, field_out )
209  class(sll_t_maxwell_clamped_1d_trafo) :: self
210  sll_real64, intent( in ) :: field_in(:)
211  sll_real64, intent( out ) :: field_out(:)
212 
213  call self%poisson_solver%solve( field_in, self%work0 )
214  call multiply_g( self, self%work0, field_out )
215  field_out = -field_out
216 
217  end subroutine sll_s_compute_e_from_rho_1d_trafo
218 
219 
221  subroutine compute_rho_from_e_1d_trafo(self, field_in, field_out)
222  class(sll_t_maxwell_clamped_1d_trafo) :: self
223  sll_real64, intent( in ) :: field_in(:)
224  sll_real64, intent( out ) :: field_out(:)
225 
226  call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
227  call multiply_gt( self, self%work1, field_out )
228  field_out = - field_out
229 
230  end subroutine compute_rho_from_e_1d_trafo
231 
232 
234  subroutine compute_e_from_j_1d_trafo(self, current, component, E)
235  class(sll_t_maxwell_clamped_1d_trafo) :: self
236  sll_real64,dimension(:),intent(in) :: current
237  sll_int32, intent(in) :: component
238  sll_real64,dimension(:),intent(inout) :: e
239 
240  ! Multiply by inverse mass matrix using the eigenvalues of the circulant inverse matrix
241  if (component == 1) then
242  call self%invert_mass( current, self%work1, self%s_deg_1 )
243  e = e - self%work1
244  elseif (component == 2) then
245  call self%invert_mass( current, self%work0, self%s_deg_0 )
246  e = e - self%work0
247  else
248  print*, 'Component ', component, 'not implemented in compute_E_from_j_1d_trafo.'
249  end if
250 
251  end subroutine compute_e_from_j_1d_trafo
252 
253 
255  subroutine compute_phi_from_rho_1d_trafo( self, in, phi, efield )
256  class(sll_t_maxwell_clamped_1d_trafo) :: 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_trafo
269 
270 
272  subroutine compute_phi_from_j_1d_trafo( self, in, phi, efield )
273  class(sll_t_maxwell_clamped_1d_trafo) :: 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%work01 )
280 
281  ! Compute phi by inverting the mass matrix
282  call self%invert_mass( self%work01, self%work0, self%s_deg_0 )
283  phi = phi + self%work0
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_trafo
290 
291 
294  subroutine sll_s_compute_rhs_trafo(self, func, degree, coefs_dofs)
295  class(sll_t_maxwell_clamped_1d_trafo) :: 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,quad,q
301  sll_real64 :: c
302  sll_real64, allocatable :: xw_gauss(:,:)
303  sll_real64, allocatable :: bspl(:,:)
304  sll_real64 :: jacobian
305 
306  q = 2*degree+1
307  allocate( xw_gauss(2,q) )
308  allocate( bspl(degree+1,q) )
309  ! take enough Gauss points so that projection is exact for splines of degree deg
310  ! rescale on [0,1] for compatibility with B-splines
311  xw_gauss = sll_f_gauss_legendre_points_and_weights(q, 0.0_f64, 1.0_f64)
312 
313  if( degree == self%s_deg_0 ) then
314  coefs_dofs = 0._f64
315  !first degree-1 cells are different
316  !loop over cells
317  do i = 1, degree-1
318  !loop over splines
319  do j = 1, degree+1
320  ! loop over Gauss points
321  do quad = 1, q
322  c = self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64))
323  jacobian= self%map%jacobian( [c, 0._f64, 0._f64])
324  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
325  self%delta_x* xw_gauss(2,quad) * func(self%map%get_x1( [c, 0._f64, 0._f64])) *&
326  sll_f_spline_pp_horner_1d( degree, self%spline0_pp%poly_coeffs_boundary_left(:,:,i), xw_gauss(1,quad), j)*abs(jacobian)
327  enddo
328  enddo
329  enddo
330  bspl=0._f64
331  ! Compute bsplines at gauss_points
332  do quad=1,q
333  do j=1, degree+1
334  bspl(j,quad) = sll_f_spline_pp_horner_1d( degree, self%spline0_pp%poly_coeffs, xw_gauss(1,quad), j)
335  end do
336  end do
337 
338  ! Compute coefs_dofs = int f(x)N_i(x)
339  !loop over cells
340  do i = degree, self%n_cells-degree+1
341  ! loop over splines
342  do j = 1, degree+1
343  ! loop over Gauss points
344  do quad = 1, q
345  c = self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64))
346  jacobian= self%map%jacobian( [c, 0._f64, 0._f64])
347  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
348  self%delta_x * xw_gauss(2,quad) * func(self%map%get_x1( [c, 0._f64, 0._f64])) * bspl(j,quad) * abs(jacobian)
349  enddo
350  enddo
351  enddo
352 
353  !last degree-1 cells are different
354  !loop over cells
355  do i = self%n_cells-degree+2, self%n_cells
356  !loop over splines
357  do j = 1, degree+1
358  ! loop over Gauss points
359  do quad = 1, q
360  c = self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64))
361  jacobian= self%map%jacobian( [c, 0._f64, 0._f64])
362  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
363  self%delta_x * xw_gauss(2,quad) * func(self%map%get_x1( [c, 0._f64, 0._f64])) *&
364  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) * abs(jacobian)
365  enddo
366  enddo
367  end do
368 
369  else if (degree == self%s_deg_1)then
370 
371  coefs_dofs = 0._f64
372  !first degree-1 cells are different
373  !loop over cells
374  do i = 1, degree-1
375  !loop over splines
376  do j = 1, degree+1
377  ! loop over Gauss points
378  do quad = 1, q
379  c = self%delta_x * (xw_gauss(1,quad) + real(i - 1,f64))
380  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
381  self%delta_x * xw_gauss(2,quad)*func(self%map%get_x1( [c, 0._f64, 0._f64])) *&
382  sll_f_spline_pp_horner_1d( degree, self%spline1_pp%poly_coeffs_boundary_left(:,:,i), xw_gauss(1,quad), j) * sign( 1._f64, self%map%jacobian( [c, 0._f64, 0._f64] ) )
383  enddo
384  enddo
385  enddo
386 
387  bspl=0._f64
388  ! Compute bsplines at gauss_points
389  do quad=1, q
390  do j=1, degree+1
391  bspl(j,quad) = sll_f_spline_pp_horner_1d( degree, self%spline1_pp%poly_coeffs, xw_gauss(1,quad), j)
392  end do
393  end do
394 
395  ! Compute coefs_dofs = int f(x)N_i(x)
396  !loop over cells
397  do i = degree, self%n_cells-degree+1
398  !loop over splines
399  do j = 1, degree+1
400  ! loop over Gauss points
401  do quad = 1, q
402  c = self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64))
403  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
404  self%delta_x * xw_gauss(2,quad) * func(self%map%get_x1( [c, 0._f64, 0._f64])) * bspl(j,quad) * sign( 1._f64, self%map%jacobian( [c, 0._f64, 0._f64] ) )
405  enddo
406  enddo
407  enddo
408 
409  !last degree-1 cells are different
410  !loop over cells
411  do i = self%n_cells-degree+2, self%n_cells
412  !loop over splines
413  do j = 1, degree+1
414  ! loop over Gauss points
415  do quad = 1, q
416  c = self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64))
417  coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
418  self%delta_x * xw_gauss(2,quad) * func(self%map%get_x1( [c, 0._f64, 0._f64])) *&
419  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) * sign( 1._f64, self%map%jacobian( [c, 0._f64, 0._f64] ) )
420  enddo
421  enddo
422  end do
423 
424  endif
425 
426  end subroutine sll_s_compute_rhs_trafo
427 
428 
430  subroutine l2projection_1d_trafo(self, func, degree, coefs_dofs)
431  class(sll_t_maxwell_clamped_1d_trafo) :: self
432  procedure(sll_i_function_1d_real64) :: func
433  sll_int32, intent( in ) :: degree
434  sll_real64, intent( out ) :: coefs_dofs(:)
435 
436  ! Multiply by inverse mass matrix (! complex numbers stored in real array with fftpack ordering)
437  if (degree == self%s_deg_0) then
438  ! Compute right-hand-side
439  call sll_s_compute_rhs_trafo(self, func, degree, self%work0)
440  call self%invert_mass( self%work0, coefs_dofs, self%s_deg_0 )
441  elseif (degree == self%s_deg_1) then
442  ! Compute right-hand-side
443  call sll_s_compute_rhs_trafo(self, func, degree, self%work1)
444  call self%invert_mass( self%work1, coefs_dofs, self%s_deg_1 )
445  else
446  print*, 'degree ', degree, 'not availlable in maxwell_clamped_1d_trafo object'
447  endif
448  end subroutine l2projection_1d_trafo
449 
450 
452  function l2norm_squared_1d_trafo(self, coefs_dofs, degree) result (r)
453  class(sll_t_maxwell_clamped_1d_trafo) :: self
454  sll_real64 :: coefs_dofs(:)
455  sll_int32 :: degree
456  sll_real64 :: r
457 
458  ! Multiply coefficients by mass matrix (use diagonalization FFT and mass matrix eigenvalues)
459  if (degree == self%s_deg_0 ) then
460  call self%multiply_mass( coefs_dofs, self%work0, self%s_deg_0 )
461  ! Multiply by the coefficients from the left (inner product)
462  r = sum(coefs_dofs*self%work0)
463  elseif (degree == self%s_deg_1) then
464  call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_1 )
465  ! Multiply by the coefficients from the left (inner product)
466  r = sum(coefs_dofs*self%work1)
467  end if
468 
469  end function l2norm_squared_1d_trafo
470 
472  function inner_product_1d_trafo(self, coefs1_dofs, coefs2_dofs, degree, degree2) result (r)
473  class(sll_t_maxwell_clamped_1d_trafo) :: self
474  sll_real64 :: coefs1_dofs(:)
475  sll_real64 :: coefs2_dofs(:)
476  sll_int32 :: degree
477  sll_int32, optional :: degree2
478  sll_real64 :: r
479 
480  ! Multiply coefficients by mass matrix (use diagonalization FFT and mass matrix eigenvalues)
481  if (present(degree2)) then
482  if (degree == degree2) then
483  if (degree == self%s_deg_0 ) then
484  call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
485  ! Multiply by the coefficients from the left (inner product)
486  r = sum(coefs1_dofs*self%work0)
487  elseif (degree == self%s_deg_1) then
488  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
489  ! Multiply by the coefficients from the left (inner product)
490  r = sum(coefs1_dofs*self%work1)
491  end if
492  else
493  if (degree == self%s_deg_0) then
494  call self%multiply_mass( coefs2_dofs, self%work01, 10 )
495  ! Multiply by the coefficients from the left (inner product)
496  r = sum(coefs1_dofs*self%work01)
497  else
498  call self%multiply_mass( coefs1_dofs, self%work01, 10 )
499  ! Multiply by the coefficients from the left (inner product)
500  r = sum(coefs2_dofs*self%work01)
501  end if
502  end if
503  else
504  if (degree == self%s_deg_0 ) then
505  call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
506  ! Multiply by the coefficients from the left (inner product)
507  r = sum(coefs1_dofs*self%work0)
508  elseif (degree == self%s_deg_1) then
509  call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
510  ! Multiply by the coefficients from the left (inner product)
511  r = sum(coefs1_dofs*self%work1)
512  end if
513  end if
514 
515  end function inner_product_1d_trafo
516 
517 
519  subroutine init_1d_trafo( self, domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, solver_tolerance )
520  class(sll_t_maxwell_clamped_1d_trafo), intent(out) :: self
521  sll_real64, intent(in) :: domain(2)
522  sll_int32, intent(in) :: n_cells
523  sll_int32, intent(in) :: s_deg_0
524  sll_int32, intent(in) :: boundary
525  type(sll_t_mapping_3d), target, intent(inout ) :: map
526  sll_real64, intent(in), optional :: mass_tolerance
527  sll_real64, intent(in), optional :: poisson_tolerance
528  sll_real64, intent(in), optional :: solver_tolerance
529  ! local variables
530  sll_int32 :: ierr
531 
532  if (present( mass_tolerance) ) then
533  self%mass_solver_tolerance = mass_tolerance
534  else
535  self%mass_solver_tolerance = 1d-12
536  end if
537  if (present( poisson_tolerance) ) then
538  self%poisson_solver_tolerance = poisson_tolerance
539  else
540  self%poisson_solver_tolerance = 1d-12
541  end if
542 
543  if (present( solver_tolerance) ) then
544  self%solver_tolerance = solver_tolerance
545  else
546  self%solver_tolerance = 1d-12
547  end if
548 
549  self%n_cells = n_cells
550  self%n_dofs0 = n_cells+s_deg_0
551  self%n_dofs1 = n_cells+s_deg_0-1
552  self%Lx = map%params(1)
553  self%delta_x = 1._f64 / real(n_cells,f64)
554  self%s_deg_0 = s_deg_0
555  self%s_deg_1 = s_deg_0 - 1
556  self%map=>map
557 
558  call sll_s_spline_pp_init_1d( self%spline0_pp, self%s_deg_0, n_cells, boundary)
559  call sll_s_spline_pp_init_1d( self%spline1_pp, self%s_deg_1, n_cells, boundary)
560 
561  sll_allocate(self%work1(self%n_dofs1),ierr)
562  sll_allocate(self%work0(self%n_dofs0),ierr)
563  sll_allocate(self%work01(self%n_dofs0),ierr)
564 
565  ! Sparse matrices
566  call sll_s_spline_fem_mass1d_clamped_full ( n_cells, self%s_deg_0, self%spline0_pp, self%mass0, profile_0 )
567  call sll_s_spline_fem_mass1d_clamped_full ( n_cells, self%s_deg_1, self%spline1_pp, self%mass1, profile_1 )
568 
569  call self%linear_solver_mass0%create( self%mass0)
570  self%linear_solver_mass0%atol = self%mass_solver_tolerance
571  call self%linear_solver_mass1%create( self%mass1)
572  self%linear_solver_mass1%atol = self%mass_solver_tolerance /self%Lx
573  !self%linear_solver_mass0%verbose = .true.
574  !self%linear_solver_mass1%verbose = .true.
575 
576  call sll_s_spline_fem_mixedmass1d_clamped_full( n_cells, self%s_deg_0, self%s_deg_1, self%mixed_mass, profile_m0, self%spline0_pp, self%spline1_pp )
577 
578 
579  ! Poisson solver
580  call self%poisson_matrix%create( self%mass1, self%s_deg_0, self%n_dofs0, self%delta_x )
581  call self%poisson_solver%create( self%poisson_matrix )
582  self%poisson_solver%atol = self%poisson_solver_tolerance
583  !self%poisson_solver%verbose = .true.
584  !self%poisson_solver%n_maxiter=40000
585 
586  ! Only for Schur complement eb solver
587  call self%linear_op_schur_eb%create( self%mass0, self%mass1, self%n_dofs0, self%delta_x, self%s_deg_0 )
588  call self%linear_solver_schur_eb%create( self%linear_op_schur_eb )
589  self%linear_solver_schur_eb%atol = self%solver_tolerance
590  self%linear_solver_schur_eb%rtol = self%solver_tolerance
591  !self%linear_solver_schur_eb%verbose = .true.
592 
593  contains
594  function profile_0(x)
595  sll_real64 :: profile_0
596  sll_real64, intent(in) :: x
597 
598  profile_0 = map%jacobian( [x, 0._f64, 0._f64] )
599 
600  end function profile_0
601 
602  function profile_1(x)
603  sll_real64 :: profile_1
604  sll_real64, intent(in) :: x
605 
606  profile_1 = 1._f64/map%jacobian( [x, 0._f64, 0._f64] )
607 
608  end function profile_1
609 
610  function profile_m0(x)
611  sll_real64 :: profile_m0
612  sll_real64, intent(in) :: x
613 
614  profile_m0 = 1._f64
615  end function profile_m0
616 
617  end subroutine init_1d_trafo
618 
619 
621  subroutine init_from_file_1d_trafo( self, domain, n_cells, s_deg_0, boundary, map, nml_file )
622  class(sll_t_maxwell_clamped_1d_trafo), intent(out) :: self
623  sll_real64, intent(in) :: domain(2)
624  sll_int32, intent(in) :: n_cells
625  sll_int32, intent(in) :: s_deg_0
626  sll_int32, intent(in) :: boundary
627  type(sll_t_mapping_3d), target, intent(inout) :: map
628  character(len=*), intent(in) :: nml_file
629  ! local variables
630  character(len=256) :: file_prefix
631  sll_int32 :: input_file
632  sll_int32 :: io_stat, io_stat0, io_stat1, rank, file_id
633  sll_real64 :: mass_tolerance
634  sll_real64 :: poisson_tolerance
635  sll_real64 :: maxwell_tolerance
636 
637  namelist /output/ file_prefix
638  namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
639  namelist /time_solver/ maxwell_tolerance
640 
642 
643  ! Read in solver tolerance
644  open(newunit = input_file, file=nml_file, status='old',iostat=io_stat)
645  if (io_stat /= 0) then
646  if (rank == 0 ) then
647  print*, 'sll_m_maxwell_clamped_1d_trafo: Input file does not exist. Set default tolerance.'
648  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
649  write(file_id, *) 'mass solver tolerance:', 1d-12
650  write(file_id, *) 'poisson solver tolerance:', 1d-12
651  close(file_id)
652  end if
653  call self%init( domain, n_cells, s_deg_0, boundary, map )
654  else
655  read(input_file, output,iostat=io_stat0)
656  read(input_file, maxwell_solver,iostat=io_stat)
657  read(input_file, time_solver,iostat=io_stat1)
658  if (io_stat /= 0 .or. io_stat1 /= 0 ) then
659  if (rank == 0 ) then
660  print*, 'sll_m_maxwell_clamped_1d_trafo: Input parameter does not exist. Set default tolerance.'
661  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
662  write(file_id, *) 'mass solver tolerance:', 1d-12
663  write(file_id, *) 'poisson solver tolerance:', 1d-12
664  close(file_id)
665  end if
666  call self%init( domain, n_cells, s_deg_0, boundary, map )
667  else
668  if (rank == 0 ) then
669  open(newunit=file_id, file=trim(file_prefix)//'_parameters_used.dat', position = 'append', status='old', action='write', iostat=io_stat)
670  write(file_id, *) 'mass solver tolerance:', mass_tolerance
671  write(file_id, *) 'poisson solver tolerance:', poisson_tolerance
672  close(file_id)
673  end if
674  call self%init( domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, maxwell_tolerance )
675  end if
676  close(input_file)
677  end if
678 
679 
680  end subroutine init_from_file_1d_trafo
681 
682 
684  subroutine free_1d_trafo(self)
685  class(sll_t_maxwell_clamped_1d_trafo) :: self
686 
687  self%map=> null()
688  call self%linear_solver_mass0%free()
689  call self%linear_solver_mass1%free()
690  call self%poisson_solver%free()
691  call self%poisson_matrix%free()
692  call self%linear_solver_schur_eb%free()
693  call self%linear_op_schur_eb%free()
694 
695  call sll_s_spline_pp_free_1d( self%spline0_pp )
696  call sll_s_spline_pp_free_1d( self%spline1_pp )
697 
698  deallocate(self%work1)
699  deallocate(self%work0)
700  deallocate(self%work01)
701 
702  end subroutine free_1d_trafo
703 
704 
706  subroutine multiply_g( self, in, out)
707  class(sll_t_maxwell_clamped_1d_trafo), intent(in) :: self
708  sll_real64, intent(in) :: in(:)
709  sll_real64, intent(out) :: out(:)
710 
711  call sll_s_multiply_g_clamped_1d( self%n_dofs0, self%delta_x, self%s_deg_0, in, out)
712 
713  end subroutine multiply_g
714 
715 
717  subroutine multiply_gt( self, in, out)
718  class(sll_t_maxwell_clamped_1d_trafo), intent(in) :: self
719  sll_real64, intent(in) :: in(:)
720  sll_real64, intent(out) :: out(:)
721 
722  call sll_s_multiply_gt_clamped_1d( self%n_dofs0, self%delta_x, self%s_deg_0, in, out)
723 
724  end subroutine multiply_gt
725 
726 
728  subroutine multiply_mass_1d_trafo( self, in, out, degree)
729  class(sll_t_maxwell_clamped_1d_trafo), intent(inout) :: self
730  sll_real64, intent(in) :: in(:)
731  sll_real64, intent(out) :: out(:)
732  sll_int32, intent(in) :: degree
733 
734  if (degree == self%s_deg_0 ) then
735  call self%mass0%dot( in, out )
736  elseif (degree == self%s_deg_1) then
737  call self%mass1%dot( in, out )
738  elseif(degree == 10) then
739  call self%mixed_mass%dot( in, out )
740  else
741  print*, 'maxwell_solver_clamped_1d_trafo: multiply mass for other form not yet implemented'
742  stop
743  end if
744 
745  end subroutine multiply_mass_1d_trafo
746 
747 
749  subroutine invert_mass_1d_trafo( self, in, out, degree)
750  class(sll_t_maxwell_clamped_1d_trafo), intent(inout) :: self
751  sll_real64, intent(in) :: in(:)
752  sll_real64, intent(out) :: out(:)
753  sll_int32, intent(in) :: degree
754 
755  if (degree == self%s_deg_0 ) then
756  call self%linear_solver_mass0%solve( in, out )
757  out(1) = 0._f64
758  out(self%n_dofs0) = 0._f64
759  elseif (degree == self%s_deg_1) then
760  call self%linear_solver_mass1%solve( in, out )
761  else
762  print*, 'Invert mass for other form not yet implemented'
763  stop
764  end if
765 
766  end subroutine invert_mass_1d_trafo
767 
768 
770  subroutine compute_field_energy( self, efield_dofs1, efield_dofs2, bfield_dofs, energy)
771  class(sll_t_maxwell_clamped_1d_trafo) :: self
772  sll_real64, intent( in ) :: efield_dofs1(:)
773  sll_real64, intent( in ) :: efield_dofs2(:)
774  sll_real64, intent( in ) :: bfield_dofs(:)
775  sll_real64, intent( out ) :: energy
776  !local variables
777  sll_real64 :: field_energy(3)
778 
779 
780  field_energy(1) = self%l2norm_squared &
781  ( efield_dofs1(1:self%n_dofs1), self%s_deg_1 )
782  field_energy(2) = self%l2norm_squared &
783  ( efield_dofs2(1:self%n_dofs0), self%s_deg_0 )
784  field_energy(3) =self%l2norm_squared &
785  ( bfield_dofs(1:self%n_dofs1), self%s_deg_1 )
786 
787  energy = 0.5_f64*sum(field_energy)
788 
789  end subroutine compute_field_energy
790 
791 
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 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 with boundary conditions in 1D based on spline F...
subroutine sll_s_compute_curl_part_1d_trafo(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
subroutine init_from_file_1d_trafo(self, domain, n_cells, s_deg_0, boundary, map, nml_file)
Initialization from nml file.
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 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_e_from_b_1d_trafo(self, delta_t, field_in, field_out)
compute Ey from Bz using weak Ampere formulation
subroutine compute_field_energy(self, efield_dofs1, efield_dofs2, bfield_dofs, energy)
Compute field energy.
subroutine multiply_mass_1d_trafo(self, in, out, degree)
Multiply by the mass matrix.
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 )
subroutine init_1d_trafo(self, domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, solver_tolerance)
Initialization.
real(kind=f64) function inner_product_1d_trafo(self, coefs1_dofs, coefs2_dofs, degree, degree2)
Compute inner product.
real(kind=f64) function l2norm_squared_1d_trafo(self, coefs_dofs, degree)
Compute square of the L2norm.
subroutine sll_s_compute_rhs_trafo(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 l2projection_1d_trafo(self, func, degree, coefs_dofs)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine compute_phi_from_j_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 multiply_g(self, in, out)
Multiply by dicrete gradient matrix.
subroutine compute_rho_from_e_1d_trafo(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.
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_clamped_full(n_cells, deg, spline, matrix, profile)
Set up 1d mass matrix for specific spline degree and profile function.
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.
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_1(x)
type collecting functions for analytical coordinate mapping
    Report Typos and Errors