8 #include "sll_assert.h"
9 #include "sll_errors.h"
10 #include "sll_memory.h"
11 #include "sll_working_precision.h"
63 sll_int32 :: spline_degree(3)
65 sll_real64 :: x_min(3)
66 sll_real64 :: x_max(3)
70 sll_real64 :: betar(2)
72 sll_real64,
pointer :: phi_dofs(:)
73 sll_real64,
pointer :: efield_dofs(:)
74 sll_real64,
pointer :: bfield_dofs(:)
75 sll_real64,
allocatable :: j_dofs(:)
76 sll_real64,
allocatable :: j_dofs_local(:)
78 sll_int32 :: boundary_particles = 100
79 sll_int32 :: counter_left = 0
80 sll_int32 :: counter_right = 0
81 sll_real64,
pointer :: rhob(:) => null()
83 logical :: electrostatic = .false.
84 logical :: adiabatic_electrons = .false.
85 logical :: lindf = .false.
89 sll_int32 :: i_weight = 1
111 sll_real64,
intent(in) :: dt
112 sll_int32,
intent(in) :: number_steps
116 do i_step = 1, number_steps
117 call self%operatorHB(0.5_f64*dt)
118 call self%operatorHE(0.5_f64*dt)
119 call self%operatorHp(dt)
120 call self%operatorHE(0.5_f64*dt)
121 call self%operatorHB(0.5_f64*dt)
130 sll_real64,
intent(in) :: dt
131 sll_int32,
intent(in) :: number_steps
135 do i_step = 1,number_steps
136 call self%operatorHB(dt)
137 call self%operatorHE(dt)
138 call self%operatorHp(dt)
148 sll_real64,
intent(in) :: dt
149 sll_int32,
intent(in) :: number_steps
153 do i_step = 1,number_steps
154 call self%operatorHp(dt)
155 call self%operatorHE(dt)
156 call self%operatorHB(dt)
168 sll_real64,
intent( in ) :: dt
170 sll_int32 :: i_part, i_sp
171 sll_real64 :: xnew(3), vi(3), wi(1), xi(3), wall(3)
173 self%j_dofs_local = 0.0_f64
174 do i_sp = 1, self%particle_group%n_species
175 do i_part = 1, self%particle_group%group(i_sp)%n_particles
177 xi = self%particle_group%group(i_sp)%get_x(i_part)
178 vi = self%particle_group%group(i_sp)%get_v(i_part)
184 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
188 call self%particle_group%group(i_sp)%set_x(i_part, xnew)
189 call self%particle_group%group(i_sp)%set_v(i_part, vi)
191 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
192 wall = self%particle_group%group(i_sp)%get_weights(i_part)
193 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
194 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
198 self%j_dofs = 0.0_f64
201 self%n_total1+2*self%n_total0, mpi_sum, self%j_dofs )
204 if( self%adiabatic_electrons)
then
205 call self%maxwell_solver%compute_phi_from_j( self%j_dofs, self%phi_dofs, self%efield_dofs )
207 call self%maxwell_solver%compute_E_from_j( self%j_dofs, self%efield_dofs )
215 sll_real64,
intent( in ) :: xold(3)
216 sll_real64,
intent( inout ) :: xnew(3)
217 sll_real64,
intent( inout ) :: vi(3)
218 sll_real64,
intent( in ) :: wi(1)
220 sll_real64 :: xmid(3), xbar, dx, vh(3)
222 if(xnew(1) < -self%x_max(1) .or. xnew(1) > 2._f64*self%x_max(1) )
then
224 sll_error(
"particle boundary",
"particle out of bound")
225 else if(xnew(1) < self%x_min(1) .or. xnew(1) > self%x_max(1) )
then
226 if(xnew(1) < self%x_min(1) )
then
228 self%counter_left = self%counter_left+1
229 else if(xnew(1) > self%x_max(1))
then
231 self%counter_right = self%counter_right+1
234 dx = (xbar- xold(1))/(xnew(1)-xold(1))
235 xmid = xold + dx * (xnew-xold)
237 vh = (xmid - xold)*wi(1)
238 call self%particle_mesh_coupling%add_current( xold, xmid, vh, self%j_dofs_local )
239 select case(self%boundary_particles)
241 xnew(1) = 2._f64*xbar-xnew(1)
244 call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
246 call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
247 xnew(1) = self%x_min(1) + modulo(xnew(1)-self%x_min(1), self%Lx(1))
248 xmid(1) = self%x_max(1)+self%x_min(1)-xbar
249 call self%particle_mesh_coupling%add_charge(xmid, -wi(1), self%spline_degree, self%rhob)
251 xnew(1) = self%x_min(1) + modulo(xnew(1)-self%x_min(1), self%Lx(1))
252 xmid(1) = self%x_max(1)+self%x_min(1)-xbar
257 vh = (xnew - xmid)*wi(1)
258 call self%particle_mesh_coupling%add_current( xmid, xnew, vh, self%j_dofs_local )
259 xnew(2:3) = self%x_min(2:3) + modulo(xnew(2:3)-self%x_min(2:3), self%Lx(2:3))
270 sll_real64,
intent(in) :: dt
273 sll_int32 :: i_part, i_sp
275 sll_real64 :: vi(3), vnew(3), xi(3)
276 sll_real64 :: bfield(3), bsq(3), denom, wall(3)
278 do i_sp = 1, self%particle_group%n_species
280 qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt*0.5_f64;
281 do i_part = 1, self%particle_group%group(i_sp)%n_particles
282 vi = self%particle_group%group(i_sp)%get_v(i_part)
283 xi = self%particle_group%group(i_sp)%get_x(i_part)
284 call self%particle_mesh_coupling%evaluate &
285 (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)-1], self%bfield_dofs(1:self%n_total0), bfield(1))
286 call self%particle_mesh_coupling%evaluate &
287 (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)-1],self%bfield_dofs(self%n_total0+1:self%n_total0+self%n_total1), bfield(2))
288 call self%particle_mesh_coupling%evaluate &
289 (xi, [self%spline_degree(1)-1, self%spline_degree(2)-1, self%spline_degree(3)],self%bfield_dofs(self%n_total0+self%n_total1+1:self%n_total0+2*self%n_total1), bfield(3))
293 denom = sum(bsq)+1.0_f64
295 vnew(1) = ( (bsq(1)-bsq(2)-bsq(3)+1.0_f64)*vi(1) + &
296 2.0_f64*(bfield(1)*bfield(2)+bfield(3))*vi(2) + &
297 2.0_f64*(bfield(1)*bfield(3)-bfield(2))*vi(3) )/denom
298 vnew(2) = ( 2.0_f64*(bfield(1)*bfield(2)-bfield(3))*vi(1) + &
299 (-bsq(1)+bsq(2)-bsq(3)+1.0_f64)*vi(2) + &
300 2.0_f64*(bfield(2)*bfield(3)+bfield(1))*vi(3) )/denom
301 vnew(3) = ( 2.0_f64*(bfield(1)*bfield(3)+bfield(2))*vi(1) + &
302 2.0_f64*(bfield(2)*bfield(3)-bfield(1))*vi(2) + &
303 (-bsq(1)-bsq(2)+bsq(3)+1.0_f64)*vi(3) )/denom
305 call self%particle_group%group(i_sp)%set_v( i_part, vnew )
307 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
308 wall = self%particle_group%group(i_sp)%get_weights(i_part)
309 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vnew, 0.0_f64, wall(1), wall(2) )
310 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
315 if(self%electrostatic .eqv. .false.)
then
317 call self%maxwell_solver%compute_E_from_B(&
318 self%betar(1)*dt, self%bfield_dofs, self%efield_dofs)
329 sll_real64,
intent(in) :: dt
331 sll_int32 :: i_part, i_sp
332 sll_real64 :: vnew(3), xi(3), wall(self%i_weight), rx(3)
333 sll_real64 :: efield(3)
334 sll_real64 :: qoverm, q, m
335 sll_int32 :: i_weight
337 i_weight = self%i_weight
340 do i_sp = 1, self%particle_group%n_species
341 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
342 q = self%particle_group%group(i_sp)%species%q
343 m = self%particle_group%group(i_sp)%species%m
345 do i_part=1,self%particle_group%group(i_sp)%n_particles
346 xi = self%particle_group%group(i_sp)%get_x(i_part)
347 vnew = self%particle_group%group(i_sp)%get_v(i_part)
349 call self%particle_mesh_coupling%evaluate &
350 (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], self%efield_dofs(1:self%n_total1), efield(1))
351 call self%particle_mesh_coupling%evaluate &
352 (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)],self%efield_dofs(self%n_total1+1:self%n_total1+self%n_total0), efield(2))
353 call self%particle_mesh_coupling%evaluate &
354 (xi, [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1],self%efield_dofs(self%n_total1+self%n_total0+1:self%n_total1+2*self%n_total0), efield(3))
355 if( self%lindf .eqv. .false.)
then
356 vnew = vnew + dt* qoverm * efield
357 call self%particle_group%group(i_sp)%set_v(i_part, vnew)
359 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
360 wall = self%particle_group%group(i_sp)%get_weights(i_part)
361 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vnew, 0.0_f64, wall(1), wall(2) )
362 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
366 wall = self%particle_group%group(i_sp)%get_weights(i_part)
367 select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
370 rx(1) = rx(1) + m*vnew(2)/q
371 rx = (rx-self%x_min)/self%Lx
373 wall(1) = wall(1) + dt* (q/p%profile%T_i(rx(1)) * sum(efield * vnew)-&
374 efield(2)*(p%profile%drho_0(rx(1))/p%profile%rho_0(rx(1))+(0.5_f64*m*sum(vnew**2)/p%profile%T_i(rx(1)) - 1.5_f64)* p%profile%dT_i(rx(1))/p%profile%T_i(rx(1)) ) ) *&
375 self%control_variate%cv(i_sp)%control_variate(rx, vnew, 0._f64)/p%eval_v_density(vnew, xi, m)*product(self%Lx)
378 wall(1) = wall(1) + dt* (q/p%profile%T_i(rx(1)) * sum(efield * vnew)-&
379 efield(2)*(p%profile%drho_0(rx(1))/p%profile%rho_0(rx(1))+(0.5_f64*m*sum(vnew**2)/p%profile%T_i(rx(1)) - 1.5_f64)* p%profile%dT_i(rx(1))/p%profile%T_i(rx(1)) ) ) *product(self%Lx)
381 wall(1) = wall(1) + dt* qoverm* sum(efield * vnew) *product(self%Lx)
383 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
388 if(self%electrostatic .eqv. .false.)
then
390 call self%maxwell_solver%compute_B_from_E( &
391 dt, self%efield_dofs, self%bfield_dofs)
401 particle_mesh_coupling, &
408 boundary_particles, &
417 sll_real64,
target,
intent( in ) :: phi_dofs(:)
418 sll_real64,
target,
intent(in) :: efield_dofs(:)
419 sll_real64,
target,
intent(in) :: bfield_dofs(:)
420 sll_real64,
intent(in) :: x_min(3)
421 sll_real64,
intent(in) :: lx(3)
422 sll_int32,
optional,
intent( in ) :: boundary_particles
423 sll_real64,
optional,
intent(in) :: betar(2)
424 logical,
optional,
intent(in) :: electrostatic
425 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
430 if(
present(electrostatic) )
then
431 self%electrostatic = electrostatic
434 if (
present(boundary_particles) )
then
435 self%boundary_particles = boundary_particles
438 if(
present(rhob) )
then
442 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
444 self%maxwell_solver => maxwell_solver
445 self%particle_mesh_coupling => particle_mesh_coupling
446 self%particle_group => particle_group
447 self%phi_dofs => phi_dofs
448 self%efield_dofs => efield_dofs
449 self%bfield_dofs => bfield_dofs
451 self%n_total0 = self%maxwell_solver%n_total0
452 self%n_total1 = self%maxwell_solver%n_total1
454 sll_allocate( self%j_dofs(1:self%n_total1+self%n_total0*2), ierr )
455 sll_allocate( self%j_dofs_local(1:self%n_total1+self%n_total0*2), ierr )
457 self%spline_degree = self%particle_mesh_coupling%spline_degree
459 self%x_max = x_min + lx
463 if (
present(control_variate))
then
464 allocate(self%control_variate )
465 allocate(self%control_variate%cv(self%particle_group%n_species) )
466 self%control_variate => control_variate
467 if(self%particle_group%group(1)%n_weights == 1 ) self%lindf = .true.
468 self%i_weight = self%particle_group%group(1)%n_weights
471 if (
present(betar))
then
485 deallocate(self%j_dofs)
486 deallocate(self%j_dofs_local)
487 self%maxwell_solver => null()
488 self%particle_mesh_coupling => null()
489 self%particle_group => null()
490 self%phi_dofs => null()
491 self%efield_dofs => null()
492 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 Hamiltonian splitting using in Crouseilles, Einkemmer, Faou for 3d3v Vlasov-...
subroutine lie_splitting_pic_vm_3d3v(self, dt, number_steps)
Lie splitting.
subroutine operatorhb_pic_vm_3d3v(self, dt)
Push H_B: Equations to be solved $(\mathbb{I}-\Delta \frac{\Delta t q}{2 m} \mathbb{B}(X^n,...
subroutine operatorhe_pic_vm_3d3v(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)...
subroutine strang_splitting_pic_vm_3d3v(self, dt, number_steps)
Finalization.
subroutine operatorhp_pic_vm_3d3v(self, dt)
Push H_p: Equations to be solved $X^{n+1}=X^n+\Delta t V^n$ $M_1 e^n= M_1 e^n- \int_{t^n}^{t^{n+1}} \...
subroutine initialize_pic_vm_3d3v(self, maxwell_solver, particle_mesh_coupling, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, boundary_particles, betar, electrostatic, rhob, control_variate)
Constructor.
subroutine lie_splitting_back_pic_vm_3d3v(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine compute_particle_boundary(self, xold, xnew, vi, wi)
Helper function for operatorHp.
subroutine delete_pic_vm_3d3v(self)
Destructor.
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 3d3v.