def test_angles_beam90_reacazi0(self): for azi in numpy.linspace(0, 2*pi, 100): proj = pytpc.Particle(4, 2, 2, polar=pi/2, azimuth=azi) ejec, recoil = rel.elastic_scatter(proj, self.target, pi/2, 0) self.assertAlmostEqual(ejec.azimuth, azi, places=3) self.assertAlmostEqual(recoil.azimuth, azi, places=3) self.assertAlmostEqual(abs(ejec.polar - recoil.polar), pi/2, places=2)
def test_azimuth(self): for azi in numpy.linspace(0, 2*pi, 20): ejec, recoil = rel.elastic_scatter(self.proj, self.target, self.cm_angle, azi) self.assertAlmostEqual(ejec.azimuth, azi) self.assertAlmostEqual(recoil.azimuth, constrain_angle(azi + pi))
def test_polar(self): for cm_angle in numpy.linspace(0.01, pi, 20, endpoint=False): ejec, recoil = rel.elastic_scatter(self.proj, self.target, cm_angle, self.azi) self.assertAlmostEqual(ejec.polar + recoil.polar, pi/2, delta=2.0)
def test_energy(self): ejec, recoil = rel.elastic_scatter(self.proj, self.target, self.cm_angle, self.azi) self.assertAlmostEqual(recoil.energy, 0, places=4) self.assertAlmostEqual(ejec.energy, self.proj.energy, places=4)
def test_energy_large_angle(self): ejec, recoil = rel.elastic_scatter(self.proj, self.target, pi-0.01, self.azi) self.assertAlmostEqual(ejec.energy, 0, places=3)
def test_energy_equal(self): ejec, recoil = rel.elastic_scatter(self.proj, self.target, pi/2, self.azi) self.assertAlmostEqual(recoil.energy, ejec.energy)
def simulate_elastic_scattering_track(proj, target, gas, ef, bf, interact_energy, cm_angle, azimuth): """Simulate an elastic scattering event with the given particles and parameters. The projectile will be tracked in the detector until it has total energy equal to `interact_energy`. Then, an elastic scattering interaction will happen with the provided COM angle and final azimuthal angle. Parameters ---------- proj : Particle The projectile. It must have non-zero energy. target : Particle The target. It must have zero energy (at least for now) gas : pytpc.gases.Gas or subclass The gas in the detector. If it's a subclass, make sure it is compatible with both the target and the projectile. ef : array-like The electric field, in SI units bf : array-like The magnetic field, in Tesla interact_energy : number The energy at which to stop tracking the projectile and perform the interaction cm_angle : number The center-of-momentum angle for the relativistic scattering calculation azimuth : number The final azimuthal angle of the ejectile particle Returns ------- pandas.DataFrame The concatenated outputs of the `track` function for each particle Raises ------ ValueError If the projectile has zero energy NotImplementedError If the target has nonzero energy. In the future, the code could be changed to allow a moving target particle, but it seems unnecessary for now. See Also -------- pytpc.relativity.elastic_scatter """ if proj.energy == 0: raise ValueError('Projectile must have energy > 0') if target.energy > 0.0: raise NotImplementedError('Target energy must be zero (for now at least)') # Track projectile until the collision proj_track = track(proj, gas, ef, bf, interact_energy) if not(0 <= proj.position[2] <= 1) or sqrt(proj.position[0]**2 + proj.position[1]**2) > 0.275: # The particle left the chamber before interacting return proj_track reaction_time = proj_track.time.max() ejec, recoil = rel.elastic_scatter(proj, target, cm_angle, azimuth) ejec_track = track(ejec, gas, ef, bf) ejec_track.time += reaction_time recoil_track = track(recoil, gas, ef, bf) recoil_track.time += reaction_time return pd.concat((proj_track, ejec_track, recoil_track), ignore_index=True)