7 #include "sll_assert.h"
8 #include "sll_errors.h"
9 #include "sll_memory.h"
10 #include "sll_working_precision.h"
70 sll_int32 :: spline_degree(3)
72 sll_real64 :: x_min(3)
73 sll_real64 :: x_max(3)
77 sll_real64 :: betar(2)
79 sll_real64,
pointer :: phi_dofs(:)
80 sll_real64,
pointer :: efield_dofs(:)
81 sll_real64,
pointer :: bfield_dofs(:)
82 sll_real64,
allocatable :: j_dofs(:)
83 sll_real64,
allocatable :: j_dofs_local(:)
84 sll_int32 :: boundary_particles = 100
85 sll_int32 :: counter_left = 0
86 sll_int32 :: counter_right = 0
87 sll_real64,
pointer :: rhob(:) => null()
89 logical :: electrostatic = .false.
90 logical :: adiabatic_electrons = .false.
91 logical :: lindf = .false.
93 sll_real64 :: iter_tolerance
98 sll_int32 :: i_weight = 1
121 sll_real64,
intent(in) :: dt
122 sll_int32,
intent(in) :: number_steps
126 if(self%electrostatic)
then
127 do i_step = 1, number_steps
128 call self%operatorHE(0.5_f64*dt)
129 call self%operatorHp(dt)
130 call self%operatorHE(0.5_f64*dt)
133 do i_step = 1, number_steps
134 call self%operatorHB(0.5_f64*dt)
135 call self%operatorHE(0.5_f64*dt)
136 call self%operatorHp(dt)
137 call self%operatorHE(0.5_f64*dt)
138 call self%operatorHB(0.5_f64*dt)
147 sll_real64,
intent(in) :: dt
148 sll_int32,
intent(in) :: number_steps
152 if(self%electrostatic)
then
153 do i_step = 1, number_steps
154 call self%operatorHE(dt)
155 call self%operatorHp(dt)
158 do i_step = 1,number_steps
159 call self%operatorHB(dt)
160 call self%operatorHE(dt)
161 call self%operatorHp(dt)
171 sll_real64,
intent( in ) :: dt
172 sll_int32,
intent( in ) :: number_steps
176 if(self%electrostatic)
then
177 do i_step = 1, number_steps
178 call self%operatorHp(dt)
179 call self%operatorHE(dt)
182 do i_step = 1,number_steps
183 call self%operatorHp(dt)
184 call self%operatorHE(dt)
185 call self%operatorHB(dt)
199 sll_real64,
intent( in ) :: dt
201 sll_int32 :: i_part, i, j, i_sp
202 sll_real64 :: xi(3), xbar(3), xnew(3), xphys(3), vt(3), vi(3), vbar(3), vnew(3)
203 sll_real64 :: jmat(3,3)
204 sll_real64 :: qoverm, wi(1), wall(3)
207 sll_real64 :: bfield(3), rhs(3)
210 self%j_dofs_local = 0.0_f64
211 do i_sp = 1, self%particle_group%n_species
212 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
214 do i_part = 1, self%particle_group%group(i_sp)%n_particles
216 xi = self%particle_group%group(i_sp)%get_x(i_part)
217 vi = self%particle_group%group(i_sp)%get_v(i_part)
220 call self%particle_mesh_coupling%evaluate &
221 (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)-1], self%bfield_dofs(1:self%n_total0), bfield(1))
222 call self%particle_mesh_coupling%evaluate &
223 (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))
224 call self%particle_mesh_coupling%evaluate &
225 (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))
226 jmat=self%map%jacobian_matrix_inverse(xi)
227 if( self%map%inverse)
then
228 xphys = self%map%get_x(xi)
229 xbar = xphys + dt * vi
230 xnew = self%map%get_xi(xbar)
234 c(1) = bfield(3)*vt(2) - bfield(2)*vt(3)
235 c(2) = bfield(1)*vt(3) - bfield(3)*vt(1)
236 c(3) = bfield(2)*vt(1) - bfield(1)*vt(2)
240 vnew(j)= vi(j) + qmdt*(jmat(1,j)*c(1)+jmat(2,j)*c(2)+jmat(3,j)*c(3))
242 err= maxval(abs(vi - vnew))
245 do while(i < self%max_iter .and. err > self%iter_tolerance)
246 xbar = 0.5_f64*(xnew+xi)
247 vbar = 0.5_f64*(vnew+vi)
249 if (xbar(1) >= 0._f64 .and. xbar(1) <= 1._f64)
then
250 jmat = self%map%jacobian_matrix_inverse(xbar)
252 call self%particle_mesh_coupling%evaluate &
253 (xbar, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)-1], self%bfield_dofs(1:self%n_total0), bfield(1))
254 call self%particle_mesh_coupling%evaluate &
255 (xbar, [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))
256 call self%particle_mesh_coupling%evaluate &
257 (xbar, [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))
259 xbar = xphys + dt * vbar
260 xnew = self%map%get_xi(xbar)
264 c(1) = bfield(3)*vt(2) - bfield(2)*vt(3)
265 c(2) = bfield(1)*vt(3) - bfield(3)*vt(1)
266 c(3) = bfield(2)*vt(1) - bfield(1)*vt(2)
270 rhs(j)= vi(j) + qmdt*(jmat(1,j)*c(1)+jmat(2,j)*c(2)+jmat(3,j)*c(3))
272 err = maxval(abs(vnew - rhs))
281 vt(j) = jmat(j,1)*vi(1) + jmat(j,2)*vi(2) + jmat(j,3)*vi(3)
284 c(1)=bfield(3)*vt(2)-bfield(2)*vt(3)
285 c(2)=bfield(1)*vt(3)-bfield(3)*vt(1)
286 c(3)=bfield(2)*vt(1)-bfield(1)*vt(2)
289 vnew(j)= vi(j) + qmdt*(jmat(1,j)*c(1)+jmat(2,j)*c(2)+jmat(3,j)*c(3))
294 err= max( maxval(abs(xi - xnew)), maxval(abs(vi - vnew)) )
296 do while(i < self%max_iter .and. err > self%iter_tolerance)
297 xbar = 0.5_f64*(xnew+xi)
298 vbar = 0.5_f64*(vnew+vi)
301 call self%particle_mesh_coupling%evaluate &
302 (xbar, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)-1], self%bfield_dofs(1:self%n_total0), bfield(1))
303 call self%particle_mesh_coupling%evaluate &
304 (xbar, [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))
305 call self%particle_mesh_coupling%evaluate &
306 (xbar, [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))
308 jmat = self%map%jacobian_matrix_inverse( xbar )
311 vt(j) = jmat(j,1)*vbar(1) + jmat(j,2)*vbar(2)+ jmat(j,3)*vbar(3)
315 c(1)=bfield(3)*vt(2)-bfield(2)*vt(3)
316 c(2)=bfield(1)*vt(3)-bfield(3)*vt(1)
317 c(3)=bfield(2)*vt(1)-bfield(1)*vt(2)
320 rhs(j)= vi(j) + qmdt*(jmat(1,j)*c(1)+jmat(2,j)*c(2)+jmat(3,j)*c(3))
323 err = max( maxval(abs(xnew - xbar)), maxval(abs(vnew - rhs)) )
330 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
331 call sll_s_compute_particle_boundary_trafo_current( self%boundary_particles, self%counter_left, self%counter_right, self%map, self%particle_mesh_coupling, self%j_dofs_local, self%spline_degree, self%rhob, xi, xnew, vnew, wi )
334 call self%particle_group%group(i_sp)%set_x( i_part, xnew )
335 call self%particle_group%group(i_sp)%set_v( i_part, vnew )
337 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
338 wall = self%particle_group%group(i_sp)%get_weights(i_part)
339 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vnew, 0.0_f64, wall(1), wall(2) )
340 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
345 self%j_dofs = 0.0_f64
348 self%n_total1+2*self%n_total0, mpi_sum, self%j_dofs)
350 if( self%adiabatic_electrons)
then
351 call self%maxwell_solver%compute_phi_from_j( self%j_dofs, self%phi_dofs, self%efield_dofs )
353 call self%maxwell_solver%compute_E_from_j( self%betar(2)*self%j_dofs, self%efield_dofs )
364 sll_real64,
intent( in ) :: dt
366 call self%maxwell_solver%compute_E_from_B( self%betar(1)*dt, self%bfield_dofs, self%efield_dofs)
377 sll_real64,
intent( in ) :: dt
379 sll_int32 :: i_part, j, i_sp
380 sll_real64 :: xi(3), vi(3), jmat(3,3)
381 sll_real64 :: efield(3), ephys(3), wall(self%i_weight), rx(3)
382 sll_real64 :: qoverm, q, m
384 do i_sp = 1, self%particle_group%n_species
385 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
386 q = self%particle_group%group(i_sp)%species%q
387 m = self%particle_group%group(i_sp)%species%m
388 do i_part = 1, self%particle_group%group(i_sp)%n_particles
390 xi = self%particle_group%group(i_sp)%get_x(i_part)
391 vi = self%particle_group%group(i_sp)%get_v(i_part)
394 call self%particle_mesh_coupling%evaluate &
395 (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], self%efield_dofs(1:self%n_total1), efield(1))
396 call self%particle_mesh_coupling%evaluate &
397 (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))
398 call self%particle_mesh_coupling%evaluate &
399 (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))
401 jmat=self%map%jacobian_matrix_inverse_transposed(xi)
403 ephys(j) = jmat(j,1)* efield(1)+jmat(j,2)* efield(2)+jmat(j,3)* efield(3)
406 if( self%lindf .eqv. .false.)
then
408 vi = vi + dt* qoverm * ephys
409 call self%particle_group%group(i_sp)%set_v( i_part, vi )
412 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
413 wall = self%particle_group%group(i_sp)%get_weights(i_part)
414 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vi, 0.0_f64, wall(1), wall(2) )
415 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
419 wall = self%particle_group%group(i_sp)%get_weights(i_part)
420 select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
423 rx(1) = self%map%get_x1(xi) + m*vi(2)/q
424 rx(1) = (rx(1)-self%x_min(1))/self%Lx(1)
426 wall(1) = wall(1) + dt* (q/p%profile%T_i(rx(1)) *sum(ephys*vi) -&
427 ephys(2)*(p%profile%drho_0(rx(1))/p%profile%rho_0(rx(1))+(0.5_f64*m*sum(vi**2)/p%profile%T_i(rx(1)) - 1.5_f64)* p%profile%dT_i(rx(1))/p%profile%T_i(rx(1)) ) ) *&
428 self%control_variate%cv(i_sp)%control_variate(rx, vi, 0._f64)/p%eval_v_density(vi, xi, m)* self%map%jacobian(xi)
430 wall(1) = wall(1) + dt* qoverm* sum(ephys*vi) * self%map%jacobian(xi)
432 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
437 if(self%electrostatic .eqv. .false.)
then
438 call self%maxwell_solver%compute_B_from_E( dt, self%efield_dofs, self%bfield_dofs)
449 particle_mesh_coupling, &
457 boundary_particles, &
458 iter_tolerance, max_iter, &
467 sll_real64,
target,
intent( in ) :: phi_dofs(:)
468 sll_real64,
target,
intent( in ) :: efield_dofs(:)
469 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
470 sll_real64,
intent( in ) :: x_min(3)
471 sll_real64,
intent( in ) :: lx(3)
473 sll_int32,
optional,
intent( in ) :: boundary_particles
474 sll_real64,
optional,
intent( in ) :: iter_tolerance
475 sll_int32,
optional,
intent( in ) :: max_iter
476 sll_real64,
optional,
intent( in ) :: betar(2)
477 logical,
optional,
intent( in ) :: electrostatic
478 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
483 if (
present(iter_tolerance) )
then
484 self%iter_tolerance = iter_tolerance
485 self%max_iter = max_iter
487 self%iter_tolerance = 1d-12
491 if(
present(electrostatic) )
then
492 self%electrostatic = electrostatic
495 if (
present(boundary_particles) )
then
496 self%boundary_particles = boundary_particles
499 if(
present(rhob) )
then
503 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
505 self%maxwell_solver => maxwell_solver
506 self%particle_mesh_coupling => particle_mesh_coupling
507 self%particle_group => particle_group
508 self%phi_dofs => phi_dofs
509 self%efield_dofs => efield_dofs
510 self%bfield_dofs => bfield_dofs
511 self%n_total0 = self%maxwell_solver%n_total0
512 self%n_total1 = self%maxwell_solver%n_total1
513 self%spline_degree = self%particle_mesh_coupling%spline_degree
515 self%x_max = x_min + lx
519 sll_allocate( self%j_dofs(1:self%n_total1+self%n_total0*2), ierr )
520 sll_allocate( self%j_dofs_local(1:self%n_total1+self%n_total0*2), ierr )
521 self%j_dofs = 0.0_f64
522 self%j_dofs_local = 0.0_f64
524 if (
present(betar))
then
530 if (
present(control_variate))
then
531 allocate(self%control_variate )
532 allocate(self%control_variate%cv(self%particle_group%n_species) )
533 self%control_variate => control_variate
534 if(self%particle_group%group(1)%n_weights == 1 ) self%lindf = .true.
535 self%i_weight = self%particle_group%group(1)%n_weights
545 particle_mesh_coupling, &
554 boundary_particles, &
563 sll_real64,
target,
intent( in ) :: phi_dofs(:)
564 sll_real64,
target,
intent( in ) :: efield_dofs(:)
565 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
566 sll_real64,
intent( in ) :: x_min(3)
567 sll_real64,
intent( in ) :: lx(3)
569 character(len=*),
intent( in ) :: filename
570 sll_int32,
optional,
intent( in ) :: boundary_particles
571 sll_real64,
optional,
intent( in ) :: betar(2)
572 logical,
optional :: electrostatic
573 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
576 sll_int32 :: input_file
578 sll_real64 :: iter_tolerance
579 sll_int32 :: max_iter, boundary_particles_set
580 logical :: electrostatic_set
581 sll_real64 :: betar_set(2)
583 namelist /time_iterate/ iter_tolerance, max_iter
585 if(
present(boundary_particles) )
then
586 boundary_particles_set = boundary_particles
588 boundary_particles_set = 100
591 if(
present(electrostatic) )
then
592 electrostatic_set = electrostatic
594 electrostatic_set = .false.
597 if(
present(betar) )
then
604 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
605 if (io_stat /= 0)
then
606 print*,
'sll_m_time_propagator_pic_vm_3d3v_hs_trafo: Input file does not exist. Set default tolerance.'
607 if(
present( control_variate ) )
then
608 call self%init( maxwell_solver, &
609 particle_mesh_coupling, &
617 boundary_particles_set, &
619 electrostatic = electrostatic_set, &
621 control_variate = control_variate)
623 call self%init( maxwell_solver, &
624 particle_mesh_coupling, &
632 boundary_particles_set, &
634 electrostatic = electrostatic_set, &
638 read(input_file, time_iterate,iostat=io_stat)
639 if (io_stat /= 0 )
then
640 if(
present( control_variate ) )
then
641 call self%init( maxwell_solver, &
642 particle_mesh_coupling, &
650 boundary_particles_set, &
652 electrostatic = electrostatic_set, &
654 control_variate = control_variate)
656 call self%init( maxwell_solver, &
657 particle_mesh_coupling, &
665 boundary_particles_set, &
667 electrostatic = electrostatic_set, &
671 if(
present( control_variate ) )
then
672 call self%init( maxwell_solver, &
673 particle_mesh_coupling, &
681 boundary_particles_set, &
682 iter_tolerance, max_iter, &
684 electrostatic = electrostatic_set, &
686 control_variate = control_variate)
688 call self%init( maxwell_solver, &
689 particle_mesh_coupling, &
697 boundary_particles_set, &
698 iter_tolerance, max_iter, &
700 electrostatic = electrostatic_set, &
716 deallocate( self%j_dofs )
717 deallocate( self%j_dofs_local )
719 self%maxwell_solver => null()
720 self%particle_mesh_coupling => null()
721 self%particle_group => null()
722 self%phi_dofs => null()
723 self%efield_dofs => null()
724 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 interfaces for coordinate transformation.
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...
subroutine, public sll_s_compute_particle_boundary_simple(boundary_particles, counter_left, counter_right, xold, xnew)
compute new position
subroutine, public sll_s_compute_particle_boundary_trafo_current(boundary_particles, counter_left, counter_right, map, particle_mesh_coupling, j_dofs_local, spline_degree, rhob, xold, xnew, vi, wi)
Compute particle boundary and current with coordinate transformation.
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
subroutine, public sll_s_compute_particle_boundary_trafo(boundary_particles, counter_left, counter_right, map, xold, xnew, vi)
Compute particle boundary with coordinate transformation.
Particle pusher based on Hamiltonian splitting for 3d3v Vlasov-Maxwell with coordinate transformation...
subroutine strang_splitting_pic_vm_3d3v_hs_trafo(self, dt, number_steps)
Finalization.
subroutine initialize_pic_vm_3d3v_hs_trafo(self, maxwell_solver, particle_mesh_coupling, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, map, boundary_particles, iter_tolerance, max_iter, betar, electrostatic, rhob, control_variate)
Constructor.
subroutine operatorhb_pic_vm_3d3v_hs_trafo(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 initialize_file_pic_vm_3d3v_hs_trafo(self, maxwell_solver, particle_mesh_coupling, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, map, filename, boundary_particles, betar, electrostatic, rhob, control_variate)
Constructor.
subroutine lie_splitting_back_pic_vm_3d3v_hs_trafo(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine lie_splitting_pic_vm_3d3v_hs_trafo(self, dt, number_steps)
Lie splitting.
subroutine operatorhe_pic_vm_3d3v_hs_trafo(self, dt)
Push H_E: Equations to be solved $V^{n+1}=V^n+\Delta t\mathbb{W}_{\frac{q}{m}} DF^{-\top}(\Xi^n) \mat...
subroutine delete_pic_vm_3d3v_hs_trafo(self)
Destructor.
subroutine operatorhp_pic_vm_3d3v_hs_trafo(self, dt)
Push H_p: Equations to be solved $\Xi^{n+1}=\Xi^n+ \Delta t DF^{-1}(\overline{\Xi})\overline{V}$,...
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
type collecting functions for analytical coordinate mapping
Basic type of a kernel smoother used for PIC simulations.
Type for Hamiltonian splittings.
Hamiltonian splitting type for Vlasov-Maxwell 3d3v with coordinate transformation.