3 #include "sll_assert.h"
4 #include "sll_errors.h"
5 #include "sll_memory.h"
6 #include "sll_working_precision.h"
97 sll_int32 :: spline_degree
101 sll_real64 :: delta_x
106 logical :: smooth = .false.
107 sll_int32 :: size_particle_mass_0
108 sll_int32 :: size_particle_mass_1
109 logical :: build_particle_mass_loc = .true.
111 sll_int32 :: boundary_particles = 100
112 sll_int32 :: counter_left = 0
113 sll_int32 :: counter_right = 0
114 logical :: boundary = .false.
116 sll_real64,
pointer :: phi_dofs(:)
117 sll_real64,
pointer :: efield_dofs(:,:)
118 sll_real64,
pointer :: bfield_dofs(:)
119 sll_real64,
allocatable :: j_dofs(:,:)
120 sll_real64,
allocatable :: j_dofs_local(:,:)
122 sll_real64,
allocatable :: particle_mass_0_local(:,:)
123 sll_real64,
allocatable :: particle_mass_1_local(:,:)
124 sll_real64,
allocatable :: residual(:)
126 sll_real64,
allocatable :: xnew(:,:)
127 sll_real64,
allocatable :: vnew(:,:,:)
128 sll_real64,
allocatable :: efield_dofs_new(:,:)
129 sll_real64,
allocatable :: efield_dofs_work(:,:)
132 sll_int32 :: niter(100000)
133 sll_int32 :: nevaliter(100000)
134 sll_real64,
allocatable :: nsubiter(:,:)
135 sll_int32 :: iter_counter = 0
136 sll_int32,
allocatable :: sub_iter_counter(:)
137 sll_int32 :: eval_counter = 0
138 sll_int32 :: max_iter = 10
139 sll_int32 :: max_iter_sub = 100
140 sll_real64 :: iter_tolerance = 1d-12
141 sll_real64 :: iter_tolerance_sub = 1d-10
142 sll_int32 :: n_failed = 0
144 sll_real64 :: betar(2) = 1.0_f64
145 sll_real64 :: force_sign = 1._f64
146 logical :: jmean = .false.
147 logical :: adiabatic_electrons = .false.
148 sll_real64 :: solver_tolerance = 1d-12
150 sll_int32 :: n_sub_iter(2) = [8,2]
152 character(len=256) :: output_prefix =
"disgrad"
154 sll_int32 :: n_particles_max
157 sll_real64,
allocatable :: efield_filter(:,:)
158 sll_real64,
allocatable :: bfield_filter(:)
160 sll_real64,
allocatable :: efield_to_val(:,:)
161 sll_real64,
allocatable :: bfield_to_val(:)
167 sll_int32 :: i_weight
191 sll_real64,
intent(in) :: dt
193 sll_int32 :: i_part, i_sp
194 sll_real64 :: xi(3), xnew(3), vi(3), wp(3)
196 do i_sp = 1, self%particle_group%n_species
197 do i_part = 1, self%particle_group%group(i_sp)%n_particles
199 xi = self%particle_group%group(i_sp)%get_x(i_part)
200 vi = self%particle_group%group(i_sp)%get_v(i_part)
202 xnew(1) = xi(1) + dt * vi(1)
205 call self%particle_group%group(i_sp)%set_x ( i_part, xnew )
206 call self%particle_group%group(i_sp)%set_v ( i_part, vi )
207 if (self%particle_group%group(i_sp)%n_weights == 3)
then
209 wp = self%particle_group%group(i_sp)%get_weights(i_part)
210 wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
211 call self%particle_group%group(i_sp)%set_weights(i_part, wp)
222 sll_real64,
intent( inout ) :: xold
223 sll_real64,
intent( inout ) :: xnew
224 sll_real64,
intent( inout ) :: vi
226 sll_real64 :: xmid, xbar, dx
228 if(xnew < -self%x_max .or. xnew > 2._f64*self%x_max )
then
230 sll_error(
"particle boundary",
"particle out of bound")
231 else if(xnew < self%x_min .or. xnew > self%x_max )
then
232 if(xnew < self%x_min )
then
234 self%counter_left = self%counter_left+1
235 else if(xnew > self%x_max)
then
237 self%counter_right = self%counter_right+1
239 dx = (xbar- xold)/(xnew-xold)
240 xmid = xold + dx * (xnew-xold)
243 select case(self%boundary_particles)
246 xnew = 2._f64*xbar-xnew
249 xnew = self%x_min + modulo(xnew-self%x_min, self%Lx)
251 xnew = self%x_min + modulo(xnew-self%x_min, self%Lx)
263 sll_real64,
intent(in) :: dt
265 sll_int32 :: i_part, i_sp
267 sll_real64 :: vi(3), v_new(3), xi(3), wp(3)
268 sll_real64 :: bfield, cs, sn
271 call self%maxwell_solver%transform_dofs( self%bfield_filter, self%bfield_to_val, 0 )
273 do i_sp = 1, self%particle_group%n_species
274 qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt;
275 do i_part = 1, self%particle_group%group(i_sp)%n_particles
276 vi = self%particle_group%group(i_sp)%get_v(i_part)
277 xi = self%particle_group%group(i_sp)%get_x(i_part)
278 call self%kernel_smoother_1%evaluate &
279 (xi(1), self%bfield_to_val, bfield)
286 v_new(1) = cs * vi(1) + sn * vi(2)
287 v_new(2) = -sn* vi(1) + cs * vi(2)
289 call self%particle_group%group(i_sp)%set_v( i_part, v_new )
290 if (self%particle_group%group(i_sp)%n_weights == 3)
then
292 wp = self%particle_group%group(i_sp)%get_weights(i_part)
293 wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
294 call self%particle_group%group(i_sp)%set_weights(i_part, wp)
309 sll_real64,
intent(in) :: dt
312 call self%maxwell_solver%compute_curl_part( dt, self%efield_dofs(:,2), self%bfield_dofs, self%betar(1) )
315 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
316 call self%filter%apply( self%bfield_dofs, self%bfield_filter )
327 sll_real64,
intent(in) :: dt
329 sll_int32 :: i_part, i_sp
330 sll_real64 :: vi(3), xi(3), wi(1), wp(3)
331 sll_real64 :: qoverm, factor
332 sll_real64 :: efield(2)
333 sll_real64 :: rhs0(self%n_dofs0)
334 sll_real64 :: rhs1(self%n_dofs1)
338 self%j_dofs_local = 0.0_f64
339 self%particle_mass_1_local = 0.0_f64
340 self%particle_mass_0_local = 0.0_f64
343 do i_sp=1,self%particle_group%n_species
344 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
345 factor = dt**2*0.25_f64*self%betar(2)*qoverm
346 do i_part = 1,self%particle_group%group(i_sp)%n_particles
347 vi = self%particle_group%group(i_sp)%get_v(i_part)
348 xi = self%particle_group%group(i_sp)%get_x(i_part)
351 wi = self%particle_group%group(i_sp)%get_charge(i_part)
354 call self%kernel_smoother_1%add_particle_mass_full( xi(1), &
356 self%particle_mass_1_local )
357 call self%kernel_smoother_0%add_particle_mass_full( xi(1), &
359 self%particle_mass_0_local )
362 call self%kernel_smoother_1%add_charge( xi(1), wi(1)*vi(1), &
363 self%j_dofs_local(1:self%n_dofs1,1) )
365 call self%kernel_smoother_0%add_charge( xi(1), wi(1)*vi(2), &
366 self%j_dofs_local(:,2) )
369 call self%kernel_smoother_1%evaluate &
370 (xi(1), self%efield_filter(1:self%n_dofs1,1), efield(1) )
372 call self%kernel_smoother_0%evaluate &
373 (xi(1), self%efield_filter(:,2), efield(2))
375 vi(1:2) = vi(1:2) + dt* 0.5_f64* qoverm * efield
376 call self%particle_group%group(i_sp)%set_v( i_part, vi )
378 if (self%particle_group%group(i_sp)%n_weights == 3)
then
380 wp = self%particle_group%group(i_sp)%get_weights(i_part)
381 wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
382 call self%particle_group%group(i_sp)%set_weights(i_part, wp)
387 self%j_dofs = 0.0_f64
388 self%particle_mass_0%particle_mass = 0.0_f64
389 self%particle_mass_1%particle_mass = 0.0_f64
392 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
394 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
396 self%particle_mass_1%particle_mass = 0.0_f64
398 self%size_particle_mass_1, mpi_sum, self%particle_mass_1%particle_mass)
399 self%particle_mass_0%particle_mass = 0.0_f64
401 self%size_particle_mass_0, mpi_sum, self%particle_mass_0%particle_mass)
403 call self%filter%apply_inplace( self%j_dofs(:,1) )
404 call self%filter%apply_inplace( self%j_dofs(:,2) )
406 if ( self%jmean )
then
407 self%j_dofs(:,1) = self%j_dofs(:,1) - sum(self%j_dofs(1:self%n_dofs1,1))/real(self%n_dofs1, f64)
410 if( self%adiabatic_electrons )
then
412 self%linear_op_schur_phiv%sign = -1._f64
413 call self%linear_op_schur_phiv%dot(self%phi_dofs, rhs0)
414 call self%maxwell_solver%multiply_gt( self%j_dofs(1:self%n_dofs1,1), self%j_dofs(:,2) )
415 rhs0 = rhs0 + dt * self%j_dofs(:,2)
418 self%linear_op_schur_phiv%sign = 1._f64
419 call self%linear_solver_schur_phiv%set_guess(self%phi_dofs)
420 call self%linear_solver_schur_phiv%solve( rhs0, self%phi_dofs )
421 call self%maxwell_solver%multiply_g( self%phi_dofs, self%efield_dofs(1:self%n_dofs1,1) )
422 self%efield_dofs(:,1) = -self%efield_dofs(:,1)
426 self%linear_operator_1%sign = -self%force_sign
427 call self%linear_operator_1%dot(self%efield_dofs(1:self%n_dofs1,1) , rhs1 )
428 rhs1 = rhs1 - dt * self%force_sign * self%j_dofs(1:self%n_dofs1,1)
430 self%linear_operator_1%sign = self%force_sign
431 call self%linear_solver_1%set_guess(self%efield_dofs(1:self%n_dofs1,1))
432 call self%linear_solver_1%solve( rhs1 , self%efield_dofs(1:self%n_dofs1,1) )
435 self%linear_operator_0%sign = -self%force_sign
436 call self%linear_operator_0%dot(self%efield_dofs(:,2) , rhs0 )
437 rhs0 = rhs0 - self%force_sign * dt * self%j_dofs(:,2)
440 self%linear_operator_0%sign = self%force_sign
441 call self%linear_solver_0%set_guess(self%efield_dofs(:,2))
442 call self%linear_solver_0%solve( rhs0 , self%efield_dofs(:,2) )
445 if( self%boundary )
then
446 self%efield_dofs(1,2) = 0._f64
447 self%efield_dofs(self%n_dofs0,2) = 0._f64
450 call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
451 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
453 do i_sp=1,self%particle_group%n_species
454 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
455 do i_part = 1, self%particle_group%group(i_sp)%n_particles
457 vi = self%particle_group%group(i_sp)%get_v(i_part)
458 xi = self%particle_group%group(i_sp)%get_x(i_part)
460 call self%kernel_smoother_1%evaluate &
461 (xi(1), self%efield_filter(1:self%n_dofs1,1), efield(1))
463 call self%kernel_smoother_0%evaluate &
464 (xi(1), self%efield_filter(:,2), efield(2))
466 vi(1:2) = vi(1:2) + dt* 0.5_f64* qoverm * efield
467 call self%particle_group%group(i_sp)%set_v( i_part, vi )
469 if (self%particle_group%group(i_sp)%n_weights == 3)
then
471 wp = self%particle_group%group(i_sp)%get_weights(i_part)
472 wp(3) = self%control_variate%cv(i_sp)%update_df_weight( xi(1:1), vi(1:2), 0.0_f64, wp(1), wp(2))
473 call self%particle_group%group(i_sp)%set_weights(i_part, wp)
485 sll_real64,
intent(in) :: dt
487 sll_int32 :: i_part, i_sp
489 sll_real64 :: vi(3), xi(3), wi(1), xnew(3), vbar(2)
491 sll_real64 :: efield(2)
492 sll_real64 :: residual, residuals(4), residuals_all(4)
493 sll_real64 :: xmid(1), xbar
499 self%efield_dofs_new = self%efield_dofs
501 do i_sp = 1, self%particle_group%n_species
502 do i_part = 1, self%particle_group%group(i_sp)%n_particles
503 vi = self%particle_group%group(i_sp)%get_v(i_part)
504 xi = self%particle_group%group(i_sp)%get_x(i_part)
505 self%xnew(i_sp,i_part) = xi(1)
506 self%vnew(i_sp,:,i_part) = vi(1:2)
513 do while ( (residual > self%iter_tolerance) .and. niter < self%max_iter )
517 call self%filter%apply( self%efield_dofs_new(:,1), self%efield_dofs_work(:,1) )
518 call self%filter%apply( self%efield_dofs_new(:,2), self%efield_dofs_work(:,2) )
520 self%efield_dofs_work = 0.5_f64*( self%efield_filter + self%efield_dofs_work )
522 call self%maxwell_solver%transform_dofs( self%efield_dofs_work(:,1), self%efield_to_val(:,1), 0 )
523 call self%maxwell_solver%transform_dofs( self%efield_dofs_work(:,2), self%efield_to_val(:,2), 1 )
526 self%j_dofs_local = 0.0_f64
528 do i_sp = 1, self%particle_group%n_species
529 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
530 do i_part = 1,self%particle_group%group(i_sp)%n_particles
531 vi = self%particle_group%group(i_sp)%get_v(i_part)
532 xi = self%particle_group%group(i_sp)%get_x(i_part)
535 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
537 vbar = 0.5_f64 * (self%vnew(i_sp,:, i_part)+vi(1:2))
538 xnew(1) = xi(1) + dt * vbar(1)
540 if(xnew(1) < -self%x_max .or. xnew(1) > 2._f64*self%x_max )
then
542 sll_error(
"particle boundary",
"particle out of bound")
543 else if(xnew(1) < self%x_min .or. xnew(1) > self%x_max )
then
544 if(xnew(1) < self%x_min )
then
546 else if(xnew(1) > self%x_max)
then
551 if ( abs(vbar(1)) > 1.0d-16 )
then
552 call self%kernel_smoother_1%add_current_evaluate &
553 ( xi(1), xmid(1), wi(1), vbar(1), self%efield_to_val(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
556 call self%kernel_smoother_0%add_current_evaluate &
557 ( xi(1), xmid(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
558 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
561 call self%kernel_smoother_1%evaluate &
562 (xi(1), self%efield_to_val(1:self%n_dofs1,1), efield(1) )
563 efield(1) = efield(1)*dt
564 call self%kernel_smoother_0%add_charge( xi(1), &
565 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
566 call self%kernel_smoother_0%evaluate &
567 (xi(1), self%efield_to_val(:,2), efield(2) )
568 efield(2) = efield(2)*dt
570 vi(1:2) = vi(1:2) + qoverm * efield(1:2)
572 select case(self%boundary_particles)
574 xnew(1) = 2._f64*xbar-xnew(1)
579 xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
580 xmid = self%x_max+self%x_min-xbar
582 xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
583 xmid = self%x_max+self%x_min-xbar
586 if ( abs(vbar(1)) > 1.0d-16 )
then
587 call self%kernel_smoother_1%add_current_evaluate &
588 ( xmid(1), xnew(1), wi(1), vbar(1), self%efield_to_val(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
590 call self%kernel_smoother_0%add_current_evaluate &
591 ( xmid(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
592 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
594 vi(1:2) = vi(1:2) + qoverm * efield(1:2)
600 if ( abs(vbar(1)) > 1.0d-16 )
then
601 call self%kernel_smoother_1%add_current_evaluate &
602 ( xi(1), xnew(1), wi(1), vbar(1), self%efield_to_val(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
605 call self%kernel_smoother_0%add_current_evaluate &
606 ( xi(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
607 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
610 call self%kernel_smoother_1%evaluate &
611 (xi(1), self%efield_to_val(1:self%n_dofs1,1), efield(1) )
612 efield(1) = efield(1)*dt
613 call self%kernel_smoother_0%add_charge( xi(1), &
614 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
615 call self%kernel_smoother_0%evaluate &
616 (xi(1), self%efield_to_val(:,2), efield(2) )
617 efield(2) = efield(2)*dt
619 vi(1:2) = vi(1:2) + qoverm * efield(1:2)
622 residuals(1) = residuals(1) + (xnew(1)-self%xnew(i_sp,i_part))**2*abs(wi(1))
623 residuals(2) = residuals(2) + (vi(1)-self%vnew(i_sp,1,i_part))**2*abs(wi(1))
624 residuals(3) = residuals(3) + (vi(2)-self%vnew(i_sp,2,i_part))**2*abs(wi(1))
625 self%xnew(i_sp,i_part) = xnew(1)
626 self%vnew(i_sp,:,i_part) = vi(1:2)
631 self%j_dofs = 0.0_f64
634 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
636 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
638 call self%filter%apply_inplace( self%j_dofs(:,1) )
639 call self%filter%apply_inplace( self%j_dofs(:,2) )
642 self%efield_dofs_work = self%efield_dofs
643 call self%maxwell_solver%compute_E_from_j(self%j_dofs(1:self%n_dofs1,1), 1, self%efield_dofs_work(1:self%n_dofs1,1) )
644 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs_work(:,2) )
657 residuals(4) = (sum((self%efield_dofs_work-self%efield_dofs_new)**2))*self%delta_x
662 residuals_all = sqrt(residuals_all)
663 residual = residuals_all(4)
667 self%efield_dofs_new = self%efield_dofs_work
671 if ( residual > self%iter_tolerance )
then
672 print*,
'Warning: Iteration no.', self%iter_counter+1 ,
'did not converge.', residuals_all(4), niter
673 self%n_failed = self%n_failed+1
676 call self%filter%apply( self%efield_dofs_new(:,1), self%efield_dofs_work(:,1) )
677 call self%filter%apply( self%efield_dofs_new(:,2), self%efield_dofs_work(:,2) )
679 self%efield_dofs_work = 0.5_f64*( self%efield_filter + self%efield_dofs_work )
681 call self%maxwell_solver%transform_dofs( self%efield_dofs_work(:,1), self%efield_to_val(:,1), 0 )
682 call self%maxwell_solver%transform_dofs( self%efield_dofs_work(:,2), self%efield_to_val(:,2), 1 )
683 self%j_dofs_local = 0.0_f64
686 do i_sp=1,self%particle_group%n_species
687 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
688 do i_part = 1,self%particle_group%group(i_sp)%n_particles
689 vi = self%particle_group%group(i_sp)%get_v(i_part)
690 xi = self%particle_group%group(i_sp)%get_x(i_part)
693 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
695 vbar = 0.5_f64 * (self%vnew(i_sp,:, i_part)+vi(1:2))
697 xnew(1) = xi(1) + dt * vbar(1)
700 call self%particle_group%group(i_sp)%set_x( i_part, xnew )
701 call self%particle_group%group(i_sp)%set_v( i_part, vi )
705 self%j_dofs = 0.0_f64
708 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
710 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
712 call self%filter%apply_inplace( self%j_dofs(:,1) )
713 call self%filter%apply_inplace( self%j_dofs(:,2) )
716 call self%maxwell_solver%compute_E_from_j(self%j_dofs(1:self%n_dofs1,1), 1, self%efield_dofs(1:self%n_dofs1,1) )
717 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs(:,2) )
719 call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
720 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
722 self%iter_counter = self%iter_counter + 1
723 self%niter(self%iter_counter) = niter
731 sll_real64,
intent( in ) :: xi(1)
732 sll_real64,
intent( inout ) :: xnew(1)
733 sll_real64,
intent( inout ) :: vi(2)
734 sll_real64,
intent( inout ) :: vbar(2)
735 sll_real64,
intent( in ) :: wi(1)
736 sll_real64,
intent( in ) :: qoverm
737 sll_real64,
intent( in ) :: dt
739 sll_real64 :: xmid(1), xbar
740 sll_real64 :: efield(2)
742 if(xnew(1) < -self%x_max .or. xnew(1) > 2._f64*self%x_max )
then
744 sll_error(
"particle boundary",
"particle out of bound")
745 else if(xnew(1) < self%x_min .or. xnew(1) > self%x_max )
then
746 if(xnew(1) < self%x_min )
then
748 self%counter_left = self%counter_left+1
749 else if(xnew(1) > self%x_max)
then
751 self%counter_right = self%counter_right+1
755 if ( abs(vbar(1)) > 1.0d-16 )
then
756 call self%kernel_smoother_1%add_current_evaluate &
757 ( xi(1), xmid(1), wi(1), vbar(1), self%efield_to_val(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
760 call self%kernel_smoother_0%add_current_evaluate &
761 ( xi(1), xmid(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
762 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
765 call self%kernel_smoother_1%evaluate &
766 (xi(1), self%efield_to_val(1:self%n_dofs1,1), efield(1) )
767 efield(1) = efield(1)*dt
768 call self%kernel_smoother_0%add_charge( xi(1), &
769 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
770 call self%kernel_smoother_0%evaluate &
771 (xi(1), self%efield_to_val(:,2), efield(2) )
772 efield(2) = efield(2)*dt
774 vi = vi + qoverm * efield
776 select case(self%boundary_particles)
778 xnew(1) = 2._f64*xbar-xnew(1)
783 xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
784 xmid = self%x_max+self%x_min-xbar
786 xnew(1) = self%x_min + modulo(xnew(1)-self%x_min, self%Lx)
787 xmid = self%x_max+self%x_min-xbar
790 if ( abs(vbar(1)) > 1.0d-16 )
then
791 call self%kernel_smoother_1%add_current_evaluate &
792 ( xmid(1), xnew(1), wi(1), vbar(1), self%efield_to_val(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
794 call self%kernel_smoother_0%add_current_evaluate &
795 ( xmid(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
796 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
798 vi = vi + qoverm * efield
801 if ( abs(vbar(1)) > 1.0d-16 )
then
802 call self%kernel_smoother_1%add_current_evaluate &
803 ( xi(1), xnew(1), wi(1), vbar(1), self%efield_to_val(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
806 call self%kernel_smoother_0%add_current_evaluate &
807 ( xi(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
808 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
811 call self%kernel_smoother_1%evaluate &
812 (xi(1), self%efield_to_val(1:self%n_dofs1,1), efield(1) )
813 efield(1) = efield(1)*dt
814 call self%kernel_smoother_0%add_charge( xi(1), &
815 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
816 call self%kernel_smoother_0%evaluate &
817 (xi(1), self%efield_to_val(:,2), efield(2) )
818 efield(2) = efield(2)*dt
820 vi = vi + qoverm * efield
830 sll_real64,
intent(in) :: dt
832 sll_real64 :: residuals(4)
833 sll_real64 :: residuals_all(4)
834 sll_real64 :: residual
836 sll_real64 :: dt_sub(self%particle_group%n_species)
837 sll_real64 :: xi(3), vi(3), wi(1)
838 sll_real64 :: efield_dofs(self%kernel_smoother_1%n_dofs,2)
839 sll_real64 :: efield_dofs_old(self%kernel_smoother_1%n_dofs,2)
840 sll_int32 :: i_part, i_sub, niter, i_sp
844 do i_sp = 1, self%particle_group%n_species
845 dt_sub(i_sp) = dt/real( self%n_sub_iter(i_sp), f64 )
848 self%j_dofs_local = 0.0_f64
855 efield_dofs = self%efield_dofs
856 do i_sp = 1, self%particle_group%n_species
857 do i_part = 1, self%particle_group%group(i_sp)%n_particles
858 vi = self%particle_group%group(i_sp)%get_v(i_part)
859 xi = self%particle_group%group(i_sp)%get_x(i_part)
860 self%xnew(i_sp,i_part) = xi(1)
861 self%vnew(i_sp,:,i_part) = vi(1:2)
864 efield_dofs_old = efield_dofs
866 do while ( (residual > self%iter_tolerance) .and. niter < self%max_iter )
869 efield_dofs = 0.5_f64*( self%efield_dofs + efield_dofs )
871 self%j_dofs_local = 0.0_f64
872 do i_sp = 1, self%particle_group%n_species
873 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
874 do i_part = 1,self%particle_group%group(i_sp)%n_particles
875 vi = self%particle_group%group(i_sp)%get_v(i_part)
876 xi = self%particle_group%group(i_sp)%get_x(i_part)
879 wi = self%particle_group%group(i_sp)%get_charge(i_part)
881 do i_sub = 1, self%n_sub_iter(i_sp)
882 call subcycle_xv( self, dt_sub(i_sp), qoverm, efield_dofs, wi, xi(1:1), &
883 vi(1:2), self%sub_iter_counter(i_sp) )
886 residuals(1) = residuals(1) + (xi(1)-self%xnew(i_sp,i_part))**2*abs(wi(1))
887 residuals(2) = residuals(2) + (vi(1)-self%vnew(i_sp,1,i_part))**2*abs(wi(1))
888 residuals(3) = residuals(3) + (vi(2)-self%vnew(i_sp,2,i_part))**2*abs(wi(1))
890 self%xnew(i_sp,i_part) = xi(1)
891 self%vnew(i_sp,:,i_part) = vi(1:2)
896 self%j_dofs = 0.0_f64
899 self%kernel_smoother_1%n_dofs, mpi_sum, self%j_dofs(:,1) )
901 self%kernel_smoother_1%n_dofs, mpi_sum, self%j_dofs(:,2) )
904 efield_dofs = self%efield_dofs
905 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,1), 1, efield_dofs(:,1) )
906 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, efield_dofs(:,2) )
907 residuals(4) = (sum((efield_dofs_old-efield_dofs)**2))*self%delta_x
910 residuals_all = sqrt(residuals_all)
911 residual = residuals_all(4)
912 efield_dofs_old = efield_dofs
914 self%efield_dofs = efield_dofs
915 do i_sp =1,self%particle_group%n_species
916 do i_part = 1, self%particle_group%group(i_sp)%n_particles
917 vi(1:2) = self%vnew(i_sp,:,i_part)
918 xi(1) = modulo(self%xnew(i_sp, i_part), self%Lx )
919 call self%particle_group%group(i_sp)%set_v( i_part, vi )
920 call self%particle_group%group(i_sp)%set_x( i_part, xi )
924 self%iter_counter = self%iter_counter + 1
925 self%niter(self%iter_counter) = niter
926 do i_sp = 1,self%particle_group%n_species
927 self%nsubiter(i_sp,self%iter_counter) = real(self%sub_iter_counter(i_sp), f64)/ &
928 real( self%particle_group%group(i_sp)%n_particles * niter * self%n_sub_iter(i_sp),f64)
930 self%sub_iter_counter = 0
937 subroutine subcycle_xv( self, dt, qoverm, efield_dofs, wi, position, velocity, sub_iter_counter )
939 sll_real64,
intent(in) :: dt
940 sll_real64,
intent(in) :: qoverm
941 sll_real64,
intent(in) :: efield_dofs(:,:)
942 sll_real64,
intent(in ) :: wi(1)
943 sll_real64,
intent(inout) :: position(1)
944 sll_real64,
intent(inout) :: velocity(2)
945 sll_int32,
intent(inout) :: sub_iter_counter
948 sll_real64 :: xnew(1), vnew(2), vbar, xold(1), vold(2)
949 sll_real64 :: efield(2)
951 sll_real64 :: residuals(3), residuals_all(3), residual
959 do while ( (residual > self%iter_tolerance_sub) .and. niter < self%max_iter_sub )
962 vbar = 0.5_f64*(velocity(1)+vnew(1))
965 xnew = position + dt*vbar
967 if ( abs(vbar) > 1.0d-16 )
then
969 select type ( q=> self%kernel_smoother_1 )
971 call q%evaluate_int &
972 ( position, xnew, vbar, efield_dofs(:,1), &
975 call q%evaluate_int &
976 ( position, xnew, vbar, efield_dofs(:,1), &
979 select type ( q0=> self%kernel_smoother_0 )
981 call q0%evaluate_int &
982 ( position, xnew, vbar, &
986 call q0%evaluate_int &
987 ( position, xnew, vbar, &
992 call self%kernel_smoother_1%evaluate &
993 (position, efield_dofs(:,1), efield(1) )
994 efield(1) = efield(1)*dt
996 call self%kernel_smoother_0%evaluate &
997 (position, efield_dofs(:,2), efield(2) )
998 efield(2) = efield(2)*dt
1001 vnew = velocity + qoverm * efield(1:2)
1003 residuals(1) = abs(xnew(1)-xold(1))
1004 residuals(2) = abs(vnew(1)-vold(1))
1005 residuals(3) = abs(vnew(2)-vold(2))
1007 residual = maxval(residuals_all)
1011 if ( residual > self%iter_tolerance_sub )
then
1012 print*,
'Warning: Inner iteration of iteration no.', self%iter_counter+1 ,
'did not converge.', residuals_all
1016 vbar = 0.5_f64*(velocity(1)+vnew(1))
1017 xnew = position + dt*vbar
1018 if ( abs(vbar) > 1.0d-16 )
then
1020 select type ( q=> self%kernel_smoother_1 )
1022 call q%add_current_evaluate &
1023 ( position, xnew, wi(1), vbar, efield_dofs(:,1), self%j_dofs_local(:,1), &
1026 call q%add_current_evaluate &
1027 ( position, xnew, wi(1), vbar, efield_dofs(:,1), self%j_dofs_local(:,1), &
1030 select type ( q0=> self%kernel_smoother_0 )
1032 call q0%add_current_evaluate &
1033 ( position, xnew, wi(1)*0.5_f64*(velocity(2)+vnew(2))/vbar, vbar, &
1034 efield_dofs(:,2), self%j_dofs_local(:,2), &
1037 call q0%add_current_evaluate &
1038 ( position, xnew, wi(1)*0.5_f64*(velocity(2)+vnew(2))/vbar, vbar, &
1039 efield_dofs(:,2), self%j_dofs_local(:,2), &
1043 call self%kernel_smoother_1%evaluate &
1044 (position, efield_dofs(:,1), efield(1) )
1045 efield(1) = efield(1)*dt
1047 call self%kernel_smoother_0%add_charge( position, &
1048 wi(1)*0.5_f64*(velocity(2)+vnew(2))*dt, self%j_dofs_local(:,2) )
1049 call self%kernel_smoother_0%evaluate &
1050 (position, efield_dofs(:,2), efield(2) )
1051 efield(2) = efield(2)*dt
1054 vnew = velocity + qoverm*efield(1:2)
1057 position = modulo(xnew, self%Lx)
1059 sub_iter_counter = sub_iter_counter + niter + 1
1091 kernel_smoother_0, &
1092 kernel_smoother_1, &
1100 build_particle_mass, &
1101 boundary_particles, &
1103 iter_tolerance, max_iter, &
1114 sll_real64,
target,
intent(in) :: phi_dofs(:)
1115 sll_real64,
target,
intent(in) :: efield_dofs(:,:)
1116 sll_real64,
target,
intent(in) :: bfield_dofs(:)
1117 sll_real64,
intent(in) :: x_min
1118 sll_real64,
intent(in) :: lx
1120 logical,
optional,
intent(in) :: build_particle_mass
1121 sll_int32,
optional,
intent( in ) :: boundary_particles
1122 sll_real64,
intent(in),
optional :: solver_tolerance
1123 sll_real64,
optional,
intent( in ) :: iter_tolerance
1124 sll_int32,
optional,
intent( in ) :: max_iter
1125 sll_real64,
optional,
intent(in) :: force_sign
1127 sll_int32,
optional,
intent(in) :: i_weight
1128 sll_real64,
optional,
intent( in ) :: betar(2)
1129 logical,
optional,
intent(in) :: jmean
1131 sll_int32 :: ierr, i_sp
1132 sll_int32 :: n_span_particle_mass_0, n_span_particle_mass_1
1134 if (
present(boundary_particles) )
then
1135 self%boundary_particles = boundary_particles
1138 if (
present(solver_tolerance) )
then
1139 self%solver_tolerance = solver_tolerance
1142 if (
present(iter_tolerance) )
then
1143 self%iter_tolerance = iter_tolerance
1146 if (
present(max_iter) )
then
1147 self%max_iter = max_iter
1150 if(
present(force_sign) )
then
1151 self%force_sign = force_sign
1154 if (self%force_sign == 1._f64)
then
1155 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
1158 if (
present(betar))
then
1162 if (
present(jmean))
then
1166 if (
present( build_particle_mass )) self%build_particle_mass_loc = build_particle_mass
1168 if( self%boundary_particles < 5 ) self%boundary = .true.
1170 self%maxwell_solver => maxwell_solver
1171 self%kernel_smoother_0 => kernel_smoother_0
1172 self%kernel_smoother_1 => kernel_smoother_1
1173 self%particle_group => particle_group
1174 self%efield_dofs => efield_dofs
1175 self%bfield_dofs => bfield_dofs
1178 sll_assert( self%kernel_smoother_0%n_cells == self%kernel_smoother_1%n_cells )
1179 sll_assert( self%kernel_smoother_0%n_cells == self%maxwell_solver%n_cells )
1181 self%n_cells = self%maxwell_solver%n_cells
1182 self%n_dofs0 = self%maxwell_solver%n_dofs0
1183 self%n_dofs1 = self%maxwell_solver%n_dofs1
1185 self%spline_degree = self%kernel_smoother_0%spline_degree
1188 self%x_max = x_min +lx
1189 self%delta_x = self%maxwell_solver%delta_x
1192 sll_allocate( self%j_dofs(self%n_dofs0,2), ierr )
1193 sll_allocate( self%j_dofs_local(self%n_dofs0,2), ierr )
1194 sll_allocate(self%residual(self%n_dofs0*2), ierr)
1198 if ( self%maxwell_solver%s_deg_0 > -1 .and. self%build_particle_mass_loc .eqv. .true. )
then
1199 n_span_particle_mass_0 = 2*self%spline_degree+1
1200 n_span_particle_mass_1 = 2*self%spline_degree-1
1201 select type( pm=>kernel_smoother_0)
1203 self%smooth = .true.
1204 n_span_particle_mass_0 = 2*self%spline_degree+5
1205 n_span_particle_mass_1 = 2*self%spline_degree+3
1207 self%size_particle_mass_0 = n_span_particle_mass_0* self%n_dofs0
1208 self%size_particle_mass_1 = n_span_particle_mass_1* self%n_dofs1
1210 sll_allocate( self%particle_mass_1_local( n_span_particle_mass_1, self%n_dofs1), ierr )
1211 sll_allocate( self%particle_mass_0_local( n_span_particle_mass_0, self%n_dofs0), ierr )
1212 self%particle_mass_1_local = 0.0_f64
1213 self%particle_mass_0_local = 0.0_f64
1214 if( self%n_cells+self%spline_degree == self%maxwell_solver%n_dofs0 )
then
1216 select type ( q => self%particle_mass_1 )
1218 call q%create( self%spline_degree-1, self%n_dofs1 )
1222 select type ( q => self%particle_mass_0 )
1224 call q%create( self%spline_degree, self%n_dofs0 )
1226 else if ( self%n_cells == self%maxwell_solver%n_dofs0 )
then
1227 if( self%smooth )
then
1229 select type ( q => self%particle_mass_1 )
1231 call q%create( self%spline_degree-1, self%n_dofs1 )
1235 select type ( q => self%particle_mass_0 )
1237 call q%create( self%spline_degree, self%n_dofs0 )
1241 select type ( q => self%particle_mass_1 )
1243 call q%create( self%spline_degree-1, self%n_dofs1 )
1247 select type ( q => self%particle_mass_0 )
1249 call q%create( self%spline_degree, self%n_dofs0 )
1254 if( self%adiabatic_electrons )
then
1255 call self%linear_op_schur_phiv%create( self%maxwell_solver, self%particle_mass_1 )
1256 call self%linear_solver_schur_phiv%create( self%linear_op_schur_phiv )
1257 self%linear_solver_schur_phiv%atol = self%solver_tolerance
1259 call self%linear_operator_1%create( self%maxwell_solver, self%particle_mass_1, self%n_dofs1, self%maxwell_solver%s_deg_1 )
1260 call self%linear_solver_1%create( self%linear_operator_1 )
1261 self%linear_solver_1%atol = self%solver_tolerance
1264 call self%linear_operator_0%create( self%maxwell_solver, self%particle_mass_0, self%n_dofs0, self%maxwell_solver%s_deg_0 )
1265 call self%linear_solver_0%create( self%linear_operator_0 )
1266 self%linear_solver_0%atol = self%solver_tolerance
1271 self%n_particles_max = self%particle_group%group(1)%n_particles
1272 do i_sp = 2,self%particle_group%n_species
1273 self%n_particles_max = max(self%n_particles_max, self%particle_group%group(i_sp)%n_particles )
1276 sll_allocate( self%xnew(self%particle_group%n_species,self%n_particles_max), ierr )
1277 sll_allocate( self%vnew(self%particle_group%n_species,2,self%n_particles_max), ierr )
1278 sll_allocate( self%efield_dofs_new(self%n_dofs0,2), ierr )
1279 sll_allocate( self%efield_dofs_work(self%n_dofs0,2), ierr )
1281 allocate(self%sub_iter_counter( self%particle_group%n_species ) )
1282 self%sub_iter_counter = 0
1283 allocate(self%nsubiter(self%particle_group%n_species,100000 ) )
1286 self%filter => filter
1287 sll_allocate(self%efield_filter(self%n_dofs0,2), ierr)
1288 sll_allocate(self%bfield_filter(self%n_dofs1), ierr)
1289 sll_allocate(self%efield_to_val(self%n_dofs0,2), ierr)
1290 sll_allocate(self%bfield_to_val(self%n_dofs1), ierr)
1292 call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
1293 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
1294 call self%filter%apply( self%bfield_dofs, self%bfield_filter )
1297 if (
present(i_weight)) self%i_weight = i_weight
1298 if(
present(control_variate))
then
1299 allocate(self%control_variate )
1300 allocate(self%control_variate%cv(self%particle_group%n_species) )
1301 self%control_variate => control_variate
1310 kernel_smoother_0, &
1311 kernel_smoother_1, &
1320 build_particle_mass, &
1321 boundary_particles, &
1332 sll_real64,
target,
intent(in) :: phi_dofs(:)
1333 sll_real64,
target,
intent(in) :: efield_dofs(:,:)
1334 sll_real64,
target,
intent(in) :: bfield_dofs(:)
1335 sll_real64,
intent(in) :: x_min
1336 sll_real64,
intent(in) :: lx
1338 character(len=*),
intent(in) :: filename
1339 logical,
optional,
intent(in) :: build_particle_mass
1340 sll_int32,
optional,
intent( in ) :: boundary_particles
1341 sll_real64,
optional,
intent(in) :: force_sign
1343 sll_int32,
optional,
intent(in) :: i_weight
1344 sll_real64,
optional,
intent( in ) :: betar(2)
1345 logical,
optional,
intent(in) :: jmean
1347 character(len=256) :: file_prefix
1348 sll_int32 :: input_file, rank
1349 sll_int32 :: io_stat, io_stat0, io_stat1, file_id, boundary_particles_set
1350 sll_real64 :: force_sign_set, betar_set(2)
1351 sll_real64 :: iter_tolerance, sub_iter_tolerance, maxwell_tolerance
1352 sll_int32 :: max_iter, max_iter_sub, n_sub_iter(2)
1353 logical :: jmean_set
1356 namelist /output/ file_prefix
1357 namelist /time_solver/ maxwell_tolerance
1358 namelist /time_iterate/ iter_tolerance, sub_iter_tolerance, max_iter, max_iter_sub, n_sub_iter
1363 if (
present(boundary_particles))
then
1364 boundary_particles_set = boundary_particles
1366 boundary_particles_set = 100
1369 if(
present(force_sign) )
then
1370 force_sign_set = force_sign
1372 force_sign_set = 1._f64
1375 if(
present(betar) )
then
1381 if (
present(jmean))
then
1389 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
1390 if (io_stat /= 0)
then
1391 print*,
'initialize_pic_vm_1d2v_helper() failed to open nml-file.'
1397 if (
present(control_variate) )
then
1399 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
1400 if (io_stat /= 0)
then
1401 if (rank == 0 )
then
1402 print*,
'sll_m_time_propagator_pic_vm_1d2v_helper: Input file does not exist. Set default tolerance.'
1403 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1404 write(file_id, *)
'solver tolerance:', 1d-12
1405 write(file_id, *)
'force_sign:', force_sign_set
1406 write(file_id, *)
'betar:', betar_set
1409 call self%init( maxwell_solver, &
1410 kernel_smoother_0, &
1411 kernel_smoother_1, &
1419 build_particle_mass, &
1420 boundary_particles = boundary_particles_set, &
1421 force_sign=force_sign_set, &
1422 control_variate = control_variate, &
1423 i_weight=i_weight, &
1427 read(input_file, output, iostat=io_stat0)
1428 read(input_file, time_solver,iostat=io_stat)
1429 read(input_file, time_iterate,iostat=io_stat1)
1431 self%output_prefix = trim(file_prefix)
1432 self%solver_tolerance = maxwell_tolerance
1433 self%iter_tolerance = iter_tolerance
1434 self%iter_tolerance_sub = sub_iter_tolerance
1435 self%max_iter = max_iter
1436 self%max_iter_sub = max_iter_sub
1437 self%n_sub_iter = n_sub_iter
1438 if (io_stat /= 0)
then
1439 if (rank == 0 )
then
1440 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1441 write(file_id, *)
'solver tolerance:', 1d-12
1442 write(file_id, *)
'force_sign:', force_sign_set
1443 write(file_id, *)
'betar:', betar_set
1446 call self%init( maxwell_solver, &
1447 kernel_smoother_0, &
1448 kernel_smoother_1, &
1456 build_particle_mass, &
1457 boundary_particles = boundary_particles_set, &
1458 force_sign=force_sign_set, &
1459 control_variate = control_variate, &
1460 i_weight=i_weight, &
1464 if (rank == 0 )
then
1465 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1466 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1467 write(file_id, *)
'force_sign:', force_sign_set
1468 write(file_id, *)
'betar:', betar_set
1471 call self%init( maxwell_solver, &
1472 kernel_smoother_0, &
1473 kernel_smoother_1, &
1481 build_particle_mass, &
1482 boundary_particles = boundary_particles_set, &
1483 solver_tolerance=maxwell_tolerance, &
1484 force_sign=force_sign_set, &
1485 control_variate = control_variate, &
1486 i_weight=i_weight, &
1495 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
1496 if (io_stat /= 0)
then
1497 if (rank == 0 )
then
1498 print*,
'sll_m_time_propagator_pic_vm_1d2v_helper: Input file does not exist. Set default tolerance.'
1499 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1500 write(file_id, *)
'solver tolerance:', 1d-12
1501 write(file_id, *)
'force_sign:', force_sign_set
1502 write(file_id, *)
'betar:', betar_set
1505 call self%init( maxwell_solver, &
1506 kernel_smoother_0, &
1507 kernel_smoother_1, &
1515 build_particle_mass, &
1516 boundary_particles = boundary_particles_set, &
1517 force_sign=force_sign_set, &
1521 read(input_file, output, iostat=io_stat0)
1522 read(input_file, time_solver,iostat=io_stat)
1523 read(input_file, time_iterate,iostat=io_stat1)
1525 self%output_prefix = trim(file_prefix)
1526 self%solver_tolerance = maxwell_tolerance
1527 self%iter_tolerance = iter_tolerance
1528 self%iter_tolerance_sub = sub_iter_tolerance
1529 self%max_iter = max_iter
1530 self%max_iter_sub = max_iter_sub
1531 self%n_sub_iter = n_sub_iter
1533 if (io_stat /= 0)
then
1534 if (rank == 0 )
then
1535 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1536 write(file_id, *)
'solver tolerance:', 1d-12
1537 write(file_id, *)
'force_sign:', force_sign_set
1538 write(file_id, *)
'betar:', betar_set
1541 call self%init( maxwell_solver, &
1542 kernel_smoother_0, &
1543 kernel_smoother_1, &
1551 build_particle_mass, &
1552 boundary_particles = boundary_particles_set, &
1553 force_sign=force_sign_set, &
1557 if (rank == 0 )
then
1558 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1559 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1560 write(file_id, *)
'force_sign:', force_sign_set
1561 write(file_id, *)
'betar:', betar_set
1564 call self%init( maxwell_solver, &
1565 kernel_smoother_0, &
1566 kernel_smoother_1, &
1574 build_particle_mass, &
1575 boundary_particles = boundary_particles_set, &
1576 solver_tolerance=maxwell_tolerance, &
1577 force_sign=force_sign_set, &
1596 sll_int32 :: file_id, j
1598 if( self%boundary )
then
1599 print*,
'left boundary', self%counter_left
1600 print*,
'right boundary', self%counter_right
1603 open(newunit=file_id, file=trim(self%output_prefix)//
"-outer-iters.dat", action=
'write')
1604 do j=1,self%iter_counter
1605 write(file_id,*) self%niter(j)
1608 open(newunit=file_id, file=trim(self%output_prefix)//
"-inner-iters.dat", action=
'write')
1609 do j=1, self%iter_counter
1610 write(file_id,*) self%nsubiter(:,j)
1613 print*,
'No. of failed iterations:', self%n_failed
1615 if ( self%maxwell_solver%s_deg_0 > -1 .and. self%build_particle_mass_loc .eqv. .true. )
then
1616 call self%linear_solver_1%free()
1617 call self%linear_operator_1%free()
1618 call self%particle_mass_1%free()
1620 call self%linear_solver_0%free()
1621 call self%linear_operator_0%free()
1622 call self%particle_mass_0%free()
1624 deallocate( self%particle_mass_1_local )
1625 deallocate( self%particle_mass_0_local )
1627 if(self%adiabatic_electrons)
then
1628 call self%linear_solver_schur_phiv%free()
1629 call self%linear_op_schur_phiv%free()
1633 deallocate(self%j_dofs)
1634 deallocate(self%j_dofs_local)
1635 self%maxwell_solver => null()
1636 self%kernel_smoother_0 => null()
1637 self%kernel_smoother_1 => null()
1638 self%particle_group => null()
1639 self%efield_dofs => null()
1640 self%bfield_dofs => null()
1650 sll_real64,
intent(in) :: dt
1653 sll_int32 :: i_part, i_sp
1655 sll_real64 :: vi(3), xi(3), wi(1), xnew(3), vnew(3), vbar
1656 sll_real64 :: qoverm
1657 sll_real64 :: efield(2)
1658 sll_real64 :: residual, residuals(4), residuals_all(4)
1659 sll_real64 :: efield_dofs(self%kernel_smoother_1%n_dofs,2)
1660 sll_real64 :: efield_dofs_old(self%kernel_smoother_1%n_dofs,2)
1666 efield_dofs = self%efield_dofs
1668 do i_sp = 1, self%particle_group%n_species
1669 do i_part = 1, self%particle_group%group(i_sp)%n_particles
1670 vnew = self%particle_group%group(i_sp)%get_v(i_part)
1671 xnew = self%particle_group%group(i_sp)%get_x(i_part)
1672 self%xnew(i_sp,i_part) = xnew(1)
1673 self%vnew(i_sp,:,i_part) = vnew(1:2)
1677 efield_dofs_old = efield_dofs
1682 do while ( (residual > self%iter_tolerance) .and. niter < self%max_iter )
1685 call self%filter%apply( efield_dofs_old(:,1), efield_dofs(:,1) )
1686 call self%filter%apply( efield_dofs_old(:,2), efield_dofs(:,2) )
1687 efield_dofs = 0.5_f64*(self%efield_filter + efield_dofs )
1689 call self%maxwell_solver%transform_dofs( efield_dofs(:,1), self%efield_to_val(:,1), 0 )
1690 call self%maxwell_solver%transform_dofs( efield_dofs(:,2), self%efield_to_val(:,2), 1 )
1693 self%j_dofs_local = 0.0_f64
1695 do i_sp = 1, self%particle_group%n_species
1696 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
1697 do i_part = 1,self%particle_group%group(i_sp)%n_particles
1698 vi = self%particle_group%group(i_sp)%get_v(i_part)
1699 xi = self%particle_group%group(i_sp)%get_x(i_part)
1702 wi = self%particle_group%group(i_sp)%get_charge(i_part)
1704 vnew(1:2) = self%vnew(i_sp,1:2, i_part)
1705 xnew(1) = xi(1) + dt * 0.5_f64 * ( vi(1) + vnew(1) )
1708 vbar = 0.5_f64*(vi(1)+vnew(1))
1709 if ( abs(vbar) > 1.0d-16 )
then
1710 call self%kernel_smoother_1%add_current_evaluate &
1711 ( xi(1), xnew(1), wi(1), vbar, self%efield_to_val(:,1), self%j_dofs_local(:,1), &
1714 call self%kernel_smoother_0%add_current_evaluate &
1715 ( xi(1), xnew(1), wi(1)*(vi(2)+vnew(2))/(vi(1)+vnew(1)), vbar, &
1716 self%efield_to_val(:,2), self%j_dofs_local(:,2), &
1719 call self%kernel_smoother_1%evaluate &
1720 (xi(1), self%efield_to_val(:,1), efield(1) )
1721 efield(1) = efield(1)*dt
1722 call self%kernel_smoother_0%add_charge( xi(1), &
1723 wi(1)* 0.5_f64*(vi(2)+vnew(2))*dt, self%j_dofs_local(:,2) )
1724 call self%kernel_smoother_0%evaluate &
1725 (xi(1), self%efield_to_val(:,2), efield(2) )
1726 efield(2) = efield(2)*dt
1728 vnew(1:2) = vi(1:2) + qoverm * efield(1:2)
1731 residuals(1) = residuals(1) + (xnew(1)-self%xnew(i_sp,i_part))**2*abs(wi(1))
1732 residuals(2) = residuals(2) + (vnew(1)-self%vnew(i_sp,1,i_part))**2*abs(wi(1))
1733 residuals(3) = residuals(3) + (vnew(2)-self%vnew(i_sp,2,i_part))**2*abs(wi(1))
1734 self%xnew(i_sp,i_part) = xnew(1)
1735 self%vnew(i_sp,:,i_part) = vnew(1:2)
1740 self%j_dofs = 0.0_f64
1743 self%kernel_smoother_1%n_dofs, mpi_sum, self%j_dofs(:,1) )
1745 self%kernel_smoother_1%n_dofs, mpi_sum, self%j_dofs(:,2) )
1747 call self%filter%apply_inplace( self%j_dofs(:,1) )
1748 call self%filter%apply_inplace( self%j_dofs(:,2) )
1764 efield_dofs = self%efield_dofs
1765 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,1), 1, efield_dofs(:,1) )
1766 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, efield_dofs(:,2) )
1768 if ( self%maxwell_solver%strong_ampere .eqv. .true. )
then
1769 residuals(4) = self%maxwell_solver%l2norm_squared( efield_dofs_old(:,1)-&
1770 efield_dofs(:,1), self%maxwell_solver%s_deg_0 ) + &
1771 self%maxwell_solver%l2norm_squared( efield_dofs_old(:,2)-&
1772 efield_dofs(:,2), self%maxwell_solver%s_deg_0 -1 )
1774 residuals(4) = self%maxwell_solver%l2norm_squared( efield_dofs_old(:,1)-&
1775 efield_dofs(:,1), self%maxwell_solver%s_deg_0 - 1 ) + &
1776 self%maxwell_solver%l2norm_squared( efield_dofs_old(:,2)-&
1777 efield_dofs(:,2), self%maxwell_solver%s_deg_0 )
1780 residuals(4) = (sum((efield_dofs_old-efield_dofs)**2))*self%delta_x
1785 residuals_all = sqrt(residuals_all)
1786 residual = residuals_all(4)
1798 efield_dofs_old = efield_dofs
1825 if ( residual > self%iter_tolerance )
then
1826 print*,
'Warning: Iteration no.', self%iter_counter+1 ,
'did not converge.', residuals_all, niter
1827 self%n_failed = self%n_failed+1
1831 self%efield_dofs = efield_dofs
1832 call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
1833 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
1834 do i_sp = 1, self%particle_group%n_species
1835 do i_part = 1, self%particle_group%group(i_sp)%n_particles
1836 vnew(1:2) = self%vnew(i_sp,:,i_part)
1837 xnew(1) = modulo(self%xnew(i_sp,i_part), self%Lx)
1838 call self%particle_group%group(i_sp)%set_v( i_part, vnew )
1839 call self%particle_group%group(i_sp)%set_x( i_part, xnew )
1843 self%iter_counter = self%iter_counter + 1
1844 self%niter(self%iter_counter) = niter
1853 sll_real64,
intent(in) :: dt
1854 sll_real64,
intent(out) :: efield_dofs(:,:)
1856 sll_int32 :: i_part, i_sp
1857 sll_real64 :: vi(3), xi(3), wi(1)
1858 sll_real64 :: qoverm, factor
1859 sll_real64 :: efield(2)
1860 sll_real64 :: rhs0(self%n_dofs0)
1861 sll_real64 :: rhs1(self%n_dofs1)
1864 self%j_dofs_local = 0.0_f64
1865 self%particle_mass_1_local = 0.0_f64
1866 self%particle_mass_0_local = 0.0_f64
1870 do i_sp=1,self%particle_group%n_species
1871 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
1872 factor = dt**2*0.25_f64*self%betar(2)*qoverm
1873 do i_part = 1,self%particle_group%group(i_sp)%n_particles
1874 vi = self%particle_group%group(i_sp)%get_v(i_part)
1875 xi = self%particle_group%group(i_sp)%get_x(i_part)
1876 xi(1) = xi(1) + 0.5_f64 * dt * vi(1)
1877 xi(1) = modulo(xi(1), self%Lx)
1881 wi = self%particle_group%group(i_sp)%get_charge(i_part)
1884 call self%kernel_smoother_1%add_particle_mass_full( xi(1), &
1886 self%particle_mass_1_local )
1887 call self%kernel_smoother_0%add_particle_mass_full( xi(1), &
1889 self%particle_mass_0_local )
1891 call self%kernel_smoother_1%add_charge( xi(1), wi(1)*vi(1), &
1892 self%j_dofs_local(:,1) )
1894 call self%kernel_smoother_0%add_charge( xi(1), wi(1)*vi(2), &
1895 self%j_dofs_local(:,2) )
1897 call self%kernel_smoother_1%evaluate &
1898 (xi(1), self%efield_dofs(:,1), efield(1) )
1900 call self%kernel_smoother_0%evaluate &
1901 (xi(1), self%efield_dofs(:,2), efield(2))
1902 vi(1:2) = vi(1:2) + dt* 0.5_f64* qoverm * efield
1903 self%vnew(i_sp,:,i_part) = vi(1:2)
1904 self%xnew(i_sp,i_part) = xi(1)
1910 self%j_dofs = 0.0_f64
1913 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
1915 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
1917 self%particle_mass_1%particle_mass = 0.0_f64
1919 self%size_particle_mass_1, mpi_sum, self%particle_mass_1%particle_mass)
1920 self%particle_mass_0%particle_mass = 0.0_f64
1922 self%size_particle_mass_0, mpi_sum, self%particle_mass_0%particle_mass)
1926 self%linear_operator_1%sign = -self%force_sign
1927 call self%linear_operator_1%dot(self%efield_dofs(1:self%n_dofs1,1) , rhs1 )
1928 rhs1 = rhs1 - dt * self%force_sign * self%j_dofs(1:self%n_dofs1,1)
1930 self%linear_operator_1%sign = self%force_sign
1931 call self%linear_solver_1%set_guess(self%efield_dofs(1:self%n_dofs1,1))
1932 call self%linear_solver_1%solve( rhs1, efield_dofs(1:self%n_dofs1,1) )
1935 self%linear_operator_0%sign = -self%force_sign
1936 call self%linear_operator_0%dot(self%efield_dofs(:,2) , rhs0 )
1937 rhs0 = rhs0 - self%force_sign * dt * self%j_dofs(:,2)
1940 self%linear_operator_0%sign = self%force_sign
1941 call self%linear_solver_0%set_guess(self%efield_dofs(:,2))
1942 call self%linear_solver_0%solve( rhs0, efield_dofs(:,2) )
1946 do i_sp=1,self%particle_group%n_species
1947 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
1948 do i_part = 1, self%particle_group%group(i_sp)%n_particles
1950 vi(1:2) = self%vnew(i_sp,:,i_part)
1951 xi(1) = self%xnew(i_sp,i_part)
1953 call self%kernel_smoother_1%evaluate &
1954 (xi(1), efield_dofs(:,1), efield(1))
1956 call self%kernel_smoother_0%evaluate &
1957 (xi(1), efield_dofs(:,2), efield(2))
1958 vi(1:2) = vi(1:2) + dt* 0.5_f64* qoverm * efield
1959 self%vnew(i_sp,:,i_part) = vi(1:2)
1960 self%xnew(i_sp,i_part) = modulo(xi(1) + 0.5_f64*dt*vi(1), self%Lx)
1973 call self%filter%apply( self%efield_dofs(:,1), self%efield_filter(:,1) )
1974 call self%filter%apply( self%efield_dofs(:,2), self%efield_filter(:,2) )
1975 call self%filter%apply( self%bfield_dofs, self%bfield_filter )
Combines values from all processes and distributes the result back to all processes.
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.
module for conjugate gradient method in pure form
Module interface to solve Maxwell's equations in 1D.
Base class for kernel smoothers for accumulation and field evaluation in PIC.
Kernel smoother for 1d with splines of arbitrary degree placed on a uniform mesh.
Kernel smoother for 2d with splines of arbitrary degree placed on a uniform mesh.
Kernel smoother for 1d with splines of arbitrary degree placed on a uniform mesh. This version is for...
Base class for Hamiltonian splittings.
subroutine subcycle_xv(self, dt, qoverm, efield_dofs, wi, position, velocity, sub_iter_counter)
Helper function for subcycle (using Picard iteration)
subroutine advect_e_sub_pic_vm_1d2v_helper(self, dt)
Operator for e,x-part with subcycling.
subroutine advect_e_start_disgrade_pic_vm_1d2v_helper(self, dt)
Operator for first variant without subcycling (Picard iteration, started by DISGRADE)
subroutine initialize_file_pic_vm_1d2v_helper(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, filter, filename, build_particle_mass, boundary_particles, force_sign, control_variate, i_weight, betar, jmean)
Constructor.
subroutine disgrade_for_start(self, dt, efield_dofs)
DISGRADE as first guess DisgradE as first guess.
subroutine initialize_pic_vm_1d2v_helper(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, filter, build_particle_mass, boundary_particles, solver_tolerance, iter_tolerance, max_iter, force_sign, control_variate, i_weight, betar, jmean)
Constructor.
subroutine advect_vb_pic_vm_1d2v_helper(self, dt)
advect_vb: Equations to be solved $V_{1,2}^{n+1}= (\cos(B_3)&\sin(B) \ -\sin(B) &\cos(B) ) V_{1,...
subroutine advect_e_pic_vm_1d2v_helper(self, dt)
Solution with Schur complement: $ S_{+}=M_1+\frac{\Delta t^2 q^2}{4 m} (\mathbb{\Lambda}^1)^T \mathbb...
subroutine advect_ex_pic_vm_1d2v_helper(self, dt)
Operator for first variant without subcycling (Picard iteration, started by DISGRADE)
subroutine reinit_fields(self)
Computes the filtered dofs.
subroutine compute_particle_boundary_current_evaluate(self, xi, xnew, vi, vbar, wi, qoverm, dt)
Helper function for advect_ex.
subroutine advect_x_pic_vm_1d2v_helper(self, dt)
Advection of x part separately.
subroutine delete_pic_vm_1d2v_helper(self)
Destructor.
subroutine compute_particle_boundary(self, xold, xnew, vi)
Helper function for advect_x.
subroutine advect_eb_pic_vm_1d2v_helper(self, dt)
advect_eb: Equations to be solved Solution with Schur complement: $ S=M_1+\frac{\Delta t^2}{4} D^\top...
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)
class for the cg linear solver
Basic type of a kernel smoother used for PIC simulations.
Spline kernel smoother in1d.
Spline kernel smoother in1d.
Basic type of a kernel smoother used for PIC simulations.
Type for Hamiltonian splittings.
Hamiltonian splitting type for Vlasov-Maxwell 1d2v.