Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_maxwell_3d_trafo_parallel.F90
Go to the documentation of this file.
1 
9 
11  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12 #include "sll_assert.h"
13 #include "sll_errors.h"
14 #include "sll_memory.h"
15 #include "sll_working_precision.h"
16 
17  use sll_m_collective, only: &
23 
24  use sll_m_mapping_3d, only: &
26 
27  use sll_m_matrix_csr, only: &
29 
30  use sll_m_maxwell_3d_trafo, only : &
32 
33  use mpi, only: &
34  mpi_sum
35 
36  use sll_m_profile_functions, only: &
38 
42 
46 
47 
48  implicit none
49 
50  public :: &
52 
53  private
54  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
55 
57 
58 
59  contains
60  procedure :: &
62 
64 
65 contains
66 
67  subroutine init_3d_trafo_parallel( self, domain, n_dofs, s_deg_0, map, mass_tolerance, poisson_tolerance, solver_tolerance, adiabatic_electrons, profile )
68  class(sll_t_maxwell_3d_trafo_parallel), intent( inout ) :: self
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)
72  type(sll_t_mapping_3d), target, intent( inout ) :: map
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
77  type(sll_t_profile_functions), intent(in), optional :: profile
78  ! local variables
79  sll_int32 :: mpi_rank
80  sll_int32 :: mpi_total
81  sll_int32 :: begin(3)
82  sll_int32 :: limit(3)
83  sll_int32 :: j
84  sll_int32 :: deg1(3), deg2(3)
85  sll_real64, allocatable :: nullspace(:,:)
86  type(sll_t_matrix_csr) :: mass0_local
87  type(sll_t_matrix_csr) :: mass1_local(3,3)
88  type(sll_t_matrix_csr) :: mass2_local(3,3)
89 
90  self%Lx = map%Lx
91 
92  if (present( mass_tolerance) ) then
93  self%mass_solver_tolerance = mass_tolerance
94  else
95  self%mass_solver_tolerance = 1d-12
96  end if
97  if (present( poisson_tolerance) ) then
98  self%poisson_solver_tolerance = poisson_tolerance
99  else
100  self%poisson_solver_tolerance = 1d-12
101  end if
102  if (present( solver_tolerance) ) then
103  self%solver_tolerance = solver_tolerance
104  else
105  self%solver_tolerance = 1d-12
106  end if
107 
108  if( present( adiabatic_electrons ) ) then
109  self%adiabatic_electrons = adiabatic_electrons
110  end if
111 
112  if( present( profile ) ) then
113  self%profile = profile
114  end if
115 
116  self%map => map
117  self%n_cells = n_dofs
118  self%n_dofs = n_dofs
119  self%n_total = product(n_dofs)
120  self%n_total0 = self%n_total
121  self%n_total1 = self%n_total
122 
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)
127 
128  ! Allocate scratch data
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) )
132 
135 
136 
137  call sll_s_compute_mpi_decomposition( mpi_rank, mpi_total, n_dofs, begin, limit )
138  ! Assemble the sparse mass matrices
139  !0-form
140  deg1=self%s_deg_0
141  if(self%adiabatic_electrons) then
142  call sll_s_spline_fem_mass3d( n_dofs, deg1, -1, mass0_local, profile_m0, begin, limit )
143  else
144  call sll_s_spline_fem_mass3d( n_dofs, deg1, 0, mass0_local, profile_0, begin, limit )
145  end if
146  do j=1, 3
147  deg1=self%s_deg_0
148  deg1(j)=self%s_deg_1(j)
149  call sll_s_spline_fem_mass3d( n_dofs, deg1, j, mass1_local(j,j), profile_1, begin, limit )
150  deg1 = self%s_deg_1
151  deg1(j) = self%s_deg_0(j)
152  call sll_s_spline_fem_mass3d( n_dofs, deg1, j, mass2_local(j,j), profile_2, begin, limit )
153  end do
154  if(self%map%flag2d)then
155  deg1=self%s_deg_0
156  deg1(1)=self%s_deg_1(1)
157  deg2=self%s_deg_0
158  deg2(2) = self%s_deg_1(2)
159  call sll_s_spline_fem_mixedmass3d( n_dofs, deg1, deg2, [1,2], mass1_local(1,2), profile_m1, begin, limit )
160  call sll_s_spline_fem_mixedmass3d( n_dofs, deg2, deg1, [2,1], mass1_local(2,1), profile_m1, begin, limit )
161 
162  deg1 = self%s_deg_1
163  deg1(1) = self%s_deg_0(1)
164  deg2 = self%s_deg_1
165  deg2(2) = self%s_deg_0(2)
166  call sll_s_spline_fem_mixedmass3d( n_dofs, deg1, deg2, [1,2], mass2_local(1,2), profile_m2, begin, limit )
167  call sll_s_spline_fem_mixedmass3d( n_dofs, deg2, deg1, [2,1], mass2_local(2,1), profile_m2, begin, limit )
168  if(self%map%flag3d)then
169  do j = 2, 3
170  deg1=self%s_deg_0
171  deg1(j)=self%s_deg_1(j)
172  deg2=self%s_deg_0
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 )
176 
177  deg1 = self%s_deg_1
178  deg1(j) = self%s_deg_0(j)
179  deg2 = self%s_deg_1
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 )
183  end do
184  end if
185  end if
186 
187 
188  !initialize global matrices
189  deg1=self%s_deg_0
190  call sll_s_spline_fem_sparsity_mass3d( deg1, n_dofs, self%mass0 )
191  do j=1, 3
192  deg1=self%s_deg_0
193  deg1(j)=self%s_deg_1(j)
194  call sll_s_spline_fem_sparsity_mass3d( deg1, n_dofs, self%mass1(j,j) )
195  deg1 = self%s_deg_1
196  deg1(j) = self%s_deg_0(j)
197  call sll_s_spline_fem_sparsity_mass3d( deg1, n_dofs, self%mass2(j,j) )
198  end do
199  if(self%map%flag2d)then
200  deg1=self%s_deg_0
201  deg1(1)=self%s_deg_1(1)
202  deg2=self%s_deg_0
203  deg2(2) = self%s_deg_1(2)
204  call sll_s_spline_fem_sparsity_mixedmass3d( deg1, deg2, n_dofs, self%mass1(1,2) )
205  call sll_s_spline_fem_sparsity_mixedmass3d( deg2, deg1, n_dofs, self%mass1(2,1) )
206  deg1 = self%s_deg_1
207  deg1(1) = self%s_deg_0(1)
208  deg2 = self%s_deg_1
209  deg2(2) = self%s_deg_0(2)
210  call sll_s_spline_fem_sparsity_mixedmass3d( deg1, deg2, n_dofs, self%mass2(1,2) )
211  call sll_s_spline_fem_sparsity_mixedmass3d( deg2, deg1, n_dofs, self%mass2(2,1) )
212  if(self%map%flag3d)then
213  do j = 2, 3
214  deg1=self%s_deg_0
215  deg1(j)=self%s_deg_1(j)
216  deg2=self%s_deg_0
217  deg2(modulo(j,3)+1) = self%s_deg_1(modulo(j,3)+1)
218  call sll_s_spline_fem_sparsity_mixedmass3d( deg1, deg2, n_dofs, self%mass1(j,modulo(j,3)+1) )
219  call sll_s_spline_fem_sparsity_mixedmass3d( deg2, deg1, n_dofs, self%mass1(modulo(j,3)+1,j) )
220  deg1 = self%s_deg_1
221  deg1(j) = self%s_deg_0(j)
222  deg2 = self%s_deg_1
223  deg2(modulo(j,3)+1) = self%s_deg_0(modulo(j,3)+1)
224  call sll_s_spline_fem_sparsity_mixedmass3d( deg1, deg2, n_dofs, self%mass2(j,modulo(j,3)+1) )
225  call sll_s_spline_fem_sparsity_mixedmass3d( deg2, deg1, n_dofs, self%mass2(modulo(j,3)+1,j) )
226  end do
227  end if
228  end if
229 
230  ! MPI to sum up contributions from each processor
231  call sll_o_collective_allreduce( sll_v_world_collective, mass0_local%arr_a(1,:), &
232  self%mass0%n_nnz, mpi_sum, self%mass0%arr_a(1,:))
233  do j=1, 3
234  call sll_o_collective_allreduce( sll_v_world_collective, mass1_local(j,j)%arr_a(1,:), &
235  self%mass1(j,j)%n_nnz, mpi_sum, self%mass1(j,j)%arr_a(1,:))
236  call sll_o_collective_allreduce( sll_v_world_collective, mass2_local(j,j)%arr_a(1,:), &
237  self%mass2(j,j)%n_nnz, mpi_sum, self%mass2(j,j)%arr_a(1,:))
238  end do
239  if(self%map%flag2d)then
240  call sll_o_collective_allreduce( sll_v_world_collective, mass1_local(1,2)%arr_a(1,:), &
241  self%mass1(1,2)%n_nnz, mpi_sum, self%mass1(1,2)%arr_a(1,:))
242  call sll_o_collective_allreduce( sll_v_world_collective, mass1_local(2,1)%arr_a(1,:), &
243  self%mass1(2,1)%n_nnz, mpi_sum, self%mass1(2,1)%arr_a(1,:))
244  call sll_o_collective_allreduce( sll_v_world_collective, mass2_local(1,2)%arr_a(1,:), &
245  self%mass2(1,2)%n_nnz, mpi_sum, self%mass2(1,2)%arr_a(1,:))
246  call sll_o_collective_allreduce( sll_v_world_collective, mass2_local(2,1)%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
249  do j = 2, 3
250  call sll_o_collective_allreduce( sll_v_world_collective, mass1_local(j,modulo(j,3)+1)%arr_a(1,:), &
251  self%mass1(j,modulo(j,3)+1)%n_nnz, mpi_sum, self%mass1(j,modulo(j,3)+1)%arr_a(1,:))
252  call sll_o_collective_allreduce( sll_v_world_collective, mass1_local(modulo(j,3)+1,j)%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,:))
254  call sll_o_collective_allreduce( sll_v_world_collective, mass2_local(j,modulo(j,3)+1)%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,:))
256  call sll_o_collective_allreduce( sll_v_world_collective, mass2_local(modulo(j,3)+1,j)%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,:))
258  end do
259  end if
260  end if
261 
262  call self%mass1_operator%create( 3, 3 )
263  call self%mass2_operator%create( 3, 3 )
264 
265  do j=1,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) )
268  end do
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
275  do j = 2, 3
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) )
280  end do
281  end if
282  end if
283 
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
291  !self%mass1_solver%verbose = .true.
292  !self%mass2_solver%verbose = .true.
293 
294  call self%poisson_matrix%create( self%mass1_operator, self%n_dofs, self%delta_x )
295  ! Penalized Poisson operator
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 )
299  ! Poisson solver
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
303  !self%poisson_solver%verbose = .true.
304  self%poisson_solver%n_maxiter=40000
305 
306 
307  ! Only for Schur complement eb solver
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)
311  !self%linear_solver_schur_eb%verbose = .true.
312  !self%linear_solver_schur_eb%n_maxiter = 2000
313 
314  contains
315  function profile_m0( x, component)
316  sll_real64 :: profile_m0
317  sll_real64, intent(in) :: x(3)
318  sll_int32, optional, intent(in) :: component(:)
319 
320  profile_m0 = self%map%jacobian( x ) * self%profile%rho_0( x(1) )/ self%profile%T_e( x(1) )
321 
322  end function profile_m0
323 
324  function profile_0(x, component)
325  sll_real64 :: profile_0
326  sll_real64, intent(in) :: x(3)
327  sll_int32, optional, intent(in) :: component(:)
328 
329  profile_0 = self%map%jacobian( x )
330 
331  end function profile_0
332 
333  function profile_1(x, component)
334  sll_real64 :: profile_1
335  sll_real64, intent(in) :: x(3)
336  sll_int32, optional, intent(in) :: component(:)
337 
338  profile_1 = self%map%metric_inverse_single_jacobian( x, component(1), component(1) )
339 
340  end function profile_1
341 
342  function profile_2(x, component)
343  sll_real64 :: profile_2
344  sll_real64, intent(in) :: x(3)
345  sll_int32, optional, intent(in) :: component(:)
346 
347  profile_2 = self%map%metric_single_jacobian( x, component(1), component(1) )
348 
349  end function profile_2
350 
351  function profile_m1(x, component)
352  sll_real64 :: profile_m1
353  sll_real64, intent(in) :: x(3)
354  sll_int32, optional, intent(in) :: component(:)
355 
356  profile_m1 = self%map%metric_inverse_single_jacobian( x, component(1), component(2) )
357 
358  end function profile_m1
359 
360  function profile_m2(x, component)
361  sll_real64 :: profile_m2
362  sll_real64, intent(in) :: x(3)
363  sll_int32, optional, intent(in) :: component(:)
364 
365  profile_m2 = self%map%metric_single_jacobian( x, component(1), component(2) )
366 
367  end function profile_m2
368 
369  end subroutine init_3d_trafo_parallel
370 
371 
372 
373  subroutine sll_s_compute_mpi_decomposition( mpi_rank, mpi_total, n_cells, begin, limit )
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)
379 
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
384  limit(3)=n_cells(3)
385  end if
386  begin(2)=1
387  limit(2)=n_cells(2)
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
391  limit(3)=begin(3)
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
394  else
395  sll_warning('maxwell_3d_trafo_parallel:init', 'amount of mpi processes not optimal')
396  if( mpi_rank < n_cells(3) ) then
397  begin(3)=1+mpi_rank
398  limit(3)=begin(3)
399  begin(2)=1
400  limit(2)=n_cells(2)
401  else
402  begin(3)=1
403  limit(3)=0
404  begin(2)=1
405  limit(2)=0
406  end if
407  end if
408  else
409  if( mpi_rank < n_cells(2)*n_cells(3) )then
410  begin(3)=1+mpi_rank/n_cells(2)
411  limit(3)=begin(3)
412  begin(2)=1+modulo(mpi_rank,n_cells(2))
413  limit(2)=begin(2)
414  else
415  begin(3)=1
416  limit(3)=0
417  begin(2)=1
418  limit(2)=0
419  end if
420  end if
421  begin(1)=1
422  limit(1)=n_cells(1)
423 
424  end subroutine sll_s_compute_mpi_decomposition
425 
426 
Combines values from all processes and distributes the result back to all processes.
Parallelizing facility.
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
    Report Typos and Errors