9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
32 sll_s_uniform_bsplines_eval_basis
72 sll_real64,
allocatable :: work1(:)
73 sll_real64,
allocatable :: work0(:)
74 sll_real64,
allocatable :: work01(:)
138 sll_real64,
intent(in) :: delta_t
139 sll_real64,
intent(in) :: field_in(:)
140 sll_real64,
intent(inout) :: field_out(:)
143 call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
144 call self%multiply_gt( self%work1, self%work0 )
145 call self%invert_mass( self%work0, self%work01, self%s_deg_0 )
148 field_out = field_out + delta_t*self%work01
157 sll_real64,
intent(in) :: delta_t
158 sll_real64,
intent(in) :: field_in(:)
159 sll_real64,
intent(inout) :: field_out(:)
161 call self%multiply_g(field_in, self%work1)
163 field_out = field_out - delta_t * self%work1
171 sll_real64,
intent(in) :: delta_t
172 sll_real64,
intent(inout) :: efield(:)
173 sll_real64,
intent(inout) :: bfield(:)
174 sll_real64,
optional :: betar
178 if(
present(betar) )
then
189 call self%multiply_mass( bfield, self%work1, self%s_deg_1 )
190 call self%multiply_gt( self%work1, self%work0 )
192 self%linear_op_schur_eb%sign = -delta_t**2*0.25_f64*factor
193 call self%linear_op_schur_eb%dot( efield, self%work01 )
194 self%work01 = self%work01 + delta_t*factor*self%work0
200 self%linear_op_schur_eb%sign = delta_t**2*0.25_f64*factor
201 call self%linear_solver_schur_eb%set_guess( efield )
202 call self%linear_solver_schur_eb%solve( self%work01, efield )
205 self%work0 = self%work0 + efield
206 call self%compute_B_from_E( delta_t*0.5_f64, self%work0, bfield )
214 sll_real64,
intent(in) :: field_in(:)
215 sll_real64,
intent(out) :: field_out(:)
217 call self%poisson_solver%solve( field_in, self%work0 )
218 call multiply_g( self, self%work0, field_out )
219 field_out = -field_out
227 sll_real64,
intent(in) :: field_in(:)
228 sll_real64,
intent(out) :: field_out(:)
230 call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
232 field_out = - field_out
240 sll_real64,
dimension(:),
intent(in) :: current
241 sll_int32,
intent(in) :: component
242 sll_real64,
dimension(:),
intent(inout) :: e
245 if (component == 1)
then
246 call self%invert_mass( current, self%work1, self%s_deg_1 )
249 elseif (component == 2)
then
250 call self%invert_mass( current, self%work0, self%s_deg_0 )
253 print*,
'Component ', component,
'not implemented in compute_E_from_j_1d_fem_sm.'
262 sll_real64,
intent(in) :: in(:)
263 sll_real64,
intent(out) :: phi(:)
264 sll_real64,
intent(out) :: efield(:)
267 call self%invert_mass( in, phi, self%s_deg_0 )
279 sll_real64,
intent(in) :: in(:)
280 sll_real64,
intent(out) :: phi(:)
281 sll_real64,
intent(out) :: efield(:)
287 call self%invert_mass( self%work01, self%work0, self%s_deg_0 )
289 phi = phi + self%work0
303 sll_int32,
intent(in) :: degree
304 sll_real64,
intent(out) :: coefs_dofs(:)
306 sll_int32 :: i,j,quad,q
307 sll_real64,
allocatable :: xw_gauss(:,:)
308 sll_real64,
allocatable :: bspl(:,:)
311 allocate( xw_gauss(2,q) )
312 allocate( bspl(degree+1,q) )
316 if( degree == self%s_deg_0 )
then
325 coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
326 self%delta_x * xw_gauss(2,quad) * func( self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64)) ) *&
341 do i = degree, self%n_cells-degree+1
346 coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
347 self%delta_x * xw_gauss(2,quad) * func(self%delta_x * (xw_gauss(1,quad) + real(i - 1,f64)) ) * bspl(j,quad)
354 do i = self%n_cells-degree+2, self%n_cells
359 coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
360 self%delta_x * xw_gauss(2,quad) * func( self%delta_x * (xw_gauss(1,quad)+real(i-1,f64)) ) *&
361 sll_f_spline_pp_horner_1d( degree, self%spline0_pp%poly_coeffs_boundary_right(:,:,i-self%n_cells+degree-1), xw_gauss(1,quad), j)
366 else if (degree == self%s_deg_1)
then
376 coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
377 self%delta_x * xw_gauss(2,quad)*func( self%delta_x * (xw_gauss(1,quad)+ real(i - 1,f64)) ) *&
393 do i = max(1,degree), min(self%n_cells,self%n_cells-degree+1)
398 coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
399 self%delta_x * xw_gauss(2,quad)*func(self%delta_x * (xw_gauss(1,quad) + real(i - 1,f64)) ) * bspl(j,quad)
406 do i = self%n_cells-degree+2, self%n_cells
411 coefs_dofs(i-1+j) = coefs_dofs(i-1+j) + &
412 self%delta_x * xw_gauss(2,quad)*func( self%delta_x * (xw_gauss(1,quad)+real(i-1,f64)) ) *&
413 sll_f_spline_pp_horner_1d( degree, self%spline1_pp%poly_coeffs_boundary_right(:,:,i-self%n_cells+degree-1), xw_gauss(1,quad), j)
426 sll_int32,
intent(in) :: degree
427 sll_real64,
intent(out) :: coefs_dofs(:)
430 if (degree == self%s_deg_0)
then
433 call self%invert_mass( self%work0, coefs_dofs, degree )
435 elseif (degree == self%s_deg_1)
then
438 call self%invert_mass( self%work1, coefs_dofs, degree )
440 print*,
'degree ', degree,
'not availlable in maxwell_clamped_1d_fem_sm object'
449 sll_real64 :: coefs_dofs(:)
454 if (degree == self%s_deg_0 )
then
455 call self%multiply_mass( coefs_dofs, self%work0, self%s_deg_0 )
457 r = sum(coefs_dofs*self%work0)
458 elseif (degree == self%s_deg_1)
then
459 call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_1 )
461 r = sum(coefs_dofs*self%work1)
470 sll_real64 :: coefs1_dofs(:)
471 sll_real64 :: coefs2_dofs(:)
473 sll_int32,
optional :: degree2
477 if (
present(degree2))
then
478 if (degree == degree2)
then
479 if (degree == self%s_deg_0 )
then
480 call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
482 r = sum(coefs1_dofs*self%work0)
483 elseif (degree == self%s_deg_1)
then
484 call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
486 r = sum(coefs1_dofs*self%work1)
489 if (degree == self%s_deg_0)
then
490 call self%multiply_mass( coefs2_dofs, self%work01, 10 )
492 r = sum(coefs1_dofs*self%work01)
494 call self%multiply_mass( coefs1_dofs, self%work01, 10 )
496 r = sum(coefs2_dofs*self%work01)
500 if (degree == self%s_deg_0 )
then
501 call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
503 r = sum(coefs1_dofs*self%work0)
504 elseif (degree == self%s_deg_1)
then
505 call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
507 r = sum(coefs1_dofs*self%work1)
515 subroutine init_1d_fem_sm( self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance )
517 sll_real64,
intent(in) :: domain(2)
518 sll_int32,
intent(in) :: n_cells
519 sll_int32,
intent(in) :: s_deg_0
520 sll_int32,
intent(in) :: boundary
521 sll_real64,
intent(in),
optional :: mass_tolerance
522 sll_real64,
intent(in),
optional :: poisson_tolerance
523 sll_real64,
intent(in),
optional :: solver_tolerance
526 sll_real64 :: mass_line_0(s_deg_0+1), mass_line_1(s_deg_0)
527 sll_real64 :: mass_line_b0((s_deg_0+1)*s_deg_0), mass_line_b1(s_deg_0*(s_deg_0-1))
529 if (
present( mass_tolerance) )
then
530 self%mass_solver_tolerance = mass_tolerance
532 self%mass_solver_tolerance = 1d-12
534 if (
present( poisson_tolerance) )
then
535 self%poisson_solver_tolerance = poisson_tolerance
537 self%poisson_solver_tolerance = 1d-12
540 if (
present( solver_tolerance) )
then
541 self%solver_tolerance = solver_tolerance
543 self%solver_tolerance = 1d-12
546 self%n_cells = n_cells
547 self%n_dofs0 = n_cells+s_deg_0
548 self%n_dofs1 = n_cells+s_deg_0-1
549 self%Lx = domain(2) - domain(1)
550 self%delta_x = self%Lx /real(n_cells,f64)
551 self%s_deg_0 = s_deg_0
552 self%s_deg_1 = s_deg_0 - 1
557 sll_allocate(self%work1(self%n_dofs1),ierr)
558 sll_allocate(self%work0(self%n_dofs0),ierr)
559 sll_allocate(self%work01(self%n_dofs0),ierr)
566 mass_line_0= mass_line_0*self%delta_x
567 mass_line_b0= mass_line_b0*self%delta_x
570 if(self%s_deg_1 > 0)
then
574 mass_line_1= mass_line_1*self%delta_x
575 mass_line_b1= mass_line_b1*self%delta_x
579 mass_line_1 = mass_line_1*self%delta_x
582 call self%linear_solver_mass0%create( self%mass0 )
583 call self%linear_solver_mass1%create( self%mass1 )
584 self%linear_solver_mass0%atol = self%mass_solver_tolerance
585 self%linear_solver_mass1%atol = self%mass_solver_tolerance
592 call self%poisson_matrix%create( self%mass1, self%s_deg_0, self%n_dofs0, self%delta_x)
593 call self%poisson_solver%create( self%poisson_matrix )
594 self%poisson_solver%atol = self%poisson_solver_tolerance
599 call self%linear_op_schur_eb%create( self%mass0, self%mass1, self%n_dofs0, self%delta_x, self%s_deg_0 )
600 call self%linear_solver_schur_eb%create( self%linear_op_schur_eb )
601 self%linear_solver_schur_eb%atol = self%solver_tolerance
602 self%linear_solver_schur_eb%rtol = self%solver_tolerance
608 sll_real64,
intent(in) :: x
619 sll_real64,
intent(in) :: domain(2)
620 sll_int32,
intent(in) :: n_cells
622 sll_int32,
intent(in) :: s_deg_0
623 sll_int32,
intent(in) :: boundary
624 character(len=*) :: nml_file
626 character(len=256) :: file_prefix
627 sll_int32 :: input_file
628 sll_int32 :: io_stat, io_stat0, io_stat1, rank, file_id
629 sll_real64 :: mass_tolerance
630 sll_real64 :: poisson_tolerance
631 sll_real64 :: maxwell_tolerance
633 namelist /output/ file_prefix
634 namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
635 namelist /time_solver/ maxwell_tolerance
640 open(newunit = input_file, file=nml_file, status=
'old',iostat=io_stat)
641 if (io_stat /= 0)
then
643 print*,
'sll_m_maxwell_clamped_1d_fem_sm: Input file does not exist. Set default tolerance.'
644 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
645 write(file_id, *)
'mass solver tolerance:', 1d-12
646 write(file_id, *)
'poisson solver tolerance:', 1d-12
649 call self%init( domain, n_cells, s_deg_0, boundary )
651 read(input_file, output,iostat=io_stat0)
652 read(input_file, maxwell_solver,iostat=io_stat)
653 read(input_file, time_solver,iostat=io_stat1)
654 if (io_stat /= 0)
then
656 print*,
'sll_m_maxwell_clamped_1d_fem_sm: Input parameter does not exist. Set default tolerance.'
657 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
658 write(file_id, *)
'mass solver tolerance:', 1d-12
659 write(file_id, *)
'poisson solver tolerance:', 1d-12
662 call self%init( domain, n_cells, s_deg_0, boundary )
665 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
666 write(file_id, *)
'mass solver tolerance:', mass_tolerance
667 write(file_id, *)
'poisson solver tolerance:', poisson_tolerance
670 call self%init( domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, maxwell_tolerance )
682 deallocate(self%work1)
683 deallocate(self%work0)
684 deallocate(self%work01)
685 call self%linear_solver_mass0%free()
686 call self%linear_solver_mass1%free()
687 call self%poisson_solver%free()
688 call self%poisson_matrix%free()
689 call self%linear_solver_schur_eb%free()
690 call self%linear_op_schur_eb%free()
701 sll_real64,
intent(in) :: in(:)
702 sll_real64,
intent(out) :: out(:)
712 sll_real64,
intent(in) :: in(:)
713 sll_real64,
intent(out) :: out(:)
723 sll_real64,
intent(in) :: in(:)
724 sll_real64,
intent(out) :: out(:)
725 sll_int32,
intent(in) :: degree
728 if (degree == self%s_deg_0 )
then
729 call self%mass0%dot ( in, out)
730 elseif (degree == self%s_deg_1)
then
731 call self%mass1%dot ( in, out)
732 elseif(degree == 10)
then
733 call self%mixed_mass%dot( in, out )
735 print*,
'maxwell_solver_clamped_1d_fem_sm: multiply mass for other form not yet implemented'
745 sll_real64,
intent(in) :: in(:)
746 sll_real64,
intent(out) :: out(:)
747 sll_int32,
intent(in) :: degree
750 if (degree == self%s_deg_0 )
then
752 call self%linear_solver_mass0%solve ( in, out)
755 out(self%n_dofs0) = 0._f64
756 elseif (degree == self%s_deg_1)
then
757 call self%linear_solver_mass1%solve ( in, out)
759 print*,
'Invert mass for other form not yet implemented'
768 sll_real64,
intent( in ) :: efield_dofs1(:)
769 sll_real64,
intent( in ) :: efield_dofs2(:)
770 sll_real64,
intent( in ) :: bfield_dofs(:)
771 sll_real64,
intent( out ) :: energy
773 sll_real64 :: field_energy(3)
776 field_energy(1) = self%l2norm_squared &
777 ( efield_dofs1(1:self%n_dofs1), self%s_deg_1 )
778 field_energy(2) = self%l2norm_squared &
779 ( efield_dofs2(1:self%n_dofs0), self%s_deg_0 )
780 field_energy(3) =self%l2norm_squared &
781 ( bfield_dofs(1:self%n_dofs1), self%s_deg_1 )
783 energy = 0.5_f64*sum(field_energy)
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 conjugate gradient method in pure form
module for a sequential gmres
Low level arbitrary degree splines.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations in 1D.
Solve Maxwell's equations with boundary conditions in 1D based on spline FEM, version based on sparse...
subroutine multiply_g(self, in, out)
Multiply by dicrete gradient matrix.
subroutine free_1d_fem_sm(self)
Finalization.
subroutine compute_rho_from_e_1d_fem_sm(self, field_in, field_out)
Compute rho from Gauss law for given efield.
subroutine multiply_gt(self, in, out)
Multiply by transpose of dicrete gradient matrix.
subroutine sll_s_compute_rhs_fem_sm(self, func, degree, coefs_dofs)
Compute the FEM right-hand-side for a given function f and clamped splines of given degree Its compon...
subroutine sll_s_compute_e_from_rho_1d_fem_sm(self, field_in, field_out)
compute e from rho using weak Poisson's equation ( rho = G^T M_1 G \phi, e = G \phi )
subroutine init_1d_fem_sm(self, domain, n_cells, s_deg_0, boundary, mass_tolerance, poisson_tolerance, solver_tolerance)
Initialization.
subroutine init_from_file_1d_fem_sm(self, domain, n_cells, s_deg_0, boundary, nml_file)
Initialization from nml file.
subroutine compute_field_energy(self, efield_dofs1, efield_dofs2, bfield_dofs, energy)
Compute the field energy.
subroutine compute_phi_from_rho_1d_fem_sm(self, in, phi, efield)
For model with adiabatic electrons.
subroutine sll_s_compute_curl_part_1d_fem_sm(self, delta_t, efield, bfield, betar)
Solve curl part of Maxwell's equations.
real(kind=f64) function inner_product_1d_fem_sm(self, coefs1_dofs, coefs2_dofs, degree, degree2)
Compute inner product.
real(kind=f64) function l2norm_squared_1d_fem_sm(self, coefs_dofs, degree)
Compute square of the L2norm.
subroutine invert_mass_1d_fem_sm(self, in, out, degree)
Multiply by the inverse mass matrix.
subroutine sll_s_compute_e_from_b_1d_fem_sm(self, delta_t, field_in, field_out)
compute Ey from Bz using weak Ampere formulation
subroutine compute_e_from_j_1d_fem_sm(self, current, component, E)
Compute E_i from j_i integrated over the time interval using weak Ampere formulation.
subroutine compute_phi_from_j_1d_fem_sm(self, in, phi, efield)
For model with adiabatic electrons.
subroutine multiply_mass_1d_fem_sm(self, in, out, degree)
Multiply by the mass matrix.
subroutine l2projection_1d_fem_sm(self, func, degree, coefs_dofs)
Compute the L2 projection of a given function f on periodic splines of given degree.
subroutine sll_s_compute_b_from_e_1d_fem_sm(self, delta_t, field_in, field_out)
Compute Bz from Ey using strong 1D Faraday equation for spline coefficients $B_z^{new}(x_j) = B_z^{ol...
Utilites for Maxwell solver's with spline finite elements using sparse matrices.
subroutine, public sll_s_multiply_gt_clamped_1d(n_dofs, delta_x, s_deg_0, in, out)
Multiplication of the input vector in by the transposed clamped derivative matrix G^T.
subroutine, public sll_s_multiply_g_clamped_1d(n_dofs, delta_x, s_deg_0, in, out)
Multiplication of the input vector in by the clamped derivative matrix G.
Utilites for Maxwell solver's with spline finite elements using sparse matrix linear solvers.
subroutine, public sll_s_spline_fem_mass1d(n_cells, s_deg, mass_line, matrix)
Set up 1d mass matrix (sparsity pattern and values)
subroutine, public sll_s_spline_fem_mixedmass1d_clamped_full(n_cells, deg1, deg2, matrix, profile, spline1, spline2)
Set up 1d mixed mass matrix for specific spline degrees and profile function.
subroutine, public sll_s_spline_fem_mass1d_clamped(n_cells, s_deg, mass_line, mass_line_b, matrix)
Set up 1d mass matrix (sparsity pattern and values)
Utilites for Maxwell solver's with spline finite elements.
subroutine, public sll_s_spline_fem_mass_line_boundary(degree, spline, mass_line)
Function computing the boundary part for a mass matrix with clamped splines of degree.
subroutine, public sll_s_spline_fem_mass_line(degree, mass_line)
Computes the mass line for a mass matrix with degree splines.
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)
class for the cg linear solver
class for a sequential gmres linear solver
arbitrary degree 1d spline