9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
36 sll_s_uniform_bsplines_eval_basis
69 sll_real64,
allocatable :: wsave(:)
70 sll_real64,
allocatable :: work(:)
71 sll_real64,
allocatable :: work2(:)
81 sll_real64 :: force_sign = 1._f64
82 logical :: adiabatic_electrons
133 sll_real64,
intent(in) :: delta_t
134 sll_real64,
intent(in) :: field_in(:)
135 sll_real64,
intent(inout) :: field_out(:)
137 call self%multiply_mass( field_in, self%work2, self%s_deg_1 )
138 call self%multiply_gt( self%work2, self%work )
141 call self%linear_solver_mass0%solve ( self%work, self%work2 )
143 field_out = field_out + delta_t*self%work2
151 sll_real64,
intent(in) :: delta_t
152 sll_real64,
intent(in) :: field_in(:)
153 sll_real64,
intent(inout) :: field_out(:)
155 call self%multiply_g(field_in, self%work)
157 field_out = field_out - delta_t * self%work
165 sll_real64,
intent(in) :: delta_t
166 sll_real64,
intent(inout) :: efield(:)
167 sll_real64,
intent(inout) :: bfield(:)
168 sll_real64,
optional :: betar
172 if(
present(betar) )
then
182 call self%multiply_mass( bfield, self%work, self%s_deg_1 )
183 call self%multiply_gt( self%work, self%work2 )
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
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 )
198 self%work2 = self%work2 + efield
199 call self%compute_B_from_E( delta_t*0.5_f64, self%work2, bfield )
208 sll_real64,
intent(in) :: field_in(:)
209 sll_real64,
intent(out) :: field_out(:)
211 self%wsave = self%force_sign * field_in
212 call self%poisson_solver%solve( self%wsave, self%work )
214 field_out = -field_out
222 sll_real64,
intent(in) :: field_in(:)
223 sll_real64,
intent(out) :: field_out(:)
225 call self%multiply_mass( field_in, self%work, self%s_deg_1 )
227 field_out = - self%force_sign * field_out
235 sll_real64,
dimension(:),
intent(in) :: current
236 sll_int32,
intent(in) :: component
237 sll_real64,
dimension(:),
intent(inout) :: e
240 if (component == 1)
then
241 call self%linear_solver_mass1%solve( current, self%work )
243 elseif (component == 2)
then
244 call self%linear_solver_mass0%solve( current, self%work )
246 print*,
'Component ', component,
'not implemented in compute_E_from_j_1d_fem_sm.'
250 e = e - self%force_sign * self%work
257 sll_real64,
intent(in) :: in(:)
258 sll_real64,
intent(out) :: phi(:)
259 sll_real64,
intent(out) :: efield(:)
262 call self%invert_mass( in, phi, self%s_deg_0 )
274 sll_real64,
intent(in) :: in(:)
275 sll_real64,
intent(out) :: phi(:)
276 sll_real64,
intent(out) :: efield(:)
282 call self%invert_mass( self%work, self%wsave, self%s_deg_0 )
283 phi = phi + self%wsave
297 sll_int32,
intent(in) :: degree
298 sll_real64,
intent(out) :: coefs_dofs(:)
302 sll_real64,
dimension(2,degree+1) :: xw_gauss
303 sll_real64,
dimension(degree+1,degree+1) :: bspl
310 call sll_s_uniform_bsplines_eval_basis(degree,xw_gauss(1,k), bspl(:,k))
315 do i = 1, self%n_cells
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)
325 coefs_dofs(i) = coef*self%delta_x
335 sll_int32,
intent(in) :: degree
336 sll_real64,
intent(out) :: coefs_dofs(:)
342 if (degree == self%s_deg_0)
then
343 call self%linear_solver_mass0%solve ( self%work, coefs_dofs )
345 elseif (degree == self%s_deg_0-1)
then
346 call self%linear_solver_mass1%solve ( self%work, coefs_dofs )
348 print*,
'degree ', degree,
'not availlable in maxwell_1d_fem_sm object'
357 sll_real64 :: coefs_dofs(:)
362 if (degree == self%s_deg_0 )
then
363 call self%multiply_mass( coefs_dofs, self%work, self%s_deg_0 )
365 elseif (degree == self%s_deg_1)
then
366 call self%multiply_mass( coefs_dofs, self%work, self%s_deg_1 )
370 r = sum(coefs_dofs*self%work)
377 sll_real64 :: coefs1_dofs(:)
378 sll_real64 :: coefs2_dofs(:)
380 sll_int32,
optional :: degree2
383 if (
present(degree2))
then
384 if (degree == degree2)
then
385 if (degree == self%s_deg_0 )
then
388 call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_0 )
390 elseif (degree == self%s_deg_1)
then
392 call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_1 )
398 r = sum(coefs1_dofs*self%work)
400 if (degree == self%s_deg_0)
then
401 call self%multiply_mass( coefs2_dofs, self%work, 10 )
403 r = sum(coefs1_dofs*self%work)
405 call self%multiply_mass( coefs1_dofs, self%work, 10 )
407 r = sum(coefs2_dofs*self%work)
411 if (degree == self%s_deg_0 )
then
412 call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_0 )
414 elseif (degree == self%s_deg_1)
then
415 call self%multiply_mass( coefs2_dofs, self%work, self%s_deg_1 )
419 r = sum(coefs1_dofs*self%work)
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 )
427 sll_real64,
intent(in) :: domain(2)
428 sll_int32,
intent(in) :: n_dofs
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
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
443 if (
present( mass_tolerance) )
then
444 self%mass_solver_tolerance = mass_tolerance
446 self%mass_solver_tolerance = 1d-12
448 if (
present( poisson_tolerance) )
then
449 self%poisson_solver_tolerance = poisson_tolerance
451 self%poisson_solver_tolerance = 1d-12
454 if (
present( solver_tolerance) )
then
455 self%solver_tolerance = solver_tolerance
457 self%solver_tolerance = 1d-12
460 if (
present( force_sign) )
then
461 self%force_sign = force_sign
464 if (
present( adiabatic_electrons) )
then
465 self%adiabatic_electrons = adiabatic_electrons
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
477 sll_allocate(self%work(n_dofs),ierr)
478 sll_allocate(self%work2(n_dofs),ierr)
479 sll_allocate(self%wsave(n_dofs),ierr)
485 if(self%adiabatic_electrons)
then
486 mass_line_0= mass_line_0*self%delta_x/t_e
488 mass_line_0= mass_line_0*self%delta_x
490 mass_line_1= mass_line_1*self%delta_x
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
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, &
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
513 mass_line_mixed=mass_line_mixed*self%delta_x
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
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
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
547 character(len=256) :: initial_distrib
548 character(len=256) :: initial_bfield
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
558 if(
present(force_sign) )
then
559 self%force_sign = force_sign
562 if (
present( adiabatic_electrons) )
then
563 self%adiabatic_electrons = adiabatic_electrons
567 open(newunit = input_file, file=nml_file, status=
'old',iostat=io_stat)
568 if (io_stat /= 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
576 call self%init( domain, n_dofs, s_deg_0, delta_t*0.5_f64 )
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
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
590 call self%init( domain, n_dofs, s_deg_0, delta_t*0.5_f64 )
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
598 call self%init( domain, n_dofs, s_deg_0, delta_t*0.5_f64, mass_tolerance, poisson_tolerance, solver_tolerance=maxwell_tolerance )
611 deallocate(self%wsave)
612 deallocate(self%work)
613 call self%linear_solver_schur_eb%free()
614 call self%linear_op_schur_eb%free()
622 sll_real64,
intent(in) :: in(:)
623 sll_real64,
intent(out) :: out(:)
633 sll_real64,
intent(in) :: in(:)
634 sll_real64,
intent(out) :: out(:)
644 sll_real64,
intent(in) :: in(:)
645 sll_real64,
intent(out) :: out(:)
646 sll_int32,
intent(in) :: degree
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 )
656 print*,
'maxwell_solver_1d_fem_sm: multiply mass for other form not yet implemented'
666 sll_real64,
intent(in) :: in(:)
667 sll_real64,
intent(out) :: out(:)
668 sll_int32,
intent(in) :: degree
671 if (degree == self%s_deg_0 )
then
673 call self%linear_solver_mass0%solve( in, out)
675 elseif (degree == self%s_deg_1)
then
677 call self%linear_solver_mass1%solve ( in, out)
679 print*,
'Invert mass for other form not yet implemented'
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.
Gauss-Legendre integration.
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.
class for a linear operator_penalized
class for the cg linear solver
class for a sequential gmres linear solver
Maxwell solver class for spline FEM with sparse matrix solvers.