11 #include "sll_assert.h"
12 #include "sll_memory.h"
13 #include "sll_working_precision.h"
77 subroutine init_3d_trafo_parallel( self, domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile )
79 sll_real64,
intent(in) :: domain(3,2)
80 sll_int32,
intent( in ) :: n_cells(3)
81 sll_int32,
intent( in ) :: s_deg_0(3)
82 sll_int32,
intent( in ) :: boundary(3)
84 sll_real64,
intent(in),
optional :: mass_tolerance
85 sll_real64,
intent(in),
optional :: poisson_tolerance
86 sll_real64,
intent(in),
optional :: solver_tolerance
87 logical,
intent(in),
optional :: adiabatic_electrons
91 sll_int32 :: mpi_total
94 sll_int32 :: j, deg1(3), deg2(3)
101 if (
present( mass_tolerance) )
then
102 self%mass_solver_tolerance = mass_tolerance
104 self%mass_solver_tolerance = 1d-12
106 if (
present( poisson_tolerance) )
then
107 self%poisson_solver_tolerance = poisson_tolerance
109 self%poisson_solver_tolerance = 1d-12
111 if (
present( solver_tolerance) )
then
112 self%solver_tolerance = solver_tolerance
114 self%solver_tolerance = 1d-12
117 if(
present( adiabatic_electrons ) )
then
118 self%adiabatic_electrons = adiabatic_electrons
121 if(
present( profile ) )
then
122 self%profile = profile
125 self%n_cells = n_cells
126 self%n_dofs = n_cells
127 self%n_dofs(1) = n_cells(1)+s_deg_0(1)
128 self%n_total = product(n_cells)
129 self%n_total0 = product(self%n_dofs)
130 self%n_total1 = (self%n_dofs(1)-1)*n_cells(2)*n_cells(3)
131 self%delta_x = 1._f64 / real(n_cells,f64)
132 self%s_deg_0 = s_deg_0
133 self%s_deg_1 = s_deg_0 - 1
134 self%volume = product(self%delta_x)
137 allocate( self%spline0_pp )
138 allocate( self%spline1_pp )
143 allocate(self%work0(1:self%n_total0))
144 allocate(self%work01(1:self%n_total0))
145 allocate(self%work02(1:self%n_total0))
146 allocate(self%work1(1:self%n_total1+2*self%n_total0))
147 allocate(self%work12(1:self%n_total1+2*self%n_total0))
148 allocate(self%work2(1:self%n_total0+2*self%n_total1))
149 allocate(self%work22(1:self%n_total0+2*self%n_total1))
161 if(self%adiabatic_electrons)
then
167 deg1(1) = self%s_deg_1(1)
168 if(deg1(1) == 0 )
then
174 deg1(1) = self%s_deg_0(1)
179 deg1(j) = self%s_deg_1(j)
183 deg1(j) = self%s_deg_0(j)
184 if(deg1(1) == 0 )
then
193 if(self%map%flag2d )
then
196 deg1(1) = self%s_deg_1(1)
198 deg2(2) = self%s_deg_1(2)
199 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg1,deg2,[1,2], mass1_local(1,2),
profile_m1, self%spline1_pp, self%spline0_pp, begin, limit )
200 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg2,deg1,[2,1],mass1_local(2,1),
profile_m1, self%spline0_pp, self%spline1_pp, begin, limit )
202 deg1(1) = self%s_deg_0(1)
204 deg2(2) = self%s_deg_0(2)
205 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells, deg1, deg2, [1,2], mass2_local(1,2),
profile_m2, self%spline0_pp, self%spline1_pp, begin, limit )
206 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells, deg2, deg1, [2,1], mass2_local(2,1),
profile_m2, self%spline1_pp, self%spline0_pp, begin, limit )
207 if(self%map%flag3d)
then
210 deg1(2)=self%s_deg_1(2)
212 deg2(3) = self%s_deg_1(3)
213 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg1,deg2,[2,3],mass1_local(2,3),
profile_m1, self%spline0_pp, self%spline0_pp, begin, limit )
214 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg2,deg1,[3,2],mass1_local(3,2),
profile_m1, self%spline0_pp, self%spline0_pp, begin, limit )
216 deg1(2) = self%s_deg_0(2)
218 deg2(3) = self%s_deg_0(3)
219 if(deg1(1) == 0 .and. deg2(1) == 0)
then
223 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg1,deg2,[2,3],mass2_local(2,3),
profile_m2, self%spline1_pp, self%spline1_pp, begin, limit )
224 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg2,deg1,[3,2],mass2_local(3,2),
profile_m2, self%spline1_pp, self%spline1_pp, begin, limit )
227 deg1(3)=self%s_deg_1(3)
229 deg2(1) = self%s_deg_1(1)
230 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg1,deg2,[3,1],mass1_local(3,1),
profile_m1, self%spline0_pp, self%spline1_pp, begin, limit )
231 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg2,deg1,[1,3],mass1_local(1,3),
profile_m1, self%spline1_pp, self%spline0_pp, begin, limit )
233 deg1(3) = self%s_deg_0(3)
235 deg2(1) = self%s_deg_0(1)
236 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg1,deg2,[3,1],mass2_local(3,1),
profile_m2, self%spline1_pp, self%spline0_pp, begin, limit )
237 call sll_s_spline_fem_mixedmass3d_clamped( self%n_cells,deg2,deg1,[1,3],mass2_local(1,3),
profile_m2, self%spline0_pp, self%spline1_pp, begin, limit )
246 deg1(j)=self%s_deg_1(j)
248 deg2(modulo(j,3)+1) = self%s_deg_1(modulo(j,3)+1)
253 deg1(j) = self%s_deg_0(j)
255 deg2(modulo(j,3)+1) = self%s_deg_0(modulo(j,3)+1)
263 self%mass0%n_nnz, mpi_sum, self%mass0%arr_a(1,:))
267 self%mass1(j,j)%n_nnz, mpi_sum, self%mass1(j,j)%arr_a(1,:))
269 self%mass2(j,j)%n_nnz, mpi_sum, self%mass2(j,j)%arr_a(1,:))
272 if(self%map%flag2d)
then
274 self%mass1(1,2)%n_nnz, mpi_sum, self%mass1(1,2)%arr_a(1,:))
276 self%mass1(2,1)%n_nnz, mpi_sum, self%mass1(2,1)%arr_a(1,:))
278 self%mass2(1,2)%n_nnz, mpi_sum, self%mass2(1,2)%arr_a(1,:))
280 self%mass2(2,1)%n_nnz, mpi_sum, self%mass2(2,1)%arr_a(1,:))
281 if(self%map%flag3d)
then
284 self%mass1(j,modulo(j,3)+1)%n_nnz, mpi_sum, self%mass1(j,modulo(j,3)+1)%arr_a(1,:))
286 self%mass1(modulo(j,3)+1,j)%n_nnz, mpi_sum, self%mass1(modulo(j,3)+1,j)%arr_a(1,:))
288 self%mass2(j,modulo(j,3)+1)%n_nnz, mpi_sum, self%mass2(j,modulo(j,3)+1)%arr_a(1,:))
290 self%mass2(modulo(j,3)+1,j)%n_nnz, mpi_sum, self%mass2(modulo(j,3)+1,j)%arr_a(1,:))
296 call self%mass1_operator%create( 3, 3 )
297 call self%mass2_operator%create( 3, 3 )
300 call self%mass1_operator%set( j, j, self%mass1(j,j) )
301 call self%mass2_operator%set( j, j, self%mass2(j,j) )
303 if(self%map%flag2d)
then
304 call self%mass1_operator%set( 1, 2, self%mass1(1,2) )
305 call self%mass1_operator%set( 2, 1, self%mass1(2,1) )
306 call self%mass2_operator%set( 1, 2, self%mass2(1,2) )
307 call self%mass2_operator%set( 2, 1, self%mass2(2,1) )
308 if(self%map%flag3d)
then
310 call self%mass1_operator%set( j, modulo(j,3)+1, self%mass1(j,modulo(j,3)+1) )
311 call self%mass1_operator%set( modulo(j,3)+1, j, self%mass1(modulo(j,3)+1,j) )
312 call self%mass2_operator%set( j, modulo(j,3)+1, self%mass2(j,modulo(j,3)+1) )
313 call self%mass2_operator%set( modulo(j,3)+1, j, self%mass2(modulo(j,3)+1,j) )
318 call self%preconditioner_fft%init( self%Lx, n_cells, s_deg_0, .true. )
321 call self%mass1_operator%dot(self%work12, self%work1)
322 do j = 1, self%n_dofs(2)*self%n_dofs(3)
323 self%work1(self%n_total1+1+(j-1)*self%n_dofs(1)) = 1._f64
324 self%work1(self%n_total1+j*self%n_dofs(1)) = 1._f64
325 self%work1(self%n_total1+self%n_total0+1+(j-1)*self%n_dofs(1)) = 1._f64
326 self%work1(self%n_total1+self%n_total0+j*self%n_dofs(1)) = 1._f64
328 self%work1 = 1._f64/sqrt(abs(self%work1))
331 call self%mass2_operator%dot(self%work22, self%work2)
332 do j = 1, self%n_dofs(2)*self%n_dofs(3)
333 self%work2(1+(j-1)*self%n_dofs(1)) = 1._f64
334 self%work2(j*self%n_dofs(1)) = 1._f64
336 self%work2 = 1._f64/sqrt(abs(self%work2))
337 call self%preconditioner1%create( self%preconditioner_fft%inverse_mass1_3d, self%work1, 2*self%n_total0+self%n_total1 )
338 call self%preconditioner2%create( self%preconditioner_fft%inverse_mass2_3d, self%work2, 2*self%n_total1+self%n_total0 )
348 call self%mass0_solver%create( self%mass0 )
349 call self%mass1_solver%create( self%mass1_operator, self%preconditioner1)
350 call self%mass2_solver%create( self%mass2_operator, self%preconditioner2)
351 self%mass0_solver%atol = self%mass_solver_tolerance
352 self%mass1_solver%atol = self%mass_solver_tolerance/maxval(self%Lx)
353 self%mass2_solver%atol = self%mass_solver_tolerance/maxval(self%Lx)**2
359 call self%poisson_matrix%create( self%mass1_operator, self%s_deg_0, self%n_dofs, self%delta_x)
363 do j= 1, self%n_total0
365 self%work01(j) = 1._f64
366 call self%mass0%dot( self%work01, self%work02 )
367 if (abs(self%work02(j))< 1d-13)
then
368 self%work0(j) = 1._f64
370 self%work0(j) = 1._f64/sqrt(self%work02(j))
374 call self%poisson_preconditioner%create( self%n_dofs, self%s_deg_0, self%delta_x, self%work0 )
375 call self%poisson_solver%create( self%poisson_matrix, self%poisson_preconditioner )
376 self%poisson_solver%atol = self%poisson_solver_tolerance
383 call self%linear_op_schur_eb%create( self%mass1_operator, self%mass2_operator, self%n_dofs, self%delta_x, self%s_deg_0 )
384 call self%linear_solver_schur_eb%create( self%linear_op_schur_eb, self%preconditioner1 )
385 self%linear_solver_schur_eb%atol = self%solver_tolerance
392 sll_real64,
intent(in) :: x(3)
393 sll_int32,
optional,
intent(in) :: component(:)
395 profile_m0 = self%map%jacobian( x ) * self%profile%rho_0( x(1) )/ self%profile%T_e( x(1) )
401 sll_real64,
intent(in) :: x(3)
402 sll_int32,
optional,
intent(in) :: component(:)
410 sll_real64,
intent(in) :: x(3)
411 sll_int32,
optional,
intent(in) :: component(:)
413 profile_1 = self%map%metric_inverse_single_jacobian( x, component(1), component(1) )
419 sll_real64,
intent(in) :: x(3)
420 sll_int32,
optional,
intent(in) :: component(:)
422 profile_2 = self%map%metric_single_jacobian( x, component(1), component(1) )
428 sll_real64,
intent(in) :: x(3)
429 sll_int32,
optional,
intent(in) :: component(:)
431 profile_m1 = self%map%metric_inverse_single_jacobian( x, component(1), component(2) )
436 sll_real64,
intent(in) :: x(3)
437 sll_int32,
optional,
intent(in) :: component(:)
439 profile_m2 = self%map%metric_single_jacobian( x, component(1), component(2) )
447 sll_int32,
intent( in ) :: mpi_rank
448 sll_int32,
intent( in ) :: mpi_total
449 sll_int32,
intent( in ) :: n_cells(3)
450 sll_int32,
intent( out ) :: begin(3)
451 sll_int32,
intent( out ) :: limit(3)
453 if( mpi_total <= n_cells(3) )
then
454 begin(3)=1+mpi_rank*n_cells(3)/mpi_total
455 limit(3)=(mpi_rank+1)*n_cells(3)/mpi_total
456 if( mpi_rank == mpi_total-1 )
then
461 else if( mpi_total > n_cells(3) .and. mpi_total < n_cells(2)*n_cells(3) )
then
462 if(modulo(real(n_cells(3)*n_cells(2),f64)/real(mpi_total,f64),1._f64)==0 )
then
463 begin(3)=1+mpi_rank*n_cells(3)/mpi_total
465 begin(2)=1+modulo((mpi_rank*n_cells(2)*n_cells(3))/mpi_total, n_cells(2))
466 limit(2)=modulo(((mpi_rank+1)*n_cells(2)*n_cells(3))/mpi_total-1,n_cells(2))+1
468 print*,
'bad amount of mpi processes'
469 if( mpi_rank < n_cells(3) )
then
482 if( mpi_rank < n_cells(2)*n_cells(3) )
then
483 begin(3)=1+mpi_rank/n_cells(2)
485 begin(2)=1+modulo(mpi_rank,n_cells(2))
Combines values from all processes and distributes the result back to all processes.
integer(kind=i32) function, public sll_f_get_collective_rank(col)
Determines the rank of the calling process in the communicator.
subroutine, public sll_s_collective_reduce_real64(col, send_buf, size, op, root_rank, rec_buf)
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.
integer(kind=i32) function, public sll_f_get_collective_size(col)
Determines the size of the group associated with a communicator.
Module interfaces for coordinate transformation.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations with coordinate transformation in 3D.
subroutine init_3d_trafo_parallel(self, domain, n_cells, s_deg_0, boundary, map, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile)
subroutine sll_s_compute_mpi_decomposition(mpi_rank, mpi_total, n_cells, begin, limit)
Module interface to solve Maxwell's equations with coordinate transformation in 3D.
This module is a wrapper around the spline FEM Poisson solver for the uniform grid with periodic boun...
functions for initial profile of the particle distribution function
Utilites for Maxwell solver's with spline finite elements using sparse matrices.
subroutine, public sll_s_spline_fem_mixedmass3d_clamped(n_cells, deg1, deg2, component, matrix, profile, spline1, spline2, n_cells_min, n_cells_max)
Set up 3d clamped mixed mass matrix for specific spline degree and profile function.
subroutine, public sll_s_spline_fem_mass3d_clamped(n_cells, deg, component, matrix, profile, spline, n_cells_min, n_cells_max)
Set up 3d clamped mass matrix for specific spline degrees and profile function.
Helper for spline finite elements utilites.
subroutine, public sll_s_spline_fem_sparsity_mixedmass3d_clamped(deg1, deg2, n_cells, spmat)
Helper function to create sparsity pattern of the 3d clamped mixed mass matrix.
subroutine, public sll_s_spline_fem_sparsity_mass3d_clamped(deg, n_cells, spmat)
Helper function to create sparsity pattern of the 3d clamped mass matrix.
Utilites for 3D Maxwell solvers with spline finite elements.
subroutine, public sll_s_spline_fem_mass3d(n_cells, deg, component, matrix, profile, n_cells_min, n_cells_max)
Set up 3d mass matrix for specific spline degrees and profile function.
subroutine, public sll_s_spline_fem_mixedmass3d(n_cells, deg1, deg2, component, matrix, profile, n_cells_min, n_cells_max)
Set up 3d mixed mass matrix for specific spline degree 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)
real(kind=f64) function profile_0(x)
real(kind=f64) function profile_m0(x)
real(kind=f64) function profile_1(x)
real(kind=f64) function profile_m2(x, component)
real(kind=f64) function profile_2(x, component)
real(kind=f64) function profile_m1(x, component)
type collecting functions for analytical coordinate mapping