9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
36 sll_s_uniform_bsplines_eval_basis
66 sll_real64,
allocatable :: work1(:)
67 sll_real64,
allocatable :: work2(:)
80 sll_real64 :: force_sign = 1._f64
131 sll_real64,
intent( in ) :: delta_t
132 sll_real64,
intent( in ) :: field_in(:)
133 sll_real64,
intent( inout ) :: field_out(:)
135 call self%multiply_mass( field_in, self%work2, self%s_deg_1 )
136 call self%multiply_gt( self%work2, self%work1 )
138 call self%linear_solver_mass0%solve ( self%work1, self%work2 )
140 field_out = field_out + delta_t*self%work2
149 sll_real64,
intent( in ) :: delta_t
150 sll_real64,
intent( in ) :: field_in(:)
151 sll_real64,
intent( inout ) :: field_out(:)
153 call self%multiply_g(field_in, self%work1)
155 field_out = field_out - delta_t * self%work1
163 sll_real64,
intent(in) :: delta_t
164 sll_real64,
intent(inout) :: efield(:)
165 sll_real64,
intent(inout) :: bfield(:)
166 sll_real64,
optional :: betar
170 if(
present(betar) )
then
180 call self%multiply_mass( bfield, self%work1, self%s_deg_1 )
181 call self%multiply_gt( self%work1, self%work2 )
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
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 )
196 self%work2 = self%work2 + efield
197 call self%compute_B_from_E( delta_t*0.5_f64, self%work2, bfield )
205 sll_real64,
intent( in ) :: field_in(:)
206 sll_real64,
intent( out ) :: field_out(:)
208 call self%poisson_solver%solve( field_in, self%work1 )
209 call multiply_g( self, self%work1, field_out )
210 field_out = -field_out
218 sll_real64,
intent( in ) :: field_in(:)
219 sll_real64,
intent( out ) :: field_out(:)
221 call self%multiply_mass( field_in, self%work1, self%s_deg_1 )
223 field_out = - self%force_sign * field_out
231 sll_real64,
dimension(:),
intent(in) :: current
232 sll_int32,
intent(in) :: component
233 sll_real64,
dimension(:),
intent(inout) :: e
236 if (component == 1)
then
237 call self%linear_solver_mass1%solve( current, self%work1 )
239 elseif (component == 2)
then
240 call self%linear_solver_mass0%solve( current, self%work1 )
242 print*,
'Component ', component,
'not implemented in compute_E_from_j_1d_trafo.'
246 e = e - self%force_sign * self%work1
254 sll_real64,
intent(in) :: in(:)
255 sll_real64,
intent(out) :: phi(:)
256 sll_real64,
intent(out) :: efield(:)
259 call self%invert_mass( in, phi, self%s_deg_0 )
271 sll_real64,
intent(in) :: in(:)
272 sll_real64,
intent(out) :: phi(:)
273 sll_real64,
intent(out) :: efield(:)
279 call self%invert_mass( self%work1, self%work2, self%s_deg_0 )
280 phi = phi + self%work2
294 sll_int32,
intent( in ) :: degree
295 sll_real64,
intent( out ) :: coefs_dofs(:)
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
308 call sll_s_uniform_bsplines_eval_basis(degree,xw_gauss(1,k), bspl(:,k))
311 if( degree == self%s_deg_0 )
then
313 do i = 1, self%n_cells
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)
325 coefs_dofs(i) = coef*self%delta_x
329 do i = 1, self%n_cells
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] ) )
340 coefs_dofs(i) = coef*self%delta_x
351 sll_int32,
intent( in ) :: degree
352 sll_real64,
intent( out ) :: coefs_dofs(:)
355 call self%compute_rhs_from_function( func, degree, self%work1)
358 if (degree == self%s_deg_0)
then
359 call self%linear_solver_mass0%solve ( self%work1, coefs_dofs )
361 elseif (degree == self%s_deg_1)
then
362 call self%linear_solver_mass1%solve ( self%work1, coefs_dofs )
364 print*,
'degree ', degree,
'not availlable in maxwell_1d_trafo object'
372 sll_real64 :: coefs_dofs(:)
377 if (degree == self%s_deg_0 )
then
379 call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_0 )
381 elseif (degree == self%s_deg_1)
then
383 call self%multiply_mass( coefs_dofs, self%work1, self%s_deg_1 )
387 r = sum(coefs_dofs*self%work1)
395 sll_real64 :: coefs1_dofs(:)
396 sll_real64 :: coefs2_dofs(:)
398 sll_int32,
optional :: degree2
402 if (
present(degree2))
then
403 if (degree == degree2)
then
404 if (degree == self%s_deg_0 )
then
406 call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_0 )
408 elseif (degree == self%s_deg_1)
then
410 call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
414 r = sum(coefs1_dofs*self%work1)
416 if (degree == self%s_deg_0)
then
417 call self%multiply_mass( coefs2_dofs, self%work1, 10 )
419 r = sum(coefs1_dofs*self%work1)
421 call self%multiply_mass( coefs1_dofs, self%work1, 10 )
423 r = sum(coefs2_dofs*self%work1)
427 if (degree == self%s_deg_0 )
then
429 call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_0 )
431 elseif (degree == self%s_deg_1)
then
433 call self%multiply_mass( coefs2_dofs, self%work1, self%s_deg_1 )
437 r = sum(coefs1_dofs*self%work1)
443 subroutine init_1d_trafo( self, domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance, force_sign )
445 sll_real64,
intent(in) :: domain(2)
446 sll_int32,
intent(in) :: n_dofs
447 sll_int32,
intent(in) :: s_deg_0
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
454 sll_real64,
allocatable :: nullspace(:,:)
457 if (
present( mass_tolerance) )
then
458 self%mass_solver_tolerance = mass_tolerance
460 self%mass_solver_tolerance = 1d-12
462 if (
present( poisson_tolerance) )
then
463 self%poisson_solver_tolerance = poisson_tolerance
465 self%poisson_solver_tolerance = 1d-12
468 if (
present( solver_tolerance) )
then
469 self%solver_tolerance = solver_tolerance
471 self%solver_tolerance = 1d-12
474 if (
present( force_sign) )
then
475 self%force_sign = force_sign
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
487 sll_allocate(self%work1(n_dofs),ierr)
488 sll_allocate(self%work2(n_dofs),ierr)
494 call self%linear_solver_mass0%create( self%mass0)
495 self%linear_solver_mass0%atol = self%mass_solver_tolerance
497 call self%linear_solver_mass1%create( self%mass1)
498 self%linear_solver_mass1%atol = self%mass_solver_tolerance /self%Lx
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, &
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
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
526 sll_real64,
intent(in) :: x
528 profile_0 = map%jacobian( [x, 0._f64, 0._f64] )
534 sll_real64,
intent(in) :: x
536 profile_1 = 1._f64/map%jacobian( [x, 0._f64, 0._f64] )
542 sll_real64,
intent(in) :: x
553 sll_real64,
intent(in) :: domain(2)
554 sll_int32,
intent(in) :: n_dofs
555 sll_int32,
intent(in) :: s_deg_0
557 character(len=*),
intent(in) :: nml_file
558 sll_real64,
intent(in),
optional :: force_sign
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
567 namelist /output/ file_prefix
568 namelist /maxwell_solver/ mass_tolerance, poisson_tolerance
569 namelist /time_solver/ maxwell_tolerance
573 if (
present( force_sign) )
then
574 self%force_sign = force_sign
578 open(newunit = input_file, file=nml_file, status=
'old',iostat=io_stat)
579 if (io_stat /= 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
587 call self%init( domain, n_dofs, s_deg_0, map )
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
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
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
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
610 call self%init( domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance )
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
618 call self%init( domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance=maxwell_tolerance )
631 deallocate(self%work1)
632 deallocate(self%work2)
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()
648 sll_real64,
intent(in) :: in(:)
649 sll_real64,
intent(out) :: out(:)
659 sll_real64,
intent(in) :: in(:)
660 sll_real64,
intent(out) :: out(:)
670 sll_real64,
intent(in) :: in(:)
671 sll_real64,
intent(out) :: out(:)
672 sll_int32,
intent(in) :: degree
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 )
681 print*,
'maxwell_solver_1d_trafo: multiply mass for other form not yet implemented'
691 sll_real64,
intent(in) :: in(:)
692 sll_real64,
intent(out) :: out(:)
693 sll_int32,
intent(in) :: degree
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 )
700 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 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)
class for a linear operator_penalized
class for the cg linear solver
class for a sequential gmres linear solver
type collecting functions for analytical coordinate mapping