Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_time_propagator_pic_vm_1d2v_zigsub.F90
Go to the documentation of this file.
1 
8 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 #include "sll_assert.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
12 
13  use sll_m_collective, only: &
16 
17  use sll_m_binomial_filter, only: &
19 
20  use sll_m_control_variate, only: &
22 
23  use sll_m_time_propagator_base, only: &
25 
28 
29  use sll_m_maxwell_1d_base, only: &
31 
32  use sll_m_particle_group_base, only: &
34 
35  use mpi, only: &
36  mpi_sum
37 
38  implicit none
39 
40  public :: &
44 
45  private
46 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
47 
50  class(sll_c_maxwell_1d_base), pointer :: maxwell_solver
51  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_0
52  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_1
53  class(sll_t_particle_array), pointer :: particle_group
54 
55  sll_int32 :: spline_degree
56  sll_real64 :: lx
57  sll_real64 :: x_min
58  sll_real64 :: delta_x
59 
60  sll_real64 :: cell_integrals_0(4)
61  sll_real64 :: cell_integrals_1(3)
62 
63 
64  sll_real64, pointer :: efield_dofs(:,:)
65  sll_real64, pointer :: bfield_dofs(:)
66  sll_real64, allocatable :: j_dofs(:,:)
67  sll_real64, allocatable :: j_dofs_local(:,:)
68  sll_int32 :: n_species
69 
70  logical :: electrostatic = .false.
71 
72  logical :: jmean = .false.
73  sll_real64, allocatable :: bfield_old(:)
74 
75  type(sll_t_binomial_filter), pointer :: filter
76 
77  ! For version with control variate
79  sll_int32 :: i_weight
80 
81  sll_int32 :: n_sub_iter
82 
83  contains
84  procedure :: lie_splitting => lie_splitting_pic_vm_1d2v
85  procedure :: lie_splitting_back => lie_splitting_back_pic_vm_1d2v
86  procedure :: strang_splitting => strang_splitting_pic_vm_1d2v
87  procedure :: reinit_fields
88 
89  procedure :: init => initialize_pic_vm_1d2v
90  procedure :: free => delete_pic_vm_1d2v
91 
92  procedure :: operator_all
93 
95 
96 contains
97 
98  subroutine reinit_fields( self )
99  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent(inout) :: self
100 
101  end subroutine reinit_fields
102 
104  subroutine strang_splitting_pic_vm_1d2v(self,dt, number_steps)
105  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent(inout) :: self
106  sll_real64, intent(in) :: dt
107  sll_int32, intent(in) :: number_steps
108  !local variables
109  sll_int32 :: i_step
110 
111  if(self%electrostatic) then
112  do i_step = 1, number_steps
113  call operator_all(self, dt)
114  end do
115  else
116  do i_step = 1, number_steps
117  call operator_all(self, dt)
118  end do
119  end if
120 
121  end subroutine strang_splitting_pic_vm_1d2v
122 
124  subroutine lie_splitting_pic_vm_1d2v(self,dt, number_steps)
125  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent(inout) :: self
126  sll_real64, intent(in) :: dt
127  sll_int32, intent(in) :: number_steps
128  !local variables
129  sll_int32 :: i_step
130  if(self%electrostatic) then
131  do i_step = 1, number_steps
132  call operator_all(self, dt)
133  end do
134  else
135  do i_step = 1,number_steps
136  call operator_all(self, dt)
137  end do
138  end if
139 
140 
141  end subroutine lie_splitting_pic_vm_1d2v
142 
144  subroutine lie_splitting_back_pic_vm_1d2v(self,dt, number_steps)
145  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent(inout) :: self
146  sll_real64, intent(in) :: dt
147  sll_int32, intent(in) :: number_steps
148  !local variables
149  sll_int32 :: i_step
150 
151  if(self%electrostatic) then
152  do i_step = 1, number_steps
153  call operator_all(self, dt)
154  end do
155  else
156  do i_step = 1,number_steps
157  call operator_all(self, dt)
158  end do
159  end if
160 
161  end subroutine lie_splitting_back_pic_vm_1d2v
162 
163  subroutine operator_all( self, dt )
164  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent(inout) :: self
165  sll_real64, intent(in) :: dt
166  !local variables
167  sll_int32 :: i_sp, i_part
168  sll_real64 :: bfield, efield(2)
169  sll_real64 :: dtau
170  sll_real64 :: qoverm
171  sll_real64 :: wi(1), vi(3), xi(3), wp(3), x_new(3)
172  sll_int32 :: n_cells, iter
173 
174  dtau = dt/real(self%n_sub_iter, f64)
175 
176  n_cells = self%kernel_smoother_0%n_dofs
177 
178  ! Update bfield
179  self%bfield_old = self%bfield_dofs
180  call self%maxwell_solver%compute_B_from_E( &
181  dt, self%efield_dofs(:,2), self%bfield_dofs)
182 
183  ! Particle loop with subcycling
184  self%j_dofs_local = 0.0_f64
185  ! Then update particle position: X_new = X_old + dt * V
186  do i_sp = 1,self%n_species
187  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
188  do i_part=1,self%particle_group%group(i_sp)%n_particles
189  ! Read out particle position and velocity
190  xi = self%particle_group%group(i_sp)%get_x(i_part)
191  vi = self%particle_group%group(i_sp)%get_v(i_part)
192 
193  ! Get charge for accumulation of j
194  wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
195 
196  ! First push v_1
197  ! Evaluate bfield at particle position (splines of order p)
198  call self%kernel_smoother_1%evaluate &
199  (xi(1), self%bfield_old, bfield)
200  vi(1) = vi(1) + dtau*qoverm*vi(2)*bfield
201  ! Evaluate efields at particle position
202  call self%kernel_smoother_1%evaluate &
203  (xi(1), self%efield_dofs(:,1), efield(1))
204  vi(1) = vi(1) + dt* qoverm * efield(1)
205 
206  call self%kernel_smoother_0%add_charge(xi(1:1), wi(1)*vi(2)*dtau, self%j_dofs_local(:,2))
207 
208  if (self%particle_group%group(i_sp)%n_weights == 3) then
209  ! Update weights if control variate
210  wp = self%particle_group%group(i_sp)%get_weights(i_part)
211  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
212  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
213 
214  ! Get charge for accumulation of j
215  wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
216  end if
217 
218  ! Then update particle position: X_new = X_old + dt * V
219  x_new = xi + dtau * vi
220 
221  call self%kernel_smoother_1%add_current_update_v( xi, x_new, wi(1), qoverm, &
222  self%bfield_dofs, vi, self%j_dofs_local(:,1))
223  ! Accumulate rho for Poisson diagnostics
224  !call self%kernel_smoother_0%add_charge( x_new, wi(1), &
225  ! self%j_dofs_local(:,2))
226  ! Evaluate efields at particle position
227  call self%kernel_smoother_0%evaluate &
228  (xi(1), self%efield_dofs(:,2), efield(2))
229  vi(2) = vi(2) + dt* qoverm * efield(2)
230 
231  x_new(1) = modulo(x_new(1), self%Lx)
232 
233  if (self%particle_group%group(i_sp)%n_weights == 3) then
234  ! Update weights if control variate
235  wp = self%particle_group%group(i_sp)%get_weights(i_part)
236  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( x_new(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
237  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
238  end if
239 
240  do iter = 2, self%n_sub_iter
241  xi = x_new
242  ! First push v_1
243  ! Evaluate bfield at particle position (splines of order p)
244  call self%kernel_smoother_1%evaluate &
245  (xi(1), self%bfield_dofs, bfield)
246  vi(1) = vi(1) + dtau*qoverm*vi(2)*bfield
247 
248  call self%kernel_smoother_0%add_charge(xi(1:1), wi(1)*vi(2)*dtau, self%j_dofs_local(:,2))
249 
250  if (self%particle_group%group(i_sp)%n_weights == 3) then
251  ! Update weights if control variate
252  wp = self%particle_group%group(i_sp)%get_weights(i_part)
253  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
254  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
255 
256  ! Get charge for accumulation of j
257  wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
258  end if
259 
260  ! Then update particle position: X_new = X_old + dt * V
261  x_new = xi + dtau * vi
262 
263  call self%kernel_smoother_1%add_current_update_v( xi, x_new, wi(1), qoverm, &
264  self%bfield_dofs, vi, self%j_dofs_local(:,1))
265  ! Accumulate rho for Poisson diagnostics
266  !call self%kernel_smoother_0%add_charge( x_new, wi(1), &
267  ! self%j_dofs_local(:,2))
268  x_new(1) = modulo(x_new(1), self%Lx)
269 
270  if (self%particle_group%group(i_sp)%n_weights == 3) then
271  ! Update weights if control variate
272  wp = self%particle_group%group(i_sp)%get_weights(i_part)
273  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( x_new(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
274  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
275  end if
276  end do
277 
278  call self%particle_group%group(i_sp)%set_x(i_part, x_new)
279  call self%particle_group%group(i_sp)%set_v(i_part, vi)
280  end do
281  end do
282 
283  ! Update the electric field
284  self%j_dofs = 0.0_f64
285  ! MPI to sum up contributions from each processor
286  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,1), &
287  n_cells, mpi_sum, self%j_dofs(:,1))
288  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,2), &
289  n_cells, mpi_sum, self%j_dofs(:,2))
290  call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,1), 1, self%efield_dofs(:,1))
291  call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs(:,2))
292  call self%maxwell_solver%compute_E_from_B(&
293  dt, self%bfield_dofs, self%efield_dofs(:,2))
294 
295 
296  end subroutine operator_all
297 
298 
299 
300  !---------------------------------------------------------------------------!
303  self, &
304  maxwell_solver, &
305  kernel_smoother_0, &
306  kernel_smoother_1, &
307  particle_group, &
308  efield_dofs, &
309  bfield_dofs, &
310  x_min, &
311  Lx, &
312  n_sub_iter, &
313  filter, &
314  jmean, &
315  control_variate, &
316  i_weight, &
317  electrostatic)
318  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent(out) :: self
319  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
320  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
321  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
322  class(sll_t_particle_array), target, intent(in) :: particle_group
323  sll_real64, target, intent(in) :: efield_dofs(:,:)
324  sll_real64, target, intent(in) :: bfield_dofs(:)
325  sll_real64, intent(in) :: x_min
326  sll_real64, intent(in) :: lx
327  sll_int32, intent(in) :: n_sub_iter
328  type( sll_t_binomial_filter ), intent( in ), target :: filter
329  logical, optional, intent(in) :: jmean
330  class(sll_t_control_variates), optional, target, intent(in) :: control_variate
331  sll_int32, optional, intent(in) :: i_weight
332  logical, optional :: electrostatic
333  !local variables
334  sll_int32 :: ierr
335 
336  if( present(electrostatic) )then
337  self%electrostatic = electrostatic
338  end if
339 
340  self%maxwell_solver => maxwell_solver
341  self%kernel_smoother_0 => kernel_smoother_0
342  self%kernel_smoother_1 => kernel_smoother_1
343 
344  self%n_species = particle_group%n_species
345 
346  self%particle_group => particle_group
347  self%efield_dofs => efield_dofs
348  self%bfield_dofs => bfield_dofs
349 
350  ! Check that n_dofs is the same for both kernel smoothers.
351  sll_assert( self%kernel_smoother_0%n_dofs == self%kernel_smoother_1%n_dofs )
352 
353  sll_allocate(self%j_dofs(self%kernel_smoother_0%n_dofs,2), ierr)
354  sll_allocate(self%j_dofs_local(self%kernel_smoother_0%n_dofs,2), ierr)
355  sll_allocate(self%bfield_old(self%kernel_smoother_0%n_dofs), ierr)
356 
357  self%spline_degree = self%kernel_smoother_0%spline_degree
358  self%x_min = x_min
359  self%Lx = lx
360  self%delta_x = self%Lx/real(self%kernel_smoother_1%n_dofs, f64)
361 
362  self%cell_integrals_1 = [0.5_f64, 2.0_f64, 0.5_f64]
363  self%cell_integrals_1 = self%cell_integrals_1 / 3.0_f64
364 
365  self%cell_integrals_0 = [1.0_f64,11.0_f64,11.0_f64,1.0_f64]
366  self%cell_integrals_0 = self%cell_integrals_0 / 24.0_f64
367 
368 
369  if (present(jmean)) then
370  self%jmean = jmean
371  end if
372 
373  self%i_weight = 1
374  if (present(i_weight)) self%i_weight = i_weight
375  if(present(control_variate)) then
376  allocate(self%control_variate )
377  allocate(self%control_variate%cv(self%n_species) )
378  self%control_variate => control_variate
379  end if
380 
381  self%n_sub_iter = n_sub_iter
382 
383  end subroutine initialize_pic_vm_1d2v
384 
385  !---------------------------------------------------------------------------!
387  subroutine delete_pic_vm_1d2v(self)
388  class(sll_t_time_propagator_pic_vm_1d2v_zigsub), intent( inout ) :: self
389 
390  deallocate(self%j_dofs)
391  deallocate(self%j_dofs_local)
392  self%maxwell_solver => null()
393  self%kernel_smoother_0 => null()
394  self%kernel_smoother_1 => null()
395  self%particle_group => null()
396  self%efield_dofs => null()
397  self%bfield_dofs => null()
398 
399  end subroutine delete_pic_vm_1d2v
400 
401 
402  !---------------------------------------------------------------------------!
405  splitting, &
406  maxwell_solver, &
407  kernel_smoother_0, &
408  kernel_smoother_1, &
409  particle_group, &
410  efield_dofs, &
411  bfield_dofs, &
412  x_min, &
413  Lx, &
414  n_sub_iter, &
415  filter, &
416  jmean, &
417  control_variate, &
418  i_weight, &
419  electrostatic)
420  class(sll_c_time_propagator_base), allocatable, intent(out) :: splitting
421  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
422  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
423  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
424  class(sll_t_particle_array), target, intent(in) :: particle_group
425  sll_real64, target, intent(in) :: efield_dofs(:,:)
426  sll_real64, target, intent(in) :: bfield_dofs(:)
427  sll_real64, intent(in) :: x_min
428  sll_real64, intent(in) :: lx
429  sll_int32, intent(in) :: n_sub_iter
430  type( sll_t_binomial_filter ), intent( in ), target :: filter
431  logical, optional, intent(in) :: jmean
432  class(sll_t_control_variates), optional, target, intent(in) :: control_variate
433  sll_int32, optional, intent(in) :: i_weight
434  logical, optional :: electrostatic
435  !local variables
436  sll_int32 :: ierr
437  logical :: jmean_val
438 
439  sll_allocate(sll_t_time_propagator_pic_vm_1d2v_zigsub :: splitting, ierr)
440 
441  if (present(jmean) ) then
442  jmean_val = jmean
443  else
444  jmean_val = .false.
445  end if
446 
447  select type (splitting)
449  if (present(control_variate) ) then
450  call splitting%init(&
451  maxwell_solver, &
452  kernel_smoother_0, &
453  kernel_smoother_1, &
454  particle_group, &
455  efield_dofs, &
456  bfield_dofs, &
457  x_min, &
458  lx, &
459  n_sub_iter, &
460  filter, &
461  jmean_val, &
462  control_variate, &
463  i_weight, &
464  electrostatic=electrostatic)
465  else
466  call splitting%init(&
467  maxwell_solver, &
468  kernel_smoother_0, &
469  kernel_smoother_1, &
470  particle_group, &
471  efield_dofs, &
472  bfield_dofs, &
473  x_min, &
474  lx, &
475  n_sub_iter, &
476  filter, &
477  jmean_val, &
478  electrostatic=electrostatic)
479  end if
480  end select
481 
483 
484  !---------------------------------------------------------------------------!
487  splitting, &
488  maxwell_solver, &
489  kernel_smoother_0, &
490  kernel_smoother_1, &
491  particle_group, &
492  efield_dofs, &
493  bfield_dofs, &
494  x_min, &
495  Lx, &
496  n_sub_iter, &
497  filter, &
498  jmean, &
499  electrostatic)
500  class(sll_c_time_propagator_base), pointer, intent(out) :: splitting
501  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
502  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
503  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
504  class(sll_t_particle_array), target, intent(in) :: particle_group
505  sll_real64, target, intent(in) :: efield_dofs(:,:)
506  sll_real64, target, intent(in) :: bfield_dofs(:)
507  sll_real64, intent(in) :: x_min
508  sll_real64, intent(in) :: lx
509  sll_int32, intent(in) :: n_sub_iter
510  type( sll_t_binomial_filter ), intent( in ), target :: filter
511  logical, optional, intent(in) :: jmean
512  logical, optional :: electrostatic
513  !local variables
514  sll_int32 :: ierr
515  logical :: jmean_val
516 
517  sll_allocate(sll_t_time_propagator_pic_vm_1d2v_zigsub :: splitting, ierr)
518 
519 
520  if (present(jmean) ) then
521  jmean_val = jmean
522  else
523  jmean_val = .false.
524  end if
525 
526  select type (splitting)
528  call splitting%init(&
529  maxwell_solver, &
530  kernel_smoother_0, &
531  kernel_smoother_1, &
532  particle_group, &
533  efield_dofs, &
534  bfield_dofs, &
535  x_min, &
536  lx, &
537  n_sub_iter, &
538  filter, &
539  jmean_val, &
540  electrostatic=electrostatic)
541  end select
542 
544 
545 
Combines values from all processes and distributes the result back to all processes.
Binomial filter for smooting of fields.
Parallelizing facility.
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.
Module interface to solve Maxwell's equations in 1D.
Base class for kernel smoothers for accumulation and field evaluation in PIC.
Base class for Hamiltonian splittings.
Particle pusher based on the subcycling algorithm for the 1d2v Vlasov-Maxwell equation with splitting...
subroutine lie_splitting_back_pic_vm_1d2v(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine initialize_pic_vm_1d2v(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, efield_dofs, bfield_dofs, x_min, Lx, n_sub_iter, filter, jmean, control_variate, i_weight, electrostatic)
Constructor.
subroutine, public sll_s_new_time_propagator_pic_vm_1d2v_zigsub(splitting, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, efield_dofs, bfield_dofs, x_min, Lx, n_sub_iter, filter, jmean, control_variate, i_weight, electrostatic)
Constructor for allocatable abstract type.
subroutine lie_splitting_pic_vm_1d2v(self, dt, number_steps)
Lie splitting.
subroutine strang_splitting_pic_vm_1d2v(self, dt, number_steps)
Strang splitting.
subroutine, public sll_s_new_time_propagator_pic_vm_1d2v_zigsub_ptr(splitting, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, efield_dofs, bfield_dofs, x_min, Lx, n_sub_iter, filter, jmean, electrostatic)
Constructor for pointer abstract type.
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
    Report Typos and Errors