12 #include "sll_assert.h"
13 #include "sll_errors.h"
14 #include "sll_memory.h"
15 #include "sll_working_precision.h"
67 subroutine init_3d_trafo_parallel( self, domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile )
69 sll_real64,
intent(in) :: domain(3,2)
70 sll_int32,
intent( in ) :: n_dofs(3)
71 sll_int32,
intent( in ) :: s_deg_0(3)
73 sll_real64,
intent(in),
optional :: mass_tolerance
74 sll_real64,
intent(in),
optional :: poisson_tolerance
75 sll_real64,
intent(in),
optional :: solver_tolerance
76 logical,
intent(in),
optional :: adiabatic_electrons
80 sll_int32 :: mpi_total
84 sll_int32 :: deg1(3), deg2(3)
85 sll_real64,
allocatable :: nullspace(:,:)
92 if (
present( mass_tolerance) )
then
93 self%mass_solver_tolerance = mass_tolerance
95 self%mass_solver_tolerance = 1d-12
97 if (
present( poisson_tolerance) )
then
98 self%poisson_solver_tolerance = poisson_tolerance
100 self%poisson_solver_tolerance = 1d-12
102 if (
present( solver_tolerance) )
then
103 self%solver_tolerance = solver_tolerance
105 self%solver_tolerance = 1d-12
108 if(
present( adiabatic_electrons ) )
then
109 self%adiabatic_electrons = adiabatic_electrons
112 if(
present( profile ) )
then
113 self%profile = profile
117 self%n_cells = n_dofs
119 self%n_total = product(n_dofs)
120 self%n_total0 = self%n_total
121 self%n_total1 = self%n_total
123 self%delta_x = 1._f64 / real(n_dofs,f64)
124 self%s_deg_0 = s_deg_0
125 self%s_deg_1 = s_deg_0 - 1
126 self%volume = product(self%delta_x)
129 allocate( self%work0(1:self%n_total) )
130 allocate( self%work(1:self%n_total*3) )
131 allocate( self%work2(1:self%n_total*3) )
141 if(self%adiabatic_electrons)
then
148 deg1(j)=self%s_deg_1(j)
151 deg1(j) = self%s_deg_0(j)
154 if(self%map%flag2d)
then
156 deg1(1)=self%s_deg_1(1)
158 deg2(2) = self%s_deg_1(2)
163 deg1(1) = self%s_deg_0(1)
165 deg2(2) = self%s_deg_0(2)
168 if(self%map%flag3d)
then
171 deg1(j)=self%s_deg_1(j)
173 deg2(modulo(j,3)+1) = self%s_deg_1(modulo(j,3)+1)
174 call sll_s_spline_fem_mixedmass3d( n_dofs, deg1, deg2, [j,modulo(j,3)+1], mass1_local(j,modulo(j,3)+1),
profile_m1, begin, limit )
175 call sll_s_spline_fem_mixedmass3d( n_dofs, deg2, deg1, [modulo(j,3)+1,j], mass1_local(modulo(j,3)+1,j),
profile_m1, begin, limit )
178 deg1(j) = self%s_deg_0(j)
180 deg2(modulo(j,3)+1) = self%s_deg_0(modulo(j,3)+1)
181 call sll_s_spline_fem_mixedmass3d( n_dofs, deg1, deg2, [j,modulo(j,3)+1], mass2_local(j,modulo(j,3)+1),
profile_m2, begin, limit )
182 call sll_s_spline_fem_mixedmass3d( n_dofs, deg2, deg1, [modulo(j,3)+1,j], mass2_local(modulo(j,3)+1,j),
profile_m2, begin, limit )
193 deg1(j)=self%s_deg_1(j)
196 deg1(j) = self%s_deg_0(j)
199 if(self%map%flag2d)
then
201 deg1(1)=self%s_deg_1(1)
203 deg2(2) = self%s_deg_1(2)
207 deg1(1) = self%s_deg_0(1)
209 deg2(2) = self%s_deg_0(2)
212 if(self%map%flag3d)
then
215 deg1(j)=self%s_deg_1(j)
217 deg2(modulo(j,3)+1) = self%s_deg_1(modulo(j,3)+1)
221 deg1(j) = self%s_deg_0(j)
223 deg2(modulo(j,3)+1) = self%s_deg_0(modulo(j,3)+1)
232 self%mass0%n_nnz, mpi_sum, self%mass0%arr_a(1,:))
235 self%mass1(j,j)%n_nnz, mpi_sum, self%mass1(j,j)%arr_a(1,:))
237 self%mass2(j,j)%n_nnz, mpi_sum, self%mass2(j,j)%arr_a(1,:))
239 if(self%map%flag2d)
then
241 self%mass1(1,2)%n_nnz, mpi_sum, self%mass1(1,2)%arr_a(1,:))
243 self%mass1(2,1)%n_nnz, mpi_sum, self%mass1(2,1)%arr_a(1,:))
245 self%mass2(1,2)%n_nnz, mpi_sum, self%mass2(1,2)%arr_a(1,:))
247 self%mass2(2,1)%n_nnz, mpi_sum, self%mass2(2,1)%arr_a(1,:))
248 if(self%map%flag3d)
then
251 self%mass1(j,modulo(j,3)+1)%n_nnz, mpi_sum, self%mass1(j,modulo(j,3)+1)%arr_a(1,:))
253 self%mass1(modulo(j,3)+1,j)%n_nnz, mpi_sum, self%mass1(modulo(j,3)+1,j)%arr_a(1,:))
255 self%mass2(j,modulo(j,3)+1)%n_nnz, mpi_sum, self%mass2(j,modulo(j,3)+1)%arr_a(1,:))
257 self%mass2(modulo(j,3)+1,j)%n_nnz, mpi_sum, self%mass2(modulo(j,3)+1,j)%arr_a(1,:))
262 call self%mass1_operator%create( 3, 3 )
263 call self%mass2_operator%create( 3, 3 )
266 call self%mass1_operator%set( j, j, self%mass1(j,j) )
267 call self%mass2_operator%set( j, j, self%mass2(j,j) )
269 if(self%map%flag2d)
then
270 call self%mass1_operator%set( 1, 2, self%mass1(1, 2) )
271 call self%mass1_operator%set( 2, 1, self%mass1(2, 1) )
272 call self%mass2_operator%set( 1, 2, self%mass2(1, 2) )
273 call self%mass2_operator%set( 2, 1, self%mass2(2, 1) )
274 if(self%map%flag3d)
then
276 call self%mass1_operator%set( j, modulo(j,3)+1, self%mass1(j, modulo(j,3)+1) )
277 call self%mass1_operator%set( modulo(j,3)+1, j, self%mass1(modulo(j,3)+1, j) )
278 call self%mass2_operator%set( j, modulo(j,3)+1, self%mass2(j, modulo(j,3)+1) )
279 call self%mass2_operator%set( modulo(j,3)+1, j, self%mass2(modulo(j,3)+1, j) )
284 call self%preconditioner_fft%init( self%Lx, n_dofs, s_deg_0 )
285 call self%mass0_solver%create( self%mass0 )
286 call self%mass1_solver%create( self%mass1_operator, self%preconditioner_fft%inverse_mass1_3d)
287 call self%mass2_solver%create( self%mass2_operator, self%preconditioner_fft%inverse_mass2_3d)
288 self%mass0_solver%atol = self%mass_solver_tolerance
289 self%mass1_solver%atol = self%mass_solver_tolerance/maxval(self%Lx)
290 self%mass2_solver%atol = self%mass_solver_tolerance/maxval(self%Lx)**2
294 call self%poisson_matrix%create( self%mass1_operator, self%n_dofs, self%delta_x )
296 allocate(nullspace(1,1:self%n_total))
297 nullspace(1,:) = 1.0_f64
298 call self%poisson_operator%create( self%poisson_matrix, nullspace, 1 )
300 call self%poisson_solver%create( self%poisson_operator )
301 self%poisson_solver%null_space = .true.
302 self%poisson_solver%atol = self%poisson_solver_tolerance
304 self%poisson_solver%n_maxiter=40000
308 call self%linear_op_schur_eb%create( self%mass1_operator, self%mass2_operator, self%n_total, self%n_dofs, self%delta_x )
309 call self%linear_solver_schur_eb%create( self%linear_op_schur_eb, self%preconditioner_fft%inverse_mass1_3d)
310 self%linear_solver_schur_eb%atol = self%solver_tolerance/maxval(self%Lx)
317 sll_real64,
intent(in) :: x(3)
318 sll_int32,
optional,
intent(in) :: component(:)
320 profile_m0 = self%map%jacobian( x ) * self%profile%rho_0( x(1) )/ self%profile%T_e( x(1) )
326 sll_real64,
intent(in) :: x(3)
327 sll_int32,
optional,
intent(in) :: component(:)
335 sll_real64,
intent(in) :: x(3)
336 sll_int32,
optional,
intent(in) :: component(:)
338 profile_1 = self%map%metric_inverse_single_jacobian( x, component(1), component(1) )
344 sll_real64,
intent(in) :: x(3)
345 sll_int32,
optional,
intent(in) :: component(:)
347 profile_2 = self%map%metric_single_jacobian( x, component(1), component(1) )
353 sll_real64,
intent(in) :: x(3)
354 sll_int32,
optional,
intent(in) :: component(:)
356 profile_m1 = self%map%metric_inverse_single_jacobian( x, component(1), component(2) )
362 sll_real64,
intent(in) :: x(3)
363 sll_int32,
optional,
intent(in) :: component(:)
365 profile_m2 = self%map%metric_single_jacobian( x, component(1), component(2) )
374 sll_int32,
intent( in ) :: mpi_rank
375 sll_int32,
intent( in ) :: mpi_total
376 sll_int32,
intent( in ) :: n_cells(3)
377 sll_int32,
intent( out ) :: begin(3)
378 sll_int32,
intent( out ) :: limit(3)
380 if( mpi_total <= n_cells(3) )
then
381 begin(3)=1+mpi_rank*n_cells(3)/mpi_total
382 limit(3)=(mpi_rank+1)*n_cells(3)/mpi_total
383 if( mpi_rank == mpi_total-1 )
then
388 else if( mpi_total > n_cells(3) .and. mpi_total < n_cells(2)*n_cells(3) )
then
389 if(modulo(real(n_cells(3)*n_cells(2),f64)/real(mpi_total,f64),1._f64)==0 )
then
390 begin(3)=1+mpi_rank*n_cells(3)/mpi_total
392 begin(2)=1+modulo((mpi_rank*n_cells(2)*n_cells(3))/mpi_total, n_cells(2))
393 limit(2)=modulo(((mpi_rank+1)*n_cells(2)*n_cells(3))/mpi_total-1,n_cells(2))+1
395 sll_warning(
'maxwell_3d_trafo_parallel:init',
'amount of mpi processes not optimal')
396 if( mpi_rank < n_cells(3) )
then
409 if( mpi_rank < n_cells(2)*n_cells(3) )
then
410 begin(3)=1+mpi_rank/n_cells(2)
412 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 The linear systems...
subroutine sll_s_compute_mpi_decomposition(mpi_rank, mpi_total, n_cells, begin, limit)
subroutine init_3d_trafo_parallel(self, domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile)
Module interface to solve Maxwell's equations with coordinate transformation in 3D.
functions for initial profile of the particle distribution function
Helper for spline finite elements utilites.
subroutine, public sll_s_spline_fem_sparsity_mass3d(deg, n_cells, spmat)
Helper function to create sparsity pattern of the 3d mass matrix.
subroutine, public sll_s_spline_fem_sparsity_mixedmass3d(deg1, deg2, n_cells, spmat)
Helper function to create sparsity pattern of the 3d 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.
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