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_hs.F90
Go to the documentation of this file.
1 
6 
9  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
10 #include "sll_assert.h"
11 #include "sll_errors.h"
12 #include "sll_memory.h"
13 #include "sll_working_precision.h"
14 
15  use sll_m_collective, only: &
18 
19  use sll_m_control_variate, only: &
21 
22  use sll_m_filter_base_1d, only: &
24 
25  use sll_m_time_propagator_base, only: &
27 
30 
31  use sll_m_maxwell_1d_base, only: &
33 
34  use sll_m_particle_group_base, only: &
36 
37  use mpi, only: &
38  mpi_sum
39 
45 
46  implicit none
47 
48  public :: &
51 
52  private
53  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
54 
57  class(sll_c_maxwell_1d_base), pointer :: maxwell_solver
58  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_0
59  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_1
60  class(sll_t_particle_array), pointer :: particle_group
61 
62  sll_int32 :: spline_degree
63  sll_real64 :: lx
64  sll_real64 :: x_min
65  sll_real64 :: x_max
66  sll_real64 :: delta_x
67  sll_int32 :: n_cells
68  sll_int32 :: n_total0
69  sll_int32 :: n_total1
70  sll_int32 :: boundary_particles = 100
71  sll_int32 :: counter_left = 0
72  sll_int32 :: counter_right = 0
73  logical :: boundary = .false.
74  sll_real64, pointer :: rhob(:) => null()
75 
76  sll_real64 :: betar(2)
77 
78  sll_real64, pointer :: phi_dofs(:)
79  sll_real64, pointer :: efield_dofs(:,:)
80  sll_real64, pointer :: bfield_dofs(:)
81  sll_real64, allocatable :: j_dofs(:,:)
82  sll_real64, allocatable :: j_dofs_local(:,:)
83 
84  sll_real64 :: force_sign = 1._f64
85  logical :: electrostatic = .false.
86  logical :: adiabatic_electrons = .false.
87 
88  logical :: jmean = .false.
89 
90  sll_real64, allocatable :: efield_filter(:,:)
91  sll_real64, allocatable :: bfield_filter(:)
92 
93 
94  sll_real64, allocatable :: efield_to_val(:,:)
95  sll_real64, allocatable :: bfield_to_val(:)
96 
97  class(sll_c_filter_base_1d), pointer :: filter
98 
99  sll_int32 :: n_species
100 
101  ! For version with control variate
102  class(sll_t_control_variates), pointer :: control_variate => null()
103  sll_int32 :: i_weight
104 
105  contains
106  procedure :: operatorhp1 => operatorhp1_pic_vm_1d2v_hs
107  procedure :: operatorhp2 => operatorhp2_pic_vm_1d2v_hs
108  procedure :: operatorhe => operatorhe_pic_vm_1d2v_hs
109  procedure :: operatorhb => operatorhb_pic_vm_1d2v_hs
110  procedure :: lie_splitting => lie_splitting_pic_vm_1d2v_hs
111  procedure :: lie_splitting_back => lie_splitting_back_pic_vm_1d2v_hs
112  procedure :: strang_splitting => strang_splitting_pic_vm_1d2v_hs
113  procedure :: reinit_fields
114 
115  procedure :: init => initialize_pic_vm_1d2v_hs
116  procedure :: free => delete_pic_vm_1d2v_hs
117 
119 
120 contains
121 
122  subroutine reinit_fields( self )
123  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
124 
125  call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
126  call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
127  call self%filter%apply( self%bfield_dofs, self%bfield_filter )
128 
129  end subroutine reinit_fields
130 
132  subroutine strang_splitting_pic_vm_1d2v_hs(self,dt, number_steps)
133  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
134  sll_real64, intent(in) :: dt
135  sll_int32, intent(in) :: number_steps
136  !local variables
137  sll_int32 :: i_step
138 
139  if(self%electrostatic) then
140  do i_step = 1, number_steps
141  call self%operatorHE(0.5_f64*dt)
142  call self%operatorHp1(dt)
143  call self%operatorHE(0.5_f64*dt)
144  end do
145  else
146  do i_step = 1, number_steps
147  call self%operatorHB(0.5_f64*dt)
148  call self%operatorHE(0.5_f64*dt)
149  call self%operatorHp2(0.5_f64*dt)
150  call self%operatorHp1(dt)
151  call self%operatorHp2(0.5_f64*dt)
152  call self%operatorHE(0.5_f64*dt)
153  call self%operatorHB(0.5_f64*dt)
154  end do
155  end if
156 
157  end subroutine strang_splitting_pic_vm_1d2v_hs
158 
160  subroutine lie_splitting_pic_vm_1d2v_hs(self,dt, number_steps)
161  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
162  sll_real64, intent(in) :: dt
163  sll_int32, intent(in) :: number_steps
164  !local variables
165  sll_int32 :: i_step
166  if(self%electrostatic) then
167  do i_step = 1, number_steps
168  call self%operatorHE(dt)
169  call self%operatorHp1(dt)
170  end do
171  else
172  do i_step = 1,number_steps
173  call self%operatorHE(dt)
174  call self%operatorHB(dt)
175  call self%operatorHp1(dt)
176  call self%operatorHp2(dt)
177  end do
178  end if
179 
180 
181  end subroutine lie_splitting_pic_vm_1d2v_hs
182 
184  subroutine lie_splitting_back_pic_vm_1d2v_hs(self,dt, number_steps)
185  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
186  sll_real64, intent(in) :: dt
187  sll_int32, intent(in) :: number_steps
188  !local variables
189  sll_int32 :: i_step
190 
191  if(self%electrostatic) then
192  do i_step = 1, number_steps
193  call self%operatorHp1(dt)
194  call self%operatorHE(dt)
195  end do
196  else
197  do i_step = 1,number_steps
198  call self%operatorHp2(dt)
199  call self%operatorHp1(dt)
200  call self%operatorHB(dt)
201  call self%operatorHE(dt)
202  end do
203  end if
204 
205  end subroutine lie_splitting_back_pic_vm_1d2v_hs
206 
207 
208  !---------------------------------------------------------------------------!
215  subroutine operatorhp1_pic_vm_1d2v_hs(self, dt)
216  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
217  sll_real64, intent(in) :: dt
218  !local variables
219  sll_int32 :: i_part
220  sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wp(3)
221  sll_int32 :: i_sp
222  sll_real64 :: qoverm
223 
224  call self%maxwell_solver%transform_dofs( self%bfield_filter, self%bfield_to_val, 0 )
225 
226 
227  ! Here we have to accumulate j and integrate over the time interval.
228  ! At each k=1,...,n_grid, we have for s \in [0,dt]:
229  ! j_k(s) = \sum_{i=1,..,N_p} q_i N((x_k+sv_{1,k}-x_i)/h) v_k,
230  ! where h is the grid spacing and N the normalized B-spline
231  ! In order to accumulate the integrated j, we normalize the values of x to the grid spacing, calling them y, we have
232  ! j_k(s) = \sum_{i=1,..,N_p} q_i N(y_k+s/h v_{1,k}-y_i) v_k.
233  ! Now, we want the integral
234  ! \int_{0..dt} j_k(s) d s = \sum_{i=1,..,N_p} q_i v_k \int_{0..dt} N(y_k+s/h v_{1,k}-y_i) ds = \sum_{i=1,..,N_p} q_i v_k \int_{0..dt} N(y_k + w v_{1,k}-y_i) dw
235 
236 
237  self%j_dofs_local = 0.0_f64
238 
239  ! For each particle compute the index of the first DoF on the grid it contributes to and its position (normalized to cell size one). Note: j_dofs(_local) does not hold the values for j itself but for the integrated j.
240  ! Then update particle position: X_new = X_old + dt * V
241  do i_sp = 1,self%n_species
242  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
243  do i_part=1,self%particle_group%group(i_sp)%n_particles
244  ! Read out particle position and velocity
245  xold = self%particle_group%group(i_sp)%get_x(i_part)
246  vi = self%particle_group%group(i_sp)%get_v(i_part)
247 
248  ! Then update particle position: X_new = X_old + dt * V
249  xnew = xold + dt * vi
250 
251  ! Get charge for accumulation of j
252  wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
253 
254  call compute_particle_boundary_current( self, xold, xnew, vi, wi(1), qoverm )
255  call self%particle_group%group(i_sp)%set_x(i_part, xnew)
256  call self%particle_group%group(i_sp)%set_v(i_part, vi)
257 
258  if (self%particle_group%group(i_sp)%n_weights == 3) then
259  ! Update weights if control variate
260  wp = self%particle_group%group(i_sp)%get_weights(i_part)
261  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
262  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
263  end if
264 
265  end do
266  end do
267 
268  self%j_dofs = 0.0_f64
269  ! MPI to sum up contributions from each processor
270  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,1), &
271  self%n_total1, mpi_sum, self%j_dofs(1:self%n_total1,1))
272 
273  !call filter( self%j_dofs(:,1), self%j_dofs_local(:,1), n_cells )
274  !call filter( self%j_dofs_local(:,1), self%j_dofs(:,1), n_cells )
275  !self%j_dofs(:,1) = self%j_dofs_local(:,1)
276  call self%filter%apply_inplace( self%j_dofs(:,1) )
277 
278  if ( self%jmean .eqv. .true. ) then
279  self%j_dofs(:,1) = self%j_dofs(:,1) - sum(self%j_dofs(1:self%n_total1,1))/real(self%n_total1, f64)
280  end if
281  ! Update the electric field.
282  if(self%adiabatic_electrons) then
283  call self%maxwell_solver%compute_phi_from_j(self%j_dofs(1:self%n_total1,1), self%phi_dofs, self%efield_dofs(1:self%n_total1,1))
284  else
285  call self%maxwell_solver%compute_E_from_j(self%force_sign*self%betar(2)*self%j_dofs(1:self%n_total1,1), 1, self%efield_dofs(1:self%n_total1,1))
286  end if
287  call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
288 
289  end subroutine operatorhp1_pic_vm_1d2v_hs
290 
291 
292  subroutine compute_particle_boundary_current( self, xold, xnew, vi, wi, qoverm )
293  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent( inout ) :: self
294  sll_real64, intent( inout ) :: xold(3)
295  sll_real64, intent( inout ) :: xnew(3)
296  sll_real64, intent( inout ) :: vi(3)
297  sll_real64, intent( in ) :: wi(1)
298  sll_real64, intent( in ) :: qoverm
299  !local variables
300  sll_real64 :: xmid(3), xbar
301 
302  if(xnew(1) < self%x_min .or. xnew(1) > self%x_max )then
303  if(xnew(1) < self%x_min )then
304  xbar = self%x_min
305  self%counter_left = self%counter_left+1
306  else if(xnew(1) > self%x_max)then
307  xbar = self%x_max
308  self%counter_right = self%counter_right+1
309  end if
310 
311  xmid = xnew
312  xmid(1) = xbar
313 
314  call self%kernel_smoother_1%add_current_update_v( xold, xmid, wi(1), qoverm, &
315  self%bfield_to_val, vi, self%j_dofs_local(1:self%n_total1,1))
316  select case(self%boundary_particles)
318  xnew(1) = 2._f64*xbar-xnew(1)
319  vi(1) = -vi(1)
321  call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
323  xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
324  xmid = self%x_max+self%x_min-xbar
325  case default
326  xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
327  xmid = self%x_max+self%x_min-xbar
328  end select
329  if (xnew(1) >= self%x_min .and. xnew(1) <= self%x_max) then
330  call self%kernel_smoother_1%add_current_update_v( xmid, xnew, wi(1), qoverm, &
331  self%bfield_to_val, vi, self%j_dofs_local(1:self%n_total1,1))
332  end if
333  else if(xnew(1) < -self%x_max .or. xnew(1) > 2._f64*self%x_max ) then
334  print*, xnew
335  sll_error("particle boundary", "particle out of bound")
336  else
337  call self%kernel_smoother_1%add_current_update_v( xold, xnew, wi(1), qoverm, &
338  self%bfield_to_val, vi, self%j_dofs_local(1:self%n_total1,1))
339  end if
340 
341  end subroutine compute_particle_boundary_current
342 
343 
344  !---------------------------------------------------------------------------!
351  subroutine operatorhp2_pic_vm_1d2v_hs(self, dt)
352  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
353  sll_real64, intent(in) :: dt
354 
355  !local variables
356  sll_int32 :: i_part, i_sp
357  sll_real64 :: vi(3), xi(3), wi(1), wp(3)
358  sll_real64 :: bfield
359  sll_real64 :: qm
360 
361 
362  self%j_dofs_local = 0.0_f64
363 
364  call self%maxwell_solver%transform_dofs( self%bfield_filter, self%bfield_to_val, 0 )
365 
366  do i_sp = 1, self%n_species
367  qm = self%particle_group%group(i_sp)%species%q_over_m();
368  ! Update v_1
369  do i_part=1,self%particle_group%group(i_sp)%n_particles
370  ! Evaluate bfield at particle position (splines of order p)
371  xi = self%particle_group%group(i_sp)%get_x(i_part)
372  call self%kernel_smoother_1%evaluate &
373  (xi(1), self%bfield_to_val, bfield)
374  vi = self%particle_group%group(i_sp)%get_v(i_part)
375  vi(1) = vi(1) + dt*qm*vi(2)*bfield
376  call self%particle_group%group(i_sp)%set_v(i_part, vi)
377 
378  xi = self%particle_group%group(i_sp)%get_x(i_part)
379 
380  ! Scale vi by weight to combine both factors for accumulation of integral over j
381  wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)*vi(2)
382 
383  call self%kernel_smoother_0%add_charge(xi(1:1), wi(1), self%j_dofs_local(:,2))
384 
385  if (self%particle_group%group(i_sp)%n_weights == 3) then
386  ! Update weights if control variate
387  wp = self%particle_group%group(i_sp)%get_weights(i_part)
388  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
389  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
390  end if
391  end do
392  end do
393 
394  self%j_dofs = 0.0_f64
395  ! MPI to sum up contributions from each processor
396  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,2), &
397  self%n_total0, mpi_sum, self%j_dofs(:,2))
398  ! Update the electric field. Also, we still need to scale with 1/Lx ! TODO: Which scaling?
399  if ( self%jmean .eqv. .true. ) then
400  self%j_dofs(:,2) = self%j_dofs(:,2) - sum(self%j_dofs(:,2))/real(self%n_total0, f64)
401  end if
402  self%j_dofs(:,2) = self%j_dofs(:,2)*dt!/self%Lx
403 
404 
405  call self%filter%apply_inplace( self%j_dofs(:,2) )
406 
407  if(self%adiabatic_electrons) then
408  call self%maxwell_solver%compute_phi_from_j(self%j_dofs(:,2), self%phi_dofs, self%efield_dofs(:,1))
409  else
410  call self%maxwell_solver%compute_E_from_j(self%force_sign*self%betar(2)*self%j_dofs(:,2), 2, self%efield_dofs(:,2))
411  end if
412  call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
413 
414  end subroutine operatorhp2_pic_vm_1d2v_hs
415 
416  !---------------------------------------------------------------------------!
422  subroutine operatorhe_pic_vm_1d2v_hs(self, dt)
423  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
424  sll_real64, intent(in) :: dt
425 
426  !local variables
427  sll_int32 :: i_part, i_sp
428  sll_real64 :: v_new(3), xi(3), wp(3)
429  sll_real64 :: efield(2)
430  sll_real64 :: qm
431 
432 
433  call self%maxwell_solver%transform_dofs( self%efield_filter(:,1), self%efield_to_val(:,1), 0 )
434  call self%maxwell_solver%transform_dofs( self%efield_filter(:,2), self%efield_to_val(:,2), 1 )
435 
436  do i_sp = 1,self%n_species
437  qm = self%particle_group%group(i_sp)%species%q_over_m();
438  ! V_new = V_old + dt * E
439  do i_part=1,self%particle_group%group(i_sp)%n_particles
440  v_new = self%particle_group%group(i_sp)%get_v(i_part)
441  ! Evaluate efields at particle position
442  xi = self%particle_group%group(i_sp)%get_x(i_part)
443  call self%kernel_smoother_1%evaluate &
444  (xi(1), self%efield_to_val(1:self%n_total1,1), efield(1))
445  call self%kernel_smoother_0%evaluate &
446  (xi(1), self%efield_to_val(:,2), efield(2))
447  v_new = self%particle_group%group(i_sp)%get_v(i_part)
448  v_new(1:2) = v_new(1:2) + dt* qm * efield
449  call self%particle_group%group(i_sp)%set_v(i_part, v_new)
450 
451  if (self%particle_group%group(i_sp)%n_weights == 3) then
452  ! Update weights if control variate
453  wp = self%particle_group%group(i_sp)%get_weights(i_part)
454  !wp(3) = wp(3) + dt*qm*efield(1)*v_new(1)*self%Lx
455  wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), v_new(1:2), 0.0_f64, wp(1), wp(2))
456  call self%particle_group%group(i_sp)%set_weights(i_part, wp)
457  end if
458  end do
459  end do
460 
461  if(self%electrostatic .eqv. .false.) then
462  ! Update bfield
463  call self%maxwell_solver%compute_B_from_E( &
464  dt, self%efield_dofs(:,2), self%bfield_dofs)
465  call self%filter%apply( self%bfield_dofs, self%bfield_filter )
466  end if
467 
468  end subroutine operatorhe_pic_vm_1d2v_hs
469 
470 
471  !---------------------------------------------------------------------------!
477  subroutine operatorhb_pic_vm_1d2v_hs(self, dt)
478  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(inout) :: self
479  sll_real64, intent(in) :: dt
480 
481  ! Update efield2
482  call self%maxwell_solver%compute_E_from_B(&
483  dt*self%betar(1), self%bfield_dofs, self%efield_dofs(:,2))
484 
485  call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
486 
487  end subroutine operatorhb_pic_vm_1d2v_hs
488 
489 
490  !---------------------------------------------------------------------------!
493  self, &
494  maxwell_solver, &
495  kernel_smoother_0, &
496  kernel_smoother_1, &
497  particle_group, &
498  phi_dofs, &
499  efield_dofs, &
500  bfield_dofs, &
501  x_min, &
502  Lx, &
503  filter, &
504  boundary_particles, &
505  force_sign, &
506  jmean, &
507  control_variate, &
508  i_weight, &
509  betar, &
510  electrostatic, &
511  rhob)
512  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent(out) :: self
513  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
514  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
515  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
516  class(sll_t_particle_array), target, intent(in) :: particle_group
517  sll_real64, target, intent(in) :: phi_dofs(:)
518  sll_real64, target, intent(in) :: efield_dofs(:,:)
519  sll_real64, target, intent(in) :: bfield_dofs(:)
520  sll_real64, intent(in) :: x_min
521  sll_real64, intent(in) :: lx
522  class( sll_c_filter_base_1d ), intent( in ), target :: filter
523  sll_int32, optional, intent( in ) :: boundary_particles
524  sll_real64, optional, intent(in) :: force_sign
525  logical, optional, intent(in) :: jmean
526  class(sll_t_control_variates), optional, target, intent(in) :: control_variate
527  sll_int32, optional, intent(in) :: i_weight
528  sll_real64, optional, intent(in) :: betar(2)
529  logical, optional :: electrostatic
530  sll_real64, optional, target, intent( in ) :: rhob(:)
531  !local variables
532  sll_int32 :: ierr
533 
534  if( present(electrostatic) )then
535  self%electrostatic = electrostatic
536  end if
537 
538  if( present(rhob) )then
539  self%rhob => rhob
540  end if
541 
542  if (present(betar)) then
543  self%betar = betar!32.89_f64
544  else
545  self%betar = 1.0_f64
546  end if
547 
548  if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
549 
550  self%maxwell_solver => maxwell_solver
551  self%kernel_smoother_0 => kernel_smoother_0
552  self%kernel_smoother_1 => kernel_smoother_1
553  self%n_species = particle_group%n_species
554  self%particle_group => particle_group
555  self%phi_dofs => phi_dofs
556  self%efield_dofs => efield_dofs
557  self%bfield_dofs => bfield_dofs
558  self%spline_degree = self%kernel_smoother_0%spline_degree
559  self%x_min = x_min
560  self%x_max = x_min + lx
561  self%Lx = lx
562  self%delta_x = self%Lx/real(self%maxwell_solver%n_cells,f64)
563  self%n_cells = self%maxwell_solver%n_cells
564  self%n_total0 = self%maxwell_solver%n_dofs0
565  self%n_total1 = self%maxwell_solver%n_dofs1
566 
567  ! Check that n_dofs is the same for both kernel smoothers.
568  sll_assert( self%kernel_smoother_0%n_cells == self%kernel_smoother_1%n_cells )
569  sll_assert( self%kernel_smoother_0%n_cells == self%maxwell_solver%n_cells )
570 
571  sll_allocate(self%j_dofs(self%n_total0,2), ierr)
572  sll_allocate(self%j_dofs_local(self%n_total0,2), ierr)
573  sll_allocate(self%efield_filter(self%n_total0,2), ierr)
574  sll_allocate(self%bfield_filter(self%n_total1), ierr)
575  sll_allocate(self%efield_to_val(self%n_total0,2), ierr)
576  sll_allocate(self%bfield_to_val(self%n_total1), ierr)
577 
578  if( self%n_cells+self%spline_degree == self%maxwell_solver%n_dofs0 ) then
579  self%boundary = .true.
580  self%boundary_particles = boundary_particles
581  end if
582 
583  if( present(force_sign) )then
584  self%force_sign = force_sign
585  end if
586  self%filter => filter
587 
588  call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
589  call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
590  call self%filter%apply( self%bfield_dofs, self%bfield_filter )
591 
592  if (present(jmean)) then
593  self%jmean = jmean
594  end if
595 
596  self%i_weight = 1
597  if (present(i_weight)) self%i_weight = i_weight
598  if(present(control_variate)) then
599  allocate(self%control_variate )
600  allocate(self%control_variate%cv(self%n_species) )
601  self%control_variate => control_variate
602  end if
603  end subroutine initialize_pic_vm_1d2v_hs
604 
605  !---------------------------------------------------------------------------!
607  subroutine delete_pic_vm_1d2v_hs(self)
608  class(sll_t_time_propagator_pic_vm_1d2v_hs), intent( inout ) :: self
609 
610  if( self%boundary ) then
611  print*, 'left boundary', self%counter_left
612  print*, 'right boundary', self%counter_right
613  end if
614 
615  deallocate(self%j_dofs)
616  deallocate(self%j_dofs_local)
617  self%maxwell_solver => null()
618  self%kernel_smoother_0 => null()
619  self%kernel_smoother_1 => null()
620  self%particle_group => null()
621  self%phi_dofs => null()
622  self%efield_dofs => null()
623  self%bfield_dofs => null()
624 
625  end subroutine delete_pic_vm_1d2v_hs
626 
627 
628  !---------------------------------------------------------------------------!
631  splitting, &
632  maxwell_solver, &
633  kernel_smoother_0, &
634  kernel_smoother_1, &
635  particle_group, &
636  phi_dofs, &
637  efield_dofs, &
638  bfield_dofs, &
639  x_min, &
640  Lx, &
641  filter, &
642  boundary_particles, &
643  force_sign, &
644  jmean, &
645  control_variate, &
646  i_weight, &
647  betar, &
648  electrostatic, &
649  rhob)
650  class(sll_c_time_propagator_base), allocatable, intent(out) :: splitting
651  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
652  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
653  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
654  class(sll_t_particle_array), target, intent(in) :: particle_group
655  !class(sll_c_particle_group_base),target, intent(in) :: particle_group(:) !< Particle group
656  sll_real64, target, intent(in) :: phi_dofs(:)
657  sll_real64, target, intent(in) :: efield_dofs(:,:)
658  sll_real64, target, intent(in) :: bfield_dofs(:)
659  sll_real64, intent(in) :: x_min
660  sll_real64, intent(in) :: lx
661  class( sll_c_filter_base_1d ), intent( in ), target :: filter
662  sll_int32, optional, intent( in ) :: boundary_particles
663  sll_real64, optional, intent(in) :: force_sign
664  logical, optional, intent(in) :: jmean
665  class(sll_t_control_variates), optional, target, intent(in) :: control_variate
666  sll_int32, optional, intent(in) :: i_weight
667  sll_real64, intent( in ), optional :: betar(2)
668  logical, optional :: electrostatic
669  sll_real64, optional, target, intent( in ) :: rhob(:)
670  !local variables
671  sll_int32 :: ierr, boundary_particles_set
672  sll_real64 :: force_sign_set
673  logical :: jmean_set
674  sll_real64 :: betar_set(2)
675  logical :: electrostatic_set
676 
677  sll_allocate(sll_t_time_propagator_pic_vm_1d2v_hs :: splitting, ierr)
678 
679  if (present(boundary_particles)) then
680  boundary_particles_set = boundary_particles
681  else
682  boundary_particles_set = 100
683  end if
684 
685  if( present(force_sign) )then
686  force_sign_set = force_sign
687  else
688  force_sign_set = 1._f64
689  end if
690 
691  if (present(jmean) ) then
692  jmean_set = jmean
693  else
694  jmean_set = .false.
695  end if
696 
697  if (present(betar) ) then
698  betar_set = betar
699  else
700  betar_set = 1._f64
701  end if
702 
703  if (present(electrostatic) ) then
704  electrostatic_set = electrostatic
705  else
706  electrostatic = .false.
707  end if
708 
709  select type (splitting)
711  if (present(control_variate) ) then
712  call splitting%init(&
713  maxwell_solver, &
714  kernel_smoother_0, &
715  kernel_smoother_1, &
716  particle_group, &
717  phi_dofs, &
718  efield_dofs, &
719  bfield_dofs, &
720  x_min, &
721  lx, &
722  filter, &
723  boundary_particles_set, &
724  force_sign_set, &
725  jmean_set, &
726  control_variate, &
727  i_weight, &
728  betar = betar_set, &
729  electrostatic=electrostatic_set, &
730  rhob = rhob)
731  else
732  call splitting%init(&
733  maxwell_solver, &
734  kernel_smoother_0, &
735  kernel_smoother_1, &
736  particle_group, &
737  phi_dofs, &
738  efield_dofs, &
739  bfield_dofs, &
740  x_min, &
741  lx, &
742  filter, &
743  boundary_particles=boundary_particles_set, &
744  force_sign=force_sign_set, &
745  jmean = jmean_set, &
746  betar = betar_set, &
747  electrostatic=electrostatic_set, &
748  rhob = rhob)
749  end if
750  end select
751 
753 
754 
755 
Combines values from all processes and distributes the result back to all processes.
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 Hamiltonian splitting for 1d2v Vlasov-Poisson.
subroutine compute_particle_boundary_current(self, xold, xnew, vi, wi, qoverm)
subroutine operatorhp1_pic_vm_1d2v_hs(self, dt)
Push Hp1: Equations to solve are \partial_t f + v_1 \partial_{x_1} f = 0 -> X_new = X_old + dt V_1 V_...
subroutine strang_splitting_pic_vm_1d2v_hs(self, dt, number_steps)
Strang splitting.
subroutine lie_splitting_pic_vm_1d2v_hs(self, dt, number_steps)
Lie splitting.
subroutine operatorhp2_pic_vm_1d2v_hs(self, dt)
Push Hp2: Equations to solve are X_new = X_old V_new,1 = V_old,1 + \int_0 h V_old,...
subroutine operatorhe_pic_vm_1d2v_hs(self, dt)
Push H_E: Equations to be solved \partial_t f + E_1 \partial_{v_1} f + E_2 \partial_{v_2} f = 0 -> V_...
subroutine lie_splitting_back_pic_vm_1d2v_hs(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine operatorhb_pic_vm_1d2v_hs(self, dt)
Push H_B: Equations to be solved V_new = V_old \partial_t E_1 = 0 -> E_{1,new} = E_{1,...
subroutine, public sll_s_new_time_propagator_pic_vm_1d2v_hs(splitting, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, filter, boundary_particles, force_sign, jmean, control_variate, i_weight, betar, electrostatic, rhob)
Constructor for allocatable abstract type.
subroutine initialize_pic_vm_1d2v_hs(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, filter, boundary_particles, force_sign, jmean, control_variate, i_weight, betar, electrostatic, rhob)
Constructor.
Particle pusher based on antisymmetric splitting with AVF for 3d3v Vlasov-Maxwell with coordinate tra...
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
    Report Typos and Errors