def test_species(scaling): g = PeriodicTestGrid(1e-8, 1, 100, c=lightspeed, epsilon_0=epsilon_zero) species = Species(electric_charge, electron_rest_mass, 1, g, scaling=scaling) species.v[:, 0] = 10 kinetic_energy_single_electron = 4.554692e-29 assert np.isclose(species.kinetic_energy, kinetic_energy_single_electron * scaling)
def __init__(self, filename, n_macroparticles, n_cells): """ A simulation of laser-hydrogen shield interaction. Parameters ---------- filename : str Filename for the simulation. n_macroparticles : int Number of macroparticles for each species. The simulation is normalized to 75000 macroparticles by default, n_cells : int Number of grid cells. """ grid = PeriodicGrid(T=total_time, L=length, NG=int(n_cells), c =lightspeed, epsilon_0 =epsilon_zero) cells_per_wl = laser_wavelength / grid.dx print(cells_per_wl) vtherm = 2 * np.pi / cells_per_wl * lightspeed * 10 print(vtherm / lightspeed) if n_macroparticles: electrons = Species(-electric_charge, electron_rest_mass, n_macroparticles, grid, "electrons", scaling) electrons.random_velocity_init(vtherm) protons = Species(electric_charge, proton_mass, n_macroparticles, grid, "protons", scaling) list_species = [electrons, protons] omega_p = (cold_plasma_frequency(electrons.scaling * electrons.N / grid.dx, electron_rest_mass, epsilon_zero, electric_charge)**2 + 3 * (grid.NG * 2 * np.pi / grid.L * vtherm)**2)**0.5 debye_length = vtherm / omega_p print(grid.dx, debye_length) print("grid stability", grid.dx , 3.4 * debye_length, grid.dx < 3.4 * debye_length) print("step stability", grid.dt , 2/omega_p, grid.dt < 2/omega_p) else: list_species = [] description = "Stability test" super().__init__(grid, list_species, filename=filename, category_type="stability", config_version=VERSION, title=description, considered_large = True) print("Simulation prepared.")
def test_relativistic_magnetic_field(g, _n_particles, _v0): """Tests movement in uniform magnetic field in the z direction. The particle should move in a uniform circle. This also covers the non-relativistic case at small velocities. """ B0 = 1 s = Species(1, 1, _n_particles, g, individual_diagnostics=True) t = np.arange(0, g.T, g.dt * s.save_every_n_iterations) - g.dt / 2 s.v[:, 1] = _v0 def uniform_magnetic_field(*args, **kwargs): return np.array([[0, 0, 0]], dtype=float), np.array([[0, 0, B0]], dtype=float) gamma = physics.gamma_from_v(s.v, s.c)[0, 0] vy_analytical = _v0 * np.cos(s.q * B0 * (t - g.dt / 2) / (s.m * gamma)) s.velocity_push(uniform_magnetic_field, 0.5) for i in range(g.NT): s.save_particle_values(i) s.velocity_push(uniform_magnetic_field) s.position_push() assert (s.velocity_history < g.c).all(), plot( t, vy_analytical, s.velocity_history[:, 0, 1], f"Velocity went over c! Max velocity: {s.velocity_history.max()}") assert np.allclose(s.kinetic_energy_history[1:-1], s.kinetic_energy_history[1:-1].mean(), atol=atol, rtol=rtol), "Energy is off!" assert np.allclose(s.velocity_history[:, 0, 1], vy_analytical, atol=atol, rtol=rtol) return Simulation(g, [s])
def test_relativistic_harmonic_oscillator(g, _n_particles, E0): """Tests relativistic particle movement in a harmonic oscillator trajectory. The velocity is compared to an analytical result.""" E0 = 1 omega = 2 * np.pi / g.T s = Species(1, 1, _n_particles, g, individual_diagnostics=True) t = np.arange(0, g.T, g.dt * s.save_every_n_iterations) - g.dt / 2 t_s = t - g.dt / 2 v_analytical = E0 * s.c * s.q * np.sin( omega * t_s) / np.sqrt((E0 * s.q * np.sin(omega * t_s))**2 + (s.m * omega * s.c)**2) def electric_field(x, t): return np.array([[1, 0, 0]], dtype=float) * E0 * np.cos( omega * t), np.array([[0, 0, 0]], dtype=float) s.velocity_push(lambda x: electric_field(x, 0), 0.5) for i in range(g.NT): s.save_particle_values(i) s.velocity_push(lambda x: electric_field(x, i * g.dt)) s.position_push() s.save_particle_values(g.NT - 1) assert (s.velocity_history < 1).all(), plot( t, v_analytical, s.velocity_history[:, 0, 0], f"Velocity went over c! Max velocity: {s.velocity_history.max()}") assert np.allclose(s.velocity_history[:, 0, 0], v_analytical, atol=atol, rtol=rtol), \ plot(t, v_analytical, s.velocity_history[:, 0, 0], )
def test_periodic_particles(g): """Tests that particles on periodic grids don't disappear.""" s = Species(1, 1, 100, g, individual_diagnostics=True) s.distribute_uniformly(g.L) s.v[:] = 0.5 for i in range(g.NT): force = lambda x: (np.array([[0, 0, 0]], dtype=float), np.array([[0, 0, 0]], dtype=float)) s.velocity_push(force) s.position_push() g.apply_particle_bc(s) assert s.N_alive == s.N, "They're dead, Jim."
def test_density_helper(_fraction, _second_fraction, _profile, _N_particles): g = PeriodicTestGrid(1, 100, 100) s = Species(1, 1, _N_particles, g) moat_length = g.L * _fraction ramp_length = g.L * _second_fraction plasma_length = 2*ramp_length # plasma_length = plasma_length if plasma_length > ramp_length else ramp_length s.distribute_nonuniformly(moat_length, ramp_length, plasma_length, profile=_profile) return s, g, moat_length, plasma_length, _profile
def test_nonperiodic_particles(g_aperiodic): """Tests that particles on nonperiodic grids disappear when running out the cell boundaries.""" g = g_aperiodic s = Species(1, 1, 100, g, individual_diagnostics=True) s.distribute_uniformly(g.L) s.v[:] = 0.5 for i in range(g.NT): force = lambda x: (np.array([[0, 0, 0]], dtype=float), np.array([[0, 0, 0]], dtype=float)) s.velocity_push(force) s.position_push() g.apply_particle_bc(s) assert s.N_alive == 0
def test_many_particles_periodic_deposition(N, _velocity): NG = 10 L = NG g = Grid(1, L=L, NG=NG, periodic=True) s = Species(1.0 / N, 1, N, g) s.distribute_uniformly(L) s.v[:, 0] = _velocity s.v[:, 1] = 1 s.v[:, 2] = -1 dt = g.dx / s.c g.gather_current([s]) longitudinal_collected_weights = g.current_density_x[1:-2].sum( axis=0) / s.v[0, 0] transversal_collected_weights = g.current_density_yz[2:-2].sum( axis=0) / s.v[0, 1:] label = {0: 'x', 1: 'y', 2: 'z'} def plot(): fig, ax = plt.subplots() i = 0 fig.suptitle( f"Longitudinal weights: {longitudinal_collected_weights}, transversal: {transversal_collected_weights}" ) ax.plot(g.x, g.current_density_x[1:-2], alpha=(3 - i) / 3, lw=1 + i, label=f"{label[i]}") ax.scatter(s.x, np.zeros_like(s.x)) ax.legend(loc='lower right') ax.set_xticks(g.x) ax.grid() for i in range(1, 3): ax.plot(g.x, g.current_density_yz[2:-2, i - 1], alpha=(3 - i) / 3, lw=1 + i, label=f"{label[i]}") ax.scatter(s.x, np.zeros_like(s.x)) ax.legend(loc='lower right') ax.set_xticks(g.x) ax.grid() filename = f"data_analysis/test/periodic_multiple_{N}_{_velocity:.2f}.png" make_sure_path_exists(filename) fig.savefig(filename) fig.clf() plt.close(fig) assert np.allclose(longitudinal_collected_weights, 1), ("Longitudinal weights don't match!", plot()) assert np.allclose(transversal_collected_weights, 1), ("Transversal weights don't match!", plot())
def test_relativistic_constant_field(g, _n_particles): """Tests relativistic movement in constant electric field along the direction of motion.""" s = Species(1, 1, _n_particles, g, individual_diagnostics=True) t = np.arange(0, g.T, g.dt * s.save_every_n_iterations) - g.dt / 2 def uniform_field(*args, **kwargs): return np.array([[1, 0, 0]], dtype=float), np.array([[0, 0, 0]], dtype=float) v_analytical = (t - g.dt / 2) / np.sqrt((t - g.dt / 2)**2 + 1) s.velocity_push(uniform_field, -0.5) for i in range(g.NT): s.save_particle_values(i) s.velocity_push(uniform_field) s.position_push() s.save_particle_values(g.NT - 1) assert (s.velocity_history < 1).all(), plot( t, v_analytical, s.velocity_history[:, 0, 0], f"Velocity went over c! Max velocity: {s.velocity_history.max()}") assert np.allclose(s.velocity_history[:, 0, 0], v_analytical, atol=atol, rtol=rtol), \ plot(t, v_analytical, s.velocity_history[:, 0, 0], ) return Simulation(g, [s])
def __init__(self, filename, n_macroparticles, n_cells, impulse_duration, laser_intensity, perturbation_amplitude, laser_polarization="Ez", individual_diagnostics=False): """ A simulation of laser-hydrogen shield interaction. Parameters ---------- filename : str Filename for the simulation. n_macroparticles : int Number of macroparticles for each species. The simulation is normalized to 75000 macroparticles by default, impulse_duration : float Duration of the laser impulse. laser_intensity : float Laser impulse intensity, in W/m^2. A good default is 1e21. perturbation_amplitude : float Amplitude of the initial position perturbation. """ if laser_intensity: bc_laser = BoundaryCondition.bcs[laser_polarization]( laser_intensity=laser_intensity, laser_wavelength=laser_wavelength, envelope_center_t=total_time / 2, envelope_width=impulse_duration, envelope_power=6, c=lightspeed, epsilon_0=epsilon_zero, ) print(f"Laser amplitude: {bc_laser.laser_amplitude:e}") bc = bc_laser else: bc = BoundaryCondition.BC() grid = NonperiodicGrid(T=total_time, L=length, NG=n_cells, c=lightspeed, epsilon_0=epsilon_zero, bc=bc) cells_per_wl = laser_wavelength / grid.dx print(f"{cells_per_wl:.1f} grid cells per laser wavelength.") vtherm = 2 * np.pi / cells_per_wl * lightspeed print( f"Thermal velocity for this simulation should be on the order of {vtherm / lightspeed:.3f}c." ) if n_macroparticles: electrons = Species(-electric_charge, electron_rest_mass, n_macroparticles, grid, "electrons", scaling, individual_diagnostics=individual_diagnostics) protons = Species(electric_charge, proton_mass, n_macroparticles, grid, "protons", scaling, individual_diagnostics=individual_diagnostics) list_species = [electrons, protons] else: list_species = [] self.perturbation_amplitude = perturbation_amplitude # in units of dx description = "Hydrogen shield-laser interaction" super().__init__(grid, list_species, filename=filename, category_type="laser-shield", config_version=VERSION, title=description, considered_large=True) print("Simulation prepared.")
def test_species(scaling): g = PeriodicTestGrid(1e-8, 1, 100, c=lightspeed, epsilon_0=epsilon_zero) species = Species(electric_charge, electron_rest_mass, 1, g, scaling=scaling) species.v[:, 0] = 10 kinetic_energy_single_electron = 4.554692e-29 assert np.isclose(species.kinetic_energy, kinetic_energy_single_electron*scaling)
def test_two_particles_deposition(_position, _velocity, _truefalse, _truefalse2): NG = 7 L = NG g = Grid(1, L=L, NG=NG) c = 1 dt = g.dx / c positions = [_position * g.dx, (L - _position * g.dx) % L] # print(positions) for position in positions: s = Particle(g, position, _velocity, 1, -1) # print(f"\n======PARTICLE AT {position}=======") # print(s) # print(s.x) # print(s.v) if _truefalse: longitudinal_current_deposition(g.current_density_x, s.v[:, 0], s.x, g.dx, dt, s.q) if _truefalse2: transversal_current_deposition(g.current_density_yz, s.v, s.x, g.dx, dt, s.q) # print(g.current_density) collected_weights_x = g.current_density_x.sum(axis=0) / _velocity collected_weights_yz = g.current_density_yz.sum(axis=0) / np.array( [1, -1], dtype=float) g2 = Grid(1, L=L, NG=NG) s = Species(1, 1, 2, g2) s.x[:] = positions s.v[:, 0] = _velocity s.v[:, 1] = 1 s.v[:, 2] = -1 # print("\n\n======TWO PARTICLES=======") # print(s) # print(s.x) # print(s.v) if _truefalse: longitudinal_current_deposition(g2.current_density_x, s.v[:, 0], s.x, g2.dx, dt, s.q) if _truefalse2: transversal_current_deposition(g2.current_density_yz, s.v, s.x, g2.dx, dt, s.q) # print(g2.current_density) collected_weights_x2 = g2.current_density_x.sum(axis=0) / s.v[0, 0] collected_weights_yz2 = g2.current_density_yz.sum(axis=0) / np.array( [1, -1], dtype=float) label = {0: 'x', 1: 'y', 2: 'z'} def plot(): fig, (ax1, ax2) = plt.subplots(2) plt.suptitle(f"x: {positions}, vx: {_velocity}") i = 0 ax1.plot(g.x, g.current_density_x[1:-2], alpha=(3 - i) / 3, lw=1 + i, label=f"1 {label[i]}") ax1.plot(g.x, g2.current_density_x[1:-2], alpha=(3 - i) / 3, lw=1 + i, label=f"2 {label[i]}") ax2.plot(g.x, (g.current_density_x - g2.current_density_x)[1:-2], alpha=(3 - i) / 3, lw=1 + i, label=f"1 - 2 {label[i]}") for i in range(1, 3): ax1.plot(g.x, g.current_density_yz[2:-2, i - 1], alpha=(3 - i) / 3, lw=1 + i, label=f"1 {label[i]}") ax1.plot(g.x, g2.current_density_yz[2:-2, i - 1], alpha=(3 - i) / 3, lw=1 + i, label=f"2 {label[i]}") ax2.plot(g.x, (g.current_density_yz - g2.current_density_yz)[2:-2, i - 1], alpha=(3 - i) / 3, lw=1 + i, label=f"1 - 2 {label[i]}") for ax in [ax1, ax2]: ax.scatter(s.x, np.zeros_like(s.x)) ax.legend(loc='lower right') ax.set_xticks(g.x) ax.grid() fig.savefig( f"data_analysis/deposition/{_position:.2f}_{_velocity:.2f}.png") assert np.allclose( g.current_density_x, g2.current_density_x), ("Longitudinal currents don't match!", plot()) assert np.allclose( g.current_density_yz, g2.current_density_yz), ("Transversal currents don't match!", plot()) assert np.allclose( collected_weights_x, collected_weights_x2), ("Longitudinal weights don't match!", plot()) assert np.allclose( collected_weights_yz, collected_weights_yz2), ("Transversal weights don't match!", plot())
def __init__(self, filename, n_macroparticles, impulse_duration, laser_intensity, perturbation_amplitude, additional_scaling=1): """ A simulation of laser-hydrogen shield interaction. Parameters ---------- filename : str Filename for the simulation. n_macroparticles : int Number of macroparticles for each species. The simulation is normalized to 75000 macroparticles by default, impulse_duration : float Duration of the laser impulse. laser_intensity : float Laser impulse intensity, in W/m^2. A good default is 1e21. perturbation_amplitude : float Amplitude of the initial position perturbation. """ if laser_intensity: bc_laser = BoundaryCondition.Laser( laser_intensity=laser_intensity, laser_wavelength=laser_wavelength, envelope_center_t=total_time / 2, envelope_width=impulse_duration, envelope_power=6, c=lightspeed, epsilon_0=epsilon_zero, ) print(f"Laser amplitude: {bc_laser.laser_amplitude:e}") bc = bc_laser.laser_pulse else: bc = lambda x: None grid = Grid(T=total_time, L=length, NG=number_cells, c=lightspeed, epsilon_0=epsilon_zero, bc=bc, periodic=False) if n_macroparticles: scaling = default_scaling * N_MACROPARTICLES / n_macroparticles * additional_scaling electrons = Species(-electric_charge, electron_rest_mass, n_macroparticles, grid, "electrons", scaling) protons = Species(electric_charge, proton_mass, n_macroparticles, grid, "protons", scaling) list_species = [electrons, protons] else: list_species = [] self.perturbation_amplitude = perturbation_amplitude # in units of dx description = "Hydrogen shield-laser interaction" super().__init__(grid, list_species, filename=filename, category_type="laser-shield", config_version=VERSION, title=description, considered_large=True) print("Simulation prepared.")