7 #include "sll_assert.h"
8 #include "sll_errors.h"
9 #include "sll_memory.h"
10 #include "sll_working_precision.h"
72 sll_int32 :: spline_degree(3)
74 sll_real64 :: x_min(3)
75 sll_real64 :: x_max(3)
79 sll_real64 :: betar(2)
81 sll_real64,
pointer :: phi_dofs(:)
82 sll_real64,
pointer :: efield_dofs(:)
83 sll_real64,
pointer :: bfield_dofs(:)
84 sll_real64,
allocatable :: j_dofs(:)
85 sll_real64,
allocatable :: j_dofs_local(:)
88 sll_int32 :: boundary_particles = 100
89 sll_int32 :: counter_left = 0
90 sll_int32 :: counter_right = 0
91 sll_real64,
pointer :: rhob(:) => null()
93 logical :: electrostatic = .false.
94 logical :: adiabatic_electrons = .false.
95 logical :: lindf = .false.
97 sll_real64 :: iter_tolerance
102 sll_int32 :: i_weight = 1
124 sll_real64,
intent(in) :: dt
125 sll_int32,
intent(in) :: number_steps
129 do i_step = 1, number_steps
130 call self%operatorHB(0.5_f64*dt)
131 call self%operatorHE(0.5_f64*dt)
132 call self%operatorHp(dt)
133 call self%operatorHE(0.5_f64*dt)
134 call self%operatorHB(0.5_f64*dt)
143 sll_real64,
intent(in) :: dt
144 sll_int32,
intent(in) :: number_steps
148 do i_step = 1,number_steps
149 call self%operatorHB(dt)
150 call self%operatorHE(dt)
151 call self%operatorHp(dt)
160 sll_real64,
intent( in ) :: dt
161 sll_int32,
intent( in ) :: number_steps
165 do i_step = 1,number_steps
166 call self%operatorHp(dt)
167 call self%operatorHE(dt)
168 call self%operatorHB(dt)
180 sll_real64,
intent( in ) :: dt
182 sll_int32 :: i_part, i, j, i_sp
183 sll_real64 :: xi(3), xbar(3), xnew(3), vi(3), vt(3), jmat(3,3)
184 sll_real64 :: wi(1), wall(3), rx(3), q, m
187 self%j_dofs_local = 0.0_f64
188 do i_sp = 1, self%particle_group%n_species
189 q = self%particle_group%group(i_sp)%species%q
190 m = self%particle_group%group(i_sp)%species%m
191 do i_part = 1, self%particle_group%group(i_sp)%n_particles
193 xi = self%particle_group%group(i_sp)%get_x(i_part)
194 vi = self%particle_group%group(i_sp)%get_v(i_part)
196 if( self%map%inverse)
then
197 xbar = self%map%get_x(xi)
198 xbar = xbar + dt * vi
199 xnew = self%map%get_xi(xbar)
202 jmat=self%map%jacobian_matrix_inverse(xi)
205 vt(j) = jmat(j,1)*vi(1) + jmat(j,2)*vi(2) + jmat(j,3)*vi(3)
210 err = maxval(abs(xi - xnew))
212 do while(i < self%max_iter .and. err > self%iter_tolerance)
213 xbar = 0.5_f64*(xnew+xi)
215 jmat=self%map%jacobian_matrix_inverse(xbar)
217 vt(j) = jmat(j,1)*vi(1) + jmat(j,2)*vi(2)+ jmat(j,3)*vi(3)
220 err = maxval(abs(xnew - xbar))
226 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
227 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, vi, wi )
229 call self%particle_group%group(i_sp)%set_x ( i_part, xnew )
230 call self%particle_group%group(i_sp)%set_v(i_part, vi)
232 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
233 wall = self%particle_group%group(i_sp)%get_weights(i_part)
234 select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
237 rx(1) = self%map%get_x1(xnew) + m*vi(2)/q
238 rx(1) = (rx(1)-self%x_min(1))/self%Lx(1)
240 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( rx, vi, 0.0_f64, wall(1), wall(2) )
242 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
244 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
248 self%j_dofs = 0.0_f64
251 self%n_total1+2*self%n_total0, mpi_sum, self%j_dofs)
253 if( self%adiabatic_electrons)
then
254 call self%maxwell_solver%compute_phi_from_j( self%j_dofs, self%phi_dofs, self%efield_dofs )
256 call self%maxwell_solver%compute_E_from_j( self%betar(2)*self%j_dofs, self%efield_dofs )
268 sll_real64,
intent( in ) :: dt
270 sll_int32 :: i_part, i_sp, j
272 sll_real64 :: vi(3), xi(3)
273 sll_real64 :: bfield(3), jmatrix(3,3), rhs(3)
274 sll_real64 :: vt(3), c(3), wall(3), rx(3), q, m
276 do i_sp = 1, self%particle_group%n_species
277 qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt*0.5_f64;
278 q = self%particle_group%group(i_sp)%species%q
279 m = self%particle_group%group(i_sp)%species%m
280 do i_part = 1, self%particle_group%group(i_sp)%n_particles
281 vi = self%particle_group%group(i_sp)%get_v(i_part)
282 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))
290 jmatrix=self%map%jacobian_matrix_inverse(xi)
293 vt(j)=jmatrix(j,1)*vi(1)+jmatrix(j,2)*vi(2)+jmatrix(j,3)*vi(3)
296 c(1)=bfield(3)*vt(2)-bfield(2)*vt(3)
297 c(2)=bfield(1)*vt(3)-bfield(3)*vt(1)
298 c(3)=bfield(2)*vt(1)-bfield(1)*vt(2)
301 rhs(j)= vi(j) + qmdt*(jmatrix(1,j)*c(1)+jmatrix(2,j)*c(2)+jmatrix(3,j)*c(3))
306 call self%particle_group%group(i_sp)%set_v( i_part, vi )
308 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
309 wall = self%particle_group%group(i_sp)%get_weights(i_part)
310 select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
313 rx(1) = self%map%get_x1(xi) + m*vi(2)/q
314 rx(1) = (rx(1)-self%x_min(1))/self%Lx(1)
316 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( rx, vi, 0.0_f64, wall(1), wall(2) )
318 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vi, 0.0_f64, wall(1), wall(2) )
320 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
325 if(self%electrostatic .eqv. .false.)
then
326 call self%maxwell_solver%compute_E_from_B( self%betar(1)*dt, self%bfield_dofs, self%efield_dofs)
339 sll_real64,
intent( in ) :: dt
341 sll_int32 :: i_part, j, i_sp
342 sll_real64 :: xi(3), vi(3), jmat(3,3), vbar(3), vnew(3)
343 sll_real64 :: efield(3), ephys(3), wall(self%i_weight), rx(3)
344 sll_real64 :: qoverm, q, m
346 do i_sp = 1, self%particle_group%n_species
347 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
348 q = self%particle_group%group(i_sp)%species%q
349 m = self%particle_group%group(i_sp)%species%m
350 do i_part = 1, self%particle_group%group(i_sp)%n_particles
352 xi = self%particle_group%group(i_sp)%get_x(i_part)
353 vi = self%particle_group%group(i_sp)%get_v(i_part)
356 call self%particle_mesh_coupling%evaluate &
357 (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], self%efield_dofs(1:self%n_total1), efield(1))
358 call self%particle_mesh_coupling%evaluate &
359 (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))
360 call self%particle_mesh_coupling%evaluate &
361 (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))
363 jmat=self%map%jacobian_matrix_inverse_transposed(xi)
365 ephys(j) = jmat(j,1)* efield(1)+jmat(j,2)* efield(2)+jmat(j,3)* efield(3)
368 if( self%lindf .eqv. .false.)
then
370 vnew = vi + dt* qoverm * ephys
371 call self%particle_group%group(i_sp)%set_v( i_part, vnew )
374 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
375 wall = self%particle_group%group(i_sp)%get_weights(i_part)
376 select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
378 vbar = 0.5_f64*(vi+vnew)
380 rx(1) = self%map%get_x1(xi) + m*vbar(2)/q
381 rx(1) = (rx(1)-self%x_min(1))/self%Lx(1)
383 wall(3) = wall(3) + dt* (q/p%profile%T_i(rx(1)) *sum(ephys*vbar) -&
384 ephys(2)*(p%profile%drho_0(rx(1))/p%profile%rho_0(rx(1))+(0.5_f64*m*sum(vbar**2)/p%profile%T_i(rx(1)) - 1.5_f64)* p%profile%dT_i(rx(1))/p%profile%T_i(rx(1)) ) ) *&
385 self%control_variate%cv(i_sp)%control_variate(rx, vbar, 0._f64)/p%eval_v_density(vbar, xi, m)* self%map%jacobian(xi)
388 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vi, 0.0_f64, wall(1), wall(2) )
390 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
394 wall = self%particle_group%group(i_sp)%get_weights(i_part)
395 select type(p => self%control_variate%cv(i_sp)%control_variate_distribution_params)
398 rx(1) = self%map%get_x1(xi) + m*vi(2)/q
399 rx(1) = (rx(1)-self%x_min(1))/self%Lx(1)
401 wall(1) = wall(1) + dt* (q/p%profile%T_i(rx(1)) *sum(ephys*vi) -&
402 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)) ) ) *&
403 self%control_variate%cv(i_sp)%control_variate(rx, vi, 0._f64)/p%eval_v_density(vi, xi, m)* self%map%jacobian(xi)
405 wall(1) = wall(1) + dt* qoverm* sum(ephys*vi) * self%map%jacobian(xi)
407 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
412 if(self%electrostatic .eqv. .false.)
then
413 call self%maxwell_solver%compute_B_from_E( dt, self%efield_dofs, self%bfield_dofs)
424 particle_mesh_coupling, &
432 boundary_particles, &
433 iter_tolerance, max_iter, &
442 sll_real64,
target,
intent( in ) :: phi_dofs(:)
443 sll_real64,
target,
intent( in ) :: efield_dofs(:)
444 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
445 sll_real64,
intent( in ) :: x_min(3)
446 sll_real64,
intent( in ) :: lx(3)
448 sll_int32,
optional,
intent( in ) :: boundary_particles
449 sll_real64,
optional,
intent( in ) :: iter_tolerance
450 sll_int32,
optional,
intent( in ) :: max_iter
451 sll_real64,
optional,
intent( in ) :: betar(2)
452 logical,
optional :: electrostatic
453 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
458 if (
present(iter_tolerance) )
then
459 self%iter_tolerance = iter_tolerance
460 self%max_iter = max_iter
462 self%iter_tolerance = 1d-12
466 if(
present(electrostatic) )
then
467 self%electrostatic = electrostatic
470 if (
present(boundary_particles) )
then
471 self%boundary_particles = boundary_particles
474 if(
present(rhob) )
then
478 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
480 self%maxwell_solver => maxwell_solver
481 self%particle_mesh_coupling => particle_mesh_coupling
482 self%particle_group => particle_group
483 self%phi_dofs => phi_dofs
484 self%efield_dofs => efield_dofs
485 self%bfield_dofs => bfield_dofs
486 self%n_total0 = self%maxwell_solver%n_total0
487 self%n_total1 = self%maxwell_solver%n_total1
488 self%spline_degree = self%particle_mesh_coupling%spline_degree
490 self%x_max = x_min + lx
494 sll_allocate( self%j_dofs(1:self%n_total1+self%n_total0*2), ierr )
495 sll_allocate( self%j_dofs_local(1:self%n_total1+self%n_total0*2), ierr )
497 self%j_dofs = 0.0_f64
498 self%j_dofs_local = 0.0_f64
500 if (
present(betar))
then
506 if (
present(control_variate))
then
507 allocate(self%control_variate )
508 allocate(self%control_variate%cv(self%particle_group%n_species) )
509 self%control_variate => control_variate
510 if(self%particle_group%group(1)%n_weights == 1 ) self%lindf = .true.
511 self%i_weight = self%particle_group%group(1)%n_weights
521 particle_mesh_coupling, &
530 boundary_particles, &
539 sll_real64,
target,
intent( in ) :: phi_dofs(:)
540 sll_real64,
target,
intent( in ) :: efield_dofs(:)
541 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
542 sll_real64,
intent( in ) :: x_min(3)
543 sll_real64,
intent( in ) :: lx(3)
545 character(len=*),
intent( in ) :: filename
546 sll_int32,
optional,
intent( in ) :: boundary_particles
547 sll_real64,
optional,
intent( in ) :: betar(2)
548 logical,
optional :: electrostatic
549 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
552 sll_int32 :: input_file
554 sll_real64 :: iter_tolerance
555 sll_int32 :: max_iter, boundary_particles_set
556 logical :: electrostatic_set
557 sll_real64 :: betar_set(2)
559 namelist /time_iterate/ iter_tolerance, max_iter
561 if(
present(boundary_particles) )
then
562 boundary_particles_set = boundary_particles
564 boundary_particles_set = 100
567 if(
present(electrostatic) )
then
568 electrostatic_set = electrostatic
570 electrostatic_set = .false.
573 if(
present(betar) )
then
580 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
581 if (io_stat /= 0)
then
582 print*,
'sll_m_time_propagator_pic_vm_3d3v_cef_trafo: Input file does not exist. Set default tolerance.'
583 if(
present( control_variate ) )
then
584 call self%init( maxwell_solver, &
585 particle_mesh_coupling, &
593 boundary_particles = boundary_particles_set, &
595 electrostatic = electrostatic_set, &
597 control_variate = control_variate)
599 call self%init( maxwell_solver, &
600 particle_mesh_coupling, &
608 boundary_particles = boundary_particles_set, &
610 electrostatic = electrostatic_set, &
614 read(input_file, time_iterate,iostat=io_stat)
615 if (io_stat /= 0 )
then
616 if(
present( control_variate ) )
then
617 call self%init( maxwell_solver, &
618 particle_mesh_coupling, &
626 boundary_particles = boundary_particles_set, &
628 electrostatic = electrostatic_set, &
630 control_variate = control_variate)
632 call self%init( maxwell_solver, &
633 particle_mesh_coupling, &
641 boundary_particles = boundary_particles_set, &
643 electrostatic = electrostatic_set, &
647 if(
present( control_variate ) )
then
648 call self%init( maxwell_solver, &
649 particle_mesh_coupling, &
657 boundary_particles_set, &
658 iter_tolerance, max_iter, &
660 electrostatic = electrostatic_set, &
662 control_variate = control_variate)
664 call self%init( maxwell_solver, &
665 particle_mesh_coupling, &
673 boundary_particles_set, &
674 iter_tolerance, max_iter, &
676 electrostatic = electrostatic_set, &
690 deallocate( self%j_dofs )
691 deallocate( self%j_dofs_local )
693 self%maxwell_solver => null()
694 self%particle_mesh_coupling => null()
695 self%particle_group => null()
696 self%phi_dofs => null()
697 self%efield_dofs => null()
698 self%bfield_dofs => null()
Combines values from all processes and distributes the result back to all processes.
Broadcasts a message from the process with rank "root" to all other processes of the communicator.
Reduces values on all processes to a single value.
integer(kind=i32) function, public sll_f_get_collective_rank(col)
Determines the rank of the calling process in the communicator.
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 Hamiltonian splitting for 3d3v Vlasov-Maxwell with coordinate transformation...
subroutine strang_splitting_pic_vm_3d3v_cef_trafo(self, dt, number_steps)
Finalization.
subroutine operatorhp_pic_vm_3d3v_cef_trafo(self, dt)
Push H_p: Equations to be solved $\Xi^{n+1}=\Xi^n+\Delta t DF^{-1}(\bar{\Xi}) V^n$ $M_1 e^n= M_1 e^n-...
subroutine delete_pic_vm_3d3v_cef_trafo(self)
Destructor.
subroutine operatorhe_pic_vm_3d3v_cef_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 operatorhb_pic_vm_3d3v_cef_trafo(self, dt)
Push H_B: Equations to be solved $(\mathbb{I}-\Delta \frac{\Delta t q}{2 m} DF^{-\top} \mathbb{B}(\Xi...
subroutine lie_splitting_back_pic_vm_3d3v_cef_trafo(self, dt, number_steps)
Lie splitting (oposite ordering)
subroutine initialize_file_pic_vm_3d3v_cef_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 initialize_pic_vm_3d3v_cef_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 lie_splitting_pic_vm_3d3v_cef_trafo(self, dt, number_steps)
Lie splitting.
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
subroutine, public sll_s_compute_matrix_inverse(x, y, bf, jm, sign)
invert matrix
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)
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.