def test_constraint(self): for ang in np.linspace(-8 * pi, 8 * pi, 100): c_ang = util.constrain_angle(ang) self.assertAlmostEqual(abs(np.sin(ang)), abs(np.sin(c_ang))) self.assertAlmostEqual(abs(np.cos(ang)), abs(np.cos(c_ang))) self.assertLessEqual(c_ang, 2 * pi) self.assertGreaterEqual(c_ang, 0)
def test_constraint(self): for ang in np.linspace(-8*pi, 8*pi, 100): c_ang = util.constrain_angle(ang) self.assertAlmostEqual(abs(np.sin(ang)), abs(np.sin(c_ang))) self.assertAlmostEqual(abs(np.cos(ang)), abs(np.cos(c_ang))) self.assertLessEqual(c_ang, 2*pi) self.assertGreaterEqual(c_ang, 0)
def elastic_scatter(proj, target, cm_angle, azi): """Perform the special relativity calculation needed for elastic scattering. This takes two particles and scatters them elastically at the given center-of-mass angle and azimuthal angle. These two angles are free parameters in the special relativity calculation, so they need to be given to the function. These equations are based on those at http://skisickness.com/2010/04/25/ Parameters ---------- proj : pytpc.simulation.Particle The projectile particle target : pytpc.simulation.Particle The target particle cm_angle : number The scattering angle in the center-of-momentum frame, in radians azi : number The final azimuthal angle for the scattered particles. The ejectile will be given this azimuthal angle, and the recoil particle will be given this angle + pi. Returns ------- ejec : pytpc.simulation.Particle The ejectile particle recoil : pytpc.simulation.Particle The recoil particle """ recoil = copy.copy(target) ejec = copy.copy(proj) m1 = target.mass m2 = proj.mass m3 = ejec.mass m4 = recoil.mass T1 = proj.energy # Note: This is the kinetic energy only s = (m1 + m2) ** 2 + 2 * m1 * T1 # The Lorentz invariant. We don't need c's since the mass & mom are in MeV pcm = sqrt(((s - m1 ** 2 - m2 ** 2) ** 2 - 4 * m1 ** 2 * m2 ** 2) / (4 * s)) # COM momentum of the reactants ppcm = sqrt(((s - m3 ** 2 - m4 ** 2) ** 2 - 4 * m3 ** 2 * m4 ** 2) / (4 * s)) # COM momentum of the products chi = log((sqrt(pcm ** 2 + m1 ** 2) + pcm) / m1) # rapidity of the COM frame T3 = sqrt(ppcm ** 2 + m3 ** 2) * cosh(chi) + ppcm * cos(cm_angle) * sinh(chi) - m3 # ejectile KE T4 = sqrt(ppcm ** 2 + m4 ** 2) * cosh(chi) - ppcm * cos(cm_angle) * sinh(chi) - m4 # recoil KE E3cm = sqrt(ppcm ** 2 + m3 ** 2) # ejectile COM total energy E4cm = sqrt(ppcm ** 2 + m4 ** 2) # recoil COM total energy pol3 = atan(ppcm * sin(cm_angle) / (sinh(chi) * E3cm + cosh(chi) * ppcm * cos(cm_angle))) # ejectile lab polar ang pol4 = atan(ppcm * sin(cm_angle) / (sinh(chi) * E4cm - cosh(chi) * ppcm * cos(cm_angle))) # recoil lab polar angle ejec.energy = T3 ejec.polar = pol3 ejec.azimuth = 0 ejec.position = proj.position recoil.energy = T4 recoil.polar = pol4 recoil.azimuth = pi recoil.position = proj.position # These angles are relative to the projectile's original trajectory, and need to be rotated into the lab frame. # This can be done with the Euler angle rotations. We need to use the transpose of the Euler matrix here. # (I'm not sure why. It just seems to be what works...) eulermat = euler_matrix(phi=proj.azimuth, theta=proj.polar, psi=azi).T # the transpose is the inverse (ortho. mat.) recoil.momentum = eulermat.dot(recoil.momentum) ejec.momentum = eulermat.dot(ejec.momentum) assert ejec.polar >= 0, "ejectile polar angle < 0" assert recoil.polar >= 0, "recoil polar angle < 0" # The Euler angle rotation might have pushed the azimuthal angles outside [0, 2*pi), so fix them. recoil.azimuth = constrain_angle(recoil.azimuth) ejec.azimuth = constrain_angle(ejec.azimuth) assert 0 <= recoil.azimuth <= 2 * pi, "recoil azimuth out of bounds" assert 0 <= ejec.azimuth <= 2 * pi, "ejectile azimuth out of bounds" assert ejec.energy - T3 < 1e-2, "ejectile energy was changed by rotation: {} -> {}".format(T3, ejec.energy) assert recoil.energy - T4 < 1e-2, "recoil energy was changed by rotation: {} -> {}".format(T4, recoil.energy) return ejec, recoil
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))