7 #include "sll_assert.h"
8 #include "sll_errors.h"
9 #include "sll_memory.h"
10 #include "sll_working_precision.h"
91 sll_int32 :: spline_degree
98 sll_real64,
pointer :: efield_dofs(:,:)
99 sll_real64,
pointer :: bfield_dofs(:)
100 sll_real64,
allocatable :: j_dofs(:,:)
101 sll_real64,
allocatable :: j_dofs_local(:,:)
102 sll_real64,
allocatable :: particle_mass_0_local(:,:)
103 sll_real64,
allocatable :: particle_mass_1_local(:,:)
105 sll_int32 :: n_particles_max
106 sll_real64,
allocatable :: xnew(:,:)
107 sll_real64,
allocatable :: vnew(:,:,:)
108 sll_real64,
allocatable :: efield_dofs_new(:,:)
109 sll_real64,
allocatable :: efield_dofs_work(:,:)
111 sll_int32 :: boundary_particles = 100
112 sll_int32 :: counter_left = 0
113 sll_int32 :: counter_right = 0
114 logical :: boundary = .false.
115 sll_real64,
pointer :: rhob(:) => null()
116 sll_real64 :: force_sign = 1._f64
117 logical :: jmean = .false.
119 sll_real64 :: solver_tolerance = 1d-12
122 sll_int32 :: max_iter = 10
123 sll_real64 :: iter_tolerance = 1d-10
125 sll_int32 :: n_failed = 0
126 sll_int32 :: iter_counter = 0
127 sll_int32 :: niter(100000)
150 sll_real64,
intent( in ) :: dt
152 sll_int32 :: i_part, i_sp, i
153 sll_real64 :: xi(3), xnew(3), vi(3), vt, matrix(3,3), xs
156 do i_sp=1,self%particle_group%n_species
157 do i_part=1,self%particle_group%group(i_sp)%n_particles
159 xi = self%particle_group%group(i_sp)%get_x(i_part)
160 vi = self%particle_group%group(i_sp)%get_v(i_part)
162 matrix=self%map%jacobian_matrix_inverse( [xi(1), 0._f64, 0._f64] )
164 vt = matrix(1,1) * vi(1)
171 do while(i < self%max_iter .and. err > self%iter_tolerance)
173 matrix=self%map%jacobian_matrix_inverse( [xs, 0._f64, 0._f64] )
174 xs = xi(1) + 0.5_f64 * dt * (vt + matrix(1,1) * vi(1) )
175 err = abs(xs - xnew(1))
181 call self%particle_group%group(i_sp)%set_x ( i_part, xnew )
182 call self%particle_group%group(i_sp)%set_v ( i_part, vi )
192 sll_real64,
intent( inout ) :: xold
193 sll_real64,
intent( inout ) :: xnew
194 sll_real64,
intent( inout ) :: vi
196 sll_real64 :: xmid, xbar, dx
198 if(xnew < -1._f64 .or. xnew > 2._f64)
then
200 sll_error(
"particle boundary",
"particle out of bound")
201 else if(xnew < 0._f64 .or. xnew > 1._f64 )
then
202 if(xnew < 0._f64 )
then
204 self%counter_left = self%counter_left+1
205 else if(xnew > 1._f64)
then
207 self%counter_right = self%counter_right+1
209 dx = (xbar- xold)/(xnew-xold)
210 xmid = xold + dx * (xnew-xold)
213 select case(self%boundary_particles)
216 xnew = 2._f64*xbar-xnew
219 xnew = modulo(xnew, 1._f64)
221 xnew = modulo(xnew, 1._f64)
233 sll_real64,
intent( in ) :: dt
235 sll_int32 :: i_part, i_sp
237 sll_real64 :: vi(3), vnew(3), xi(3), factor(3,3)
238 sll_real64 :: bfield, cs, sn
240 do i_sp=1,self%particle_group%n_species
241 qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt;
243 do i_part = 1, self%particle_group%group(i_sp)%n_particles
244 vi = self%particle_group%group(i_sp)%get_v(i_part)
245 xi = self%particle_group%group(i_sp)%get_x(i_part)
247 call self%kernel_smoother_1%evaluate(xi(1), self%bfield_dofs, bfield)
249 factor=self%map%jacobian_matrix( [xi(1), 0._f64, 0._f64])/self%map%jacobian( [xi(1), 0._f64, 0._f64])*qmdt
251 cs = cos(factor(3,3)*bfield)
252 sn = sin(factor(3,3)*bfield)
254 vnew(1) = cs * vi(1) + sn * vi(2)
255 vnew(2) = -sn* vi(1) + cs * vi(2)
257 call self%particle_group%group(i_sp)%set_v( i_part, vnew )
271 sll_real64,
intent( in ) :: dt
273 call self%maxwell_solver%compute_curl_part( dt, self%efield_dofs(:,2), self%bfield_dofs )
286 sll_real64,
intent( in ) :: dt
288 sll_int32 :: i_part, i_sp, j
289 sll_real64 :: vi(3), xi(3), wi(1)
290 sll_real64 :: qoverm, jmat(3,3), metric, factor
291 sll_real64 :: efield(2)
292 sll_real64 :: rhs0(self%n_dofs0)
293 sll_real64 :: rhs1(self%n_dofs1)
296 self%j_dofs_local = 0.0_f64
297 self%particle_mass_1_local = 0.0_f64
298 self%particle_mass_0_local = 0.0_f64
301 do i_sp = 1, self%particle_group%n_species
302 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
303 factor = dt**2 * 0.25_f64* qoverm
304 do i_part = 1, self%particle_group%group(i_sp)%n_particles
305 vi = self%particle_group%group(i_sp)%get_v(i_part)
306 xi = self%particle_group%group(i_sp)%get_x(i_part)
309 wi = self%particle_group%group(i_sp)%get_charge(i_part)
311 metric= self%map%metric_inverse_single( [xi(1), 0._f64, 0._f64], 1, 1 )
312 jmat=self%map%jacobian_matrix_inverse( [xi(1), 0._f64, 0._f64] )
315 call self%kernel_smoother_1%add_particle_mass_full( xi(1), wi(1) * metric * factor, &
316 self%particle_mass_1_local )
317 call self%kernel_smoother_0%add_particle_mass_full( xi(1), wi(1) * factor , &
318 self%particle_mass_0_local )
321 call self%kernel_smoother_1%add_charge( xi(1), wi(1)*jmat(1,1)*vi(1), &
322 self%j_dofs_local(1:self%n_dofs1,1) )
324 call self%kernel_smoother_0%add_charge( xi(1), wi(1)*vi(2), &
325 self%j_dofs_local(:,2) )
328 call self%kernel_smoother_1%evaluate &
329 ( xi(1), self%efield_dofs(1:self%n_dofs1,1), efield(1) )
330 call self%kernel_smoother_0%evaluate &
331 ( xi(1), self%efield_dofs(:,2), efield(2))
335 vi(j) = vi(j) + dt* 0.5_f64* qoverm *(jmat(1,j)* efield(1)+jmat(2,j)* efield(2))
338 call self%particle_group%group(i_sp)%set_v( i_part, vi )
342 self%j_dofs = 0.0_f64
343 self%particle_mass_0%particle_mass = 0.0_f64
344 self%particle_mass_1%particle_mass = 0.0_f64
348 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
350 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
353 self%n_dofs1*(2*self%spline_degree-1), mpi_sum, self%particle_mass_1%particle_mass)
355 self%n_dofs0*(2*self%spline_degree+1), mpi_sum, self%particle_mass_0%particle_mass)
358 if ( self%jmean )
then
359 self%j_dofs(:,1) = self%j_dofs(:,1) - sum(self%j_dofs(:,1))/real(self%n_dofs1, f64)
363 self%linear_operator_1%sign = -self%force_sign
364 call self%linear_operator_1%dot(self%efield_dofs(1:self%n_dofs1,1) , rhs1 )
365 rhs1 = rhs1 - dt * self%force_sign * self%j_dofs(1:self%n_dofs1,1)
367 self%linear_operator_1%sign = self%force_sign
368 call self%linear_solver_1%set_guess(self%efield_dofs(1:self%n_dofs1,1))
369 call self%linear_solver_1%solve( rhs1 , self%efield_dofs(1:self%n_dofs1,1) )
372 self%linear_operator_0%sign = -self%force_sign
373 call self%linear_operator_0%dot(self%efield_dofs(:,2) , rhs0 )
374 rhs0 = rhs0 - self%force_sign * dt * self%j_dofs(:,2)
377 self%linear_operator_0%sign = self%force_sign
378 call self%linear_solver_0%set_guess(self%efield_dofs(:,2))
379 call self%linear_solver_0%solve( rhs0 , self%efield_dofs(:,2) )
381 if( self%boundary ) then
382 self%efield_dofs(1,2) = 0._f64
383 self%efield_dofs(self%n_dofs0,2) = 0._f64
387 do i_sp = 1, self%particle_group%n_species
388 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
389 do i_part = 1, self%particle_group%group(i_sp)%n_particles
390 vi = self%particle_group%group(i_sp)%get_v(i_part)
391 xi = self%particle_group%group(i_sp)%get_x(i_part)
394 call self%kernel_smoother_1%evaluate &
395 ( xi(1), self%efield_dofs(1:self%n_dofs1,1), efield(1))
396 call self%kernel_smoother_0%evaluate &
397 ( xi(1), self%efield_dofs(:,2), efield(2))
399 jmat = self%map%jacobian_matrix_inverse_transposed( [xi(1), 0._f64, 0._f64] )
402 vi(j) = vi(j) + dt* 0.5_f64* qoverm *(jmat(j,1)*efield(1) + jmat(j,2)*efield(2))
405 call self%particle_group%group(i_sp)%set_v( i_part, vi )
419 sll_real64,
intent( in ) :: dt
421 sll_int32 :: i_part, i_sp, j
422 sll_real64 :: vi(3), xi(3), wi(1), xnew(3), vbar(2)
424 sll_real64 :: jmat(3,3), jmatrix(3,3), efield(2)
426 sll_real64 :: residual(1), residual_local(1)
427 sll_real64 :: xmid(1), xbar
429 self%efield_dofs_new = self%efield_dofs
430 do i_sp=1,self%particle_group%n_species
431 do i_part = 1,self%particle_group%group(i_sp)%n_particles
432 vi = self%particle_group%group(i_sp)%get_v(i_part)
433 xnew = self%particle_group%group(i_sp)%get_x(i_part)
434 self%vnew(i_sp,:, i_part) = vi(1:2)
435 self%xnew(i_sp, i_part) = xnew(1)
441 do while ( (residual(1) > self%iter_tolerance) .and. niter < self%max_iter )
444 self%efield_dofs_work = 0.5_f64*( self%efield_dofs + self%efield_dofs_new )
445 self%j_dofs_local = 0.0_f64
448 do i_sp=1,self%particle_group%n_species
449 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
450 do i_part = 1,self%particle_group%group(i_sp)%n_particles
451 vi = self%particle_group%group(i_sp)%get_v(i_part)
452 xi = self%particle_group%group(i_sp)%get_x(i_part)
455 wi = self%particle_group%group(i_sp)%get_charge(i_part)
457 vbar = 0.5_f64 * (self%vnew(i_sp,:, i_part)+vi(1:2))
458 xnew(1) = self%xnew(i_sp, i_part)
460 jmat = self%map%jacobian_matrix_inverse_transposed( [xi(1), 0._f64, 0._f64] )
461 jmatrix=self%map%jacobian_matrix_inverse_transposed( [xnew(1), 0._f64, 0._f64] )
462 vbar(1) = 0.5_f64 * (jmatrix(1,1)+jmat(1,1))*vbar(1)
463 xnew(1) = xi(1) + dt * vbar(1)
465 if(xnew(1) < -1._f64 .or. xnew(1) > 2._f64)
then
467 sll_error(
"particle boundary",
"particle out of bound")
468 else if(xnew(1) < 0._f64 .or. xnew(1) > 1._f64 )
then
469 if(xnew(1) < 0._f64 )
then
471 else if(xnew(1) > 1._f64)
then
476 if ( abs(vbar(1)) > 1.0d-16 )
then
477 call self%kernel_smoother_1%add_current_evaluate &
478 ( xi(1), xmid(1), wi(1), vbar(1), self%efield_dofs_work(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
480 call self%kernel_smoother_0%add_current_evaluate &
481 ( xi(1), xmid(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
482 self%efield_dofs_work(:,2), self%j_dofs_local(:,2), &
485 call self%kernel_smoother_1%evaluate &
486 (xi(1), self%efield_dofs_work(1:self%n_dofs1,1), efield(1) )
487 efield(1) = efield(1)*dt
488 call self%kernel_smoother_0%add_charge( xi(1), &
489 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
490 call self%kernel_smoother_0%evaluate &
491 (xi(1), self%efield_dofs_work(:,2), efield(2) )
492 efield(2) = efield(2)*dt
495 jmatrix = self%map%jacobian_matrix_inverse_transposed( [xmid(1), 0._f64, 0._f64] )
497 vi(j) = vi(j) + qoverm *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2))
500 select case(self%boundary_particles)
502 xnew = 2._f64*xbar-xnew
506 call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
508 call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
509 xnew = modulo(xnew, 1._f64)
511 call self%kernel_smoother_0%add_charge(xmid, -wi(1), self%rhob)
513 xnew = modulo(xnew, 1._f64)
516 if ( abs(vbar(1)) > 1.0d-16 )
then
517 call self%kernel_smoother_1%add_current_evaluate &
518 ( xmid(1), xnew(1), wi(1), vbar(1), self%efield_dofs_work(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
520 call self%kernel_smoother_0%add_current_evaluate &
521 ( xmid(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
522 self%efield_dofs_work(:,2), self%j_dofs_local(:,2), &
524 jmatrix = self%map%jacobian_matrix_inverse_transposed( [xnew(1), 0._f64, 0._f64] )
526 vi(j) = vi(j) + qoverm *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2))
533 if ( abs(vbar(1)) > 1.0d-16 )
then
534 call self%kernel_smoother_1%add_current_evaluate &
535 ( xi(1), xnew(1), wi(1), vbar(1), self%efield_dofs_work(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
537 call self%kernel_smoother_0%add_current_evaluate &
538 ( xi(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
539 self%efield_dofs_work(:,2), self%j_dofs_local(:,2), &
542 call self%kernel_smoother_1%evaluate &
543 (xi(1), self%efield_dofs_work(1:self%n_dofs1,1), efield(1) )
544 efield(1) = efield(1)*dt
545 call self%kernel_smoother_0%add_charge( xi(1), &
546 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
547 call self%kernel_smoother_0%evaluate &
548 (xi(1), self%efield_dofs_work(:,2), efield(2) )
549 efield(2) = efield(2)*dt
551 jmatrix = self%map%jacobian_matrix_inverse_transposed( [xnew(1), 0._f64, 0._f64] )
553 vi(j) = vi(j) + qoverm *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2))
557 self%xnew(i_sp,i_part) = xnew(1)
558 self%vnew(i_sp,:,i_part) = vi(1:2)
562 self%j_dofs = 0.0_f64
565 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
567 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
569 self%efield_dofs_work = self%efield_dofs
570 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) )
571 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs_work(:,2) )
574 residual_local = (sum((self%efield_dofs_work-self%efield_dofs_new)**2))*self%maxwell_solver%delta_x
576 residual = sqrt(residual)
577 self%efield_dofs_new = self%efield_dofs_work
580 if ( residual(1) > self%iter_tolerance )
then
581 print*,
'Warning: Iteration no.', self%iter_counter+1 ,
'did not converge.', residual, niter
582 self%n_failed = self%n_failed+1
585 self%efield_dofs_work = 0.5_f64*( self%efield_dofs + self%efield_dofs_new )
586 self%j_dofs_local = 0.0_f64
589 do i_sp=1,self%particle_group%n_species
590 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
591 do i_part = 1,self%particle_group%group(i_sp)%n_particles
592 vi = self%particle_group%group(i_sp)%get_v(i_part)
593 xi = self%particle_group%group(i_sp)%get_x(i_part)
596 wi = self%particle_group%group(i_sp)%get_charge(i_part)
598 vbar = 0.5_f64 * (self%vnew(i_sp,:, i_part)+vi(1:2))
599 xnew(1) = self%xnew(i_sp, i_part)
601 jmat = self%map%jacobian_matrix_inverse_transposed( [xi(1), 0._f64, 0._f64] )
602 jmatrix=self%map%jacobian_matrix_inverse_transposed( [xnew(1), 0._f64, 0._f64] )
603 vbar(1) = 0.5_f64 * (jmatrix(1,1)+jmat(1,1))*vbar(1)
604 xnew(1) = xi(1) + dt * vbar(1)
607 call self%particle_group%group(i_sp)%set_x( i_part, xnew )
608 call self%particle_group%group(i_sp)%set_v( i_part, vi )
612 self%j_dofs = 0.0_f64
615 self%n_dofs1, mpi_sum, self%j_dofs(1:self%n_dofs1,1) )
617 self%n_dofs0, mpi_sum, self%j_dofs(:,2) )
619 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) )
620 call self%maxwell_solver%compute_E_from_j(self%j_dofs(:,2), 2, self%efield_dofs(:,2) )
622 self%iter_counter = self%iter_counter + 1
623 self%niter(self%iter_counter) = niter
631 sll_real64,
intent( in ) :: xi(1)
632 sll_real64,
intent( inout ) :: xnew(1)
633 sll_real64,
intent( inout ) :: vi(2)
634 sll_real64,
intent( inout ) :: vbar(2)
635 sll_real64,
intent( in ) :: wi(1)
636 sll_real64,
intent( in ) :: qoverm
637 sll_real64,
intent( in ) :: dt
639 sll_real64 :: xmid(1), xbar
640 sll_real64 :: jmatrix(3,3), jmat(3,3), efield(2)
644 jmat = self%map%jacobian_matrix_inverse_transposed( [xi(1), 0._f64, 0._f64] )
646 if(xnew(1) < -1._f64 .or. xnew(1) > 2._f64)
then
648 sll_error(
"particle boundary",
"particle out of bound")
649 else if(xnew(1) < 0._f64 .or. xnew(1) > 1._f64 )
then
650 if(xnew(1) < 0._f64 )
then
652 self%counter_left = self%counter_left+1
653 else if(xnew(1) > 1._f64)
then
655 self%counter_right = self%counter_right+1
659 if ( abs(vbar(1)) > 1.0d-16 )
then
660 call self%kernel_smoother_1%add_current_evaluate &
661 ( xi(1), xmid(1), wi(1), vbar(1), self%efield_dofs_work(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
663 call self%kernel_smoother_0%add_current_evaluate &
664 ( xi(1), xmid(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
665 self%efield_dofs_work(:,2), self%j_dofs_local(:,2), &
668 call self%kernel_smoother_1%evaluate &
669 (xi(1), self%efield_dofs_work(1:self%n_dofs1,1), efield(1) )
670 efield(1) = efield(1)*dt
671 call self%kernel_smoother_0%add_charge( xi(1), &
672 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
673 call self%kernel_smoother_0%evaluate &
674 (xi(1), self%efield_dofs_work(:,2), efield(2) )
675 efield(2) = efield(2)*dt
677 jmatrix = self%map%jacobian_matrix_inverse_transposed( [xmid(1), 0._f64, 0._f64] )
679 vi(j) = vi(j) + qoverm *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2))
682 select case(self%boundary_particles)
684 xnew = 2._f64*xbar-xnew
688 call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
690 call self%kernel_smoother_0%add_charge(xmid, wi(1), self%rhob)
691 xnew = modulo(xnew, 1._f64)
693 call self%kernel_smoother_0%add_charge(xmid, -wi(1), self%rhob)
695 xnew = modulo(xnew, 1._f64)
698 if ( abs(vbar(1)) > 1.0d-16 )
then
699 call self%kernel_smoother_1%add_current_evaluate &
700 ( xmid(1), xnew(1), wi(1), vbar(1), self%efield_dofs_work(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
702 call self%kernel_smoother_0%add_current_evaluate &
703 ( xmid(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
704 self%efield_dofs_work(:,2), self%j_dofs_local(:,2), &
706 jmatrix = self%map%jacobian_matrix_inverse_transposed( [xnew(1), 0._f64, 0._f64] )
708 vi(j) = vi(j) + qoverm *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2))
712 if ( abs(vbar(1)) > 1.0d-16 )
then
713 call self%kernel_smoother_1%add_current_evaluate &
714 ( xi(1), xnew(1), wi(1), vbar(1), self%efield_dofs_work(1:self%n_dofs1,1), self%j_dofs_local(1:self%n_dofs1,1), &
716 call self%kernel_smoother_0%add_current_evaluate &
717 ( xi(1), xnew(1), wi(1)*vbar(2)/vbar(1), vbar(1), &
718 self%efield_dofs_work(:,2), self%j_dofs_local(:,2), &
721 call self%kernel_smoother_1%evaluate &
722 (xi(1), self%efield_dofs_work(1:self%n_dofs1,1), efield(1) )
723 efield(1) = efield(1)*dt
724 call self%kernel_smoother_0%add_charge( xi(1), &
725 wi(1)* vbar(2)*dt, self%j_dofs_local(:,2) )
726 call self%kernel_smoother_0%evaluate &
727 (xi(1), self%efield_dofs_work(:,2), efield(2) )
728 efield(2) = efield(2)*dt
730 jmatrix = self%map%jacobian_matrix_inverse_transposed( [xnew(1), 0._f64, 0._f64] )
732 vi(j) = vi(j) + qoverm *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2))
752 boundary_particles, &
754 iter_tolerance, max_iter, &
763 sll_real64,
target,
intent( in ) :: efield_dofs(:,:)
764 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
765 sll_real64,
intent( in ) :: x_min
766 sll_real64,
intent( in ) :: lx
768 sll_int32,
optional,
intent( in ) :: boundary_particles
769 sll_real64,
optional,
intent( in ) :: solver_tolerance
770 sll_real64,
optional,
intent( in ) :: iter_tolerance
771 sll_int32,
optional,
intent( in ) :: max_iter
772 sll_real64,
optional,
intent( in ) :: force_sign
773 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
774 logical,
optional,
intent( in ) :: jmean
778 if (
present(boundary_particles) )
then
779 self%boundary_particles = boundary_particles
782 if (
present(solver_tolerance) )
then
783 self%solver_tolerance = solver_tolerance
786 if(
present(force_sign) )
then
787 self%force_sign = force_sign
790 if (
present(jmean))
then
794 if (
present(iter_tolerance) )
then
795 self%iter_tolerance = iter_tolerance
798 if (
present(max_iter) )
then
799 self%max_iter = max_iter
802 self%maxwell_solver => maxwell_solver
803 self%kernel_smoother_0 => kernel_smoother_0
804 self%kernel_smoother_1 => kernel_smoother_1
805 self%particle_group => particle_group
806 self%efield_dofs => efield_dofs
807 self%bfield_dofs => bfield_dofs
811 sll_assert( self%kernel_smoother_0%n_cells == self%kernel_smoother_1%n_cells )
812 sll_assert( self%kernel_smoother_0%n_cells == self%maxwell_solver%n_cells )
815 self%n_cells = self%maxwell_solver%n_cells
816 self%n_dofs0 = self%maxwell_solver%n_dofs0
817 self%n_dofs1 = self%maxwell_solver%n_dofs1
818 self%spline_degree = self%kernel_smoother_0%spline_degree
820 sll_allocate( self%j_dofs(self%n_dofs0,2), ierr )
821 sll_allocate( self%j_dofs_local(self%n_dofs0,2), ierr )
822 sll_allocate( self%particle_mass_1_local(2*self%spline_degree-1, self%n_dofs1), ierr )
823 sll_allocate( self%particle_mass_0_local(2*self%spline_degree+1, self%n_dofs0), ierr )
824 self%j_dofs = 0.0_f64
825 self%j_dofs_local = 0.0_f64
826 self%particle_mass_1_local = 0.0_f64
827 self%particle_mass_0_local = 0.0_f64
829 if( self%n_cells+self%spline_degree == self%maxwell_solver%n_dofs0 )
then
830 self%boundary = .true.
832 select type ( q => self%particle_mass_1 )
834 call q%create( self%spline_degree-1, self%n_dofs1 )
838 select type ( q => self%particle_mass_0 )
840 call q%create( self%spline_degree, self%n_dofs0 )
842 else if ( self%n_cells == self%maxwell_solver%n_dofs0 )
then
844 select type ( q => self%particle_mass_1 )
846 call q%create( self%spline_degree-1, self%n_dofs1 )
850 select type ( q => self%particle_mass_0 )
852 call q%create( self%spline_degree, self%n_dofs0 )
856 call self%linear_operator_1%create( self%maxwell_solver, self%particle_mass_1, self%n_dofs1, self%maxwell_solver%s_deg_1 )
857 call self%linear_solver_1%create( self%linear_operator_1 )
858 self%linear_solver_1%atol = self%solver_tolerance/lx
861 call self%linear_operator_0%create( self%maxwell_solver, self%particle_mass_0, self%n_dofs0, self%maxwell_solver%s_deg_0 )
862 call self%linear_solver_0%create( self%linear_operator_0 )
863 self%linear_solver_0%atol = self%solver_tolerance
866 self%n_particles_max = self%particle_group%group(1)%n_particles
867 do j = 2,self%particle_group%n_species
868 self%n_particles_max = max(self%n_particles_max, self%particle_group%group(j)%n_particles )
871 sll_allocate( self%xnew(self%particle_group%n_species,self%n_particles_max), ierr )
872 sll_allocate( self%vnew(self%particle_group%n_species,2,self%n_particles_max), ierr )
873 sll_allocate( self%efield_dofs_new(self%n_dofs0,2), ierr )
874 sll_allocate( self%efield_dofs_work(self%n_dofs0,2), ierr )
876 if(
present(rhob) )
then
896 boundary_particles, &
905 sll_real64,
target,
intent( in ) :: efield_dofs(:,:)
906 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
907 sll_real64,
intent( in ) :: x_min
908 sll_real64,
intent( in ) :: lx
910 character(len=*),
intent( in ) :: filename
911 sll_int32,
optional,
intent( in ) :: boundary_particles
912 sll_real64,
optional,
intent(in) :: force_sign
913 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
914 logical,
optional,
intent(in) :: jmean
916 character(len=256) :: file_prefix
917 sll_int32 :: input_file, rank
918 sll_int32 :: io_stat, io_stat0, io_stat1, file_id, boundary_particles_set, max_iter
919 sll_real64 :: maxwell_tolerance, force_sign_set, iter_tolerance
922 namelist /output/ file_prefix
923 namelist /time_solver/ maxwell_tolerance
924 namelist /time_iterate/ iter_tolerance, max_iter
928 if (
present(boundary_particles))
then
929 boundary_particles_set = boundary_particles
931 boundary_particles_set = 100
934 if(
present(force_sign) )
then
935 force_sign_set = force_sign
937 force_sign_set = 1._f64
940 if (
present(jmean))
then
947 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
948 if (io_stat /= 0)
then
950 print*,
'sll_m_time_propagator_pic_vm_1d2v_trafo_helper: Input file does not exist. Set default tolerance.'
951 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
952 write(file_id, *)
'solver tolerance:', 1d-12
953 write(file_id, *)
'iter_tolerance:', 1d-10
954 write(file_id, *)
'max_iter:', 10
955 write(file_id, *)
'force_sign:', force_sign_set
958 call self%init( maxwell_solver, &
967 boundary_particles = boundary_particles_set, &
968 force_sign=force_sign_set, &
972 read(input_file, output, iostat=io_stat0)
973 read(input_file, time_solver,iostat=io_stat)
974 read(input_file, time_iterate,iostat=io_stat1)
975 if (io_stat /= 0 .and. io_stat1 /= 0)
then
977 print*,
'sll_m_time_propagator_pic_vm_1d2v_trafo_helper: Tolerance not given. Set default tolerance.'
978 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
979 write(file_id, *)
'solver tolerance:', 1d-12
980 write(file_id, *)
'iter_tolerance:', 1d-10
981 write(file_id, *)
'max_iter:', 10
982 write(file_id, *)
'force_sign:', force_sign_set
985 call self%init( maxwell_solver, &
994 boundary_particles = boundary_particles_set, &
995 force_sign=force_sign_set, &
998 else if (io_stat == 0 .and. io_stat1 /= 0)
then
1000 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1001 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1002 write(file_id, *)
'iter_tolerance:', 1d-10
1003 write(file_id, *)
'max_iter:', 10
1004 write(file_id, *)
'force_sign:', force_sign_set
1007 call self%init( maxwell_solver, &
1008 kernel_smoother_0, &
1009 kernel_smoother_1, &
1016 boundary_particles = boundary_particles_set, &
1017 solver_tolerance=maxwell_tolerance,&
1018 force_sign=force_sign_set, &
1021 else if (io_stat /= 0 .and. io_stat1 == 0)
then
1022 if (rank == 0 )
then
1023 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1024 write(file_id, *)
'solver tolerance:', 1d-12
1025 write(file_id, *)
'iter_tolerance:', iter_tolerance
1026 write(file_id, *)
'max_iter:', max_iter
1027 write(file_id, *)
'force_sign:', force_sign_set
1030 call self%init( maxwell_solver, &
1031 kernel_smoother_0, &
1032 kernel_smoother_1, &
1039 boundary_particles = boundary_particles_set, &
1040 iter_tolerance=iter_tolerance, max_iter=max_iter, &
1041 force_sign=force_sign_set, &
1045 if (rank == 0 )
then
1046 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1047 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1048 write(file_id, *)
'force_sign:', force_sign_set
1049 write(file_id, *)
'iter_tolerance:', iter_tolerance
1050 write(file_id, *)
'max_iter:', max_iter
1053 call self%init( maxwell_solver, &
1054 kernel_smoother_0, &
1055 kernel_smoother_1, &
1062 boundary_particles = boundary_particles_set, &
1063 solver_tolerance=maxwell_tolerance,&
1064 iter_tolerance=iter_tolerance, max_iter=max_iter, &
1065 force_sign=force_sign_set, &
1080 if( self%boundary )
then
1081 print*,
'left boundary', self%counter_left
1082 print*,
'right boundary', self%counter_right
1085 call self%linear_solver_1%free()
1086 call self%linear_operator_1%free()
1087 call self%particle_mass_1%free()
1089 call self%linear_solver_0%free()
1090 call self%linear_operator_0%free()
1091 call self%particle_mass_0%free()
1093 deallocate( self%j_dofs )
1094 deallocate( self%j_dofs_local )
1095 deallocate( self%particle_mass_1_local )
1096 deallocate( self%particle_mass_0_local )
1097 self%maxwell_solver => null()
1098 self%kernel_smoother_0 => null()
1099 self%kernel_smoother_1 => null()
1100 self%particle_group => null()
1101 self%efield_dofs => null()
1102 self%bfield_dofs => null()
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.
Gauss-Legendre integration.
real(kind=f64) function, dimension(2, 1:npoints), public sll_f_gauss_legendre_points_and_weights(npoints, a, b)
Returns a 2d array of size (2,npoints) containing gauss-legendre points and weights in the interval [...
module for conjugate gradient method in pure form
Module interfaces for coordinate transformation.
module for Compressed Sparse Row Matrix (CSR)
Module interface to solve Maxwell's equations in 1D.
Base class for kernel smoothers for accumulation and field evaluation in PIC.
Utilites for Maxwell solver's with spline finite elements using sparse matrix linear solvers.
subroutine, public sll_s_spline_fem_sparsity_mass(degree, n_cells, spmat)
Helper function to create sparsity pattern of the mass matrix.
Utilites for Maxwell solver's with spline finite elements.
subroutine, public sll_s_spline_fem_mass_line(degree, mass_line)
Computes the mass line for a mass matrix with degree splines.
Particle pusher based on antisymmetric splitting with AVF for 1d2v Vlasov-Poisson with coordinate tra...
subroutine delete_pic_vm_1d2v_trafo(self)
Destructor.
subroutine advect_e_pic_vm_1d2v_trafo(self, dt)
advect_e: Equations to be solved Solution with Schur complement: $ S_{+}=M_1+\frac{\Delta t^2 q^2}{4 ...
subroutine initialize_pic_vm_1d2v_trafo(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, efield_dofs, bfield_dofs, x_min, Lx, map, boundary_particles, solver_tolerance, iter_tolerance, max_iter, force_sign, rhob, jmean)
Constructor.
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_trafo(self, dt)
Finalization.
subroutine compute_particle_boundary(self, xold, xnew, vi)
Helper function for advect_x.
subroutine advect_eb_pic_vm_1d2v_trafo(self, dt)
advect_eb: Equations to be solved Solution with Schur complement: $ S=M_1+\frac{\Delta t^2}{4} D^\top...
subroutine initialize_file_pic_vm_1d2v_trafo(self, maxwell_solver, kernel_smoother_0, kernel_smoother_1, particle_group, efield_dofs, bfield_dofs, x_min, Lx, map, filename, boundary_particles, force_sign, rhob, jmean)
Constructor.
subroutine advect_ex_pic_vm_1d2v_trafo(self, dt)
advect_ex: Equations to be solved $\frac{\Xi^{n+1}-\Xi^n}{\Delta t}=\frac{DF^{-1}(\Xi^{n+1})+DF^{-1}(...
subroutine advect_vb_pic_vm_1d2v_trafo(self, dt)
advect_vb: Equations to be solved $V^{n+1}= (\cos(DF/J_F B)&\sin(DF/J_F B) \ -\sin(DF/J_F B) &\cos(DF...
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
class for the cg linear solver
type collecting functions for analytical coordinate mapping
Basic type of a kernel smoother used for PIC simulations.
Hamiltonian splitting type for Vlasov-Maxwell 1d2v.