Ejemplo n.º 1
0
def check_timestep(pos, vel, B, E, q_dens, Ie, W_elec, Ib, W_mag, B_center, 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):
    '''
    Evaluates all the things that could cause a violation of the timestep:
        - Magnetic field dispersion (switchable in param file since this can be tiny)
        - Gyromotion resolution
        - Ion velocity (Don't cross more than half a cell in a timestep)
        - Electric field acceleration
        
    When a violating condition found, velocity is advanced by 0.5DT (since this happens
    at the top of a loop anyway). The assumption is that the timestep isn't violated by
    enough to cause instant instability (each criteria should have a little give), which 
    should be valid except under extreme instability. The timestep is then halved and all
    time-dependent counters and quantities are doubled. Velocity is then retarded back
    half a timestep to de-sync back into a leapfrog scheme.
    '''
    ND = const.ND
    NX = const.NX

    interpolate_edges_to_center(B, B_center)
    B_magnitude = np.sqrt(B_center[ND:ND + NX + 1, 0]**2 +
                          B_center[ND:ND + NX + 1, 1]**2 +
                          B_center[ND:ND + NX + 1, 2]**2)
    gyfreq = const.qm_ratios.max() * B_magnitude.max()
    ion_ts = const.orbit_res / gyfreq

    if E[:, 0].max() != 0:
        elecfreq = const.qm_ratios.max() * (
            np.abs(E[:, 0] / np.abs(vel).max()).max()
        )  # Electron acceleration "frequency"
        Eacc_ts = const.freq_res / elecfreq
    else:
        Eacc_ts = ion_ts

    vel_ts = 0.60 * const.dx / np.abs(vel[0, :]).max(
    )  # Timestep to satisfy CFL condition: Fastest particle doesn't traverse more than 'half' a cell in one time step
    DT_part = min(Eacc_ts, vel_ts,
                  ion_ts)  # Smallest of the allowable timesteps

    if DT_part < 0.9 * DT:

        particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp,
                                  B, E, v_prime, S, T, temp_N,
                                  0.5 * DT)  # Re-sync vel/pos

        DT *= 0.5
        max_inc *= 2
        qq *= 2

        field_save_iter *= 2
        part_save_iter *= 2

        particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp,
                                  B, E, v_prime, S, T, temp_N,
                                  -0.5 * DT)  # De-sync vel/pos
        print('Timestep halved. Syncing particle velocity...')
        init.set_damping_array(B_damping_array, E_damping_array, DT)

    return qq, DT, max_inc, part_save_iter, field_save_iter, B_damping_array, E_damping_array
Ejemplo n.º 2
0
def check_timestep(pos, vel, B, E, q_dens, Ie, W_elec, Ib, W_mag, B_center, \
                     qq, DT, max_inc, part_save_iter, field_save_iter, idx, damping_array):
    '''
    Evaluates all the things that could cause a violation of the timestep:
        - Magnetic field dispersion (switchable in param file since this can be tiny)
        - Gyromotion resolution
        - Ion velocity (Don't cross more than half a cell in a timestep)
        - Electric field acceleration
        
    When a violating condition found, velocity is advanced by 0.5DT (since this happens
    at the top of a loop anyway). The assumption is that the timestep isn't violated by
    enough to cause instant instability (each criteria should have a little give), which 
    should be valid except under extreme instability. The timestep is then halved and all
    time-dependent counters and quantities are doubled. Velocity is then retarded back
    half a timestep to de-sync back into a leapfrog scheme.
    
    Also evaluates if a timestep is unnneccessarily too small, which can sometimes happen
    after wave-particle interactions are complete and energetic particles are slower. This
    criteria is higher in order to provide a little hysteresis and prevent constantly switching
    timesteps.
    '''
    interpolate_edges_to_center(B, B_center)
    B_magnitude = np.sqrt(B_center[ND:ND + NX + 1, 0]**2 +
                          B_center[ND:ND + NX + 1, 1]**2 +
                          B_center[ND:ND + NX + 1, 2]**2)
    gyfreq = qm_ratios.max() * B_magnitude.max()
    ion_ts = orbit_res / gyfreq

    if E[:, 0].max() != 0:
        elecfreq = qm_ratios.max() * (np.abs(
            E[:, 0] / np.abs(vel).max()).max()
                                      )  # Electron acceleration "frequency"
        Eacc_ts = freq_res / elecfreq
    else:
        Eacc_ts = ion_ts

    if account_for_dispersion == True:
        B_tot = np.sqrt(B_center[:, 0]**2 + B_center[:, 1]**2 +
                        B_center[:, 2]**2)

        dispfreq = (
            (np.pi / dx)**2) * (B_tot /
                                (mu0 * q_dens)).max()  # Dispersion frequency

        disp_ts = dispersion_allowance * freq_res / dispfreq  # Making this a little bigger so it doesn't wreck everything
    else:
        disp_ts = ion_ts

    vel_ts = 0.60 * dx / np.abs(vel[0, :]).max(
    )  # Timestep to satisfy CFL condition: Fastest particle doesn't traverse more than 'half' a cell in one time step
    DT_part = min(Eacc_ts, vel_ts, ion_ts,
                  disp_ts)  # Smallest of the allowable timesteps

    if DT_part < 0.9 * DT:

        particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, B, E,
                                  0.5 * DT)  # Re-sync vel/pos

        DT *= 0.5
        max_inc *= 2
        qq *= 2

        field_save_iter *= 2
        part_save_iter *= 2

        particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, B, E,
                                  -0.5 * DT)  # De-sync vel/pos
        print('Timestep halved. Syncing particle velocity...')
        init.set_damping_array(damping_array, DT)


# =============================================================================
#     elif DT_part >= 4.0*DT and qq%2 == 0 and part_save_iter%2 == 0 and field_save_iter%2 == 0 and max_inc%2 == 0:
#         particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, B, E, 0.5*DT)    # Re-sync vel/pos
#         DT         *= 2.0
#         max_inc   //= 2
#         qq        //= 2
#
#         field_save_iter //= 2
#         part_save_iter //= 2
#
#         particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, B, E, -0.5*DT)   # De-sync vel/pos
#         print('Timestep Doubled. Syncing particle velocity...')
#         init.set_damping_array(damping_array, DT)
# =============================================================================

    return qq, DT, max_inc, part_save_iter, field_save_iter, damping_array