9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
33 sll_s_uniform_bsplines_eval_basis
71 sll_real64,
allocatable :: work1(:)
72 sll_real64,
allocatable :: work0(:)
73 sll_real64,
allocatable :: work01(:)
135 sll_real64,
intent( in ) :: delta_t
136 sll_real64,
intent( in ) :: field_in(:)
137 sll_real64,
intent( inout ) :: field_out(:)
139 call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
140 call self%multiply_gt( self%work1, self%work0 )
142 call self%invert_mass( self%work0, self%work01, self%s_deg_0 )
144 field_out = field_out + delta_t*self%work01
153 sll_real64,
intent( in ) :: delta_t
154 sll_real64,
intent( in ) :: field_in(:)
155 sll_real64,
intent( inout ) :: field_out(:)
157 call self%multiply_g(field_in, self%work1)
159 field_out = field_out - delta_t * self%work1
167 sll_real64,
intent(in) :: delta_t
168 sll_real64,
intent(inout) :: efield(:)
169 sll_real64,
intent(inout) :: bfield(:)
170 sll_real64,
optional :: betar
174 if(
present(betar) )
then
185 call self%multiply_mass( bfield, self%work1, self%s_deg_1 )
186 call self%multiply_gt( self%work1, self%work0 )
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
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 )
201 self%work0 = self%work0 + efield
202 call self%compute_B_from_E( delta_t*0.5_f64, self%work0, bfield )
210 sll_real64,
intent( in ) :: field_in(:)
211 sll_real64,
intent( out ) :: field_out(:)
213 call self%poisson_solver%solve( field_in, self%work0 )
214 call multiply_g( self, self%work0, field_out )
215 field_out = -field_out
223 sll_real64,
intent( in ) :: field_in(:)
224 sll_real64,
intent( out ) :: field_out(:)
226 call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
228 field_out = - field_out
236 sll_real64,
dimension(:),
intent(in) :: current
237 sll_int32,
intent(in) :: component
238 sll_real64,
dimension(:),
intent(inout) :: e
241 if (component == 1)
then
242 call self%invert_mass( current, self%work1, self%s_deg_1 )
244 elseif (component == 2)
then
245 call self%invert_mass( current, self%work0, self%s_deg_0 )
248 print*,
'Component ', component,
'not implemented in compute_E_from_j_1d_trafo.'
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%work01, self%work0, self%s_deg_0 )
283 phi = phi + self%work0
297 sll_int32,
intent(in) :: degree
298 sll_real64,
intent(out) :: coefs_dofs(:)
300 sll_int32 :: i,j,quad,q
302 sll_real64,
allocatable :: xw_gauss(:,:)
303 sll_real64,
allocatable :: bspl(:,:)
304 sll_real64 :: jacobian
307 allocate( xw_gauss(2,q) )
308 allocate( bspl(degree+1,q) )
313 if( degree == self%s_deg_0 )
then
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])) *&
340 do i = degree, self%n_cells-degree+1
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)
355 do i = self%n_cells-degree+2, self%n_cells
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)
369 else if (degree == self%s_deg_1)
then
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] ) )
397 do i = degree, self%n_cells-degree+1
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] ) )
411 do i = self%n_cells-degree+2, self%n_cells
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] ) )
433 sll_int32,
intent( in ) :: degree
434 sll_real64,
intent( out ) :: coefs_dofs(:)
437 if (degree == self%s_deg_0)
then
440 call self%invert_mass( self%work0, coefs_dofs, self%s_deg_0 )
441 elseif (degree == self%s_deg_1)
then
444 call self%invert_mass( self%work1, coefs_dofs, self%s_deg_1 )
446 print*,
'degree ', degree,
'not availlable in maxwell_clamped_1d_trafo object'
454 sll_real64 :: coefs_dofs(:)
459 if (degree == self%s_deg_0 )
then
460 call self%multiply_mass( coefs_dofs, self%work0, self%s_deg_0 )
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 )
466 r = sum(coefs_dofs*self%work1)
474 sll_real64 :: coefs1_dofs(:)
475 sll_real64 :: coefs2_dofs(:)
477 sll_int32,
optional :: degree2
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 )
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 )
490 r = sum(coefs1_dofs*self%work1)
493 if (degree == self%s_deg_0)
then
494 call self%multiply_mass( coefs2_dofs, self%work01, 10 )
496 r = sum(coefs1_dofs*self%work01)
498 call self%multiply_mass( coefs1_dofs, self%work01, 10 )
500 r = sum(coefs2_dofs*self%work01)
504 if (degree == self%s_deg_0 )
then
505 call self%multiply_mass( coefs2_dofs, self%work0, self%s_deg_0 )
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 )
511 r = sum(coefs1_dofs*self%work1)
519 subroutine init_1d_trafo( self, domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, solver_tolerance )
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
526 sll_real64,
intent(in),
optional :: mass_tolerance
527 sll_real64,
intent(in),
optional :: poisson_tolerance
528 sll_real64,
intent(in),
optional :: solver_tolerance
532 if (
present( mass_tolerance) )
then
533 self%mass_solver_tolerance = mass_tolerance
535 self%mass_solver_tolerance = 1d-12
537 if (
present( poisson_tolerance) )
then
538 self%poisson_solver_tolerance = poisson_tolerance
540 self%poisson_solver_tolerance = 1d-12
543 if (
present( solver_tolerance) )
then
544 self%solver_tolerance = solver_tolerance
546 self%solver_tolerance = 1d-12
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
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)
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
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
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
596 sll_real64,
intent(in) :: x
598 profile_0 = map%jacobian( [x, 0._f64, 0._f64] )
604 sll_real64,
intent(in) :: x
606 profile_1 = 1._f64/map%jacobian( [x, 0._f64, 0._f64] )
612 sll_real64,
intent(in) :: x
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
628 character(len=*),
intent(in) :: nml_file
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
637 namelist /output/ file_prefix
638 namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
639 namelist /time_solver/ maxwell_tolerance
644 open(newunit = input_file, file=nml_file, status=
'old',iostat=io_stat)
645 if (io_stat /= 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
653 call self%init( domain, n_cells, s_deg_0, boundary, map )
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
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
666 call self%init( domain, n_cells, s_deg_0, boundary, map )
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
674 call self%init( domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, maxwell_tolerance )
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()
698 deallocate(self%work1)
699 deallocate(self%work0)
700 deallocate(self%work01)
708 sll_real64,
intent(in) :: in(:)
709 sll_real64,
intent(out) :: out(:)
719 sll_real64,
intent(in) :: in(:)
720 sll_real64,
intent(out) :: out(:)
730 sll_real64,
intent(in) :: in(:)
731 sll_real64,
intent(out) :: out(:)
732 sll_int32,
intent(in) :: degree
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 )
741 print*,
'maxwell_solver_clamped_1d_trafo: multiply mass for other form not yet implemented'
751 sll_real64,
intent(in) :: in(:)
752 sll_real64,
intent(out) :: out(:)
753 sll_int32,
intent(in) :: degree
755 if (degree == self%s_deg_0 )
then
756 call self%linear_solver_mass0%solve( in, out )
758 out(self%n_dofs0) = 0._f64
759 elseif (degree == self%s_deg_1)
then
760 call self%linear_solver_mass1%solve( in, out )
762 print*,
'Invert mass for other form not yet implemented'
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
777 sll_real64 :: field_energy(3)
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 )
787 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 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 free_1d_trafo(self)
Finalization.
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.
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)
class for the cg linear solver
class for a sequential gmres linear solver
type collecting functions for analytical coordinate mapping
arbitrary degree 1d spline