5 #include "sll_assert.h"
6 #include "sll_errors.h"
7 #include "sll_memory.h"
8 #include "sll_working_precision.h"
115 sll_int32 :: spline_degree(3)
117 sll_real64 :: x_min(3)
118 sll_real64 :: x_max(3)
119 sll_int32 :: n_total0
120 sll_int32 :: n_total1
121 sll_int32 :: nspan_1(3), nspan_2(3)
123 sll_real64 :: betar(2) = 1._f64
125 sll_real64,
allocatable :: vec1(:)
126 sll_real64,
allocatable :: vec2(:)
128 sll_real64,
pointer :: phi_dofs(:)
129 sll_real64,
pointer :: efield_dofs(:)
130 sll_real64,
pointer :: bfield_dofs(:)
131 sll_real64,
allocatable :: j_dofs(:)
132 sll_real64,
allocatable :: j_dofs_local(:)
133 sll_real64,
allocatable :: particle_mass_1_local(:,:)
134 sll_real64,
allocatable :: particle_mass_2_local(:,:)
135 sll_real64,
allocatable :: particle_mass_3_local(:,:)
136 sll_real64,
allocatable :: particle_mass_12_local(:,:)
137 sll_real64,
allocatable :: particle_mass_21_local(:,:)
138 sll_real64,
allocatable :: particle_mass_23_local(:,:)
139 sll_real64,
allocatable :: particle_mass_32_local(:,:)
140 sll_real64,
allocatable :: particle_mass_31_local(:,:)
141 sll_real64,
allocatable :: particle_mass_13_local(:,:)
143 sll_real64 :: solver_tolerance = 1d-12
144 sll_real64 :: iter_tolerance = 1d-10
145 sll_int32 :: max_iter = 10
147 sll_int32 :: boundary_particles = 100
148 sll_int32 :: counter_left = 0
149 sll_int32 :: counter_right = 0
150 sll_real64,
pointer :: rhob(:) => null()
152 sll_real64 :: force_sign = 1._f64
153 logical :: adiabatic_electrons = .false.
154 logical :: jmean = .false.
155 logical :: boundary = .false.
157 sll_int32 :: n_particles_max
158 sll_real64,
allocatable :: xnew(:,:,:)
159 sll_real64,
allocatable :: vnew(:,:,:)
160 sll_real64,
allocatable :: efield_dofs_new(:)
161 sll_real64,
allocatable :: efield_dofs_work(:)
162 sll_real64,
allocatable :: phi_dofs_new(:)
163 sll_real64,
allocatable :: phi_dofs_work(:)
165 sll_int32 :: n_failed = 0
166 sll_int32 :: iter_counter = 0
167 sll_int32 :: niter(100000)
171 sll_int32 :: i_weight = 1
194 sll_real64,
intent( in ) :: dt
196 sll_int32 :: i_part, i, j, i_sp, iter
197 sll_real64 :: xi(3), xnew(3), xh(3), vi(3), vt(3), jmat(3,3), wall(3)
200 do i_sp = 1, self%particle_group%n_species
201 do i_part = 1, self%particle_group%group(i_sp)%n_particles
203 xi = self%particle_group%group(i_sp)%get_x(i_part)
204 vi = self%particle_group%group(i_sp)%get_v(i_part)
206 if( self%map%inverse)
then
207 xh = self%map%get_x(xi)
209 xnew = self%map%get_xi(xh)
213 jmat=self%map%jacobian_matrix_inverse(xi)
216 vt(j) = jmat(j,1)*vi(1) + jmat(j,2)*vi(2) + jmat(j,3)*vi(3)
221 err= maxval(abs(xi - xnew))
222 do while(i < self%max_iter .and. err > self%iter_tolerance)
224 jmat=self%map%jacobian_matrix_inverse( xnew )
226 xh(j) = xi(j) + 0.5_f64 * dt * (vt(j) + jmat(j,1)*vi(1) + jmat(j,2)*vi(2)+ jmat(j,3)*vi(3))
228 err = maxval(abs(xh - xnew))
235 call self%particle_group%group(i_sp)%set_x ( i_part, xnew )
236 call self%particle_group%group(i_sp)%set_v ( i_part, vi )
238 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
239 wall = self%particle_group%group(i_sp)%get_weights(i_part)
240 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
241 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
252 sll_real64,
intent( inout ) :: xold(3)
253 sll_real64,
intent( inout ) :: xnew(3)
254 sll_real64,
intent( inout ) :: vi(3)
256 sll_real64 :: xmid(3), xt(3), xbar, dx
257 sll_real64 :: jmatrix(3,3)
259 if(xnew(1) < 0._f64 .or. xnew(1) > 1._f64 )
then
260 if(xnew(1) < 0._f64 )
then
262 self%counter_left = self%counter_left+1
263 else if(xnew(1) > 1._f64)
then
265 self%counter_right = self%counter_right+1
267 dx = (xbar- xold(1))/(xnew(1)-xold(1))
268 xmid = xold + dx * (xnew-xold)
271 select case(self%boundary_particles)
273 if(xnew(1) < 0._f64 )
then
275 xnew(2) = xnew(2) + 0.5_f64
276 else if(xnew(1) > 1._f64 )
then
277 jmatrix = self%map%jacobian_matrix_inverse_transposed(xmid)
278 vi = vi-2._f64*(vi(1)*jmatrix(1,1)+vi(2)*jmatrix(2,1)+vi(3)*jmatrix(3,1))*jmatrix(:,1)/sum(jmatrix(:,1)**2)
279 xnew(1) = 2._f64 - xnew(1)
280 xnew(2) = 1._f64 - xnew(2)
284 xt(2:3) = modulo(xt(2:3),1._f64)
285 jmatrix = self%map%jacobian_matrix_inverse_transposed(xt)
286 vi = vi-2._f64*(vi(1)*jmatrix(1,1)+vi(2)*jmatrix(2,1)+vi(3)*jmatrix(3,1))*jmatrix(:,1)/sum(jmatrix(:,1)**2)
287 xnew(1) = 2._f64*xbar-xnew(1)
290 xnew(1) = modulo(xnew(1), 1._f64)
292 xnew(1) = modulo(xnew(1), 1._f64)
294 else if(xnew(1) < -1._f64 .or. xnew(1) > 2._f64 )
then
296 sll_error(
"particle boundary",
"particle out of bound")
298 xnew(2:3) = modulo(xnew(2:3), 1._f64)
308 sll_real64,
intent( in ) :: dt
310 sll_int32 :: i_part, i_sp, j
312 sll_real64 :: vi(3), xi(3), wall(3)
313 sll_real64 :: bfield(3), jmatrix(3,3), rhs(3)
314 sll_real64 :: vt(3), c(3)
316 do i_sp = 1, self%particle_group%n_species
317 qmdt = self%particle_group%group(i_sp)%species%q_over_m()*dt*0.5_f64;
318 do i_part = 1, self%particle_group%group(i_sp)%n_particles
319 vi = self%particle_group%group(i_sp)%get_v(i_part)
320 xi = self%particle_group%group(i_sp)%get_x(i_part)
322 call self%particle_mesh_coupling%evaluate &
323 (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)-1], self%bfield_dofs(1:self%n_total0), bfield(1))
324 call self%particle_mesh_coupling%evaluate &
325 (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))
326 call self%particle_mesh_coupling%evaluate &
327 (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))
329 jmatrix=self%map%jacobian_matrix_inverse(xi)
333 vt(j)=jmatrix(j,1)*vi(1)+jmatrix(j,2)*vi(2)+jmatrix(j,3)*vi(3)
336 c(1)=bfield(3)*vt(2)-bfield(2)*vt(3)
337 c(2)=bfield(1)*vt(3)-bfield(3)*vt(1)
338 c(3)=bfield(2)*vt(1)-bfield(1)*vt(2)
341 rhs(j)= vi(j) + qmdt*(jmatrix(1,j)*c(1)+jmatrix(2,j)*c(2)+jmatrix(3,j)*c(3))
346 call self%particle_group%group(i_sp)%set_v( i_part, vi )
348 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
349 wall = self%particle_group%group(i_sp)%get_weights(i_part)
350 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vi, 0.0_f64, wall(1), wall(2) )
351 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
366 sll_real64,
intent( in ) :: dt
368 call self%maxwell_solver%compute_curl_part( dt, self%efield_dofs, self%bfield_dofs, self%betar(1) )
380 sll_real64,
intent( in ) :: dt
382 sll_int32 :: i_part, j, i_sp
383 sll_real64 :: vi(3), vt(3), xi(3), wi(1), wall(3)
384 sll_real64 :: metric(3,3), jmat(3,3)
385 sll_real64 :: factor, qoverm
386 sll_real64 :: efield(3), ephys(3)
387 sll_real64 :: rhs(self%n_total1+2*self%n_total0)
390 self%j_dofs_local = 0.0_f64
391 self%j_dofs = 0.0_f64
392 self%particle_mass_1_local = 0.0_f64
393 self%particle_mass_2_local = 0.0_f64
394 self%particle_mass_3_local = 0.0_f64
395 if(self%map%flag2d)
then
396 self%particle_mass_12_local = 0.0_f64
397 self%particle_mass_21_local = 0.0_f64
398 if(self%map%flag3d)
then
399 self%particle_mass_23_local = 0.0_f64
400 self%particle_mass_32_local = 0.0_f64
401 self%particle_mass_31_local = 0.0_f64
402 self%particle_mass_13_local = 0.0_f64
406 self%particle_mass_1%particle_mass = 0.0_f64
407 self%particle_mass_2%particle_mass = 0.0_f64
408 self%particle_mass_3%particle_mass = 0.0_f64
409 if(self%map%flag2d)
then
410 self%particle_mass_12%particle_mass = 0.0_f64
411 self%particle_mass_21%particle_mass = 0.0_f64
412 if(self%map%flag3d)
then
413 self%particle_mass_23%particle_mass = 0.0_f64
414 self%particle_mass_32%particle_mass = 0.0_f64
415 self%particle_mass_13%particle_mass = 0.0_f64
416 self%particle_mass_31%particle_mass = 0.0_f64
421 do i_sp = 1, self%particle_group%n_species
422 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
423 if( self%adiabatic_electrons )
then
424 factor = dt**2 * 0.25_f64* qoverm
426 factor = dt**2 * self%betar(2) * 0.25_f64* qoverm
428 do i_part = 1, self%particle_group%group(i_sp)%n_particles
429 vi = self%particle_group%group(i_sp)%get_v(i_part)
430 xi = self%particle_group%group(i_sp)%get_x(i_part)
433 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
435 metric= self%map%metric_inverse( xi )
436 jmat=self%map%jacobian_matrix_inverse( xi )
438 vt(j)=vi(1)*jmat(j,1)+vi(2)*jmat(j,2)+vi(3)*jmat(j,3)
442 call self%particle_mesh_coupling%add_charge( xi, wi(1)*vt(1), &
443 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
444 self%j_dofs_local(1:self%n_total1) )
445 call self%particle_mesh_coupling%add_charge( xi, wi(1)*vt(2), &
446 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
447 self%j_dofs_local(1+self%n_total1:self%n_total1+self%n_total0) )
448 call self%particle_mesh_coupling%add_charge( xi, wi(1)*vt(3), &
449 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
450 self%j_dofs_local(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0) )
454 call self%particle_mesh_coupling%add_particle_mass( xi, wi(1)*metric(1,1) * factor, &
455 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
456 self%particle_mass_1_local )
457 call self%particle_mesh_coupling%add_particle_mass( xi, wi(1)*metric(2,2) * factor, &
458 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
459 self%particle_mass_2_local )
460 call self%particle_mesh_coupling%add_particle_mass( xi, wi(1)*metric(3,3) * factor, &
461 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
462 self%particle_mass_3_local )
463 if(self%map%flag2d)
then
464 call self%particle_mesh_coupling%add_particle_mass_od( xi, wi(1)*metric(1,2) * factor, &
465 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
466 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)],&
467 self%particle_mass_12_local )
468 call self%particle_mesh_coupling%add_particle_mass_od( xi, wi(1)*metric(2,1) * factor, &
469 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)],&
470 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
471 self%particle_mass_21_local )
472 if(self%map%flag3d)
then
473 call self%particle_mesh_coupling%add_particle_mass_od( xi, wi(1)*metric(2,3) * factor, &
474 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
475 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
476 self%particle_mass_23_local )
477 call self%particle_mesh_coupling%add_particle_mass_od( xi, wi(1)*metric(3,2) * factor, &
478 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
479 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
480 self%particle_mass_32_local )
481 call self%particle_mesh_coupling%add_particle_mass_od( xi, wi(1)*metric(3,1) * factor, &
482 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
483 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
484 self%particle_mass_31_local )
485 call self%particle_mesh_coupling%add_particle_mass_od( xi, wi(1)*metric(1,3) * factor, &
486 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
487 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
488 self%particle_mass_13_local )
494 call self%particle_mesh_coupling%evaluate &
495 (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
496 self%efield_dofs(1:self%n_total1), efield(1))
497 call self%particle_mesh_coupling%evaluate &
498 (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
499 self%efield_dofs(1+self%n_total1:self%n_total1+self%n_total0), efield(2))
500 call self%particle_mesh_coupling%evaluate &
501 (xi, [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
502 self%efield_dofs(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0), efield(3))
506 ephys(j) = jmat(1,j)* efield(1)+jmat(2,j)* efield(2)+jmat(3,j)* efield(3)
510 vi = vi + dt* 0.5_f64* qoverm * ephys
512 call self%particle_group%group(i_sp)%set_v( i_part, vi )
514 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
515 wall = self%particle_group%group(i_sp)%get_weights(i_part)
516 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vi, 0.0_f64, wall(1), wall(2) )
517 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
524 self%n_total1+self%n_total0*2, mpi_sum, self%j_dofs )
526 if ( self%jmean )
then
527 self%j_dofs(1:self%n_total1) = self%j_dofs(1:self%n_total1) - sum(self%j_dofs(1:self%n_total1))/real(self%n_total1, f64)
528 self%j_dofs(1+self%n_total1:self%n_total1+self%n_total0) = self%j_dofs(1+self%n_total1:self%n_total1+self%n_total0) - sum(self%j_dofs(1+self%n_total1:self%n_total1+self%n_total0))/real(self%n_total0, f64)
529 self%j_dofs(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0) = self%j_dofs(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0) - sum(self%j_dofs(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0))/real(self%n_total0, f64)
533 self%n_total1*self%nspan_1(1) , mpi_sum, self%particle_mass_1%particle_mass)
535 self%n_total0*self%nspan_1(2) , mpi_sum, self%particle_mass_2%particle_mass)
537 self%n_total0*self%nspan_1(3) , mpi_sum, self%particle_mass_3%particle_mass)
539 if(self%map%flag2d)
then
541 self%n_total1*self%nspan_2(1) , mpi_sum, self%particle_mass_12%particle_mass)
543 self%n_total0*self%nspan_2(1) , mpi_sum, self%particle_mass_21%particle_mass)
544 if(self%map%flag3d)
then
546 self%n_total0*self%nspan_2(2) , mpi_sum, self%particle_mass_23%particle_mass)
548 self%n_total0*self%nspan_2(3) , mpi_sum, self%particle_mass_31%particle_mass)
550 self%n_total0*self%nspan_2(2) , mpi_sum, self%particle_mass_32%particle_mass)
552 self%n_total1*self%nspan_2(3) , mpi_sum, self%particle_mass_13%particle_mass)
556 call self%particle_mass_op%set( 1, 1, self%particle_mass_1 )
557 call self%particle_mass_op%set( 2, 2, self%particle_mass_2 )
558 call self%particle_mass_op%set( 3, 3, self%particle_mass_3 )
559 if(self%map%flag2d)
then
560 call self%particle_mass_op%set( 1, 2, self%particle_mass_12 )
561 call self%particle_mass_op%set( 2, 1, self%particle_mass_21 )
562 if(self%map%flag3d)
then
563 call self%particle_mass_op%set( 2, 3, self%particle_mass_23 )
564 call self%particle_mass_op%set( 3, 2, self%particle_mass_32 )
565 call self%particle_mass_op%set( 3, 1, self%particle_mass_31 )
566 call self%particle_mass_op%set( 1, 3, self%particle_mass_13 )
570 if( self%adiabatic_electrons )
then
572 self%linear_op_schur_phiv%sign = -1._f64
573 call self%linear_op_schur_phiv%dot(self%phi_dofs, rhs(1: self%n_total0 ))
574 call self%maxwell_solver%multiply_gt( self%j_dofs, rhs(self%n_total0+1: 2*self%n_total0 ) )
575 rhs(1: self%n_total0 ) = rhs(1: self%n_total0 ) + dt * rhs(self%n_total0+1: 2*self%n_total0 )
578 self%linear_op_schur_phiv%sign = 1._f64
579 call self%linear_solver_schur_phiv%set_guess(self%phi_dofs)
580 call self%linear_solver_schur_phiv%solve( rhs(1: self%n_total0 ), self%phi_dofs )
581 if( self%boundary )
then
582 do j = 1, self%maxwell_solver%n_dofs(2)*self%maxwell_solver%n_dofs(3)
583 self%phi_dofs(1+(j-1)*self%maxwell_solver%n_dofs(1)) = 0._f64
584 self%phi_dofs(j*self%maxwell_solver%n_dofs(1)) = 0._f64
587 call self%maxwell_solver%multiply_g( self%phi_dofs, self%efield_dofs )
588 self%efield_dofs = -self%efield_dofs
591 self%linear_op_schur_ev%sign = -self%force_sign
592 call self%linear_op_schur_ev%dot(self%efield_dofs, rhs)
593 rhs = rhs - self%force_sign *dt * self%betar(2) * self%j_dofs
596 self%linear_op_schur_ev%sign = self%force_sign
597 call self%linear_solver_schur_ev%set_guess(self%efield_dofs)
598 call self%linear_solver_schur_ev%solve(rhs, self%efield_dofs)
601 if( self%boundary )
then
602 do j = 1, self%maxwell_solver%n_dofs(2)*self%maxwell_solver%n_dofs(3)
603 self%efield_dofs(self%n_total1+1+(j-1)*self%maxwell_solver%n_dofs(1)) = 0._f64
604 self%efield_dofs(self%n_total1+j*self%maxwell_solver%n_dofs(1)) = 0._f64
605 self%efield_dofs(self%n_total1+self%n_total0+1+(j-1)*self%maxwell_solver%n_dofs(1)) = 0._f64
606 self%efield_dofs(self%n_total1+self%n_total0+j*self%maxwell_solver%n_dofs(1)) = 0._f64
610 do i_sp = 1, self%particle_group%n_species
611 qoverm = self%particle_group%group(i_sp)%species%q_over_m();
612 do i_part = 1, self%particle_group%group(i_sp)%n_particles
613 vi = self%particle_group%group(i_sp)%get_v(i_part)
614 xi = self%particle_group%group(i_sp)%get_x(i_part)
617 call self%particle_mesh_coupling%evaluate &
618 (xi, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
619 self%efield_dofs(1:self%n_total1), efield(1))
620 call self%particle_mesh_coupling%evaluate &
621 (xi, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
622 self%efield_dofs(1+self%n_total1:self%n_total1+self%n_total0), efield(2))
623 call self%particle_mesh_coupling%evaluate &
624 (xi, [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
625 self%efield_dofs(1+self%n_total1+self%n_total0:self%n_total1+2*self%n_total0), efield(3))
627 jmat = self%map%jacobian_matrix_inverse_transposed(xi)
629 ephys(j) = jmat(j,1)* efield(1)+jmat(j,2)* efield(2)+jmat(j,3)* efield(3)
633 vi = vi + dt* 0.5_f64* qoverm* ephys
635 call self%particle_group%group(i_sp)%set_v( i_part, vi )
638 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
639 wall = self%particle_group%group(i_sp)%get_weights(i_part)
640 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xi, vi, 0.0_f64, wall(1), wall(2) )
641 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
656 sll_real64,
intent( in ) :: dt
658 sll_int32 :: i_part, i_sp, j
659 sll_real64 :: vi(3), vh(3), xi(3), xs(3), wi(1), mi(1), xnew(3), vbar(3), vnew(3)
660 sll_real64 :: sign, wall(3)
661 sll_real64 :: jmat(3,3), jmatrix(3,3)
663 sll_real64 :: residual(8), residual_local(8)
664 sll_real64 :: xmid(3), xbar, dx
665 sll_real64 :: efield(3)
667 self%efield_dofs_new = self%efield_dofs
668 self%phi_dofs_new = self%phi_dofs
669 do i_sp=1,self%particle_group%n_species
670 do i_part = 1,self%particle_group%group(i_sp)%n_particles
671 vi = self%particle_group%group(i_sp)%get_v(i_part)
672 xi = self%particle_group%group(i_sp)%get_x(i_part)
675 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
677 if( self%map%inverse)
then
678 xs = self%map%get_x(xi)
680 xnew = self%map%get_xi(xs)
682 jmat = self%map%jacobian_matrix_inverse_transposed( xi )
684 vh(j) = jmat(1,j)*vi(1) + jmat(2,j)*vi(2) + jmat(3,j)*vi(3)
689 if(xnew(1) < 0._f64 .or. xnew(1) > 1._f64 )
then
690 if(xnew(1) < 0._f64 )
then
692 else if(xnew(1) > 1._f64)
then
695 dx = (xbar- xi(1))/(xnew(1)-xi(1))
696 xmid = xi + dx * (xnew-xi)
702 vh = (xnew-xi) * wi(1)
703 call self%particle_mesh_coupling%add_current_evaluate( xi, xnew, vh, self%efield_dofs, &
704 self%j_dofs_local, efield )
706 vnew(j) = vi(j) + dx*sign*(jmat(j,1)*efield(1) + jmat(j,2)*efield(2) + jmat(j,3)*efield(3))
708 xnew(2:3) = modulo(xnew(2:3), 1._f64)
710 self%vnew(i_sp,:, i_part) = vnew
711 self%xnew(i_sp,:, i_part) = xnew
714 self%j_dofs = 0.0_f64
717 self%n_total1+2*self%n_total0, mpi_sum, self%j_dofs )
719 if( self%adiabatic_electrons)
then
720 call self%maxwell_solver%compute_phi_from_j( self%j_dofs, self%phi_dofs_new, self%efield_dofs_new )
722 call self%maxwell_solver%compute_E_from_j( self%betar(2)*self%j_dofs, self%efield_dofs_new )
728 do while ( (maxval(residual(1:7)) > self%iter_tolerance) .and. niter < self%max_iter )
730 self%efield_dofs_work = 0.5_f64*( self%efield_dofs + self%efield_dofs_new )
731 self%j_dofs_local = 0.0_f64
732 residual_local = 0._f64
734 do i_sp = 1, self%particle_group%n_species
735 sign = dt*self%particle_group%group(i_sp)%species%q_over_m();
736 do i_part = 1,self%particle_group%group(i_sp)%n_particles
737 vi = self%particle_group%group(i_sp)%get_v(i_part)
738 xi = self%particle_group%group(i_sp)%get_x(i_part)
741 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
742 mi = self%particle_group%group(i_sp)%get_mass(i_part, self%i_weight)
743 vbar = 0.5_f64 * (self%vnew(i_sp,:, i_part)+vi)
744 xnew = self%xnew(i_sp,:, i_part)
746 if( self%map%inverse)
then
747 xs = self%map%get_x(xi)
749 xnew = self%map%get_xi(xs)
751 jmat = self%map%jacobian_matrix_inverse_transposed( xi )
752 jmatrix=self%map%jacobian_matrix_inverse_transposed( xnew )
754 vh(j) = 0.5_f64 * ((jmatrix(1,j)+jmat(1,j))*vbar(1) + (jmatrix(2,j)+jmat(2,j))*vbar(2) + (jmatrix(3,j)+ jmat(3,j))*vbar(3))
761 residual_local(1) = residual_local(1) + (xnew(1)-self%xnew(i_sp,1,i_part))**2*abs(wi(1))
762 residual_local(2) = residual_local(2) + (xnew(2)-self%xnew(i_sp,2,i_part))**2*abs(wi(1))
763 residual_local(3) = residual_local(3) + (xnew(3)-self%xnew(i_sp,3,i_part))**2*abs(wi(1))
765 residual_local(4) = residual_local(4) + (vi(1)-self%vnew(i_sp,1,i_part))**2*abs(wi(1))
766 residual_local(5) = residual_local(5) + (vi(2)-self%vnew(i_sp,2,i_part))**2*abs(wi(1))
767 residual_local(6) = residual_local(6) + (vi(3)-self%vnew(i_sp,3,i_part))**2*abs(wi(1))
769 residual_local(7) = residual_local(7) + mi(1)*0.5_f64*( vi(1)**2 + vi(2)**2 + vi(3)**2-self%vnew(i_sp,1,i_part)**2 -self%vnew(i_sp,2,i_part)**2 -self%vnew(i_sp,3,i_part)**2 )
771 self%xnew(i_sp, :, i_part) = xnew
772 self%vnew(i_sp, :, i_part) = vi
776 self%j_dofs = 0.0_f64
779 self%n_total1+2*self%n_total0, mpi_sum, self%j_dofs )
781 if( self%adiabatic_electrons)
then
782 self%phi_dofs_work = self%phi_dofs
783 call self%maxwell_solver%compute_phi_from_j( self%j_dofs, self%phi_dofs_work, self%efield_dofs_work )
786 residual_local(8) = residual_local(8) + 0.5_f64*(self%maxwell_solver%inner_product( self%phi_dofs_work, self%phi_dofs_work, 0 ) - self%maxwell_solver%inner_product( self%phi_dofs_new, self%phi_dofs_new, 0 ) )
788 residual_local(7) = (sum((self%phi_dofs_work-self%phi_dofs_new)**2))*product(self%particle_mesh_coupling%delta_x)
790 self%efield_dofs_work = self%efield_dofs
791 call self%maxwell_solver%compute_E_from_j( self%betar(2)*self%j_dofs, self%efield_dofs_work )
794 residual_local(8) = residual_local(8) + 0.5_f64*(self%maxwell_solver%inner_product( self%efield_dofs_work, self%efield_dofs_work, 1 ) - self%maxwell_solver%inner_product( self%efield_dofs_new, self%efield_dofs_new, 1 ) )
796 residual_local(7) = (sum((self%efield_dofs_work-self%efield_dofs_new)**2))*product(self%particle_mesh_coupling%delta_x)
800 residual(1:7) = sqrt(residual(1:7))
801 residual(8) = abs(residual(8))
803 self%phi_dofs_new = self%phi_dofs_work
804 self%efield_dofs_new = self%efield_dofs_work
807 if ( maxval(residual(1:7)) > self%iter_tolerance )
then
808 print*,
'Warning: Iteration no.', self%iter_counter+1 ,
'did not converge.', residual, niter
809 self%n_failed = self%n_failed+1
813 self%efield_dofs_work = 0.5_f64*( self%efield_dofs + self%efield_dofs_new )
814 self%j_dofs_local = 0.0_f64
817 do i_sp=1,self%particle_group%n_species
818 sign = dt*self%particle_group%group(i_sp)%species%q_over_m();
819 do i_part = 1,self%particle_group%group(i_sp)%n_particles
820 vi = self%particle_group%group(i_sp)%get_v(i_part)
821 xi = self%particle_group%group(i_sp)%get_x(i_part)
824 wi = self%particle_group%group(i_sp)%get_charge(i_part, self%i_weight)
825 vbar = 0.5_f64 * (self%vnew(i_sp,:, i_part)+vi)
826 xnew = self%xnew(i_sp,:, i_part)
828 if( self%map%inverse)
then
829 xs = self%map%get_x(xi)
831 xnew = self%map%get_xi(xs)
833 jmat = self%map%jacobian_matrix_inverse_transposed( xi )
834 jmatrix=self%map%jacobian_matrix_inverse_transposed( xnew )
836 vh(j) = 0.5_f64 * ((jmatrix(1,j)+jmat(1,j))*vbar(1) + (jmatrix(2,j)+jmat(2,j))*vbar(2) + (jmatrix(3,j)+ jmat(3,j))*vbar(3))
842 call self%particle_group%group(i_sp)%set_v( i_part, vi )
843 call self%particle_group%group(i_sp)%set_x( i_part, xnew )
845 if (self%particle_group%group(i_sp)%n_weights == 3 )
then
846 wall = self%particle_group%group(i_sp)%get_weights(i_part)
847 wall(3) = self%control_variate%cv(i_sp)%update_df_weight( xnew, vi, 0.0_f64, wall(1), wall(2) )
848 call self%particle_group%group(i_sp)%set_weights( i_part, wall )
853 self%j_dofs = 0.0_f64
856 self%n_total1+2*self%n_total0, mpi_sum, self%j_dofs )
858 if( self%adiabatic_electrons)
then
859 call self%maxwell_solver%compute_phi_from_j( self%j_dofs, self%phi_dofs, self%efield_dofs )
861 call self%maxwell_solver%compute_E_from_j( self%betar(2)*self%j_dofs, self%efield_dofs )
864 self%iter_counter = self%iter_counter + 1
865 self%niter(self%iter_counter) = niter
873 sll_real64,
intent( in ) :: xi(3)
874 sll_real64,
intent( inout ) :: xnew(3)
875 sll_real64,
intent( inout ) :: vi(3)
876 sll_real64,
intent( in ) :: wi(1)
877 sll_real64,
intent( in ) :: sign
879 sll_real64 :: xmid(3), xt(3), vh(3), xbar, dx
880 sll_real64 :: jmatrix(3,3), jmat(3,3), efield(3)
883 jmat = self%map%jacobian_matrix_inverse_transposed( xi )
884 if(xnew(1) < -1._f64 .or. xnew(1) > 2._f64)
then
886 sll_error(
"particle boundary",
"particle out of bound")
887 else if(xnew(1) < 0._f64 .or. xnew(1) > 1._f64 )
then
888 if(xnew(1) < 0._f64 )
then
890 else if(xnew(1) > 1._f64)
then
893 dx = (xbar- xi(1))/(xnew(1)-xi(1))
894 xmid = xi + dx * (xnew-xi)
897 vh = (xmid-xi) * wi(1)
898 call self%particle_mesh_coupling%add_current_evaluate( xi, xmid, vh, self%efield_dofs_work, &
899 self%j_dofs_local, efield )
902 xt(2:3) = modulo(xt(2:3), 1._f64)
903 jmatrix = self%map%jacobian_matrix_inverse_transposed(xt)
905 vi(j) = vi(j) + dx*sign*0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2) + (jmatrix(j,3)+ jmat(j,3))*efield(3))
907 select case(self%boundary_particles)
909 call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
910 xmid(2) = xbar + (1._f64-2._f64*xbar)*xmid(2) + 0.5_f64-0.5_f64*xbar
911 xt(2:3) = modulo(xt(2:3), 1._f64)
912 jmatrix = self%map%jacobian_matrix_inverse_transposed(xt)
913 call self%particle_mesh_coupling%add_charge(xmid, -wi(1), self%spline_degree, self%rhob)
914 xnew(1) = 2._f64*xbar-xnew(1)
915 xnew(2) = xbar + (1._f64-2._f64*xbar)*xnew(2) + 0.5_f64-0.5_f64*xbar
916 if(xnew(1) > 1._f64 )
then
917 vi = vi-2._f64*(vi(1)*jmatrix(1,1)+vi(2)*jmatrix(2,1)+vi(3)*jmatrix(3,1))*jmatrix(:,1)/sum(jmatrix(:,1)**2)
920 xnew(1) = 2._f64*xbar-xnew(1)
921 vi = vi-2._f64*(vi(1)*jmatrix(1,1)+vi(2)*jmatrix(2,1)+vi(3)*jmatrix(3,1))*jmatrix(:,1)/sum(jmatrix(:,1)**2)
923 call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
925 xnew(1) = modulo(xnew(1), 1._f64)
926 xmid(1) = 1._f64-xbar
928 xnew(1) = modulo(xnew(1), 1._f64)
929 xmid(1) = 1._f64-xbar
931 vh = (xnew - xmid)*wi(1)
932 call self%particle_mesh_coupling%add_current_evaluate( xmid, xnew, vh, self%efield_dofs_work, &
933 self%j_dofs_local, efield )
934 xnew(2:3) = modulo(xnew(2:3), 1._f64)
935 jmat = self%map%jacobian_matrix_inverse_transposed(xnew)
937 vi(j) = vi(j) + (1._f64-dx) * sign *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2) + (jmatrix(j,3)+ jmat(j,3))*efield(3))
941 vh(j) = jmat(1,j)*vi(1) + jmat(2,j)*vi(2) + jmat(3,j)*vi(3)
944 jmat = self%map%jacobian_matrix(xnew)
946 vi(j) = jmat(j,1)*vh(1) + jmat(j,2)*vh(2) + jmat(j,3)*vh(3)
950 vh = (xnew-xi) * wi(1)
951 call self%particle_mesh_coupling%add_current_evaluate( xi, xnew, vh, self%efield_dofs_work, &
952 self%j_dofs_local, efield )
953 xnew(2:3) = modulo(xnew(2:3), 1._f64)
954 jmatrix = self%map%jacobian_matrix_inverse_transposed(xnew)
956 vi(j) = vi(j) + sign *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2) + (jmatrix(j,3)+ jmat(j,3))*efield(3))
966 sll_real64,
intent( in ) :: xi(3)
967 sll_real64,
intent( inout ) :: xnew(3)
968 sll_real64,
intent( inout ) :: vi(3)
969 sll_real64,
intent( in ) :: wi(1)
970 sll_real64,
intent( in ) :: sign
972 sll_real64 :: xmid(3), xt(3), vh(3), xbar, dx
973 sll_real64 :: jmatrix(3,3), jmat(3,3), efield(3)
976 jmat = self%map%jacobian_matrix_inverse_transposed( xi )
978 if(xnew(1) < -1._f64 .or. xnew(1) > 2._f64)
then
980 sll_error(
"particle boundary",
"particle out of bound")
981 else if(xnew(1) < 0._f64 .or. xnew(1) > 1._f64 )
then
982 if(xnew(1) < 0._f64 )
then
984 self%counter_left = self%counter_left+1
985 else if(xnew(1) > 1._f64)
then
987 self%counter_right = self%counter_right+1
989 dx = (xbar- xi(1))/(xnew(1)-xi(1))
990 xmid = xi + dx * (xnew-xi)
993 vh = (xmid-xi) * wi(1)
994 call self%particle_mesh_coupling%add_current_evaluate( xi, xmid, vh, self%efield_dofs_work, &
995 self%j_dofs_local, efield )
998 xt(2:3) = modulo(xt(2:3), 1._f64)
999 jmatrix = self%map%jacobian_matrix_inverse_transposed(xt)
1001 vi(j) = vi(j) + dx*sign *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2) + (jmatrix(j,3)+ jmat(j,3))*efield(3))
1003 select case(self%boundary_particles)
1005 call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
1006 xmid(2) = xbar + (1._f64-2._f64*xbar)*xmid(2) + 0.5_f64-0.5_f64*xbar
1007 xt(2:3) = modulo(xt(2:3), 1._f64)
1008 jmatrix = self%map%jacobian_matrix_inverse_transposed(xt)
1009 call self%particle_mesh_coupling%add_charge(xmid, -wi(1), self%spline_degree, self%rhob)
1010 xnew(1) = 2._f64*xbar-xnew(1)
1011 xnew(2) = xbar + (1._f64-2._f64*xbar)*xnew(2) + 0.5_f64-0.5_f64*xbar
1012 if(xnew(1) > 1._f64 )
then
1013 vi = vi-2._f64*(vi(1)*jmatrix(1,1)+vi(2)*jmatrix(2,1)+vi(3)*jmatrix(3,1))*jmatrix(:,1)/sum(jmatrix(:,1)**2)
1016 xnew(1) = 2._f64*xbar-xnew(1)
1017 vi = vi-2._f64*(vi(1)*jmatrix(1,1)+vi(2)*jmatrix(2,1)+vi(3)*jmatrix(3,1))*jmatrix(:,1)/sum(jmatrix(:,1)**2)
1019 call self%particle_mesh_coupling%add_charge(xmid, wi(1), self%spline_degree, self%rhob)
1021 xnew(1) = modulo(xnew(1), 1._f64)
1022 xmid(1) = 1._f64-xbar
1024 xnew(1) = modulo(xnew(1), 1._f64)
1025 xmid(1) = 1._f64-xbar
1027 vh = (xnew - xmid)*wi(1)
1028 call self%particle_mesh_coupling%add_current_evaluate( xmid, xnew, vh, self%efield_dofs_work, &
1029 self%j_dofs_local, efield )
1030 xnew(2:3) = modulo(xnew(2:3), 1._f64)
1031 jmat = self%map%jacobian_matrix_inverse_transposed(xnew)
1033 vi(j) = vi(j) + (1._f64-dx)*sign *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2) + (jmatrix(j,3)+ jmat(j,3))*efield(3))
1036 vh = (xnew-xi) * wi(1)
1037 call self%particle_mesh_coupling%add_current_evaluate( xi, xnew, vh, self%efield_dofs_work, &
1038 self%j_dofs_local, efield )
1039 xnew(2:3) = modulo(xnew(2:3), 1._f64)
1040 jmatrix = self%map%jacobian_matrix_inverse_transposed(xnew)
1042 vi(j) = vi(j) + sign *0.5_f64*((jmatrix(j,1)+jmat(j,1))*efield(1) + (jmatrix(j,2)+jmat(j,2))*efield(2) + (jmatrix(j,3)+ jmat(j,3))*efield(3))
1054 particle_mesh_coupling, &
1062 boundary_particles, &
1064 iter_tolerance, max_iter, &
1074 sll_real64,
target,
intent( in ) :: phi_dofs(:)
1075 sll_real64,
target,
intent( in ) :: efield_dofs(:)
1076 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
1077 sll_real64,
intent( in ) :: x_min(3)
1078 sll_real64,
intent( in ) :: lx(3)
1080 sll_int32,
optional,
intent( in ) :: boundary_particles
1081 sll_real64,
optional,
intent( in ) :: solver_tolerance
1082 sll_real64,
optional,
intent( in ) :: iter_tolerance
1083 sll_int32,
optional,
intent( in ) :: max_iter
1084 sll_real64,
optional,
intent( in ) :: betar(2)
1085 sll_real64,
optional,
intent(in) :: force_sign
1086 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
1088 logical,
optional,
intent(in) :: jmean
1090 sll_int32 :: ierr, j
1092 if (
present(solver_tolerance) )
then
1093 self%solver_tolerance = solver_tolerance
1096 if (
present(iter_tolerance) )
then
1097 self%iter_tolerance = iter_tolerance
1100 if (
present(max_iter) )
then
1101 self%max_iter = max_iter
1104 if(
present(force_sign) )
then
1105 self%force_sign = force_sign
1108 if (self%force_sign == 1._f64)
then
1109 if( particle_group%group(1)%species%q > 0._f64) self%adiabatic_electrons = .true.
1112 if (
present(jmean))
then
1116 if (
present(boundary_particles) )
then
1117 self%boundary_particles = boundary_particles
1120 if(
present(rhob) )
then
1125 self%maxwell_solver => maxwell_solver
1126 self%particle_mesh_coupling => particle_mesh_coupling
1127 self%particle_group => particle_group
1128 self%phi_dofs => phi_dofs
1129 self%efield_dofs => efield_dofs
1130 self%bfield_dofs => bfield_dofs
1132 self%n_total0 = self%maxwell_solver%n_total0
1133 self%n_total1 = self%maxwell_solver%n_total1
1134 self%spline_degree = self%particle_mesh_coupling%spline_degree
1135 self%x_min = self%map%get_x([0._f64,0._f64,0._f64])
1136 self%Lx = self%map%Lx
1137 self%x_max = x_min + lx
1140 self%nspan_1(1) = (2*self%spline_degree(1)-1)*(2*self%spline_degree(2)+1)*(2*self%spline_degree(3)+1)
1141 self%nspan_1(2) = (2*self%spline_degree(1)+1)*(2*self%spline_degree(2)-1)*(2*self%spline_degree(3)+1)
1142 self%nspan_1(3) = (2*self%spline_degree(1)+1)*(2*self%spline_degree(2)+1)*(2*self%spline_degree(3)-1)
1144 self%nspan_2(1) = (2*self%spline_degree(1))*(2*self%spline_degree(2))*(2*self%spline_degree(3)+1)
1145 self%nspan_2(2) = (2*self%spline_degree(1)+1)*(2*self%spline_degree(2))*(2*self%spline_degree(3))
1146 self%nspan_2(3) = (2*self%spline_degree(1))*(2*self%spline_degree(2)+1)*(2*self%spline_degree(3))
1148 sll_allocate( self%vec1(1:self%n_total1+self%n_total0*2), ierr )
1149 sll_allocate( self%vec2(1:self%n_total1+self%n_total0*2), ierr )
1152 sll_allocate( self%j_dofs(1:self%n_total1+self%n_total0*2), ierr )
1153 sll_allocate( self%j_dofs_local(1:self%n_total1+self%n_total0*2), ierr )
1154 sll_allocate( self%particle_mass_1_local(1:self%nspan_1(1), 1:self%n_total1), ierr )
1155 sll_allocate( self%particle_mass_2_local(1:self%nspan_1(2), 1:self%n_total0), ierr )
1156 sll_allocate( self%particle_mass_3_local(1:self%nspan_1(3), 1:self%n_total0), ierr )
1157 sll_allocate( self%particle_mass_12_local(1:self%nspan_2(1), 1:self%n_total1), ierr )
1158 sll_allocate( self%particle_mass_23_local(1:self%nspan_2(2), 1:self%n_total0), ierr )
1159 sll_allocate( self%particle_mass_31_local(1:self%nspan_2(3), 1:self%n_total0), ierr )
1160 sll_allocate( self%particle_mass_21_local(1:self%nspan_2(1), 1:self%n_total0), ierr )
1161 sll_allocate( self%particle_mass_32_local(1:self%nspan_2(2), 1:self%n_total0), ierr )
1162 sll_allocate( self%particle_mass_13_local(1:self%nspan_2(3), 1:self%n_total1), ierr )
1164 if( self%particle_mesh_coupling%n_cells(1)+self%spline_degree(1) == self%maxwell_solver%n_dofs(1) )
then
1165 self%boundary = .true.
1169 if(self%map%flag2d)
then
1172 if(self%map%flag3d)
then
1183 if(self%map%flag2d)
then
1186 if(self%map%flag3d)
then
1195 call self%particle_mass_1%create( self%particle_mesh_coupling%n_cells, [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)] )
1196 call self%particle_mass_2%create( self%particle_mesh_coupling%n_cells, [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)] )
1197 call self%particle_mass_3%create( self%particle_mesh_coupling%n_cells, [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1] )
1199 if(self%map%flag2d)
then
1200 call self%particle_mass_12%create( self%particle_mesh_coupling%n_cells, &
1201 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
1202 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)] )
1203 call self%particle_mass_21%create( self%particle_mesh_coupling%n_cells, &
1204 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
1205 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)] )
1206 if(self%map%flag3d)
then
1207 call self%particle_mass_23%create( self%particle_mesh_coupling%n_cells, &
1208 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)], &
1209 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1] )
1210 call self%particle_mass_32%create( self%particle_mesh_coupling%n_cells, &
1211 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
1212 [self%spline_degree(1), self%spline_degree(2)-1, self%spline_degree(3)] )
1213 call self%particle_mass_31%create( self%particle_mesh_coupling%n_cells, &
1214 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1], &
1215 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)] )
1216 call self%particle_mass_13%create( self%particle_mesh_coupling%n_cells, &
1217 [self%spline_degree(1)-1, self%spline_degree(2), self%spline_degree(3)], &
1218 [self%spline_degree(1), self%spline_degree(2), self%spline_degree(3)-1] )
1221 call self%particle_mass_op%create( 3, 3 )
1223 if( self%adiabatic_electrons )
then
1224 call self%linear_op_schur_phiv%create( self%maxwell_solver, self%particle_mass_op )
1225 call self%linear_solver_schur_phiv%create( self%linear_op_schur_phiv )
1226 self%linear_solver_schur_phiv%atol = self%solver_tolerance
1229 call self%linear_op_schur_ev%create( self%maxwell_solver, self%particle_mass_op )
1230 call self%preconditioner_fft%init( self%maxwell_solver%Lx, self%maxwell_solver%n_cells, self%maxwell_solver%s_deg_0, self%boundary )
1232 if( self%boundary )
then
1234 call self%maxwell_solver%multiply_mass( [1], self%vec1, self%vec2 )
1235 do j = 1, self%maxwell_solver%n_dofs(2)*self%maxwell_solver%n_dofs(3)
1236 self%vec2(self%n_total1+1+(j-1)*self%maxwell_solver%n_dofs(1)) = 1._f64
1237 self%vec2(self%n_total1+j*self%maxwell_solver%n_dofs(1)) = 1._f64
1238 self%vec2(self%n_total1+self%n_total0+1+(j-1)*self%maxwell_solver%n_dofs(1)) = 1._f64
1239 self%vec2(self%n_total1+self%n_total0+j*self%maxwell_solver%n_dofs(1)) = 1._f64
1241 self%vec2 = 1._f64/sqrt(abs(self%vec2))
1242 call self%preconditioner1%create( self%preconditioner_fft%inverse_mass1_3d, self%vec2, 2*self%n_total0+self%n_total1 )
1243 call self%linear_solver_schur_ev%create( self%linear_op_schur_ev, self%preconditioner1)
1245 call self%linear_solver_schur_ev%create( self%linear_op_schur_ev, self%preconditioner_fft%inverse_mass1_3d )
1247 self%linear_solver_schur_ev%atol = self%solver_tolerance/maxval(self%Lx)
1251 if (
present(betar))
then
1254 self%betar = 1.0_f64
1257 self%n_particles_max = self%particle_group%group(1)%n_particles
1258 do j = 2,self%particle_group%n_species
1259 self%n_particles_max = max(self%n_particles_max, self%particle_group%group(j)%n_particles )
1262 sll_allocate( self%xnew(self%particle_group%n_species,3,self%n_particles_max), ierr )
1263 sll_allocate( self%vnew(self%particle_group%n_species,3,self%n_particles_max), ierr )
1264 sll_allocate( self%efield_dofs_new(self%n_total1+2*self%n_total0), ierr )
1265 sll_allocate( self%efield_dofs_work(self%n_total1+2*self%n_total0), ierr )
1266 sll_allocate( self%phi_dofs_work(self%n_total0), ierr )
1267 sll_allocate( self%phi_dofs_new(self%n_total0), ierr )
1270 self%efield_dofs_new = 0._f64
1271 self%phi_dofs_new = 0._f64
1272 self%phi_dofs_work = 0._f64
1274 if (
present(control_variate))
then
1275 allocate(self%control_variate )
1276 allocate(self%control_variate%cv(self%particle_group%n_species) )
1277 self%control_variate => control_variate
1278 self%i_weight = self%particle_group%group(1)%n_weights
1288 particle_mesh_coupling, &
1297 boundary_particles, &
1307 sll_real64,
target,
intent( in ) :: phi_dofs(:)
1308 sll_real64,
target,
intent( in ) :: efield_dofs(:)
1309 sll_real64,
target,
intent( in ) :: bfield_dofs(:)
1310 sll_real64,
intent( in ) :: x_min(3)
1311 sll_real64,
intent( in ) :: lx(3)
1313 character(len=*),
intent( in ) :: filename
1314 sll_int32,
optional,
intent( in ) :: boundary_particles
1315 sll_real64,
optional,
intent( in ) :: betar(2)
1316 sll_real64,
optional,
intent(in) :: force_sign
1317 sll_real64,
optional,
target,
intent( in ) :: rhob(:)
1319 logical,
optional,
intent(in) :: jmean
1321 character(len=256) :: file_prefix
1322 sll_int32 :: input_file, rank
1323 sll_int32 :: io_stat, io_stat0, io_stat1, file_id
1324 sll_real64 :: maxwell_tolerance, iter_tolerance, betar_set(2), force_sign_set
1325 sll_int32 :: max_iter, boundary_particles_set
1326 logical :: jmean_set
1328 namelist /output/ file_prefix
1329 namelist /time_solver/ maxwell_tolerance
1330 namelist /time_iterate/ iter_tolerance, max_iter
1334 if(
present(boundary_particles) )
then
1335 boundary_particles_set = boundary_particles
1337 boundary_particles_set = 100
1340 if(
present(betar) )
then
1346 if(
present(force_sign) )
then
1347 force_sign_set = force_sign
1349 force_sign_set = 1._f64
1352 if (
present(jmean))
then
1358 if(
present( control_variate) )
then
1360 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
1361 if (io_stat /= 0)
then
1362 if (rank == 0 )
then
1363 print*,
'sll_m_time_propagator_pic_vm_3d3v_trafo_helper: Input file does not exist. Set default tolerance.'
1364 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1365 write(file_id, *)
'solver tolerance:', 1d-12
1366 write(file_id, *)
'iter_tolerance:', 1d-12
1367 write(file_id, *)
'max_iter:', 10
1370 call self%init( maxwell_solver, &
1371 particle_mesh_coupling, &
1379 boundary_particles_set, &
1381 force_sign=force_sign_set, &
1383 control_variate = control_variate,&
1386 read(input_file, output,iostat=io_stat0)
1387 read(input_file, time_solver,iostat=io_stat)
1388 read(input_file, time_iterate,iostat=io_stat1)
1389 if (io_stat /= 0 .and. io_stat1 /= 0)
then
1390 if (rank == 0 )
then
1391 print*,
'sll_m_time_propagator_pic_vm_3d3v_trafo_helper: Input parameter does not exist. Set default tolerance.'
1392 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1393 write(file_id, *)
'solver tolerance:', 1d-12
1394 write(file_id, *)
'iter_tolerance:', 1d-12
1395 write(file_id, *)
'max_iter:', 10
1398 call self%init( maxwell_solver, &
1399 particle_mesh_coupling, &
1407 boundary_particles_set, &
1409 force_sign=force_sign_set, &
1411 control_variate = control_variate,&
1413 else if (io_stat == 0 .and. io_stat1 /= 0)
then
1414 if (rank == 0 )
then
1415 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1416 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1417 write(file_id, *)
'iter_tolerance:', 1d-12
1418 write(file_id, *)
'max_iter:', 10
1421 call self%init( maxwell_solver, &
1422 particle_mesh_coupling, &
1430 boundary_particles_set, &
1431 maxwell_tolerance, &
1433 force_sign=force_sign_set, &
1435 control_variate = control_variate)
1436 else if (io_stat /= 0 .and. io_stat1 == 0)
then
1437 if (rank == 0 )
then
1438 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1439 write(file_id, *)
'solver tolerance:', 1d-12
1440 write(file_id, *)
'iter_tolerance:', iter_tolerance
1441 write(file_id, *)
'max_iter:', max_iter
1444 call self%init( maxwell_solver, &
1445 particle_mesh_coupling, &
1453 boundary_particles_set, &
1454 iter_tolerance=iter_tolerance, max_iter=max_iter, &
1456 force_sign=force_sign_set, &
1458 control_variate = control_variate,&
1461 if (rank == 0 )
then
1462 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1463 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1464 write(file_id, *)
'iter_tolerance:', iter_tolerance
1465 write(file_id, *)
'max_iter:', max_iter
1468 call self%init( maxwell_solver, &
1469 particle_mesh_coupling, &
1477 boundary_particles_set, &
1478 maxwell_tolerance, &
1479 iter_tolerance, max_iter, &
1481 force_sign=force_sign_set, &
1483 control_variate = control_variate,&
1490 open(newunit = input_file, file=filename, status=
'old',iostat=io_stat)
1491 if (io_stat /= 0)
then
1492 if (rank == 0 )
then
1493 print*,
'sll_m_time_propagator_pic_vm_3d3v_trafo_helper: Input file does not exist. Set default tolerance.'
1494 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1495 write(file_id, *)
'solver tolerance:', 1d-12
1496 write(file_id, *)
'iter_tolerance:', 1d-12
1497 write(file_id, *)
'max_iter:', 10
1500 call self%init( maxwell_solver, &
1501 particle_mesh_coupling, &
1509 boundary_particles_set, &
1511 force_sign=force_sign_set,&
1515 read(input_file, output,iostat=io_stat0)
1516 read(input_file, time_solver,iostat=io_stat)
1517 read(input_file, time_iterate,iostat=io_stat1)
1518 if (io_stat /= 0 .and. io_stat1 /= 0)
then
1519 if (rank == 0 )
then
1520 print*,
'sll_m_time_propagator_pic_vm_3d3v_trafo_helper: Input parameter does not exist. Set default tolerance.'
1521 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1522 write(file_id, *)
'solver tolerance:', 1d-12
1523 write(file_id, *)
'iter_tolerance:', 1d-12
1524 write(file_id, *)
'max_iter:', 10
1527 call self%init( maxwell_solver, &
1528 particle_mesh_coupling, &
1536 boundary_particles_set, &
1538 force_sign=force_sign_set,&
1541 else if (io_stat == 0 .and. io_stat1 /= 0)
then
1542 if (rank == 0 )
then
1543 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1544 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1545 write(file_id, *)
'iter_tolerance:', 1d-12
1546 write(file_id, *)
'max_iter:', 10
1549 call self%init( maxwell_solver, &
1550 particle_mesh_coupling, &
1558 boundary_particles_set, &
1559 maxwell_tolerance, &
1561 force_sign=force_sign_set,&
1564 else if (io_stat /= 0 .and. io_stat1 == 0)
then
1565 if (rank == 0 )
then
1566 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1567 write(file_id, *)
'solver tolerance:', 1d-12
1568 write(file_id, *)
'iter_tolerance:', iter_tolerance
1569 write(file_id, *)
'max_iter:', max_iter
1572 call self%init( maxwell_solver, &
1573 particle_mesh_coupling, &
1581 boundary_particles_set, &
1582 iter_tolerance=iter_tolerance, max_iter=max_iter, &
1584 force_sign=force_sign_set,&
1588 if (rank == 0 )
then
1589 open(newunit=file_id, file=trim(file_prefix)//
'_parameters_used.dat', position =
'append', status=
'old', action=
'write', iostat=io_stat)
1590 write(file_id, *)
'solver tolerance:', maxwell_tolerance
1591 write(file_id, *)
'iter_tolerance:', iter_tolerance
1592 write(file_id, *)
'max_iter:', max_iter
1595 call self%init( maxwell_solver, &
1596 particle_mesh_coupling, &
1604 boundary_particles_set, &
1605 maxwell_tolerance, &
1606 iter_tolerance, max_iter, &
1608 force_sign=force_sign_set,&
1625 sll_int32 :: file_id, j
1627 if(self%boundary)
then
1628 print*,
'left boundary', self%counter_left
1629 print*,
'right boundary', self%counter_right
1631 if(self%adiabatic_electrons)
then
1632 call self%linear_solver_schur_phiv%free()
1633 call self%linear_op_schur_phiv%free()
1635 call self%preconditioner_fft%free()
1636 call self%linear_solver_schur_ev%free()
1637 call self%linear_op_schur_ev%free()
1639 call self%particle_mass_op%free()
1640 call self%particle_mass_1%free()
1641 call self%particle_mass_2%free()
1642 call self%particle_mass_3%free()
1643 deallocate( self%particle_mass_1 )
1644 deallocate( self%particle_mass_2 )
1645 deallocate( self%particle_mass_3 )
1646 if(self%map%flag2d)
then
1647 call self%particle_mass_12%free()
1648 call self%particle_mass_21%free()
1649 deallocate( self%particle_mass_12 )
1650 deallocate( self%particle_mass_21 )
1651 if(self%map%flag3d)
then
1652 call self%particle_mass_23%free()
1653 call self%particle_mass_32%free()
1654 call self%particle_mass_31%free()
1655 call self%particle_mass_13%free()
1656 deallocate( self%particle_mass_13 )
1657 deallocate( self%particle_mass_31 )
1658 deallocate( self%particle_mass_23 )
1659 deallocate( self%particle_mass_32 )
1663 deallocate( self%j_dofs )
1664 deallocate( self%j_dofs_local )
1665 deallocate( self%particle_mass_1_local )
1666 deallocate( self%particle_mass_2_local )
1667 deallocate( self%particle_mass_3_local )
1668 deallocate( self%particle_mass_12_local )
1669 deallocate( self%particle_mass_23_local )
1670 deallocate( self%particle_mass_31_local )
1672 self%maxwell_solver => null()
1673 self%particle_mesh_coupling => null()
1674 self%particle_group => null()
1675 self%efield_dofs => null()
1676 self%bfield_dofs => null()
1679 print*,
'No. of failed iterations:', self%n_failed
1680 open(newunit=file_id, file=
"outer-iters.dat", action=
'write')
1681 do j=1,self%iter_counter
1682 write(file_id,*) self%niter(j)
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.
Parameters to define common initial distributions.
module for a block linear operator
module for conjugate gradient method in pure form
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.
Module interface to solve Maxwell's equations with coordinate transformation in 3D The linear systems...
Module interface to solve Maxwell's equations with coordinate transformation in 3D The linear systems...
functions for initial profile of the particle distribution function
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
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
subroutine delete_pic_vm_3d3v_trafo(self)
Destructor.
subroutine initialize_file_pic_vm_3d3v_trafo(self, maxwell_solver, particle_mesh_coupling, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, map, filename, boundary_particles, betar, force_sign, rhob, control_variate, jmean)
Constructor.
subroutine advect_ex_pic_vm_3d3v_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_3d3v_trafo(self, dt)
advect_vb: Equations to be solved $(\mathbb{I}-\Delta \frac{\Delta t q}{2 m} DF^{-\top} \mathbb{B}(\X...
subroutine compute_particle_boundary_current_evaluate_iter(self, xi, xnew, vi, wi, sign)
Helper function for advect_ex.
subroutine advect_e_pic_vm_3d3v_trafo(self, dt)
advect_e: Equations to be solved Solution with Schur complement: $ S_{+}=M_1+\frac{\Delta t^2 q^2}{4 ...
subroutine sll_s_compute_particle_boundary(self, xold, xnew, vi)
Helper function for advect_x.
subroutine advect_x_pic_vm_3d3v_trafo(self, dt)
Finalization.
subroutine compute_particle_boundary_current_evaluate(self, xi, xnew, vi, wi, sign)
Helper function for advect_ex.
subroutine advect_eb_pic_vm_3d3v_trafo(self, dt)
advect_eb: Equations to be solved Solution with Schur complement: $ S=M_1+\frac{\Delta t^2}{4} C^\top...
subroutine initialize_pic_vm_3d3v_trafo(self, maxwell_solver, particle_mesh_coupling, particle_group, phi_dofs, efield_dofs, bfield_dofs, x_min, Lx, map, boundary_particles, solver_tolerance, iter_tolerance, max_iter, betar, force_sign, rhob, control_variate, jmean)
Constructor.
real(kind=f64) function, dimension(size(particle, 2)) control_variate(particle)
class for a linear operator_block
class for the cg linear solver
type collecting functions for analytical coordinate mapping
Basic type of a kernel smoother used for PIC simulations.
Helper for implicit time propagator for 3d3v Vlasov-Maxwell with coordinate transformation.