def numerical_loop(real_time, pos, vel, Ie, W_elec, idx, B, E_int, q_dens, Ji, Ve, Te, DT, max_inc, data_iter, ch_flag): ''' Does the number crunching for a short snippet. Logs number of time variable changes in ch_flag as powers of 2 (-1 = half, 2 = 4 times slower) Array values are mutable: Don't have to be returned. Only integer values ''' qq = 0 while qq < data_iter: # Check timestep used for this iteration vel, qq, DT, max_inc, data_iter, ch_flag = aux.check_timestep( qq, DT, pos, vel, B, E_int, q_dens, Ie, W_elec, max_inc, data_iter, idx) # Add timestep to counter real_time += DT # Main loop pos, vel, Ie, W_elec, q_dens_adv, Ji = particles.advance_particles_and_moments( pos, vel, Ie, W_elec, idx, B, E_int, DT) q_dens = 0.5 * (q_dens + q_dens_adv) B = fields.push_B(B, E_int, DT) E_half, Ve, Te = fields.calculate_E(B, Ji, q_dens) q_dens = q_dens_adv.copy() # Predictor-Corrector: Advance fields to start of next timestep E_int, B = fields.predictor_corrector(B, E_int, E_half, pos, vel, q_dens_adv, Ie, W_elec, idx, DT) # Increment loop variable qq += 1 return DT, ch_flag, max_inc, data_iter, real_time
def test_push_B_w_varying_background(): max_inc = 101 DT = 1.0 x_offset = 200e-9 E = np.zeros((const.NX + 3, 3)) B = np.zeros((const.NX + 3, 3), dtype=float) x = np.arange(const.NX + 3) #fig, ax = plt.subplots() B[:, 0] += x_offset qq = 1 while qq < max_inc: # push_B(B, E, DT, qq) B = fields.push_B(B, E, DT, qq, half_flag=1) print('t = {}s, B = {}nT'.format((qq - 0.5) * DT, B[0, :] * 1e9)) # ============================================================================= # ax.clear() # ax.plot(x, B[:, 0] * 1e9) # ax.plot(x, B[:, 1] * 1e9) # ax.plot(x, B[:, 2] * 1e9) # ax.set_title('Bx at t = {}'.format((qq - 0.5) * DT)) # ax.set_ylim(-(const.HM_amplitude + x_offset)*1e9, (const.HM_amplitude + x_offset)*1e9) # ax.set_xlim(0, const.NX + 3) # ax.set_ylabel('Magnetic Field (nT)') # ax.set_xlabel('Cell number') # plt.pause(0.1) # ============================================================================= B = fields.push_B(B, E, DT, qq, half_flag=0) print('t = {}s, B = {}nT'.format(qq * DT, B[0, :] * 1e9)) # ============================================================================= # ax.clear() # ax.plot(x, B[:, 0] * 1e9) # ax.plot(x, B[:, 1] * 1e9) # ax.plot(x, B[:, 2] * 1e9) # ax.set_title('Bx at t = {}'.format(qq * DT)) # ax.set_ylim(-(const.HM_amplitude + x_offset)*1e9, (const.HM_amplitude + x_offset)*1e9) # ax.set_xlim(0, const.NX + 3) # ax.set_ylabel('Magnetic Field (nT)') # ax.set_xlabel('Cell number') # plt.pause(0.1) # ============================================================================= qq += 1 return
def main_loop(pos, vel, idx, Ie, W_elec, Ib, W_mag, Ep, Bp, v_prime, S, T,temp_N, \ B, E_int, E_half, q_dens, q_dens_adv, Ji, ni, nu, mp_flux, \ Ve, Te, Te0, temp3De, temp3Db, temp1D, old_particles, old_fields,\ B_damping_array, E_damping_array, qq, DT, max_inc, part_save_iter, field_save_iter): ''' Main loop separated from __main__ function, since this is the actual computation bit. Could probably be optimized further, but I wanted to njit() it. The only reason everything's not njit() is because of the output functions. Future: Come up with some way to loop until next save point Thoughts: declare a variable steps_to_go. Output all time variables at return to resync everything, and calculate steps to next stop. If no saves, steps_to_go = max_inc ''' # Check timestep qq, DT, max_inc, part_save_iter, field_save_iter, damping_array \ = check_timestep(pos, vel, B, E_int, q_dens, Ie, W_elec, Ib, W_mag, temp3De, Ep, Bp, v_prime, S, T,temp_N,\ qq, DT, max_inc, part_save_iter, field_save_iter, idx, B_damping_array) # ============================================================================= # # Check number of spare particles every 25 steps # if qq%25 == 0 and particle_open == 1: # num_spare = (idx < 0).sum() # if num_spare < inject_rate.sum() * DT * 5.0: # # Change this to dynamically expand particle arrays later on (adding more particles) # print('WARNING :: Less than 5 time increments of spare particles remaining. Widening arrays...') # pos, vel, idx, Ie, W_elec, Ib, W_mag, Ep, Bp, v_prime, S, T, temp_N, old_particles = \ # increase_particle_array_size(pos, vel, idx, Ie, W_elec, Ib, W_mag, Ep, Bp, v_prime, # S, T, temp_N, old_particles) # ============================================================================= # Move particles, collect moments particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp, v_prime, S, T,temp_N,\ B, E_int, DT, q_dens_adv, Ji, ni, nu, mp_flux) # Average N, N + 1 densities (q_dens at N + 1/2) q_dens *= 0.5 q_dens += 0.5 * q_dens_adv # Push B from N to N + 1/2 fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=1) # Calculate E at N + 1/2 fields.calculate_E(B, Ji, q_dens, E_half, Ve, Te, Te0, temp3De, temp3Db, temp1D, E_damping_array) ################################### ### PREDICTOR CORRECTOR SECTION ### ################################### # Store old values mp_flux_old = mp_flux.copy() old_particles[0, :] = pos old_particles[1:4, :] = vel old_particles[4, :] = Ie old_particles[5:8, :] = W_elec old_particles[8, :] = idx old_fields[:, 0:3] = B old_fields[:NC, 3:6] = Ji old_fields[:NC, 6:9] = Ve old_fields[:NC, 9] = Te # Predict fields E_int *= -1.0 E_int += 2.0 * E_half fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=0) # Advance particles to obtain source terms at N + 3/2 particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp, v_prime, S, T,temp_N,\ B, E_int, DT, q_dens, Ji, ni, nu, mp_flux, pc=1) q_dens *= 0.5 q_dens += 0.5 * q_dens_adv # Compute predicted fields at N + 3/2 fields.push_B(B, E_int, temp3Db, DT, qq + 1, B_damping_array, half_flag=1) fields.calculate_E(B, Ji, q_dens, E_int, Ve, Te, Te0, temp3De, temp3Db, temp1D, E_damping_array) # Determine corrected fields at N + 1 E_int *= 0.5 E_int += 0.5 * E_half # Restore old values: [:] allows reference to same memory (instead of creating new, local instance) pos[:] = old_particles[0, :] vel[:] = old_particles[1:4, :] Ie[:] = old_particles[4, :] W_elec[:] = old_particles[5:8, :] idx[:] = old_particles[8, :] B[:] = old_fields[:, 0:3] Ji[:] = old_fields[:NC, 3:6] Ve[:] = old_fields[:NC, 6:9] Te[:] = old_fields[:NC, 9] fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=0) # Advance the original B q_dens[:] = q_dens_adv mp_flux = mp_flux_old.copy() return qq, DT, max_inc, part_save_iter, field_save_iter
def main_loop(pos, vel, idx, Ie, W_elec, Ib, W_mag, \ B, E_int, E_half, q_dens, q_dens_adv, Ji, ni, nu, \ Ve, Te, temp3D, temp3D2, temp1D, old_particles, old_fields,\ qq, DT, max_inc, part_save_iter, field_save_iter): ''' Main loop separated from __main__ function, since this is the actual computation bit. Could probably be optimized further, but I wanted to njit() it. The only reason everything's not njit() is because of the output functions. Future: Come up with some way to loop until next save point Thoughts: declare a variable steps_to_go. Output all time variables at return to resync everything, and calculate steps to next stop. If no saves, steps_to_go = max_inc ''' # Check timestep qq, DT, max_inc, part_save_iter, field_save_iter \ = check_timestep(pos, vel, B, E_int, q_dens, Ie, W_elec, Ib, W_mag, temp3D, \ qq, DT, max_inc, part_save_iter, field_save_iter, idx) # Move particles, collect moments particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, \ B, E_int, DT, q_dens_adv, Ji, ni, nu, temp1D) # Average N, N + 1 densities (q_dens at N + 1/2) q_dens *= 0.5 q_dens += 0.5 * q_dens_adv # Push B from N to N + 1/2 fields.push_B(B, E_int, temp3D, DT, qq, half_flag=1) # Calculate E at N + 1/2 fields.calculate_E(B, Ji, q_dens, E_half, Ve, Te, temp3D, temp3D2, temp1D) ################################### ### PREDICTOR CORRECTOR SECTION ### ################################### # Store old values old_particles[0, :] = pos old_particles[1:4, :] = vel old_particles[4, :] = Ie old_particles[5:8, :] = W_elec old_fields[:, 0:3] = B old_fields[:, 3:6] = Ji old_fields[:, 6:9] = Ve old_fields[:, 9] = Te # Predict fields E_int *= -1.0 E_int += 2.0 * E_half fields.push_B(B, E_int, temp3D, DT, qq, half_flag=0) # Advance particles to obtain source terms at N + 3/2 particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, \ B, E_int, DT, q_dens, Ji, ni, nu, temp1D, pc=1) q_dens *= 0.5 q_dens += 0.5 * q_dens_adv # Compute predicted fields at N + 3/2 fields.push_B(B, E_int, temp3D, DT, qq + 1, half_flag=1) fields.calculate_E(B, Ji, q_dens, E_int, Ve, Te, temp3D, temp3D2, temp1D) # Determine corrected fields at N + 1 E_int *= 0.5 E_int += 0.5 * E_half # Restore old values: [:] allows reference to same memory (instead of creating new, local instance) pos[:] = old_particles[0, :] vel[:] = old_particles[1:4, :] Ie[:] = old_particles[4, :] W_elec[:] = old_particles[5:8, :] B[:] = old_fields[:, 0:3] Ji[:] = old_fields[:, 3:6] Ve[:] = old_fields[:, 6:9] Te[:] = old_fields[:, 9] fields.push_B(B, E_int, temp3D, DT, qq, half_flag=0) # Advance the original B q_dens[:] = q_dens_adv return qq, DT, max_inc, part_save_iter, field_save_iter
# Check timestep vel, qq, DT, max_inc, data_iter, ch_flag \ = aux.check_timestep(qq, DT, pos, vel, B, E_int, q_dens, Ie, W_elec, max_inc, data_iter, idx) if ch_flag == 1: print 'Timestep halved. Syncing particle velocity with DT = {}'.format( DT) elif ch_flag == 2: print 'Timestep Doubled. Syncing particle velocity with DT = {}'.format( DT) # Main loop pos, vel, Ie, W_elec, q_dens_adv, Ji = particles.advance_particles_and_moments( pos, vel, Ie, W_elec, idx, B, E_int, DT) q_dens = 0.5 * (q_dens + q_dens_adv) B = fields.push_B(B, E_int, DT) E_half, Ve, Te = fields.calculate_E(B, Ji, q_dens) q_dens = q_dens_adv.copy() # Predictor-Corrector: Advance fields to start of next timestep E_int, B = fields.predictor_corrector(B, E_int, E_half, pos, vel, q_dens_adv, Ie, W_elec, idx, DT) if generate_data == 1: if qq % data_iter == 0: save.save_data(DT, data_iter, qq, pos, vel, Ji, E_int, B, Ve, Te, q_dens) if (qq + 1) % 25 == 0: print 'Timestep {} of {} complete'.format(qq + 1, max_inc)
qq, DT, max_inc, part_save_iter, field_save_iter, idx, B_damping_array) # Move particles, collect moments, delete or inject new particles particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp, v_prime, S, T,temp_N,\ B, E_int, DT, q_dens_adv, Ji, ni, nu, flux_rem) # Average N, N + 1 densities (q_dens at N + 1/2) q_dens *= 0.5 q_dens += 0.5 * q_dens_adv if disable_waves == False: # Push B from N to N + 1/2 fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=1) # Calculate E at N + 1/2 fields.calculate_E(B, Ji, q_dens, E_half, Ve, Te, Te0, temp3De, temp3Db, temp1D, E_damping_array) ################################### ### PREDICTOR CORRECTOR SECTION ### ################################### # Store old values old_particles[0:3, :] = pos old_particles[3:6, :] = vel
def main_loop(pos, vel, idx, Ie, W_elec, Ib, W_mag, Ep, Bp, v_prime, S, T,temp_N, \ B, E_int, E_half, q_dens, q_dens_adv, Ji, ni, nu, \ Ve, Te, Te0, temp3De, temp3Db, temp1D, old_particles, old_fields,\ B_damping_array, E_damping_array, qq, DT, max_inc, part_save_iter, field_save_iter): ''' Main loop separated from __main__ function, since this is the actual computation bit. Could probably be optimized further, but I wanted to njit() it. The only reason everything's not njit() is because of the output functions. Future: Come up with some way to loop until next save point Thoughts: declare a variable steps_to_go. Output all time variables at return to resync everything, and calculate steps to next stop. If no saves, steps_to_go = max_inc ''' NC = const.NC # Check timestep #print('MAIN Checking timestep') qq, DT, max_inc, part_save_iter, field_save_iter, B_damping_array, E_damping_array \ = check_timestep(pos, vel, B, E_int, q_dens, Ie, W_elec, Ib, W_mag, temp3De, Ep, Bp, \ v_prime, S, T,temp_N, qq, DT, max_inc, part_save_iter, \ field_save_iter, idx, B_damping_array, E_damping_array) # Move particles, collect moments #print('MAIN Advancing particles/moments') particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp, v_prime, S, T,temp_N,\ B, E_int, DT, q_dens_adv, Ji, ni, nu) # Average N, N + 1 densities (q_dens at N + 1/2) #print('MAIN Averaging density') q_dens *= 0.5 q_dens += 0.5 * q_dens_adv if const.disable_waves == 0: # Push B from N to N + 1/2 fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=1) # Calculate E at N + 1/2 fields.calculate_E(B, Ji, q_dens, E_half, Ve, Te, Te0, temp3De, temp3Db, temp1D, E_damping_array, qq, DT, half_flag=1) ################################### ### PREDICTOR CORRECTOR SECTION ### ################################### # Store old values old_particles[0:3, :] = pos old_particles[3:6, :] = vel old_particles[6, :] = Ie old_particles[7:10, :] = W_elec old_particles[10, :] = idx old_fields[:, 0:3] = B old_fields[:NC, 3:6] = Ji old_fields[:NC, 6:9] = Ve old_fields[:NC, 9] = Te # Predict fields E_int *= -1.0 E_int += 2.0 * E_half fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=0) # Advance particles to obtain source terms at N + 3/2 particles.advance_particles_and_moments(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp, v_prime, S, T,temp_N,\ B, E_int, DT, q_dens, Ji, ni, nu, pc=1) # Average N + 1, N + 2 densities (q_dens at N + 3/2) q_dens *= 0.5 q_dens += 0.5 * q_dens_adv # Compute predicted fields at N + 3/2 fields.push_B(B, E_int, temp3Db, DT, qq + 1, B_damping_array, half_flag=1) fields.calculate_E(B, Ji, q_dens, E_int, Ve, Te, Te0, temp3De, temp3Db, temp1D, E_damping_array, qq + 1, DT, half_flag=1) # Determine corrected fields at N + 1 E_int *= 0.5 E_int += 0.5 * E_half # Restore old values: [:] allows reference to same memory (instead of creating new, local instance) pos[:] = old_particles[0:3, :] vel[:] = old_particles[3:6, :] Ie[:] = old_particles[6, :] W_elec[:] = old_particles[7:10, :] idx[:] = old_particles[10, :] B[:] = old_fields[:, 0:3] Ji[:] = old_fields[:NC, 3:6] Ve[:] = old_fields[:NC, 6:9] Te[:] = old_fields[:NC, 9] fields.push_B(B, E_int, temp3Db, DT, qq, B_damping_array, half_flag=0) # Advance the original B q_dens[:] = q_dens_adv return qq, DT, max_inc, part_save_iter, field_save_iter