8 #include "sll_assert.h"
9 #include "sll_errors.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
64 sll_int32 :: spline_degree(3)
66 sll_real64 :: x_min(3)
67 sll_real64 :: x_max(3)
71 sll_real64 :: betar(2)
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(:)
79 sll_int32 :: boundary_particles = 100
80 sll_int32 :: counter_left = 0
81 sll_int32 :: counter_right = 0
82 sll_real64,
pointer :: rhob(:) => null()
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.
92 sll_real64,
allocatable :: efield_filter(:)
93 sll_real64,
allocatable :: bfield_filter(:)
96 sll_int32 :: n_species
100 sll_int32 :: i_weight = 1
124 sll_real64,
intent(in) :: dt
125 sll_int32,
intent(in) :: number_steps
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)
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)
159 sll_real64,
intent(in) :: dt
160 sll_int32,
intent(in) :: number_steps
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)
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)
187 sll_real64,
intent(in) :: dt
188 sll_int32,
intent(in) :: number_steps
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)
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)
221 sll_real64,
intent(in) :: dt
223 sll_int32 :: i_part, i_sp
224 sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wall(3)
226 sll_int32 :: i_weight
227 sll_real64 :: work(self%n_total1+2*self%n_total0)
229 i_weight = self%i_weight
241 self%j_dofs_local = 0.0_f64
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))
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
254 xold = self%particle_group%group(i_sp)%get_x(i_part)
255 vi = self%particle_group%group(i_sp)%get_v(i_part)
258 xnew(1) = xold(1) + dt * vi(1)
259 xnew(2:3) = xold(2:3)
262 wi = self%particle_group%group(i_sp)%get_charge(i_part, i_weight)
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)
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 )
277 self%j_dofs = 0.0_f64
280 self%n_total1, mpi_sum, self%j_dofs(1:self%n_total1))
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)
286 call self%filter%apply_inplace(self%j_dofs)
288 if( self%adiabatic_electrons)
then
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 )
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)
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
308 sll_real64 :: xmid(3), xbar, dx
310 if(xnew(1) < -self%x_max(1) .or. xnew(1) > 2._f64*self%x_max(1) )
then
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
316 self%counter_left = self%counter_left+1
317 else if(xnew(1) > self%x_max(1))
then
319 self%counter_right = self%counter_right+1
322 dx = (xbar- xold(1))/(xnew(1)-xold(1))
323 xmid = xold + dx * (xnew-xold)
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)
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
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
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))
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))
356 sll_real64,
intent(in) :: dt
358 sll_int32 :: i_part, i_sp
359 sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wall(3)
361 sll_int32 :: i_weight
362 sll_real64 :: work(self%n_total1+2*self%n_total0)
364 i_weight = self%i_weight
366 self%j_dofs_local = 0.0_f64
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))
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
379 xold = self%particle_group%group(i_sp)%get_x(i_part)
380 vi = self%particle_group%group(i_sp)%get_v(i_part)
383 xnew(2) = xold(2) + dt * vi(2)
388 wi = self%particle_group%group(i_sp)%get_charge(i_part, i_weight)
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)
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)
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 )
406 self%j_dofs = 0.0_f64
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)
414 call self%filter%apply_inplace(self%j_dofs)
417 if( self%adiabatic_electrons)
then
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 )
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)
432 sll_real64,
intent(in) :: dt
434 sll_int32 :: i_part, i_sp
435 sll_real64 :: xnew(3), vi(3), wi(1), xold(3), wall(3)
437 sll_int32 :: i_weight
438 sll_real64 :: work(self%n_total1+2*self%n_total0)
440 i_weight = self%i_weight
443 self%j_dofs_local = 0.0_f64
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))
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
456 xold = self%particle_group%group(i_sp)%get_x(i_part)
457 vi = self%particle_group%group(i_sp)%get_v(i_part)
460 xnew(3) = xold(3) + dt * vi(3)
461 xnew(1:2) = xold(1:2)
464 wi = self%particle_group%group(i_sp)%get_charge(i_part, i_weight)
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)
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)
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 )
482 self%j_dofs = 0.0_f64
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)
490 call self%filter%apply_inplace(self%j_dofs)
492 if( self%adiabatic_electrons)
then
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 )
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)
509 sll_real64,
intent(in) :: dt
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
517 i_weight = self%i_weight
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))
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
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)
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)
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 )
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)
558 rx(1) = rx(1) + m*v_new(2)/q
559 rx = (rx-self%x_min)/self%Lx
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)
565 wall(1) = wall(1) + dt* qoverm* sum(efield * v_new) *product(self%Lx)
567 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
569 v_new = v_new + dt* qoverm * efield
570 call self%particle_group%group(i_sp)%set_v(i_part, v_new)
576 if(self%electrostatic .eqv. .false.)
then
578 call self%maxwell_solver%compute_B_from_E( &
579 dt, self%efield_dofs, self%bfield_dofs)
590 sll_real64,
intent(in) :: dt
593 call self%maxwell_solver%compute_E_from_B(&
594 dt*self%betar(1), self%bfield_dofs, self%efield_dofs)
604 particle_mesh_coupling, &
612 boundary_particles, &
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)
629 sll_int32,
optional,
intent( in ) :: boundary_particles
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(:)
636 logical,
optional,
intent(in) :: jmean
640 if(
present(electrostatic) )
then
641 self%electrostatic = electrostatic
644 if(
present(force_sign) )
then
645 self%force_sign = force_sign
648 if (self%force_sign == 1._f64)
then
649 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
652 if (
present(boundary_particles) )
then
653 self%boundary_particles = boundary_particles
656 if(
present(rhob) )
then
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
668 self%n_total0 = self%maxwell_solver%n_total0
669 self%n_total1 = self%maxwell_solver%n_total1
671 sll_allocate(self%j_dofs(self%n_total0), ierr)
672 sll_allocate(self%j_dofs_local(self%n_total0), ierr)
674 self%spline_degree = self%particle_mesh_coupling%spline_degree
676 self%x_max = x_min + lx
679 if( self%particle_mesh_coupling%n_cells(1)+self%spline_degree(1) == self%maxwell_solver%n_dofs(1) )
then
680 self%boundary = .true.
683 self%n_species = particle_group%n_species
685 self%filter => filter
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
695 if (
present(betar))
then
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()
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.
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...
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
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 delete_pic_vm_3d3v_hs(self)
Destructor.
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)
Basic type of a kernel smoother used for PIC simulations.
Type for Hamiltonian splittings.
Hamiltonian splitting type for Vlasov-Maxwell 3d3v.