10 #include "sll_assert.h"
11 #include "sll_errors.h"
12 #include "sll_memory.h"
13 #include "sll_working_precision.h"
62 sll_int32 :: spline_degree
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()
76 sll_real64 :: betar(2)
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(:,:)
84 sll_real64 :: force_sign = 1._f64
85 logical :: electrostatic = .false.
86 logical :: adiabatic_electrons = .false.
88 logical :: jmean = .false.
90 sll_real64,
allocatable :: efield_filter(:,:)
91 sll_real64,
allocatable :: bfield_filter(:)
94 sll_real64,
allocatable :: efield_to_val(:,:)
95 sll_real64,
allocatable :: bfield_to_val(:)
99 sll_int32 :: n_species
103 sll_int32 :: i_weight
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 )
134 sll_real64,
intent(in) :: dt
135 sll_int32,
intent(in) :: number_steps
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)
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)
162 sll_real64,
intent(in) :: dt
163 sll_int32,
intent(in) :: number_steps
166 if(self%electrostatic)
then
167 do i_step = 1, number_steps
168 call self%operatorHE(dt)
169 call self%operatorHp1(dt)
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)
186 sll_real64,
intent(in) :: dt
187 sll_int32,
intent(in) :: number_steps
191 if(self%electrostatic)
then
192 do i_step = 1, number_steps
193 call self%operatorHp1(dt)
194 call self%operatorHE(dt)
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)
217 sll_real64,
intent(in) :: dt
220 sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wp(3)
224 call self%maxwell_solver%transform_dofs( self%bfield_filter, self%bfield_to_val, 0 )
237 self%j_dofs_local = 0.0_f64
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
245 xold = self%particle_group%group(i_sp)%get_x(i_part)
246 vi = self%particle_group%group(i_sp)%get_v(i_part)
249 xnew = xold + dt * vi
252 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
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)
258 if (self%particle_group%group(i_sp)%n_weights == 3)
then
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)
268 self%j_dofs = 0.0_f64
271 self%n_total1, mpi_sum, self%j_dofs(1:self%n_total1,1))
276 call self%filter%apply_inplace( self%j_dofs(:,1) )
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)
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))
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))
287 call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
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
300 sll_real64 :: xmid(3), xbar
302 if(xnew(1) < self%x_min .or. xnew(1) > self%x_max )
then
303 if(xnew(1) < self%x_min )
then
305 self%counter_left = self%counter_left+1
306 else if(xnew(1) > self%x_max)
then
308 self%counter_right = self%counter_right+1
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)
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
326 xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
327 xmid = self%x_max+self%x_min-xbar
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))
333 else if(xnew(1) < -self%x_max .or. xnew(1) > 2._f64*self%x_max )
then
335 sll_error(
"particle boundary",
"particle out of bound")
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))
353 sll_real64,
intent(in) :: dt
356 sll_int32 :: i_part, i_sp
357 sll_real64 :: vi(3), xi(3), wi(1), wp(3)
362 self%j_dofs_local = 0.0_f64
364 call self%maxwell_solver%transform_dofs( self%bfield_filter, self%bfield_to_val, 0 )
366 do i_sp = 1, self%n_species
367 qm = self%particle_group%group(i_sp)%species%q_over_m();
369 do i_part=1,self%particle_group%group(i_sp)%n_particles
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)
378 xi = self%particle_group%group(i_sp)%get_x(i_part)
381 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)*vi(2)
383 call self%kernel_smoother_0%add_charge(xi(1:1), wi(1), self%j_dofs_local(:,2))
385 if (self%particle_group%group(i_sp)%n_weights == 3)
then
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)
394 self%j_dofs = 0.0_f64
397 self%n_total0, mpi_sum, self%j_dofs(:,2))
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)
402 self%j_dofs(:,2) = self%j_dofs(:,2)*dt
405 call self%filter%apply_inplace( self%j_dofs(:,2) )
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))
410 call self%maxwell_solver%compute_E_from_j(self%force_sign*self%betar(2)*self%j_dofs(:,2), 2, self%efield_dofs(:,2))
412 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
424 sll_real64,
intent(in) :: dt
427 sll_int32 :: i_part, i_sp
428 sll_real64 :: v_new(3), xi(3), wp(3)
429 sll_real64 :: efield(2)
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 )
436 do i_sp = 1,self%n_species
437 qm = self%particle_group%group(i_sp)%species%q_over_m();
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)
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)
451 if (self%particle_group%group(i_sp)%n_weights == 3)
then
453 wp = self%particle_group%group(i_sp)%get_weights(i_part)
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)
461 if(self%electrostatic .eqv. .false.)
then
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 )
479 sll_real64,
intent(in) :: dt
482 call self%maxwell_solver%compute_E_from_B(&
483 dt*self%betar(1), self%bfield_dofs, self%efield_dofs(:,2))
485 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
504 boundary_particles, &
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
523 sll_int32,
optional,
intent( in ) :: boundary_particles
524 sll_real64,
optional,
intent(in) :: force_sign
525 logical,
optional,
intent(in) :: jmean
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(:)
534 if(
present(electrostatic) )
then
535 self%electrostatic = electrostatic
538 if(
present(rhob) )
then
542 if (
present(betar))
then
548 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
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
560 self%x_max = x_min + 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
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 )
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)
578 if( self%n_cells+self%spline_degree == self%maxwell_solver%n_dofs0 )
then
579 self%boundary = .true.
580 self%boundary_particles = boundary_particles
583 if(
present(force_sign) )
then
584 self%force_sign = force_sign
586 self%filter => filter
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 )
592 if (
present(jmean))
then
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
610 if( self%boundary )
then
611 print*,
'left boundary', self%counter_left
612 print*,
'right boundary', self%counter_right
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()
642 boundary_particles, &
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
662 sll_int32,
optional,
intent( in ) :: boundary_particles
663 sll_real64,
optional,
intent(in) :: force_sign
664 logical,
optional,
intent(in) :: jmean
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(:)
671 sll_int32 :: ierr, boundary_particles_set
672 sll_real64 :: force_sign_set
674 sll_real64 :: betar_set(2)
675 logical :: electrostatic_set
679 if (
present(boundary_particles))
then
680 boundary_particles_set = boundary_particles
682 boundary_particles_set = 100
685 if(
present(force_sign) )
then
686 force_sign_set = force_sign
688 force_sign_set = 1._f64
691 if (
present(jmean) )
then
697 if (
present(betar) )
then
703 if (
present(electrostatic) )
then
704 electrostatic_set = electrostatic
706 electrostatic = .false.
709 select type (splitting)
712 call splitting%init(&
723 boundary_particles_set, &
729 electrostatic=electrostatic_set, &
732 call splitting%init(&
743 boundary_particles=boundary_particles_set, &
744 force_sign=force_sign_set, &
747 electrostatic=electrostatic_set, &
Combines values from all processes and distributes the result back to all processes.
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 reinit_fields(self)
Finalization.
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 delete_pic_vm_1d2v_hs(self)
Destructor.
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...
integer(kind=i32), parameter, public sll_p_boundary_particles_periodic
integer(kind=i32), parameter, public sll_p_boundary_particles_reflection
integer(kind=i32), parameter, public sll_p_boundary_particles_absorption
integer(kind=i32), parameter, public sll_p_boundary_particles_singular
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
Basic type of a kernel smoother used for PIC simulations.
Type for Hamiltonian splittings.
Hamiltonian splitting type for Vlasov-Maxwell 1d2v.