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_3d3v_hs.F90
Go to the documentation of this file.
1 
7  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 #include "sll_assert.h"
9 #include "sll_errors.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
12 
13  use sll_m_collective, only: &
16 
17  use sll_m_control_variate, only: &
19 
20  use sll_m_filter_base_3d, only: &
22 
23  use sll_m_time_propagator_base, only: &
25 
31 
32  use sll_m_initial_distribution, only: &
34 
35  use sll_m_maxwell_3d_base, only: &
37 
38  use mpi, only: &
39  mpi_sum
40 
41  use sll_m_particle_group_base, only: &
43 
46 
47  use sll_m_profile_functions, only: &
49 
50  implicit none
51 
52  public :: &
54 
55  private
56  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
57 
60  class(sll_c_maxwell_3d_base), pointer :: maxwell_solver
61  class(sll_c_particle_mesh_coupling_3d), pointer :: particle_mesh_coupling
62  class(sll_t_particle_array), pointer :: particle_group
63 
64  sll_int32 :: spline_degree(3)
65  sll_real64 :: lx(3)
66  sll_real64 :: x_min(3)
67  sll_real64 :: x_max(3)
68  sll_int32 :: n_total0
69  sll_int32 :: n_total1
70 
71  sll_real64 :: betar(2)
72 
73  sll_real64, pointer :: phi_dofs(:)
74  sll_real64, pointer :: efield_dofs(:)
75  sll_real64, pointer :: bfield_dofs(:)
76  sll_real64, allocatable :: j_dofs(:)
77  sll_real64, allocatable :: j_dofs_local(:)
78 
79  sll_int32 :: boundary_particles = 100
80  sll_int32 :: counter_left = 0
81  sll_int32 :: counter_right = 0
82  sll_real64, pointer :: rhob(:) => null()
83 
84  sll_real64 :: force_sign = 1._f64
85  logical :: electrostatic = .false.
86  logical :: jmean = .false.
87  logical :: adiabatic_electrons = .false.
88  logical :: lindf = .false.
89  logical :: boundary = .false.
90 
91  !filtering
92  sll_real64, allocatable :: efield_filter(:)
93  sll_real64, allocatable :: bfield_filter(:)
94  class(sll_c_filter_base_3d), pointer :: filter
95 
96  sll_int32 :: n_species
97 
98  ! For control variate
99  class(sll_t_control_variates), pointer :: control_variate => null()
100  sll_int32 :: i_weight = 1
101 
102 
103  contains
104  procedure :: operatorhp1 => operatorhp1_pic_vm_3d3v_hs
105  procedure :: operatorhp2 => operatorhp2_pic_vm_3d3v_hs
106  procedure :: operatorhp3 => operatorhp3_pic_vm_3d3v_hs
107  procedure :: operatorhe => operatorhe_pic_vm_3d3v_hs
108  procedure :: operatorhb => operatorhb_pic_vm_3d3v_hs
109  procedure :: lie_splitting => lie_splitting_pic_vm_3d3v_hs
110  procedure :: lie_splitting_back => lie_splitting_back_pic_vm_3d3v_hs
111  procedure :: strang_splitting => strang_splitting_pic_vm_3d3v_hs
112 
113  procedure :: init => initialize_pic_vm_3d3v_hs
114  procedure :: free => delete_pic_vm_3d3v_hs
115 
117 
118 contains
119 
120 
122  subroutine strang_splitting_pic_vm_3d3v_hs(self,dt, number_steps)
123  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
124  sll_real64, intent(in) :: dt
125  sll_int32, intent(in) :: number_steps
126  !local variables
127  sll_int32 :: i_step
128 
129  if(self%electrostatic) then
130  do i_step = 1, number_steps
131  call self%operatorHE(0.5_f64*dt)
132  call self%operatorHp3(0.5_f64*dt)
133  call self%operatorHp2(0.5_f64*dt)
134  call self%operatorHp1(dt)
135  call self%operatorHp2(0.5_f64*dt)
136  call self%operatorHp3(0.5_f64*dt)
137  call self%operatorHE(0.5_f64*dt)
138  end do
139  else
140  do i_step = 1, number_steps
141  call self%operatorHB(0.5_f64*dt)
142  call self%operatorHE(0.5_f64*dt)
143  call self%operatorHp3(0.5_f64*dt)
144  call self%operatorHp2(0.5_f64*dt)
145  call self%operatorHp1(dt)
146  call self%operatorHp2(0.5_f64*dt)
147  call self%operatorHp3(0.5_f64*dt)
148  call self%operatorHE(0.5_f64*dt)
149  call self%operatorHB(0.5_f64*dt)
150  end do
151  end if
152 
153  end subroutine strang_splitting_pic_vm_3d3v_hs
154 
155 
157  subroutine lie_splitting_pic_vm_3d3v_hs(self,dt, number_steps)
158  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
159  sll_real64, intent(in) :: dt
160  sll_int32, intent(in) :: number_steps
161  !local variables
162  sll_int32 :: i_step
163 
164  if(self%electrostatic) then
165  do i_step = 1,number_steps
166  call self%operatorHE(dt)
167  call self%operatorHp1(dt)
168  call self%operatorHp2(dt)
169  call self%operatorHp3(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  call self%operatorHp3(dt)
178  end do
179  end if
180 
181  end subroutine lie_splitting_pic_vm_3d3v_hs
182 
183 
185  subroutine lie_splitting_back_pic_vm_3d3v_hs(self,dt, number_steps)
186  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
187  sll_real64, intent(in) :: dt
188  sll_int32, intent(in) :: number_steps
189  !local variables
190  sll_int32 :: i_step
191 
192  if(self%electrostatic) then
193  do i_step = 1,number_steps
194  call self%operatorHp3(dt)
195  call self%operatorHp2(dt)
196  call self%operatorHp1(dt)
197  call self%operatorHE(dt)
198  end do
199  else
200  do i_step = 1,number_steps
201  call self%operatorHp3(dt)
202  call self%operatorHp2(dt)
203  call self%operatorHp1(dt)
204  call self%operatorHB(dt)
205  call self%operatorHE(dt)
206  end do
207  end if
208 
209  end subroutine lie_splitting_back_pic_vm_3d3v_hs
210 
211 
212  !---------------------------------------------------------------------------!
219  subroutine operatorhp1_pic_vm_3d3v_hs(self, dt)
220  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
221  sll_real64, intent(in) :: dt
222  !local variables
223  sll_int32 :: i_part, i_sp
224  sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wall(3)
225  sll_real64 :: qoverm
226  sll_int32 :: i_weight
227  sll_real64 :: work(self%n_total1+2*self%n_total0)
228 
229  i_weight = self%i_weight
230 
231  ! Here we have to accumulate j and integrate over the time interval.
232  ! At each k=1,...,n_grid, we have for s \in [0,dt]:
233  ! j_k(s) = \sum_{i=1,..,N_p} q_i N((x_k+sv_{1,k}-x_i)/h) v_k,
234  ! where h is the grid spacing and N the normalized B-spline
235  ! In order to accumulate the integrated j, we normalize the values of x to the grid spacing, calling them y, we have
236  ! j_k(s) = \sum_{i=1,..,N_p} q_i N(y_k+s/h v_{1,k}-y_i) v_k.
237  ! Now, we want the integral
238  ! \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
239 
240 
241  self%j_dofs_local = 0.0_f64
242 
243  self%bfield_filter = self%bfield_dofs
244  call self%filter%apply_inplace(self%bfield_filter(1:self%n_total0))
245  call self%filter%apply_inplace(self%bfield_filter(self%n_total0+1:self%n_total0+self%n_total1))
246  call self%filter%apply_inplace(self%bfield_filter(self%n_total0+self%n_total1+1:self%n_total0+2*self%n_total1))
247 
248  ! 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.
249  ! Then update particle position: xnew = xold + dt * V
250  do i_sp = 1, self%n_species
251  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
252  do i_part = 1, self%particle_group%group(i_sp)%n_particles
253  ! Read out particle position and velocity
254  xold = self%particle_group%group(i_sp)%get_x(i_part)
255  vi = self%particle_group%group(i_sp)%get_v(i_part)
256 
257  ! Then update particle position: xnew = xold + dt * V
258  xnew(1) = xold(1) + dt * vi(1)
259  xnew(2:3) = xold(2:3)
260 
261  ! Get charge for accumulation of j
262  wi = self%particle_group%group(i_sp)%get_charge(i_part, i_weight)
263 
264  call compute_particle_boundary_current( self, xold, xnew, vi, wi, qoverm )
265  call self%particle_group%group(i_sp)%set_x(i_part, xnew)
266  call self%particle_group%group(i_sp)%set_v(i_part, vi)
267 
268  ! Update particle weights
269  if (self%particle_group%group(i_sp)%n_weights == 3 ) then
270  wall = self%particle_group%group(i_sp)%get_weights(i_part)
271  wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
272  call self%particle_group%group(i_sp)%set_weights( i_part, wall )
273  end if
274  end do
275  end do
276 
277  self%j_dofs = 0.0_f64
278  ! MPI to sum up contributions from each processor
279  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local, &
280  self%n_total1, mpi_sum, self%j_dofs(1:self%n_total1))
281 
282  if ( self%jmean .eqv. .true. ) then
283  self%j_dofs(1:self%n_total1) = self%j_dofs(1:self%n_total1) - sum(self%j_dofs(1:self%n_total1))/real(self%n_total1, f64)
284  end if
285 
286  call self%filter%apply_inplace(self%j_dofs)
287  ! Update the electric field.
288  if( self%adiabatic_electrons) then
289  work = 0._f64
290  work(1:self%n_total1) = self%j_dofs(1:self%n_total1)
291  call self%maxwell_solver%compute_phi_from_j( work, self%phi_dofs, self%efield_dofs )
292  else
293  call self%maxwell_solver%compute_E_from_j( self%force_sign*self%betar(2)*self%j_dofs(1:self%n_total1), self%efield_dofs(1:self%n_total1), 1)
294  end if
295 
296  end subroutine operatorhp1_pic_vm_3d3v_hs
297 
298 
300  subroutine compute_particle_boundary_current( self, xold, xnew, vi, wi, qoverm )
301  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent( inout ) :: self
302  sll_real64, intent( inout ) :: xold(3)
303  sll_real64, intent( inout ) :: xnew(3)
304  sll_real64, intent( inout ) :: vi(3)
305  sll_real64, intent( in ) :: wi(1)
306  sll_real64, intent( in ) :: qoverm
307  !local variables
308  sll_real64 :: xmid(3), xbar, dx
309 
310  if(xnew(1) < -self%x_max(1) .or. xnew(1) > 2._f64*self%x_max(1) ) then
311  print*, xnew
312  sll_error("particle boundary", "particle out of bound")
313  else if(xnew(1) < self%x_min(1) .or. xnew(1) > self%x_max(1) )then
314  if(xnew(1) < self%x_min(1) )then
315  xbar = self%x_min(1)
316  self%counter_left = self%counter_left+1
317  else if(xnew(1) > self%x_max(1))then
318  xbar = self%x_max(1)
319  self%counter_right = self%counter_right+1
320  end if
321 
322  dx = (xbar- xold(1))/(xnew(1)-xold(1))
323  xmid = xold + dx * (xnew-xold)
324  xmid(1) = xbar
325  call self%particle_mesh_coupling%add_current_update_v_component1( xold, xmid(1), wi(1), qoverm, &
326  self%bfield_filter, vi, self%j_dofs_local(1:self%n_total1))
327  select case(self%boundary_particles)
329  xnew(1) = 2._f64*xbar-xnew(1)
330  vi(1) = -vi(1)
332  call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
334  xnew(1) = self%x_min(1) + modulo(xnew(1)-self%x_min(1), self%Lx(1))
335  xmid(1) = self%x_max(1)+self%x_min(1)-xbar
336  case default
337  xnew(1) = self%x_min(1) + modulo(xnew(1)-self%x_min(1), self%Lx(1))
338  xmid(1) = self%x_max(1)+self%x_min(1)-xbar
339  end select
340  if (xnew(1) >= self%x_min(1) .and. xnew(1) <= self%x_max(1)) then
341  call self%particle_mesh_coupling%add_current_update_v_component1( xmid, xnew(1), wi(1), qoverm, &
342  self%bfield_filter, vi, self%j_dofs_local(1:self%n_total1))
343  end if
344  else
345  call self%particle_mesh_coupling%add_current_update_v_component1( xold, xnew(1), wi(1), qoverm, &
346  self%bfield_filter, vi, self%j_dofs_local(1:self%n_total1))
347  end if
348 
349  end subroutine compute_particle_boundary_current
350 
351 
352  !---------------------------------------------------------------------------!
354  subroutine operatorhp2_pic_vm_3d3v_hs(self, dt)
355  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
356  sll_real64, intent(in) :: dt
357  !local variables
358  sll_int32 :: i_part, i_sp
359  sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wall(3)
360  sll_real64 :: qoverm
361  sll_int32 :: i_weight
362  sll_real64 :: work(self%n_total1+2*self%n_total0)
363 
364  i_weight = self%i_weight
365 
366  self%j_dofs_local = 0.0_f64
367 
368  self%bfield_filter = self%bfield_dofs
369  call self%filter%apply_inplace(self%bfield_filter(1:self%n_total0))
370  call self%filter%apply_inplace(self%bfield_filter(self%n_total0+1:self%n_total0+self%n_total1))
371  call self%filter%apply_inplace(self%bfield_filter(self%n_total0+self%n_total1+1:self%n_total0+2*self%n_total1))
372 
373  ! 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.
374  ! Then update particle position: xnew = xold + dt * V
375  do i_sp = 1, self%n_species
376  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
377  do i_part = 1, self%particle_group%group(i_sp)%n_particles
378  ! Read out particle position and velocity
379  xold = self%particle_group%group(i_sp)%get_x(i_part)
380  vi = self%particle_group%group(i_sp)%get_v(i_part)
381 
382  ! Then update particle position: xnew = xold + dt * V
383  xnew(2) = xold(2) + dt * vi(2)
384  xnew(1) = xold(1)
385  xnew(3) = xold(3)
386 
387  ! Get charge for accumulation of j
388  wi = self%particle_group%group(i_sp)%get_charge(i_part, i_weight)
389 
390  call self%particle_mesh_coupling%add_current_update_v_component2( xold, xnew(2), wi(1), qoverm, &
391  self%bfield_filter, vi, self%j_dofs_local)
392 
393  xnew(2) = self%x_min(2) + modulo(xnew(2)-self%x_min(2), self%Lx(2))
394  call self%particle_group%group(i_sp)%set_x(i_part, xnew)
395  call self%particle_group%group(i_sp)%set_v(i_part, vi)
396 
397  ! Update particle weights
398  if (self%particle_group%group(i_sp)%n_weights == 3 ) then
399  wall = self%particle_group%group(i_sp)%get_weights(i_part)
400  wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
401  call self%particle_group%group(i_sp)%set_weights( i_part, wall )
402  end if
403  end do
404  end do
405 
406  self%j_dofs = 0.0_f64
407  ! MPI to sum up contributions from each processor
408  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local, &
409  self%n_total0, mpi_sum, self%j_dofs)
410  if ( self%jmean .eqv. .true. ) then
411  self%j_dofs = self%j_dofs - sum(self%j_dofs)/real(self%n_total0, f64)
412  end if
413 
414  call self%filter%apply_inplace(self%j_dofs)
415 
416  ! Update the electric field.
417  if( self%adiabatic_electrons) then
418  work = 0._f64
419  work(self%n_total1+1:self%n_total0+self%n_total1) = self%j_dofs
420  call self%maxwell_solver%compute_phi_from_j( work, self%phi_dofs, self%efield_dofs )
421  else
422  call self%maxwell_solver%compute_E_from_j(self%force_sign*self%betar(2)*self%j_dofs, self%efield_dofs(self%n_total1+1:self%n_total1+self%n_total0), 2)
423  end if
424 
425  end subroutine operatorhp2_pic_vm_3d3v_hs
426 
427 
428  !---------------------------------------------------------------------------!
430  subroutine operatorhp3_pic_vm_3d3v_hs(self, dt)
431  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
432  sll_real64, intent(in) :: dt
433  !local variables
434  sll_int32 :: i_part, i_sp
435  sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wall(3)
436  sll_real64 :: qoverm
437  sll_int32 :: i_weight
438  sll_real64 :: work(self%n_total1+2*self%n_total0)
439 
440  i_weight = self%i_weight
441 
442 
443  self%j_dofs_local = 0.0_f64
444 
445  self%bfield_filter = self%bfield_dofs
446  call self%filter%apply_inplace(self%bfield_filter(1:self%n_total0))
447  call self%filter%apply_inplace(self%bfield_filter(self%n_total0+1:self%n_total0+self%n_total1))
448  call self%filter%apply_inplace(self%bfield_filter(self%n_total0+self%n_total1+1:self%n_total0+2*self%n_total1))
449 
450  ! 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.
451  ! Then update particle position: xnew = xold + dt * V
452  do i_sp = 1, self%n_species
453  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
454  do i_part = 1, self%particle_group%group(i_sp)%n_particles
455  ! Read out particle position and velocity
456  xold = self%particle_group%group(i_sp)%get_x(i_part)
457  vi = self%particle_group%group(i_sp)%get_v(i_part)
458 
459  ! Then update particle position: xnew = xold + dt * V
460  xnew(3) = xold(3) + dt * vi(3)
461  xnew(1:2) = xold(1:2)
462 
463  ! Get charge for accumulation of j
464  wi = self%particle_group%group(i_sp)%get_charge(i_part, i_weight)
465 
466  call self%particle_mesh_coupling%add_current_update_v_component3( xold, xnew(3), wi(1), qoverm, &
467  self%bfield_filter, vi, self%j_dofs_local)
468 
469  xnew(3) = self%x_min(3) + modulo(xnew(3)-self%x_min(3), self%Lx(3))
470  call self%particle_group%group(i_sp)%set_x(i_part, xnew)
471  call self%particle_group%group(i_sp)%set_v(i_part, vi)
472 
473  ! Update particle weights
474  if (self%particle_group%group(i_sp)%n_weights == 3 ) then
475  wall = self%particle_group%group(i_sp)%get_weights(i_part)
476  wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
477  call self%particle_group%group(i_sp)%set_weights( i_part, wall )
478  end if
479  end do
480  end do
481 
482  self%j_dofs = 0.0_f64
483  ! MPI to sum up contributions from each processor
484  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local, &
485  self%n_total0, mpi_sum, self%j_dofs)
486  if ( self%jmean .eqv. .true. ) then
487  self%j_dofs = self%j_dofs - sum(self%j_dofs)/real(self%n_total0, f64)
488  end if
489 
490  call self%filter%apply_inplace(self%j_dofs)
491  ! Update the electric field.
492  if( self%adiabatic_electrons) then
493  work = 0._f64
494  work(self%n_total1+self%n_total0+1:self%n_total1+2*self%n_total0) = self%j_dofs
495  call self%maxwell_solver%compute_phi_from_j( work, self%phi_dofs, self%efield_dofs )
496  else
497  call self%maxwell_solver%compute_E_from_j(self%force_sign*self%betar(2)*self%j_dofs, self%efield_dofs(self%n_total0+self%n_total1+1:self%n_total1+2*self%n_total0), 3)
498  end if
499 
500  end subroutine operatorhp3_pic_vm_3d3v_hs
501 
502 
503  !---------------------------------------------------------------------------!
507  subroutine operatorhe_pic_vm_3d3v_hs(self, dt)
508  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
509  sll_real64, intent(in) :: dt
510  !local variables
511  sll_int32 :: i_part, i_sp
512  sll_real64 :: v_new(3), xi(3), rx(3), wall(self%i_weight)
513  sll_real64 :: efield(3)
514  sll_real64 :: qoverm, q, m
515  sll_int32 :: i_weight
516 
517  i_weight = self%i_weight
518 
519  self%efield_filter = self%efield_dofs
520  call self%filter%apply_inplace(self%efield_filter(1:self%n_total1))
521  call self%filter%apply_inplace(self%efield_filter(1+self%n_total1:self%n_total1+self%n_total0))
522  call self%filter%apply_inplace(self%efield_filter(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0))
523 
524  do i_sp = 1, self%n_species
525  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
526  q = self%particle_group%group(i_sp)%species%q
527  m = self%particle_group%group(i_sp)%species%m
528  ! V_new = V_old + dt * E
529  do i_part=1,self%particle_group%group(i_sp)%n_particles
530  v_new = self%particle_group%group(i_sp)%get_v(i_part)
531  ! Evaluate efields at particle position
532  xi = self%particle_group%group(i_sp)%get_x(i_part)
533  call self%particle_mesh_coupling%evaluate &
534  (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
535  self%efield_filter(1:self%n_total1), efield(1))
536  call self%particle_mesh_coupling%evaluate &
537  (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
538  self%efield_filter(1+self%n_total1:self%n_total1+self%n_total0), efield(2))
539  call self%particle_mesh_coupling%evaluate &
540  (xi, [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
541  self%efield_filter(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0), efield(3))
542  if( self%lindf .eqv. .false.) then
543  v_new = v_new + dt* qoverm * efield
544  call self%particle_group%group(i_sp)%set_v(i_part, v_new)
545 
546  if (self%particle_group%group(i_sp)%n_weights == 3 ) then
547  wall = self%particle_group%group(i_sp)%get_weights(i_part)
548  wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, v_new, 0.0_f64, wall(1), wall(2) )
549  call self%particle_group%group(i_sp)%set_weights( i_part, wall )
550  end if
551  else
552  ! Update particle weights
553  if (self%particle_group%group(i_sp)%n_weights == 3 ) then
554  wall = self%particle_group%group(i_sp)%get_weights(i_part)
555  select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
557  rx = xi
558  rx(1) = rx(1) + m*v_new(2)/q
559  rx = (rx-self%x_min)/self%Lx
560 
561  wall(1) = wall(1) + dt* (q/p%profile%T_i(rx(1)) * sum(efield * v_new)-&
562  efield(2)*(p%profile%drho_0(rx(1))/p%profile%rho_0(rx(1))+(0.5_f64*m*sum(v_new**2)/p%profile%T_i(rx(1)) - 1.5_f64)* p%profile%dT_i(rx(1))/p%profile%T_i(rx(1)) ) ) *&
563  self%control_variate%cv(i_sp)%control_variate(rx, v_new, 0._f64)/p%eval_v_density(v_new, xi, m)*product(self%Lx)
564  class default
565  wall(1) = wall(1) + dt* qoverm* sum(efield * v_new) *product(self%Lx)
566  end select
567  call self%particle_group%group(i_sp)%set_weights( i_part, wall )
568  else
569  v_new = v_new + dt* qoverm * efield
570  call self%particle_group%group(i_sp)%set_v(i_part, v_new)
571  end if
572  end if
573  end do
574  end do
575 
576  if(self%electrostatic .eqv. .false.) then
577  ! Update bfield
578  call self%maxwell_solver%compute_B_from_E( &
579  dt, self%efield_dofs, self%bfield_dofs)
580  end if
581 
582  end subroutine operatorhe_pic_vm_3d3v_hs
583 
584 
585  !---------------------------------------------------------------------------!
588  subroutine operatorhb_pic_vm_3d3v_hs(self, dt)
589  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(inout) :: self
590  sll_real64, intent(in) :: dt
591 
592  ! Update efield2
593  call self%maxwell_solver%compute_E_from_B(&
594  dt*self%betar(1), self%bfield_dofs, self%efield_dofs)
595 
596  end subroutine operatorhb_pic_vm_3d3v_hs
597 
598 
599  !---------------------------------------------------------------------------!
602  self, &
603  maxwell_solver, &
604  particle_mesh_coupling, &
605  particle_group, &
606  phi_dofs, &
607  efield_dofs, &
608  bfield_dofs, &
609  x_min, &
610  Lx, &
611  filter, &
612  boundary_particles, &
613  betar, &
614  force_sign, &
615  electrostatic, &
616  rhob, &
617  control_variate, &
618  jmean)
619  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent(out) :: self
620  class(sll_c_maxwell_3d_base), target, intent(in) :: maxwell_solver
621  class(sll_c_particle_mesh_coupling_3d), target, intent(in) :: particle_mesh_coupling
622  class(sll_t_particle_array), target, intent(in) :: particle_group
623  sll_real64, target, intent( in ) :: phi_dofs(:)
624  sll_real64, target, intent(in) :: efield_dofs(:)
625  sll_real64, target, intent(in) :: bfield_dofs(:)
626  sll_real64, intent(in) :: x_min(3)
627  sll_real64, intent(in) :: lx(3)
628  class(sll_c_filter_base_3d), target :: filter
629  sll_int32, optional, intent( in ) :: boundary_particles
630 
631  sll_real64, optional, intent(in) :: betar(2)
632  sll_real64, optional, intent(in) :: force_sign
633  logical, optional, intent(in) :: electrostatic
634  sll_real64, optional, target, intent( in ) :: rhob(:)
635  class(sll_t_control_variates), optional, target, intent(in) :: control_variate
636  logical, optional, intent(in) :: jmean
637  !local variables
638  sll_int32 :: ierr
639 
640  if( present(electrostatic) )then
641  self%electrostatic = electrostatic
642  end if
643 
644  if( present(force_sign) )then
645  self%force_sign = force_sign
646  end if
647 
648  if (self%force_sign == 1._f64) then
649  if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
650  end if
651 
652  if (present(boundary_particles) ) then
653  self%boundary_particles = boundary_particles
654  end if
655 
656  if( present(rhob) )then
657  self%rhob => rhob
658  end if
659 
660 
661  self%maxwell_solver => maxwell_solver
662  self%particle_mesh_coupling => particle_mesh_coupling
663  self%particle_group => particle_group
664  self%phi_dofs => phi_dofs
665  self%efield_dofs => efield_dofs
666  self%bfield_dofs => bfield_dofs
667 
668  self%n_total0 = self%maxwell_solver%n_total0
669  self%n_total1 = self%maxwell_solver%n_total1
670 
671  sll_allocate(self%j_dofs(self%n_total0), ierr)
672  sll_allocate(self%j_dofs_local(self%n_total0), ierr)
673 
674  self%spline_degree = self%particle_mesh_coupling%spline_degree
675  self%x_min = x_min
676  self%x_max = x_min + lx
677  self%Lx = lx
678 
679  if( self%particle_mesh_coupling%n_cells(1)+self%spline_degree(1) == self%maxwell_solver%n_dofs(1) ) then
680  self%boundary = .true.
681  end if
682 
683  self%n_species = particle_group%n_species
684 
685  self%filter => filter
686 
687  if (present(control_variate)) then
688  allocate(self%control_variate )
689  allocate(self%control_variate%cv(self%n_species) )
690  self%control_variate => control_variate
691  if(self%particle_group%group(1)%n_weights == 1 ) self%lindf = .true.
692  self%i_weight = self%particle_group%group(1)%n_weights
693  end if
694 
695  if (present(betar)) then
696  self%betar = betar
697  else
698  self%betar = 1.0_f64
699  end if
700 
701  end subroutine initialize_pic_vm_3d3v_hs
702 
703 
704  !---------------------------------------------------------------------------!
706  subroutine delete_pic_vm_3d3v_hs(self)
707  class(sll_t_time_propagator_pic_vm_3d3v_hs), intent( inout ) :: self
708 
709  deallocate(self%j_dofs)
710  deallocate(self%j_dofs_local)
711  self%maxwell_solver => null()
712  self%particle_mesh_coupling => null()
713  self%particle_group => null()
714  self%phi_dofs => null()
715  self%efield_dofs => null()
716  self%bfield_dofs => null()
717 
718  end subroutine delete_pic_vm_3d3v_hs
719 
720 
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.
Parameters to define common initial distributions.
Module interface to solve Maxwell's equations in 3D.
Base class for kernel smoothers for accumulation and field evaluation in PIC.
functions for initial profile of the particle distribution function
Base class for Hamiltonian splittings.
Particle pusher based on antisymmetric splitting with AVF for 3d3v Vlasov-Maxwell with coordinate tra...
Particle pusher based on Hamiltonian splitting for 3d3v Vlasov-Maxwell.
subroutine lie_splitting_back_pic_vm_3d3v_hs(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine operatorhb_pic_vm_3d3v_hs(self, dt)
Push H_B: Equations to be solved $M_1 e^{n+1}=M_1 e^n+\Delta t C^\top M_2 b^n$.
subroutine strang_splitting_pic_vm_3d3v_hs(self, dt, number_steps)
Finalization.
subroutine operatorhp2_pic_vm_3d3v_hs(self, dt)
Push Hp2: Equations to solve are.
subroutine operatorhp3_pic_vm_3d3v_hs(self, dt)
Push Hp3: Equations to solve are.
subroutine initialize_pic_vm_3d3v_hs(self, maxwell_solver, particle_mesh_coupling, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, filter, boundary_particles, betar, force_sign, electrostatic, rhob, control_variate, jmean)
Constructor.
subroutine operatorhp1_pic_vm_3d3v_hs(self, dt)
Push Hp1: Equations to solve are \partial_t f + v_1 \partial_{x_1} f = 0 -> xnew = xold + dt V_1 V_ne...
subroutine lie_splitting_pic_vm_3d3v_hs(self, dt, number_steps)
Lie splitting.
subroutine compute_particle_boundary_current(self, xold, xnew, vi, wi, qoverm)
Helper function for operatorHp1.
subroutine operatorhe_pic_vm_3d3v_hs(self, dt)
Push H_E: Equations to be solved $V^{n+1}=V^n+\Delta t\mathbb{W}_{\frac{q}{m}} \mathbb{Lambda}^1(X^n)...
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
    Report Typos and Errors