diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 760fd11..6eeb211 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -43,6 +43,13 @@ jobs: export PYTHONPATH=$PYTHONPATH:$(pwd) python3 minepoch_py/test.py + - name: Test-substep + run: | + cp Data/two_stream_substep.deck Data/input.deck + ./bin/epoch3d + export PYTHONPATH=$PYTHONPATH:$(pwd) + python3 minepoch_py/test.py + - name: Test-Parallel run: | cp Data/two_stream.deck Data/input.deck diff --git a/Data/two_stream_substep.deck b/Data/two_stream_substep.deck new file mode 100644 index 0000000..2c9ba14 --- /dev/null +++ b/Data/two_stream_substep.deck @@ -0,0 +1,5 @@ +&CONTROL + problem = 'two_stream', + stdout_frequency = 25, + global_substeps = 2, +/ diff --git a/src/deck/deck.f90 b/src/deck/deck.f90 index 799ae37..d56b127 100644 --- a/src/deck/deck.f90 +++ b/src/deck/deck.f90 @@ -21,7 +21,7 @@ SUBROUTINE read_deck allow_cpu_reduce, timer_collect, use_balance, use_random_seed, & npart_global, nsteps, t_end, dt_multiplier, dlb_threshold, & stdout_frequency, particle_push_start_time, n_species, & - fixed_fields + fixed_fields, global_substeps IF (first) THEN ! Set the default problem here diff --git a/src/housekeeping/setup.F90 b/src/housekeeping/setup.F90 index c52014a..0776f36 100644 --- a/src/housekeeping/setup.F90 +++ b/src/housekeeping/setup.F90 @@ -254,6 +254,7 @@ SUBROUTINE setup_single_species(species) species%count_update_step = 0 species%immobile = .FALSE. species%is_driftkinetic = .FALSE. + species%nsubstep = global_substeps NULLIFY(species%next) NULLIFY(species%prev) NULLIFY(species%ext_temp_x_min) diff --git a/src/particles.F90 b/src/particles.F90 index 82396e8..b183f42 100644 --- a/src/particles.F90 +++ b/src/particles.F90 @@ -13,7 +13,7 @@ MODULE particles END TYPE fields_eval_tmps ! Some numerical factors needed for various particle-fields routines. - REAL(num) :: idtyz, idtxz, idtxy + REAL(num) :: i_yz, i_xz, i_xy ! can't store these as particle steps may vary REAL(num) :: idx, idy, idz @@ -129,7 +129,7 @@ SUBROUTINE push_particles ! Particle weighting multiplication factor REAL(num) :: cf2 REAL(num), PARAMETER :: fac = (1.0_num / 24.0_num)**c_ndims - + INTEGER :: isubstep TYPE(particle), POINTER :: current, next TYPE(particle_species), POINTER :: species, next_species @@ -156,9 +156,9 @@ SUBROUTINE push_particles dtfac = 0.5_num * dt * fac third = 1.0_num / 3.0_num - idtyz = idt * idy * idz * fac - idtxz = idt * idx * idz * fac - idtxy = idt * idx * idy * fac + i_yz = idy * idz * fac + i_xz = idx * idz * fac + i_xy = idx * idy * fac next_species => species_list DO ispecies = 1, n_species @@ -170,7 +170,9 @@ SUBROUTINE push_particles IF (species%is_driftkinetic) THEN CALL push_particles_dk0(species) ELSE - CALL push_particles_lorentz_split + DO isubstep=1,species%nsubstep + CALL push_particles_lorentz_split(dt/species%nsubstep) + END DO END IF ENDDO @@ -181,6 +183,10 @@ SUBROUTINE push_particles contains SUBROUTINE push_particles_lorentz + REAL(num) :: idtyz, idtxz, idtxy + idtyz = idt * idy * idz * fac + idtxz = idt * idx * idz * fac + idtxy = idt * idx * idy * fac current => species%attached_list%head @@ -434,18 +440,27 @@ SUBROUTINE push_particles_lorentz END SUBROUTINE push_particles_lorentz - SUBROUTINE push_particles_lorentz_split + SUBROUTINE push_particles_lorentz_split(dt_sub) + REAL(num), intent(IN) :: dt_sub TYPE(fields_eval_tmps) :: st_half REAL(num), DIMENSION(3) :: part_pos_t1p5, pos_half, Bvec, Evec - REAL(num) :: weight_back + REAL(num) :: weight_back, part_qfac REAL(num), DIMENSION(3) :: force, part_v + REAL(num) :: idt, dto2, dtco2, idt0 + REAL(num) :: dtfac + + idt = 1.0_num / dt_sub + idt0= 1.0_num / dt + dto2 = dt_sub / 2.0_num + dtco2 = c * dto2 + dtfac = 0.5_num * dt_sub * fac IF (species%solve_fluid) CALL initstep_fluid current => species%attached_list%head IF (.NOT. particles_uniformly_distributed) THEN - part_weight = species%weight + part_weight = species%weight ENDIF !DEC$ VECTOR ALWAYS @@ -455,7 +470,8 @@ SUBROUTINE push_particles_lorentz_split part_weight = current%weight ENDIF - part_q = current%charge + part_q = current%charge + part_qfac = part_q * idt0 part_mc = c * current%mass ipart_mc = 1.0_num / part_mc cmratio = part_q * dtfac * ipart_mc @@ -525,9 +541,6 @@ SUBROUTINE push_particles_lorentz_split ! calculated current. IF(species%use_deltaf) THEN weight_back = current%pvol * f0(species, current, current%mass) - fcx = idtyz * (part_weight - weight_back) - fcy = idtxz * (part_weight - weight_back) - fcz = idtxy * (part_weight - weight_back) END IF ! Now advance to t+1.5dt to calculate current. This is detailed in @@ -538,7 +551,7 @@ SUBROUTINE push_particles_lorentz_split !Current deposition uses position at t+0.5dt and t+1.5dt, particle !assumed to travel in direct line between these locations. Second order !in time for evaluation of current at t+dt - CALL current_deposition_store(st_half,part_pos_t1p5,(part_weight*part_q),.false.) + CALL current_deposition_store(st_half,part_pos_t1p5,(part_weight*part_qfac),.false.) if (species%solve_fluid) then part_v = (/part_ux, part_uy,part_uz/) @@ -575,8 +588,10 @@ SUBROUTINE push_particles_dk0(species) REAL(num) :: part_mu, part_u, bdotBmag REAL(num) :: part_u_0,part_u_h, dudt - REAL(num) :: part_q, part_weight + REAL(num) :: part_q, part_weight, part_qfac INTEGER(i8) :: ipart + REAL(num) :: idt + idt = 1.0_num/dt current => species%attached_list%head @@ -593,6 +608,7 @@ SUBROUTINE push_particles_dk0(species) ENDIF part_q = current%charge + part_qfac= part_q * idt ! Do nonrelativistic drift-kinetics for the moment. part_u = current%part_p(1) part_mu = current%part_p(2) @@ -620,7 +636,7 @@ SUBROUTINE push_particles_dk0(species) !Do current deposition using lowest order current. (current at t_{N+1}) !Before we apply this current, E+B need to be stored in a temporary; !this is the lowest order current. - CALL current_deposition_store(st_0,pos_0,(part_weight*part_q),.true.) + CALL current_deposition_store(st_0,pos_0,(part_weight*part_qfac),.true.) current => next @@ -642,9 +658,11 @@ SUBROUTINE push_particles_dk1(species) REAL(num) :: part_mu, part_u, bdotBmag REAL(num) :: part_u_h, dudt_1 - REAL(num) :: part_q, part_weight + REAL(num) :: part_q, part_weight, part_qfac INTEGER(i8) :: ipart - + REAL(num) :: idt + idt = 1.0_num/dt + current => species%attached_list%head IF (.NOT. particles_uniformly_distributed) THEN @@ -659,6 +677,7 @@ SUBROUTINE push_particles_dk1(species) ENDIF part_q = current%charge + part_qfac= part_q * idt ! Do nonrelativistic drift-kinetics for the moment. part_u = current%part_p(1) part_mu = current%part_p(2) @@ -922,9 +941,9 @@ SUBROUTINE current_deposition_store(st,pos,chargeweight,drift_switch) zmin = sf_min + (dcellz - 1) / 2 zmax = sf_max + (dcellz + 1) / 2 - fjx = idtyz * chargeweight - fjy = idtxz * chargeweight - fjz = idtxy * chargeweight + fjx = i_yz * chargeweight + fjy = i_xz * chargeweight + fjz = i_xy * chargeweight jzh = 0.0_num DO iz = zmin, zmax diff --git a/src/shared_data.F90 b/src/shared_data.F90 index 53921f7..fe31f86 100644 --- a/src/shared_data.F90 +++ b/src/shared_data.F90 @@ -220,6 +220,7 @@ MODULE shared_data LOGICAL :: is_driftkinetic LOGICAL :: use_deltaf = .FALSE. LOGICAL :: solve_fluid = .FALSE. + INTEGER :: nsubstep = 1 ! Injection of particles REAL(num) :: npart_per_cell @@ -393,6 +394,8 @@ MODULE shared_data LOGICAL, DIMENSION(c_dir_x:c_dir_z,0:c_stagger_max) :: stagger INTEGER(i8) :: push_per_field = 5 + INTEGER :: global_substeps = 1 + ! Absorption diagnostic REAL(num) :: laser_inject_local = 0.0_num REAL(num) :: laser_absorb_local = 0.0_num