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_cef.F90
Go to the documentation of this file.
1 
7  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
8 #include "sll_assert.h"
9 #include "sll_memory.h"
10 #include "sll_working_precision.h"
11 
12  use sll_m_collective, only: &
15 
16  use sll_m_time_propagator_base, only: &
18 
21 
22  use sll_m_maxwell_1d_base, only: &
24 
25  use sll_m_particle_group_base, only: &
27 
28  use mpi, only: &
29  mpi_sum
30 
36 
37  implicit none
38 
39  public :: &
41 
42  private
43  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
44 
47  class(sll_c_maxwell_1d_base), pointer :: maxwell_solver
48  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_0
49  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_1
50  class(sll_t_particle_array), pointer :: particle_group
51 
52  sll_int32 :: spline_degree
53  sll_real64 :: lx
54  sll_real64 :: x_min
55  sll_real64 :: x_max
56  sll_real64 :: delta_x
57  sll_int32 :: n_cells
58  sll_int32 :: n_total0
59  sll_int32 :: n_total1
60 
61  sll_int32 :: boundary_particles = 0
62  sll_int32 :: counter_left = 0
63  sll_int32 :: counter_right = 0
64  logical :: boundary = .false.
65  sll_real64, pointer :: rhob(:) => null()
66 
67  logical :: electrostatic = .false.
68 
69  sll_real64, pointer :: efield_dofs(:,:)
70  sll_real64, pointer :: bfield_dofs(:)
71  sll_real64, allocatable :: j_dofs(:,:)
72  sll_real64, allocatable :: j_dofs_local(:,:)
73 
74  contains
75  procedure :: operatorhp => operatorhp_pic_vm_1d2v
76  procedure :: operatorhe => operatorhe_pic_vm_1d2v
77  procedure :: operatorhb => operatorhb_pic_vm_1d2v
78  procedure :: lie_splitting => lie_splitting_pic_vm_1d2v
79  procedure :: lie_splitting_back => lie_splitting_back_pic_vm_1d2v
80  procedure :: strang_splitting => strang_splitting_pic_vm_1d2v
81 
82  procedure :: init => initialize_pic_vm_1d2v
83  procedure :: free => delete_pic_vm_1d2v
84 
86 
87 contains
88 
89 
91  subroutine strang_splitting_pic_vm_1d2v(self,dt, number_steps)
92  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(inout) :: self
93  sll_real64, intent(in) :: dt
94  sll_int32, intent(in) :: number_steps
95 
96  sll_int32 :: i_step
97 
98  do i_step = 1, number_steps
99  call self%operatorHB(0.5_f64*dt)
100  call self%operatorHE(0.5_f64*dt)
101  call self%operatorHp(dt)
102  call self%operatorHE(0.5_f64*dt)
103  call self%operatorHB(0.5_f64*dt)
104 
105  end do
106 
107  end subroutine strang_splitting_pic_vm_1d2v
108 
109 
111  subroutine lie_splitting_pic_vm_1d2v(self,dt, number_steps)
112  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(inout) :: self
113  sll_real64, intent(in) :: dt
114  sll_int32, intent(in) :: number_steps
115 
116  sll_int32 :: i_step
117 
118  do i_step = 1,number_steps
119  call self%operatorHE(dt)
120  call self%operatorHB(dt)
121  call self%operatorHp(dt)
122  end do
123 
124  end subroutine lie_splitting_pic_vm_1d2v
125 
126 
128  subroutine lie_splitting_back_pic_vm_1d2v(self,dt, number_steps)
129  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(inout) :: self
130  sll_real64, intent(in) :: dt
131  sll_int32, intent(in) :: number_steps
132 
133  sll_int32 :: i_step
134 
135  do i_step = 1,number_steps
136  call self%operatorHp(dt)
137  call self%operatorHB(dt)
138  call self%operatorHE(dt)
139  end do
140 
141  end subroutine lie_splitting_back_pic_vm_1d2v
142 
143 
144  !---------------------------------------------------------------------------!
151  subroutine operatorhp_pic_vm_1d2v(self, dt)
152  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(inout) :: self
153  sll_real64, intent(in) :: dt
154  !local variables
155  sll_int32 :: i_part, i_sp
156  sll_real64 :: xnew(3), vi(3), wi(1), xi(3)
157 
158  self%j_dofs_local = 0.0_f64
159  do i_sp = 1, self%particle_group%n_species
160  do i_part=1,self%particle_group%group(i_sp)%n_particles
161  ! Read out particle position and velocity
162  xi = self%particle_group%group(i_sp)%get_x(i_part)
163  vi = self%particle_group%group(i_sp)%get_v(i_part)
164 
165  ! Then update particle position: xnew = xold + dt * V
166  xnew = xi + dt * vi
167 
168  ! Get charge for accumulation of j
169  wi = self%particle_group%group(i_sp)%get_charge(i_part)
170  call compute_particle_boundary_current( self, xi(1), xnew(1), vi(1:2), wi, dt )
171 
172  call self%particle_group%group(i_sp)%set_x(i_part, xnew)
173  end do
174 
175  end do
176  self%j_dofs = 0.0_f64
177  ! MPI to sum up contributions from each processor
178  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,1), &
179  self%n_total1, mpi_sum, self%j_dofs(1:self%n_total1,1))
180  ! Update the electric field.
181  call self%maxwell_solver%compute_E_from_j(self%j_dofs(1:self%n_total1,1), 1, self%efield_dofs(1:self%n_total1,1))
182 
183  ! MPI to sum up contributions from each processor
184  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,2), &
185  self%n_total0, mpi_sum, self%j_dofs(:,2))
186  ! Update the electric field.
187  call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs(:,2))
188 
189  end subroutine operatorhp_pic_vm_1d2v
190 
191 
193  subroutine compute_particle_boundary_current( self, xold, xnew, vi, wi, dt )
194  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent( inout ) :: self
195  sll_real64, intent( in ) :: xold(1)
196  sll_real64, intent( inout ) :: xnew(1)
197  sll_real64, intent( inout ) :: vi(2)
198  sll_real64, intent( in ) :: wi(1)
199  sll_real64, intent( in ) :: dt
200  !local variable
201  sll_real64 :: xmid(1), vh, xbar
202 
203  if(xnew(1) < self%x_min .or. xnew(1) > self%x_max )then
204  if(xnew(1) < self%x_min )then
205  xbar = self%x_min
206  self%counter_left = self%counter_left+1
207  else if(xnew(1) > self%x_max)then
208  xbar = self%x_max
209  self%counter_right = self%counter_right+1
210  end if
211 
212  xmid = xbar
213  vh = vi(2)/vi(1)
214 
215  call self%kernel_smoother_1%add_current( xold, xmid, wi(1), self%j_dofs_local(1:self%n_total1,1))
216  call self%kernel_smoother_0%add_current( xold, xmid, wi(1)*vh, self%j_dofs_local(:,2))
217 
218  select case(self%boundary_particles)
220  xnew = 2._f64*xbar-xnew
221  vi(1) = -vi(1)
223  call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
225  call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
226  xnew = self%x_min + modulo(xnew-self%x_min, self%Lx)
227  xmid = self%x_max+self%x_min-xbar
228  call self%kernel_smoother_0%add_charge(xmid, -wi(1), self%rhob)
229  case default
230  call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
231  xnew = self%x_min + modulo(xnew-self%x_min, self%Lx)
232  xmid = self%x_max+self%x_min-xbar
233  call self%kernel_smoother_0%add_charge(xmid, -wi(1), self%rhob)
234  end select
235  if (xnew(1) >= self%x_min .and. xnew(1) <= self%x_max) then
236  vh = vi(2)/vi(1)
237  call self%kernel_smoother_1%add_current( xmid, xnew, wi(1), self%j_dofs_local(1:self%n_total1,1))
238  call self%kernel_smoother_0%add_current( xmid, xnew, wi(1)*vh, self%j_dofs_local(:,2))
239  end if
240  else
241  if ( abs(vi(1))> 1d-16 ) then
242  ! Scale vi by weight to combine both factors for accumulation of integral over j
243  call self%kernel_smoother_1%add_current( xold, xnew, wi(1), self%j_dofs_local(1:self%n_total1,1))
244  call self%kernel_smoother_0%add_current( xold, xnew, wi(1)*vi(2)/vi(1), self%j_dofs_local(:,2))
245  end if
246  end if
247 
248  end subroutine compute_particle_boundary_current
249 
250 
251 
252  !---------------------------------------------------------------------------!
258  subroutine operatorhe_pic_vm_1d2v(self, dt)
259  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(inout) :: self
260  sll_real64, intent(in) :: dt
261  !local variables
262  sll_int32 :: i_part, i_sp
263  sll_real64 :: vi(3), xi(3)
264  sll_real64 :: efield(2)
265  sll_real64 :: qm
266 
267  do i_sp = 1, self%particle_group%n_species
268  qm = self%particle_group%group(i_sp)%species%q_over_m();
269  do i_part=1,self%particle_group%group(i_sp)%n_particles
270  vi = self%particle_group%group(i_sp)%get_v(i_part)
271  ! Evaluate efields at particle position
272  xi = self%particle_group%group(i_sp)%get_x(i_part)
273  call self%kernel_smoother_1%evaluate &
274  (xi(1), self%efield_dofs(1:self%n_total1,1), efield(1))
275  call self%kernel_smoother_0%evaluate &
276  (xi(1), self%efield_dofs(:,2), efield(2))
277  vi = self%particle_group%group(i_sp)%get_v(i_part)
278  ! V_new = V_old + dt * E
279  vi(1:2) = vi(1:2) + dt* qm * efield
280 
281  call self%particle_group%group(i_sp)%set_v(i_part, vi)
282  end do
283  end do
284 
285  if(self%electrostatic .eqv. .false.) then
286  ! Update bfield
287  call self%maxwell_solver%compute_B_from_E( &
288  dt, self%efield_dofs(:,2), self%bfield_dofs)
289  end if
290 
291  end subroutine operatorhe_pic_vm_1d2v
292 
293 
294  !---------------------------------------------------------------------------!
300  subroutine operatorhb_pic_vm_1d2v(self, dt)
301  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(inout) :: self
302  sll_real64, intent(in) :: dt
303  !local variables
304  sll_int32 :: i_part, i_sp
305  sll_real64 :: qmdt
306  sll_real64 :: vi(3), v_new(3), xi(3)
307  sll_real64 :: bfield, cs, sn
308 
309  ! VxB part
310  do i_sp = 1, self%particle_group%n_species
311  qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt;
312  do i_part = 1, self%particle_group%group(i_sp)%n_particles
313  vi = self%particle_group%group(i_sp)%get_v(i_part)
314  xi = self%particle_group%group(i_sp)%get_x(i_part)
315  call self%kernel_smoother_1%evaluate &
316  (xi(1), self%bfield_dofs, bfield)
317 
318  bfield = qmdt*bfield
319 
320  cs = cos(bfield)
321  sn = sin(bfield)
322 
323  v_new(1) = cs * vi(1) + sn * vi(2)
324  v_new(2) = -sn* vi(1) + cs * vi(2)
325 
326  call self%particle_group%group(i_sp)%set_v( i_part, v_new )
327  end do
328  end do
329 
330  if(self%electrostatic .eqv. .false.) then
331  ! Update efield2
332  call self%maxwell_solver%compute_E_from_B(&
333  dt, self%bfield_dofs, self%efield_dofs(:,2))
334  end if
335 
336  end subroutine operatorhb_pic_vm_1d2v
337 
338 
339  !---------------------------------------------------------------------------!
342  self, &
343  maxwell_solver, &
344  kernel_smoother_0, &
345  kernel_smoother_1, &
346  particle_group, &
347  efield_dofs, &
348  bfield_dofs, &
349  x_min, &
350  Lx, &
351  boundary_particles, &
352  electrostatic, &
353  rhob)
354  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent(out) :: self
355  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
356  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
357  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
358  class(sll_t_particle_array), target, intent(in) :: particle_group
359  sll_real64, target, intent(in) :: efield_dofs(:,:)
360  sll_real64, target, intent(in) :: bfield_dofs(:)
361  sll_real64, intent(in) :: x_min
362  sll_real64, intent(in) :: lx
363  sll_int32, optional, intent( in ) :: boundary_particles
364  logical, optional, intent( in ) :: electrostatic
365  sll_real64, optional, target, intent( in ) :: rhob(:)
366  !local variables
367  sll_int32 :: ierr
368 
369  self%maxwell_solver => maxwell_solver
370  self%kernel_smoother_0 => kernel_smoother_0
371  self%kernel_smoother_1 => kernel_smoother_1
372  self%particle_group => particle_group
373  self%efield_dofs => efield_dofs
374  self%bfield_dofs => bfield_dofs
375 
376  self%spline_degree = self%kernel_smoother_0%spline_degree
377  self%x_min = x_min
378  self%x_max = x_min + lx
379  self%Lx = lx
380  self%delta_x = self%Lx/real(self%maxwell_solver%n_cells, f64)
381 
382  self%n_cells = self%maxwell_solver%n_cells
383  self%n_total0 = self%maxwell_solver%n_dofs0
384  self%n_total1 = self%maxwell_solver%n_dofs1
385 
386  ! Check that n_dofs is the same for both kernel smoothers.
387  sll_assert( self%kernel_smoother_0%n_cells == self%kernel_smoother_1%n_cells )
388  sll_assert( self%kernel_smoother_0%n_cells == self%maxwell_solver%n_cells )
389 
390  sll_allocate(self%j_dofs(self%n_total0, 2), ierr)
391  sll_allocate(self%j_dofs_local(self%n_total0, 2), ierr)
392 
393  if( self%n_cells+self%spline_degree == self%maxwell_solver%n_dofs0 ) then
394  self%boundary = .true.
395  self%boundary_particles = boundary_particles
396  end if
397 
398  if( present(electrostatic) )then
399  self%electrostatic = electrostatic
400  end if
401 
402  if( present(rhob) )then
403  self%rhob => rhob
404  end if
405 
406  end subroutine initialize_pic_vm_1d2v
407 
408  !---------------------------------------------------------------------------!
410  subroutine delete_pic_vm_1d2v(self)
411  class(sll_t_time_propagator_pic_vm_1d2v_cef), intent( inout ) :: self
412 
413  if( self%boundary ) then
414  print*, 'left boundary', self%counter_left
415  print*, 'right boundary', self%counter_right
416  end if
417 
418  deallocate(self%j_dofs)
419  deallocate(self%j_dofs_local)
420  self%maxwell_solver => null()
421  self%kernel_smoother_0 => null()
422  self%kernel_smoother_1 => null()
423  self%particle_group => null()
424  self%efield_dofs => null()
425  self%bfield_dofs => null()
426 
427  end subroutine delete_pic_vm_1d2v
428 
429 
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 proposed by Crouseilles, Einkemmer,...
subroutine operatorhp_pic_vm_1d2v(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 compute_particle_boundary_current(self, xold, xnew, vi, wi, dt)
Helper function for operatorHp.
subroutine lie_splitting_back_pic_vm_1d2v(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine strang_splitting_pic_vm_1d2v(self, dt, number_steps)
Finalization.
subroutine operatorhb_pic_vm_1d2v(self, dt)
Push H_B: Equations to be solved V_new = V_old \partial_t E_1 = 0 -> E_{1,new} = E_{1,...
subroutine operatorhe_pic_vm_1d2v(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 initialize_pic_vm_1d2v(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, efield_dofs, bfield_dofs, x_min, Lx, boundary_particles, electrostatic, rhob)
Constructor.
subroutine lie_splitting_pic_vm_1d2v(self, dt, number_steps)
Lie splitting.
Particle pusher based on antisymmetric splitting with AVF for 3d3v Vlasov-Maxwell with coordinate tra...
    Report Typos and Errors