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_trafo.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 
31  use sll_m_mapping_3d, only: &
33 
34  implicit none
35 
36  public :: &
38 
39  private
40  !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
41 
44  class(sll_c_maxwell_1d_base), pointer :: maxwell_solver
45  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_0
46  class(sll_c_particle_mesh_coupling_1d), pointer :: kernel_smoother_1
47  class(sll_t_particle_array), pointer :: particle_group
48 
49  type( sll_t_mapping_3d ), pointer :: map
50 
51  sll_int32 :: spline_degree
52  sll_real64 :: lx
53  sll_real64 :: x_min
54  sll_real64 :: delta_x
55 
56  sll_real64, pointer :: efield_dofs(:,:)
57  sll_real64, pointer :: bfield_dofs(:)
58  sll_real64, allocatable :: j_dofs(:,:)
59  sll_real64, allocatable :: j_dofs_local(:,:)
60 
61  logical :: electrostatic = .false.
62 
63  sll_int32 :: max_iter = 1
64  sll_real64 :: iter_tolerance = 1d-10
65 
66  contains
67  procedure :: operatorhp => operatorhp_pic_vm_1d2v
68  procedure :: operatorhe => operatorhe_pic_vm_1d2v
69  procedure :: operatorhb => operatorhb_pic_vm_1d2v
70  procedure :: lie_splitting => lie_splitting_pic_vm_1d2v
71  procedure :: lie_splitting_back => lie_splitting_back_pic_vm_1d2v
72  procedure :: strang_splitting => strang_splitting_pic_vm_1d2v
73 
74  procedure :: init => initialize_pic_vm_1d2v
75  procedure :: free => delete_pic_vm_1d2v
76 
78 
79 contains
80 
81 
83  subroutine strang_splitting_pic_vm_1d2v(self,dt, number_steps)
84  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(inout) :: self
85  sll_real64, intent(in) :: dt
86  sll_int32, intent(in) :: number_steps
87 
88  sll_int32 :: i_step
89 
90  if(self%electrostatic) then
91  do i_step = 1, number_steps
92  call self%operatorHE(0.5_f64*dt)
93  call self%operatorHp(dt)
94  call self%operatorHE(0.5_f64*dt)
95  end do
96  else
97  do i_step = 1, number_steps
98  call self%operatorHB(0.5_f64*dt)
99  call self%operatorHE(0.5_f64*dt)
100  call self%operatorHp(dt)
101  call self%operatorHE(0.5_f64*dt)
102  call self%operatorHB(0.5_f64*dt)
103  end do
104  end if
105 
106  end subroutine strang_splitting_pic_vm_1d2v
107 
108 
110  subroutine lie_splitting_pic_vm_1d2v(self,dt, number_steps)
111  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(inout) :: self
112  sll_real64, intent(in) :: dt
113  sll_int32, intent(in) :: number_steps
114 
115  sll_int32 :: i_step
116 
117  if(self%electrostatic) then
118  do i_step = 1, number_steps
119  call self%operatorHE(dt)
120  call self%operatorHp(dt)
121  end do
122  else
123  do i_step = 1,number_steps
124  call self%operatorHE(dt)
125  call self%operatorHB(dt)
126  call self%operatorHp(dt)
127  end do
128  end if
129 
130 
131  end subroutine lie_splitting_pic_vm_1d2v
132 
133 
135  subroutine lie_splitting_back_pic_vm_1d2v(self,dt, number_steps)
136  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(inout) :: self
137  sll_real64, intent(in) :: dt
138  sll_int32, intent(in) :: number_steps
139 
140  sll_int32 :: i_step
141 
142  if(self%electrostatic) then
143  do i_step = 1, number_steps
144  call self%operatorHp(dt)
145  call self%operatorHE(dt)
146  end do
147  else
148  do i_step = 1,number_steps
149  call self%operatorHp(dt)
150  call self%operatorHB(dt)
151  call self%operatorHE(dt)
152  end do
153  end if
154 
155  end subroutine lie_splitting_back_pic_vm_1d2v
156 
157 
158  !---------------------------------------------------------------------------!
165  subroutine operatorhp_pic_vm_1d2v(self, dt)
166  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(inout) :: self
167  sll_real64, intent(in) :: dt
168  !local variables
169  sll_int32 :: i_part, i_sp, i
170  sll_real64 :: x_new(3), v_new(3), vi(3), wi(1), xi(3), xbar(3), vbar(3)
171  sll_int32 :: n_cells
172  sll_real64 :: jmatrix(3,3)
173  sll_real64 :: qmdt, err
174  sll_real64 :: bfield, rhs(2)
175 
176 
177  n_cells = self%kernel_smoother_0%n_dofs
178 
179 
180  self%j_dofs_local = 0.0_f64
181 
182  do i_sp = 1, self%particle_group%n_species
183  qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt;
184  do i_part=1,self%particle_group%group(i_sp)%n_particles
185  ! Read out particle position and velocity
186  xi = self%particle_group%group(i_sp)%get_x(i_part)
187  vi = self%particle_group%group(i_sp)%get_v(i_part)
188 
189  !Predictor-Corrector with loop for corrector step
190  jmatrix=self%map%jacobian_matrix_inverse([xi(1), 0._f64, 0._f64])
191  !Transformation of the v coordinates, !VT = DF^{-1} * vi
192  !x^\star=\mod(x^n+dt*DF^{-1}(x^n)v^n,1)
193  x_new(1) = xi(1) + dt * jmatrix(1,1)*vi(1)
194 
195  call self%kernel_smoother_1%evaluate &
196  (xi(1), self%bfield_dofs, bfield)
197 
198  !rhs = vi + sign * DF^{-T} * bfield x DF^{-1} V
199  v_new(1) = vi(1) + qmdt*jmatrix(1,1)*bfield*vi(2)
200  v_new(2) = vi(2) - qmdt*bfield*jmatrix(1,1)*vi(1)
201 
202 
203  err= max( abs(xi(1) - x_new(1)), maxval(abs(vi(1:2) - v_new(1:2))) )
204  i = 0
205  do while(i < self%max_iter .and. err > self%iter_tolerance)
206  xbar(1) = modulo(0.5_f64*(x_new(1)+xi(1)), 1._f64)
207  vbar = 0.5_f64*(v_new+vi)
208 
209  jmatrix = self%map%jacobian_matrix_inverse( [xbar(1),0._f64,0._f64] )
210 
211  call self%kernel_smoother_1%evaluate &
212  (xbar(1), self%bfield_dofs, bfield)
213 
214  xbar(1) = xi(1) + dt * jmatrix(1,1)*vbar(1)
215  !rhs = vi + sign * DF^{-T} * bfield x DF^{-1} V
216  rhs(1) = vi(1) + qmdt*jmatrix(1,1)*bfield*vbar(2)
217  rhs(2) = vi(2) - qmdt*bfield*jmatrix(1,1)*vbar(1)
218 
219  err = max(abs(x_new(1) - xbar(1)), maxval(abs(v_new(1:2) - rhs(1:2))) )
220  x_new = xbar
221  v_new(1:2) = rhs
222  i = i + 1
223  end do
224  ! Get charge for accumulation of j
225  wi = self%particle_group%group(i_sp)%get_charge(i_part)
226 
227  if ( abs(vbar(1))> 1d-16 ) then
228  call self%kernel_smoother_1%add_current( xi(1), x_new(1), wi(1), self%j_dofs_local(:,1) )
229  call self%kernel_smoother_0%add_current( xi(1), x_new(1), wi(1)*vbar(2)/(jmatrix(1,1)*vbar(1)), self%j_dofs_local(:,2) )
230  else
231  call self%kernel_smoother_0%add_charge( xi(1), wi(1)*dt*vbar(2), self%j_dofs_local(:,2) )
232  end if
233 
234  x_new(1) = modulo(x_new(1), 1._f64)
235  call self%particle_group%group(i_sp)%set_x(i_part, x_new)
236  call self%particle_group%group(i_sp)%set_v( i_part, v_new )
237 
238  end do
239  end do
240 
241  self%j_dofs = 0.0_f64
242  ! MPI to sum up contributions from each processor
243  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,1), &
244  n_cells, mpi_sum, self%j_dofs(:,1))
245 
246  ! Update the electric field.
247  call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,1), 1, self%efield_dofs(:,1))
248  ! MPI to sum up contributions from each processor
249  call sll_o_collective_allreduce( sll_v_world_collective, self%j_dofs_local(:,2), &
250  n_cells, mpi_sum, self%j_dofs(:,2))
251 
252  call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs(:,2))
253 
254  end subroutine operatorhp_pic_vm_1d2v
255 
256 
257  !---------------------------------------------------------------------------!
263  subroutine operatorhe_pic_vm_1d2v(self, dt)
264  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(inout) :: self
265  sll_real64, intent(in) :: dt
266  !local variables
267  sll_int32 :: i_part, i_sp
268  sll_real64 :: vi(3), xi(3)
269  sll_real64 :: efield(2)
270  sll_real64 :: qoverm, jmat(3,3)
271 
272  do i_sp = 1, self%particle_group%n_species
273  qoverm = self%particle_group%group(i_sp)%species%q_over_m();
274  ! V_new = V_old + dt * E
275  do i_part=1,self%particle_group%group(i_sp)%n_particles
276  xi = self%particle_group%group(i_sp)%get_x(i_part)
277  vi = self%particle_group%group(i_sp)%get_v(i_part)
278 
279  ! Evaluate efields at particle position
280  call self%kernel_smoother_1%evaluate &
281  (xi(1), self%efield_dofs(:,1), efield(1))
282  call self%kernel_smoother_0%evaluate &
283  (xi(1), self%efield_dofs(:,2), efield(2))
284 
285  jmat = self%map%jacobian_matrix_inverse_transposed( [xi(1), 0._f64, 0._f64] )
286 
287  vi(1) = vi(1) + dt* qoverm * jmat(1,1)* efield(1)
288  vi(2) = vi(2) + dt* qoverm * jmat(2,2)*efield(2)
289  call self%particle_group%group(i_sp)%set_v(i_part, vi)
290  end do
291  end do
292 
293  ! Update bfield
294  if(self%electrostatic .eqv. .false.) then
295  call self%maxwell_solver%compute_B_from_E( &
296  dt, self%efield_dofs(:,2), self%bfield_dofs)
297  end if
298 
299  end subroutine operatorhe_pic_vm_1d2v
300 
301 
302  !---------------------------------------------------------------------------!
308  subroutine operatorhb_pic_vm_1d2v(self, dt)
309  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(inout) :: self
310  sll_real64, intent(in) :: dt
311 
312  ! Update efield2
313  call self%maxwell_solver%compute_E_from_B(&
314  dt, self%bfield_dofs, self%efield_dofs(:,2))
315 
316  end subroutine operatorhb_pic_vm_1d2v
317 
318 
319  !---------------------------------------------------------------------------!
322  self, &
323  maxwell_solver, &
324  kernel_smoother_0, &
325  kernel_smoother_1, &
326  particle_group, &
327  efield_dofs, &
328  bfield_dofs, &
329  x_min, &
330  Lx, &
331  map, &
332  electrostatic)
333  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent(out) :: self
334  class(sll_c_maxwell_1d_base), target, intent(in) :: maxwell_solver
335  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_0
336  class(sll_c_particle_mesh_coupling_1d), target, intent(in) :: kernel_smoother_1
337  class(sll_t_particle_array), target, intent(in) :: particle_group
338  sll_real64, target, intent(in) :: efield_dofs(:,:)
339  sll_real64, target, intent(in) :: bfield_dofs(:)
340  sll_real64, intent(in) :: x_min
341  sll_real64, intent(in) :: lx
342  type(sll_t_mapping_3d), target, intent( inout ) :: map
343  logical, optional :: electrostatic
344  !local variables
345  sll_int32 :: ierr
346 
347  if( present(electrostatic) )then
348  self%electrostatic = electrostatic
349  end if
350 
351  self%maxwell_solver => maxwell_solver
352  self%kernel_smoother_0 => kernel_smoother_0
353  self%kernel_smoother_1 => kernel_smoother_1
354  self%particle_group => particle_group
355  self%efield_dofs => efield_dofs
356  self%bfield_dofs => bfield_dofs
357  self%map => map
358 
359  ! Check that n_dofs is the same for both kernel smoothers.
360  sll_assert( self%kernel_smoother_0%n_dofs == self%kernel_smoother_1%n_dofs )
361 
362  sll_allocate(self%j_dofs(self%kernel_smoother_0%n_dofs,2), ierr)
363  sll_allocate(self%j_dofs_local(self%kernel_smoother_0%n_dofs,2), ierr)
364 
365  self%spline_degree = self%kernel_smoother_0%spline_degree
366  self%x_min = x_min
367  self%Lx = lx
368  self%delta_x = 1._f64/real(self%kernel_smoother_1%n_dofs,f64)
369 
370  end subroutine initialize_pic_vm_1d2v
371 
372 
373  !---------------------------------------------------------------------------!
375  subroutine delete_pic_vm_1d2v(self)
376  class(sll_t_time_propagator_pic_vm_1d2v_hs_trafo), intent( inout ) :: self
377 
378  deallocate(self%j_dofs)
379  deallocate(self%j_dofs_local)
380  self%maxwell_solver => null()
381  self%kernel_smoother_0 => null()
382  self%kernel_smoother_1 => null()
383  self%particle_group => null()
384  self%efield_dofs => null()
385  self%bfield_dofs => null()
386  self%map => null()
387 
388  end subroutine delete_pic_vm_1d2v
389 
390 
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 interfaces for coordinate transformation.
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-Maxwell with coordinate transformation...
subroutine strang_splitting_pic_vm_1d2v(self, dt, number_steps)
Finalization.
subroutine lie_splitting_back_pic_vm_1d2v(self, dt, number_steps)
Lie splitting (oposite ordering)
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 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 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, map, electrostatic)
Constructor.
subroutine lie_splitting_pic_vm_1d2v(self, dt, number_steps)
Lie splitting.
type collecting functions for analytical coordinate mapping
    Report Typos and Errors