Пример #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
Пример #2
0
def test_particle_orbit():
    def position_update(pos, vel, DT):
        for ii in range(3):
            pos[ii] += vel[ii, 0] * dt
        return pos

    NX = 64
    B0 = 0.01
    v0 = 1e5
    mi = 1.672622e-27  # Mass of proton (kg)
    qi = 1.602177e-19  # Elementary charge (C)

    resolution = 10
    num_rev = 5000
    maxtime = int(resolution * num_rev)
    gyperiod = (2 * np.pi * mi) / (qi * B0)
    dt = gyperiod / resolution

    B = np.zeros((NX + 3, 3), dtype=np.float64)
    E = np.zeros((NX + 3, 3), dtype=np.float64)
    B[:, 0] += B0

    Ie = np.array([NX // 2])
    Ib = np.array([NX // 2])
    We = np.array([0., 1., 0.]).reshape((3, 1))
    Wb = np.array([0., 1., 0.]).reshape((3, 1))
    idx = np.array([0])

    vp = np.array([[0.], [v0], [0.]])
    rL = (mi * vp[1][0]) / (qi * B0)

    xp = np.array([-rL, 0., 0.])

    print('\nNumber of revolutions: {}'.format(num_rev))
    print('Points per revolution: {}'.format(resolution))
    print('Total number of points: {}'.format(maxtime))

    print('\nGyroradius: {}m'.format(rL))
    print('Gyroperiod: {}s'.format(round(gyperiod, 2)))
    print('Timestep: {}s'.format(round(dt, 3)))

    particles.velocity_update(vp, Ie, We, Ib, Wb, idx, B, E, -0.5 * dt)

    xy = np.zeros((maxtime + 1, 2))

    for ii in range(maxtime + 1):
        xy[ii, 0] = xp[1]
        xy[ii, 1] = xp[2]

        position_update(xp, vp, dt)
        particles.velocity_update(vp, Ie, We, Ib, Wb, idx, B, E, dt)
    print(xp)
    print(vp)
    #plt.plot(xy[:, 0], xy[:, 1])
    #plt.axis('equal')
    return
Пример #3
0
def check_timestep(pos, vel, B, E, q_dens, Ie, W_elec, Ib, W_mag, B_cent, \
                     qq, DT, max_inc, part_save_iter, field_save_iter, idx):
    
    interpolate_to_center_cspline3D(B, B_cent)
    B_tot           = np.sqrt(B_cent[:, 0] ** 2 + B_cent[:, 1] ** 2 + B_cent[:, 2] ** 2)

    dispfreq        = ((np.pi / const.dx) ** 2) * (B_tot / (const.mu0 * q_dens)).max()           # Dispersion frequency
    local_gyfreq    = const.high_rat  * np.abs(B_tot).max() / (2 * np.pi)      
    ion_ts          = const.orbit_res * 1./local_gyfreq
    
    if E[:, 0].max() != 0:
        if vel.max() != 0:
            elecfreq        = const.high_rat*(np.abs(E[:, 0] / vel.max()).max())               # Electron acceleration "frequency"
            Eacc_ts         = const.freq_res / elecfreq                            
        else:
            Eacc_ts = ion_ts
    else:
        Eacc_ts = ion_ts
    
    if const.account_for_dispersion == True:
        disp_ts     = const.dispersion_allowance * const.freq_res / dispfreq     # Making this a little bigger so it doesn't wreck everything
    else:
        disp_ts     = ion_ts

    vel_ts          = 0.80 * const.dx / 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(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(vel, Ie, W_elec, Ib, W_mag, idx, B, E, -0.5*DT)   # De-sync vel/pos 
        print('Timestep halved. Syncing particle velocity...')
        
            
    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(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(vel, Ie, W_elec, Ib, W_mag, idx, B, E, -0.5*DT)   # De-sync vel/pos 
        print('Timestep Doubled. Syncing particle velocity...')

    
    return qq, DT, max_inc, part_save_iter, field_save_iter
Пример #4
0
def initialize():
    pos, vel, Ie, W_elec, idx = init.initialize_particles()
    B, E_int = init.initialize_fields()
    DT, max_inc, data_iter = aux.set_timestep(vel)

    if data_iter == 0:
        data_iter = max_inc

    q_dens, Ji = sources.collect_moments(vel, Ie, W_elec, idx)

    E_int, Ve, Te = fields.calculate_E(B, Ji, q_dens)
    vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E_int,
                                    -0.5 * DT)
    return pos, vel, Ie, W_elec, idx, B, E_int, q_dens, Ji, Ve, Te, DT, max_inc, data_iter
Пример #5
0
        = init.set_timestep(vel, Te0)

    fields.calculate_E(B, Ji, q_dens, E_int, Ve, Te, Te0, temp3De, temp3Db,
                       temp1D, E_damping_array, 0, DT, 0)

    print('Saving initial conditions...')
    if save_particles == 1:
        save.save_particle_data(0, DT, part_save_iter, 0, pos, vel, idx)

    if save_fields == 1:
        save.save_field_data(0, DT, field_save_iter, 0, Ji, E_int,\
                             B, Ve, Te, q_dens, B_damping_array, E_damping_array)

    # Retard velocity
    print('Retarding velocity...')
    particles.velocity_update(pos, vel, Ie, W_elec, Ib, W_mag, idx, Ep, Bp, B,
                              E_int, v_prime, S, T, temp_N, -0.5 * DT)

    qq = 1
    sim_time = DT
    print('Starting main loop...')
    while qq < max_inc:
        qq, DT, max_inc, part_save_iter, field_save_iter =                                \
        aux.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)

        if qq % part_save_iter == 0 and save_particles == 1:
            save.save_particle_data(sim_time, DT, part_save_iter, qq, pos, vel,
                                    idx)
Пример #6
0
def check_timestep(qq, DT, pos, vel, B, E, dns, Ie, W_elec, max_inc, data_iter,
                   plot_iter, subcycles, idx):
    max_Vx = np.max(vel[0, :])
    max_V = np.max(vel)
    k_max = np.pi / const.dx

    B_cent = interpolate_to_center_cspline3D(B)
    B_tot = np.sqrt(B_cent[:, 0]**2 + B_cent[:, 1]**2 + B_cent[:, 2]**2)
    high_rat = (const.charge / const.mass).max()

    gyfreq = high_rat * np.abs(B_tot).max() / (2 * np.pi)
    ion_ts = const.orbit_res * 1. / gyfreq

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

    vel_ts = 0.75 * const.dx / max_Vx  # 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 particle conditions

    if DT_part < 0.9 * DT:
        vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E,
                                        0.5 * DT)  # Re-sync vel/pos
        DT *= 0.5
        max_inc *= 2
        qq *= 2
        vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E,
                                        -0.5 * DT)  # De-sync vel/pos

        if plot_iter != None:
            plot_iter *= 2

        if data_iter != None:
            data_iter *= 2

        print('Timestep halved. Syncing particle velocity with DT = {}'.format(
            DT))

    elif DT_part >= 4.0 * DT and qq % 2 == 0:
        vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E,
                                        0.5 * DT)  # Re-sync vel/pos
        DT *= 2.0
        max_inc = (max_inc + 1) / 2
        qq /= 2
        vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E,
                                        -0.5 * DT)  # De-sync vel/pos

        if plot_iter == None or plot_iter == 1:
            plot_iter = 1
        else:
            plot_iter /= 2

        if data_iter == None or data_iter == 1:
            data_iter = 1
        else:
            data_iter /= 2

        print(
            'Timestep Doubled. Syncing particle velocity with DT = {}'.format(
                DT))

    if const.adaptive_subcycling == True:
        dispfreq = (k_max**
                    2) * (B_tot /
                          (const.mu0 * dns)).max()  # Dispersion frequency
        dt_sc = const.freq_res * 1. / dispfreq
        new_subcycles = int(DT / dt_sc + 1)

        if subcycles < 0.75 * new_subcycles:
            subcycles *= 2
            print('Number of subcycles per timestep doubled to {}'.format(
                subcycles))
        if subcycles > 3.0 * new_subcycles:
            subcycles = (subcycles + 1) / 2
            print('Number of subcycles per timestep halved to {}'.format(
                subcycles))

        if subcycles > const.subcycle_max:
            const.adaptive_subcycling = False
            subcycles = const.subcycle_max
    else:
        pass

    return pos, vel, qq, DT, max_inc, data_iter, plot_iter, subcycles
Пример #7
0
            qq, DT, part, B, E, dns_int, max_inc, data_dump_iter,
            plot_dump_iter)

        if change_flag == 1:
            print(
                'Timestep halved. Syncing particle velocity/position with DT = {}'
                .format(DT))
            part, dns_int, dns_half, J_plus, J_minus, G, L = sources.init_collect_moments(
                part, 0.5 * DT)

        B = fields.cyclic_leapfrog(B, dns_int, J_minus, DT)
        E = fields.calculate_E(B, J_minus, dns_half)
        J = sources.push_current(J_plus, E, B, L, G, DT)
        E = fields.calculate_E(B, J, dns_half)

        part = particles.velocity_update(part, B, E, DT)

        part, dns_int, J_plus, J_minus, G, L = sources.collect_moments(
            part, DT)

        dns_int = 0.5 * (dns_int + dns_half)
        J = 0.5 * (J_plus + J_minus)
        B = fields.cyclic_leapfrog(B, dns_int, J, DT)

        if qq % data_dump_iter == 0 and generate_data == 1:  # Save data, if flagged
            pas.save_data(DT, data_dump_iter, qq, part, J, E, B, dns_int)

        if qq % plot_dump_iter == 0 and generate_plots == 1:  # Generate and save plots, if flagged
            pas.create_figure_and_save(part, J, B, dns_int, qq, DT,
                                       plot_dump_iter)
Пример #8
0
    DT, max_inc, part_save_iter, field_save_iter = init.set_timestep(vel)

    # Collect initial moments and save initial state
    sources.collect_moments(vel, Ie, W_elec, idx, q_dens, Ji, ni, nu, temp1D)
    fields.calculate_E(B, Ji, q_dens, E_int, Ve, Te, temp3D, temp3D2, temp1D)

    if save_particles == 1:
        save.save_particle_data(DT, part_save_iter, 0, pos, vel)

    if save_fields == 1:
        save.save_field_data(DT, field_save_iter, 0, Ji, E_int, B, Ve, Te,
                             q_dens)

    particles.assign_weighting_TSC(pos, Ib, W_mag, E_nodes=False)
    particles.velocity_update(vel, Ie, W_elec, Ib, W_mag, idx, B, E_int,
                              -0.5 * DT)

    qq = 1
    print('Starting main loop...')
    while qq < max_inc:
        qq, DT, max_inc, part_save_iter, field_save_iter =               \
        aux.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)

        if qq % part_save_iter == 0 and save_particles == 1:
            save.save_particle_data(DT, part_save_iter, qq, pos, vel)

        if qq % field_save_iter == 0 and save_fields == 1:
            save.save_field_data(DT, field_save_iter, qq, Ji, E_int, B, Ve, Te,
Пример #9
0
if __name__ == '__main__':
    start_time = timer()

    pos, vel, Ie, W_elec, idx = init.initialize_particles()
    B, E_int = init.initialize_fields()

    DT, max_inc, data_iter = aux.set_timestep(vel)
    print 'Timestep: %.4fs, %d iterations total' % (DT, max_inc)
    if generate_data == 1:
        save.store_run_parameters(DT, data_iter)

    q_dens, Ji = sources.collect_moments(vel, Ie, W_elec, idx)

    E_int, Ve, Te = fields.calculate_E(B, Ji, q_dens)
    vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E_int,
                                    -0.5 * DT)

    qq = 0
    while qq < max_inc:
        # 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
Пример #10
0
                pos, Ie, W_elec, dns_int, dns_half, J_plus, J_minus, G, L   = sources.init_collect_moments(pos, vel, Ie, W_elec, idx, 0.5*DT)
            elif change_flag == 2:
                print('Timestep doubled. Syncing particle velocity/position with DT = {}'.format(DT))
                pos, Ie, W_elec, dns_int, dns_half, J_plus, J_minus, G, L   = sources.init_collect_moments(pos, vel, Ie, W_elec, idx, 0.5*DT)
                                                        
        
        #######################
        ###### MAIN LOOP ######
        #######################
        B         = fields.cyclic_leapfrog(B, dns_int, J_minus, DT, subcycles)
        E, Ve, Te = fields.calculate_E(B, J_minus, dns_half)

        J         = sources.push_current(J_plus, E, B, L, G, DT)
        E, Ve, Te = fields.calculate_E(B, J, dns_half)
        
        vel = particles.velocity_update(pos, vel, Ie, W_elec, idx, B, E, J, DT)

        # Store pc(1/2) here while pc(3/2) is collected
        dns_int = dns_half          
        pos, Ie, W_elec, dns_half, J_plus, J_minus, G, L = sources.collect_moments(pos, vel, Ie, W_elec, idx, DT)
        
        dns_int = 0.5 * (dns_int + dns_half)
        J       = 0.5 * (J_plus  +  J_minus)
        
        B           = fields.cyclic_leapfrog(B, dns_int, J, DT, subcycles)
        E, Ve, Te   = fields.calculate_E(B, J, dns_int)                                     # This one's just for output


        ########################
        ##### OUTPUT DATA  #####
        ########################
Пример #11
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