Пример #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.
    '''
    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

    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)  # 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
Пример #2
0
def set_timestep(vel, E, Te0):
    '''
    INPUT:
        vel -- Initial particle velocities
    OUTPUT:
        DT              -- Maximum allowable timestep (seconds)
        max_inc         -- Number of integer timesteps to get to end time
        part_save_iter  -- Number of timesteps between particle data saves
        field_save_iter -- Number of timesteps between field    data saves
    
    Note : Assumes no dispersion effects or electric field acceleration to
           be initial limiting factor. This may change for inhomogenous loading
           of particles or initial fields.
    '''
    ion_ts = const.orbit_res / const.gyfreq  # Timestep to resolve gyromotion
    vel_ts = 0.5 * const.dx / np.max(
        np.abs(vel[0, :])
    )  # Timestep to satisfy CFL condition: Fastest particle doesn't traverse more than half a cell in one time step

    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

    gyperiod = 2 * np.pi / const.gyfreq
    DT = min(ion_ts, vel_ts, Eacc_ts)
    max_time = const.max_rev * 2 * np.pi / const.gyfreq_eq  # Total runtime in seconds
    max_inc = int(max_time / DT) + 1  # Total number of time steps

    if const.part_res == 0:
        part_save_iter = 1
    else:
        part_save_iter = int(const.part_res * gyperiod / DT)

    if const.field_res == 0:
        field_save_iter = 1
    else:
        field_save_iter = int(const.field_res * gyperiod / DT)

    if const.save_fields == 1 or const.save_particles == 1:
        save.store_run_parameters(DT, part_save_iter, field_save_iter, Te0)

    damping_array = np.ones(NC + 1)
    set_damping_array(damping_array, DT)

    print('Timestep: %.4fs, %d iterations total\n' % (DT, max_inc))
    return DT, max_inc, part_save_iter, field_save_iter, damping_array
Пример #3
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