def test_class_E(self): """ Testing with LHE event: 21 -1 0 0 502 501 +0.0000000000e+00 +0.0000000000e+00 +4.1758290104e+02 4.1758290104e+02 21 -1 0 0 501 502 -0.0000000000e+00 -0.0000000000e+00 -9.3527493892e+00 9.3527493892e+00 25 2 1 2 0 0 +0.0000000000e+00 -1.7763568394e-15 +4.0823015165e+02 4.2693565043e+02 -24 2 3 3 0 0 +3.1392005803e+01 +3.9830546942e+00 +2.4197449191e+02 2.5697832303e+02 -11 1 3 3 0 0 -1.8065699537e+01 +5.1144469720e+00 +7.7093957249e+01 7.9347371172e+01 13 1 4 4 0 0 +3.6021334597e+01 +3.3915572129e+01 +1.9426779434e+02 2.0046889658e+02 12 1 3 3 0 0 -1.3326306266e+01 -9.0975016661e+00 +8.9161702490e+01 9.0609956220e+01 -14 1 4 4 0 0 -4.6293287943e+00 -2.9932517435e+01 +4.7706697567e+01 5.6509426451e+01 """ p4_e = FourMomentum(7.9347371172e+01, -1.8065699537e+01, +5.1144469720e+00, +7.7093957249e+01) p4_mu = FourMomentum(2.0046889658e+02, +3.6021334597e+01, +3.3915572129e+01, +1.9426779434e+02) p4_ve = FourMomentum(9.0609956220e+01, -1.3326306266e+01, -9.0975016661e+00, +8.9161702490e+01) p4_vm = FourMomentum(5.6509426451e+01, -4.6293287943e+00, -2.9932517435e+01, +4.7706697567e+01) p4_w1 = p4_e + p4_ve p4_w2 = p4_mu + p4_vm p4_h = p4_w1 + p4_w2 input_event = Event(13000) input_event.add_particle("e-", Particle(-11, 2, p4_e)) input_event.add_particle("mu+", Particle(13, 2, p4_mu)) class_E_sols = cv.class_E(input_event, ["nu1", "nu2", "e-", "mu+"], p4_w1.mass(), p4_w2.mass(), p4_h.mass(), 1.89940637) passed = False for sol in class_E_sols: if p4_ve == sol["nu1"].four_momentum and p4_vm == sol["nu2"].four_momentum: passed = True self.assertTrue(passed)
def block_D(event_list, particle_keys, sqrt_s12, theta_1=None, phi_1=None, m1=0, m2=-1): """ s_12 ╭── p2 (visible) ┄┄┄┄┄┄┤ ╰── |p1| (missing) """ solutions = [] if not isinstance(event_list, list): if isinstance(event_list, Event): event_list = [event_list] else: raise TypeError("'event_list' should be a list of Event objects") for event in event_list: p2 = event[particle_keys[1]] if particle_keys[0] not in event.particles: event.add_particle(particle_keys[0], Particle(0, 1, FourMomentum())) p1 = event[particle_keys[0]] m2 = set_mass(m2, p2) s12 = sqrt_s12**2 R12 = (s12 - m1**2 - m2**2) / 2.0 # Make unit vectors to get cos(angle) theta_1, phi_1 = p1.theta, p1.phi theta_2, phi_2 = p2.theta, p2.phi u1 = ThreeVector.from_mag_and_angles(1.0, theta_1, phi_1) u2 = ThreeVector.from_mag_and_angles(1.0, theta_2, phi_2) cos_angle_difference = u1 * u2 # Now solve 2nd order polynomial denominator = 1 / (p2.three_vector().mag2() * cos_angle_difference**2) E1_sols = np.roots( np.nan_to_num([ 1 - p2.E**2 * denominator, 2 * p2.E * R12 * denominator, -m1**2 - R12**2 * denominator ])) E1_sols = remove_complex(E1_sols) for E1_sol in E1_sols: if not valid_energy(E1_sol): continue p1_mag = (E1_sol**2 - m1**2)**0.5 if isinstance(p1_mag, complex): continue output_event = deepcopy(event) output_event[particle_keys[0]].four_momentum = \ FourMomentum.from_mag_and_angles(E1_sol, p1_mag, theta_1, phi_1) solutions.append(output_event) return solutions
def test_energy_scaling(self): test_particle = Particle(0, 0, FourMomentum(20.0, 5.0, 5.0, 5.0)) prescaled_energy = test_particle.E prescaled_mass = test_particle.mass() test_particle.scale_energy(2.0) scaled_energy = test_particle.E scaled_mass = test_particle.mass() self.assertEqual(scaled_energy, 2.0*prescaled_energy) self.assertAlmostEqual(prescaled_mass, scaled_mass, 5)
def test_class_B(self): """ Testing with W+y LHE event: -1 -1 0 0 0 501 -0.0000000000e+00 +0.0000000000e+00 +7.4827774544e+00 7.4827774544e+00 2 -1 0 0 501 0 +0.0000000000e+00 -0.0000000000e+00 -4.0157473806e+02 4.0157473806e+02 24 2 1 2 0 0 +1.4717751207e+01 +1.9702783714e+01 -2.5724660044e+02 2.7001987857e+02 -13 1 3 3 0 0 +3.2395050227e+01 -5.3817378176e+00 -4.5790709849e+01 5.6348837518e+01 14 1 3 3 0 0 -1.7677299020e+01 +2.5084521531e+01 -2.1145589059e+02 2.1367104106e+02 22 1 1 2 0 0 -1.4717751207e+01 -1.9702783714e+01 -1.3684536016e+02 1.3903763694e+02 """ p4_w = FourMomentum(2.7001987857e+02, 1.4717751207e+01, 1.9702783714e+01, -2.5724660044e+02) p4_l = FourMomentum(5.6348837518e+01, 3.2395050227e+01, -5.3817378176e+00, -4.5790709849e+01) p4_nu = FourMomentum(2.1367104106e+02, -1.7677299020e+01, +2.5084521531e+01, -2.1145589059e+02) p4_y = FourMomentum(1.3903763694e+02, -1.4717751207e+01, -1.9702783714e+01, -1.3684536016e+02) x1 = 7.4827774544e+00/6500.0 x2 = 4.0157473806e+02/6500.0 input_event = Event(13000, l=Particle(-13, 2, p4_l), y=Particle(22, 2, p4_y)) class_B_sols = cv.class_B(input_event, ["nu", "l"], p4_w.mass()) passed = False for sol in class_B_sols: if sol["nu"].four_momentum == p4_nu and abs(sol.x1 - x1) < 1E-5 and abs(sol.x2 - x2) < 1E-5: passed = True self.assertTrue(passed)
def test_permutations(self): test_event = Event(13000) test_event.x1 = 0.5 test_event.x2 = 0.1 test_event.add_particle("j/1", Particle(2, 2, FourMomentum(10.0, 1.0, 1.0, 1.0))) test_event.add_particle("j/2", Particle(-3, 2, FourMomentum(20.0, 2.0, 2.0, 2.0))) test_event.add_particle("v1", Particle(0, 0, FourMomentum())) test_event.add_particle("v2", Particle(0, 0, FourMomentum())) test_event.add_particle("l/1", Particle(-11, 2, FourMomentum(100.0, 10.0, 10.0, 10.0))) test_event.add_particle("l/2", Particle(11, 2, FourMomentum(200.0, 20.0, 20.0, 20.0))) test_event.add_particle("l/3", Particle(13, 2, FourMomentum(300.0, 30.0, 30.0, 30.0))) test_event.add_particle("b/1", Particle(5, 2, FourMomentum(1000.0, 100.0, 100.0, 100.0))) permutations = test_event.make_permutations() # Should add some extra code to check the permutations, but for now the inspection seems okay self.assertEqual(len(permutations), 2*1*3*2*1*1)
def test_block_D(self): """ Testing with a Higgs -> bb event 25 2 1 2 0 0 -8.26690105298e+01 -9.73227425370e+00 +4.43133829811e+01 1.56579999860e+02 5 1 13 13 504 0 -1.10535285330e+02 +1.52021136715e+01 +4.01076612446e+01 1.18658619796e+02 -5 1 13 13 0 504 +2.78662748006e+01 -2.49343879252e+01 +4.20572173656e+00 3.79213800645e+01 """ p4_b1 = FourMomentum(1.18658619796e+02, -1.10535285330e+02, +1.52021136715e+01, +4.01076612446e+01) p4_b2 = FourMomentum(3.79213800645e+01, +2.78662748006e+01, -2.49343879252e+01, +4.20572173656e+00) p4_h = FourMomentum(1.56579999860e+02, -8.26690105298e+01, -9.73227425370e+00, +4.43133829811e+01) input_event = Event(13000, pb1=Particle(5, 2, p4_b1), pb2=Particle(5, 2, p4_b2)) block_D_sols = cv.block_D(input_event, ["pb1", "pb2"], p4_h.mass(), p4_b1.theta, p4_b1.phi, p4_b1.mass()) passed = False for sol in block_D_sols: if p4_b1 == sol["pb1"].four_momentum: passed = True self.assertTrue(passed)
def test_class_D(self): """ Testing with LHE event: 21 -1 0 0 501 502 +0.00000000000e+00 +0.00000000000e+00 +1.54270123210e+02 1.54270123210e+02 21 -1 0 0 502 503 +0.00000000000e+00 +0.00000000000e+00 -1.78313397110e+03 1.78313397110e+03 6 2 1 2 501 0 +2.21796373830e+02 -1.39027387052e+02 -6.28762112083e+02 7.02379511610e+02 5 1 3 3 501 0 +8.09346302052e+01 -1.07816045715e+02 -3.87091333836e+02 4.09922559527e+02 24 2 3 3 0 0 +1.40861743625e+02 -3.12113413375e+01 -2.41670778248e+02 2.92456952084e+02 -13 1 5 5 0 0 +1.19984134623e+02 -4.38501699278e+01 -2.34469954878e+02 2.67011590955e+02 14 1 5 5 0 0 +2.08776090020e+01 +1.26388285904e+01 -7.20082336998e+00 2.54453611289e+01 -6 2 1 2 0 503 -1.39127363300e+02 +1.48759661306e+02 -1.04441511879e+03 1.07844458284e+03 -5 1 8 8 0 503 -1.23288432443e+02 +2.98887004115e+01 -5.95113687202e+02 6.08502886337e+02 -24 2 8 8 0 0 -1.58389308569e+01 +1.18870960894e+02 -4.49301431586e+02 4.69941696503e+02 13 1 10 10 0 0 -3.56865149184e+01 +4.85974772445e+01 -2.63406562920e+02 2.70218910387e+02 -14 1 10 10 0 0 +1.98475840615e+01 +7.02734836498e+01 -1.85894868666e+02 1.99722786115e+02 25 2 1 2 0 0 -8.26690105298e+01 -9.73227425370e+00 +4.43133829811e+01 1.56579999860e+02 5 1 13 13 504 0 -1.10535285330e+02 +1.52021136715e+01 +4.01076612446e+01 1.18658619796e+02 -5 1 13 13 0 504 +2.78662748006e+01 -2.49343879252e+01 +4.20572173656e+00 3.79213800645e+01 """ p4_t1 = FourMomentum(7.02379511610e+02, +2.21796373830e+02, -1.39027387052e+02, -6.28762112083e+02) p4_t2 = FourMomentum(1.07844458284e+03, -1.39127363300e+02, +1.48759661306e+02, -1.04441511879e+03) p4_W1 = FourMomentum(2.92456952084e+02, +1.40861743625e+02, -3.12113413375e+01, -2.41670778248e+02) p4_W2 = FourMomentum(4.69941696503e+02, -1.58389308569e+01, +1.18870960894e+02, -4.49301431586e+02) p4_b1 = FourMomentum(4.09922559527e+02, +8.09346302052e+01, -1.07816045715e+02, -3.87091333836e+02) p4_b2 = FourMomentum(6.08502886337e+02, -1.23288432443e+02, +2.98887004115e+01, -5.95113687202e+02) p4_mu1 = FourMomentum(2.67011590955e+02, +1.19984134623e+02, -4.38501699278e+01, -2.34469954878e+02) p4_mu2 = FourMomentum(2.70218910387e+02, -3.56865149184e+01, +4.85974772445e+01, -2.63406562920e+02) p4_nu1 = FourMomentum(2.54453611289e+01, +2.08776090020e+01, +1.26388285904e+01, -7.20082336998e+00) p4_nu2 = FourMomentum(1.99722786115e+02, +1.98475840615e+01, +7.02734836498e+01, -1.85894868666e+02) p4_h = FourMomentum(1.56579999860e+02, -8.26690105298e+01, -9.73227425370e+00, +4.43133829811e+01) p4_hb1 = FourMomentum(1.18658619796e+02, -1.10535285330e+02, +1.52021136715e+01, +4.01076612446e+01) p4_hb2 = FourMomentum(3.79213800645e+01, +2.78662748006e+01, -2.49343879252e+01, +4.20572173656e+00) x1 = 1.54270123210e+02/6500.0 x2 = 1.78313397110e+03/6500.0 input_event = Event(13000, mu1=Particle(-13, 2, p4_mu1), b1=Particle(5, 2, p4_b1), mu2=Particle(13, 2, p4_mu2), b2=Particle(-5, 2, p4_b2), hb1=Particle(5, 2, p4_hb1), hb2=Particle(-5, 2, p4_hb2)) class_D_sols = cv.class_D(input_event, ["nu1", "nu2", "mu1", "b1", "mu2", "b2"], p4_t1.mass(), p4_t2.mass(), p4_W1.mass(), p4_W2.mass()) passed = False for sol in class_D_sols: if sol["nu1"].four_momentum == p4_nu1 and sol["nu2"].four_momentum == p4_nu2 and abs(sol.x1 - x1) < 1E-5 and abs(sol.x2 - x2) < 1E-5: passed = True self.assertTrue(passed)
def lhe_event_loop(lhe_filename, ordering, sqrt_s=13000): with open(lhe_filename, 'r') as lhe_file: reading_event = False for line in lhe_file: if reading_event: lhe_event += line ls = line.split() if len(ls) == 13: if int(ls[1]) == -1: z_mom = float(ls[8]) if z_mom > 0.0: event.x1 = z_mom/(event.sqrt_s/2) else: event.x2 = -z_mom/(event.sqrt_s/2) if int(ls[1]) == 1: if abs(int(ls[0])) == 12 or abs(int(ls[0])) == 14: status = 1 else: status = 2 event.add_particle(ordering[index], Particle(int(ls[0]), status, FourMomentum(float(ls[9]), float(ls[6]), float(ls[7]), float(ls[8])))) index += 1 if "<event>" in line: reading_event = True event = Event(sqrt_s) lhe_event = "" index = 0 elif "</event>" in line: reading_event = False lhe_event = lhe_event.replace("\n</event>", "") yield event, lhe_event
def class_B(event_list, particle_keys, sqrt_s12, m1=0, m2=-1): """ Gets the missing momentum for the following topology: x1 ╲ s_12 ╭── p2 (visible) █████┄┄┄┄┄┤ x2 ╱ ╰── p1 (missing) m2 can be specified, if -1 it is calculated """ solutions = [] if not isinstance(event_list, list): if isinstance(event_list, Event): event_list = [event_list] else: raise TypeError("'event_list' should be a list of Event objects") for event in event_list: p2 = event[particle_keys[1]] p_branches = FourMomentum(0.0, 0.0, 0.0, 0.0) for k in event.particles: if event.is_visible(k): p_branches += event[k] if particle_keys[0] not in event.particles: event.add_particle(particle_keys[0], Particle(0, 1, FourMomentum())) p1x = -1 * p_branches.x p1y = -1 * p_branches.y m2 = set_mass(m2, p2) s12 = sqrt_s12**2 R12 = (s12 - m1**2 - m2**2) / 2.0 # Solve polynomial equation for p1z (Ax^2 + Bx + C) A = 1 - p2.z**2 / p2.E**2 B = -2.0 * p2.z / p2.E**2 * (R12 + p1x * p2.x + p1y * p2.y) C = m1**2 + p1x**2 + p1y**2 - 1.0/p2.E**2*(R12**2 + p1x**2*p2.x**2 + p1y**2*p2.y**2 + \ 2*(R12*p1x*p2.x + R12*p1y*p2.y + p1x*p2.x*p1y*p2.y)) p1z_sols = np.roots([A, B, C]) E1_sols = (m1**2 + p1x**2 + p1y**2 + p1z_sols**2)**0.5 E1_sols = remove_complex(E1_sols) for E1, p1z in zip(E1_sols, p1z_sols): if not valid_energy(E1): continue p1_sol = FourMomentum(E1, p1x, p1y, p1z) if abs(p1_sol.m2 - m1**2) > FP_TOLERANCE: continue x1 = (E1 + p1z + p_branches.E + p_branches.z) / event.sqrt_s x2 = (E1 - p1z + p_branches.E - p_branches.z) / event.sqrt_s if x1 < 0.0 or x2 < 0.0 or x1 > 1.0 or x2 > 1.0: continue output_event = deepcopy(event) output_event.set_momentum(particle_keys[0], p1_sol) output_event.x1 = x1 output_event.x2 = x2 solutions.append(output_event) return solutions
def class_E(event_list, particle_keys, sqrt_s13, sqrt_s24, sqrt_s_hat, rapidity, m1=0, m2=0, m3=-1, m4=-1): """ Gets the two missing momenta for the following topology: ╭─────── missing (p1) x1 ╲ s_13 ╱╰─────── visible (p3) ╲ ╱ ███┄┄┄┄███ ╱ s_hat ╲ x2 ╱ s_24 ╲╭─────── missing (p2) ╰─────── visible (p4) x1 and x2 can be set manually for debugging m1, ..., m4 can be specified, if -1 they are calculated """ solutions = [] if not isinstance(event_list, list): if isinstance(event_list, Event): event_list = [event_list] else: raise TypeError("'event_list' should be a list of Event objects") for event in event_list: # Set up the kinematic variables s_13, s_24 = sqrt_s13**2, sqrt_s24**2 p3 = event[particle_keys[2]] p4 = event[particle_keys[3]] p_branches = FourMomentum(0.0, 0.0, 0.0, 0.0) for k in event.particles: if event.is_visible(k): p_branches += event[k] [event.add_particle(key, Particle(0, 1, FourMomentum())) for key in particle_keys[:2] \ if not key in event.particles] x1 = math.exp(rapidity) * sqrt_s_hat / event.sqrt_s x2 = math.exp(-rapidity) * sqrt_s_hat / event.sqrt_s m3 = set_mass(m3, p3) m4 = set_mass(m4, p4) p_i1 = FourMomentum(x1 * event.sqrt_s / 2, 0.0, 0.0, x1 * event.sqrt_s / 2) p_i2 = FourMomentum(x2 * event.sqrt_s / 2, 0.0, 0.0, -x2 * event.sqrt_s / 2) p_vis = p_i1 + p_i2 - p_branches Rvis = (m2**2 - m1**2 + p_vis * p_vis) / 2 R3 = p_vis * p3 - (s_13 - m1**2 - m3**2) / 2 R4 = (s_24 - m2**2 - m4**2) / 2 # Solved equations in terms of E2 from SymPy # p = E2*v_s + v_i <- vector equation PF = 1/(p3.x*p4.y*p_vis.z - p3.x*p4.z*p_vis.y - p3.y*p4.x*p_vis.z + \ p3.y*p4.z*p_vis.x + p3.z*p4.x*p_vis.y - p3.z*p4.y*p_vis.x) v_i = PF*np.array([-(R3*p4.y*p_vis.z - R3*p4.z*p_vis.y - R4*p3.y*p_vis.z + \ R4*p3.z*p_vis.y + Rvis*p3.y*p4.z - Rvis*p3.z*p4.y), (R3*p4.x*p_vis.z - R3*p4.z*p_vis.x - R4*p3.x*p_vis.z + \ R4*p3.z*p_vis.x + Rvis*p3.x*p4.z - Rvis*p3.z*p4.x), -(R3*p4.x*p_vis.y - R3*p4.y*p_vis.x - R4*p3.x*p_vis.y + \ R4*p3.y*p_vis.x + Rvis*p3.x*p4.y - Rvis*p3.y*p4.x)], dtype=np.float) v_s = PF*np.array([-(-p3.E*p4.y*p_vis.z + p3.E*p4.z*p_vis.y + p3.y*p4.E*p_vis.z - \ p3.y*p4.z*p_vis.E - p3.z*p4.E*p_vis.y + p3.z*p4.y*p_vis.E), (-p3.E*p4.x*p_vis.z + p3.E*p4.z*p_vis.x + p3.x*p4.E*p_vis.z - \ p3.x*p4.z*p_vis.E - p3.z*p4.E*p_vis.x + p3.z*p4.x*p_vis.E), -(-p3.E*p4.x*p_vis.y + p3.E*p4.y*p_vis.x + p3.x*p4.E*p_vis.y - \ p3.x*p4.y*p_vis.E - p3.y*p4.E*p_vis.x + p3.y*p4.x*p_vis.E)], dtype=np.float) # Now the solutions can be taken from E2^2 = m2^2 + p2·p2 # Using the symbols above, we have A*E2^2 + B*E2 + C = 0 A = 1 - np.dot(v_s, v_s) B = -2 * (np.dot(v_s, v_i)) C = -(m2**2 + np.dot(v_i, v_i)) E2_sols = np.roots(np.nan_to_num([A, B, C])) E2_sols = remove_complex(E2_sols) p2_sols = [ FourMomentum(E2_sol, *(E2_sol * v_s + v_i)) for E2_sol in E2_sols ] p1_sols = [p_vis - p2_sol for p2_sol in p2_sols] solutions = [] for p1_sol, p2_sol in zip(p1_sols, p2_sols): if valid_energy(p1_sol.E) and valid_energy(p2_sol.E): output_event = deepcopy(event) output_event.set_momentum(particle_keys[0], p1_sol) output_event.set_momentum(particle_keys[1], p2_sol) output_event.x1 = x1 output_event.x2 = x2 solutions.append(output_event) return solutions
def class_D(event_list, particle_keys, sqrt_s134, sqrt_s256, sqrt_s13, sqrt_s25, m1=0, m2=0, m3=-1, m4=-1, m5=-1, m6=-1): """ Gets the two missing momenta for the following topology: ╭────────── missing (p1) x1 ╲ s_13 ╱╰────────── visible (p3) ╲ ╱──────────── visible (p4) ╲ ╱ s_134 █████ ╱ ╲ s_256 ╱ ╲──────────── visible (p6) x2 ╱ s_25 ╲╭────────── visible (p5) ╰────────── missing (p2) m3, ..., m6 can be specified, if -1 they are calculated """ solutions = [] if not isinstance(event_list, list): if isinstance(event_list, Event): event_list = [event_list] else: raise TypeError("'event_list' should be a list of Event objects") for event in event_list: p3 = event[particle_keys[2]] p4 = event[particle_keys[3]] p5 = event[particle_keys[4]] p6 = event[particle_keys[5]] p_branches = FourMomentum(0.0, 0.0, 0.0, 0.0) for k in event.particles: if event.is_visible(k): p_branches += event[k] [event.add_particle(key, Particle(0, 1, FourMomentum())) for key in particle_keys[:2] \ if not key in event.particles] m3 = set_mass(m3, p3) m4 = set_mass(m4, p4) m5 = set_mass(m5, p5) m6 = set_mass(m6, p6) s13 = sqrt_s13**2 s25 = sqrt_s25**2 s134 = sqrt_s134**2 s256 = sqrt_s256**2 R13 = (s13 - m3**2 - m1**2) / 2.0 R25 = (s25 - m5**2 - m2**2) / 2.0 R134 = (s134 - m1**2 - m3**2 - m4**2 - 2 * (p3 * p4)) / 2.0 R256 = (s256 - m2**2 - m5**2 - m6**2 - 2 * (p5 * p6)) / 2.0 R14 = R134 - R13 R26 = R256 - R25 # First define coefficients for vector equations: # p1 = a1 + b1*E1 + c1*E2 / p2 = a2 + b2*E2 + c2*E1 # Numbers from SymPy PF = 1/(p3.x*p4.z*p5.y*p6.z - p3.x*p4.z*p5.z*p6.y - \ p3.y*p4.z*p5.x*p6.z + p3.y*p4.z*p5.z*p6.x - \ p3.z*p4.x*p5.y*p6.z + p3.z*p4.x*p5.z*p6.y + \ p3.z*p4.y*p5.x*p6.z - p3.z*p4.y*p5.z*p6.x) a1 = PF*np.array( [-(R13*p4.z*p5.y*p6.z - R13*p4.z*p5.z*p6.y - R14*p3.z*p5.y*p6.z + \ R14*p3.z*p5.z*p6.y + R25*p3.y*p4.z*p6.z - R25*p3.z*p4.y*p6.z - \ R26*p3.y*p4.z*p5.z + R26*p3.z*p4.y*p5.z - p3.y*p4.z*p5.x*p6.z*p_branches.x - \ p3.y*p4.z*p5.y*p6.z*p_branches.y + p3.y*p4.z*p5.z*p6.x*p_branches.x + \ p3.y*p4.z*p5.z*p6.y*p_branches.y + p3.z*p4.y*p5.x*p6.z*p_branches.x + \ p3.z*p4.y*p5.y*p6.z*p_branches.y - p3.z*p4.y*p5.z*p6.x*p_branches.x - \ p3.z*p4.y*p5.z*p6.y*p_branches.y), (R13*p4.z*p5.x*p6.z - R13*p4.z*p5.z*p6.x - R14*p3.z*p5.x*p6.z + \ R14*p3.z*p5.z*p6.x + R25*p3.x*p4.z*p6.z - R25*p3.z*p4.x*p6.z - \ R26*p3.x*p4.z*p5.z + R26*p3.z*p4.x*p5.z - p3.x*p4.z*p5.x*p6.z*p_branches.x - \ p3.x*p4.z*p5.y*p6.z*p_branches.y + p3.x*p4.z*p5.z*p6.x*p_branches.x + \ p3.x*p4.z*p5.z*p6.y*p_branches.y + p3.z*p4.x*p5.x*p6.z*p_branches.x + \ p3.z*p4.x*p5.y*p6.z*p_branches.y - p3.z*p4.x*p5.z*p6.x*p_branches.x - \ p3.z*p4.x*p5.z*p6.y*p_branches.y), (R13*p4.x*p5.y*p6.z - R13*p4.x*p5.z*p6.y - R13*p4.y*p5.x*p6.z + R13*p4.y*p5.z*p6.x - \ R14*p3.x*p5.y*p6.z + R14*p3.x*p5.z*p6.y + R14*p3.y*p5.x*p6.z - R14*p3.y*p5.z*p6.x - \ R25*p3.x*p4.y*p6.z + R25*p3.y*p4.x*p6.z + R26*p3.x*p4.y*p5.z - R26*p3.y*p4.x*p5.z + \ p3.x*p4.y*p5.x*p6.z*p_branches.x + p3.x*p4.y*p5.y*p6.z*p_branches.y - \ p3.x*p4.y*p5.z*p6.x*p_branches.x - p3.x*p4.y*p5.z*p6.y*p_branches.y - \ p3.y*p4.x*p5.x*p6.z*p_branches.x - p3.y*p4.x*p5.y*p6.z*p_branches.y + \ p3.y*p4.x*p5.z*p6.x*p_branches.x + p3.y*p4.x*p5.z*p6.y*p_branches.y)], dtype=np.float ) b1 = PF*np.array( [-(-p3.E*p4.z*p5.y*p6.z + p3.E*p4.z*p5.z*p6.y + p3.z*p4.E*p5.y*p6.z - p3.z*p4.E*p5.z*p6.y), -p3.E*p4.z*p5.x*p6.z + p3.E*p4.z*p5.z*p6.x + p3.z*p4.E*p5.x*p6.z - p3.z*p4.E*p5.z*p6.x, (-p3.E*p4.x*p5.y*p6.z + p3.E*p4.x*p5.z*p6.y + p3.E*p4.y*p5.x*p6.z - p3.E*p4.y*p5.z*p6.x + \ p3.x*p4.E*p5.y*p6.z - p3.x*p4.E*p5.z*p6.y - p3.y*p4.E*p5.x*p6.z + p3.y*p4.E*p5.z*p6.x)], dtype=np.float ) c1 = PF * np.array([ -(-p3.y * p4.z * p5.E * p6.z + p3.y * p4.z * p5.z * p6.E + p3.z * p4.y * p5.E * p6.z - p3.z * p4.y * p5.z * p6.E), -p3.x * p4.z * p5.E * p6.z + p3.x * p4.z * p5.z * p6.E + p3.z * p4.x * p5.E * p6.z - p3.z * p4.x * p5.z * p6.E, (p3.x * p4.y * p5.E * p6.z - p3.x * p4.y * p5.z * p6.E - p3.y * p4.x * p5.E * p6.z + p3.y * p4.x * p5.z * p6.E) ], dtype=np.float) a2 = PF*np.array( [R13*p4.z*p5.y*p6.z - R13*p4.z*p5.z*p6.y - R14*p3.z*p5.y*p6.z + R14*p3.z*p5.z*p6.y + \ R25*p3.y*p4.z*p6.z - R25*p3.z*p4.y*p6.z - R26*p3.y*p4.z*p5.z + R26*p3.z*p4.y*p5.z - \ p3.x*p4.z*p5.y*p6.z*p_branches.x + p3.x*p4.z*p5.z*p6.y*p_branches.x - \ p3.y*p4.z*p5.y*p6.z*p_branches.y + p3.y*p4.z*p5.z*p6.y*p_branches.y + \ p3.z*p4.x*p5.y*p6.z*p_branches.x - p3.z*p4.x*p5.z*p6.y*p_branches.x + \ p3.z*p4.y*p5.y*p6.z*p_branches.y - p3.z*p4.y*p5.z*p6.y*p_branches.y, -(R13*p4.z*p5.x*p6.z - R13*p4.z*p5.z*p6.x - R14*p3.z*p5.x*p6.z + R14*p3.z*p5.z*p6.x + \ R25*p3.x*p4.z*p6.z - R25*p3.z*p4.x*p6.z - R26*p3.x*p4.z*p5.z + R26*p3.z*p4.x*p5.z - \ p3.x*p4.z*p5.x*p6.z*p_branches.x + p3.x*p4.z*p5.z*p6.x*p_branches.x - \ p3.y*p4.z*p5.x*p6.z*p_branches.y + p3.y*p4.z*p5.z*p6.x*p_branches.y + \ p3.z*p4.x*p5.x*p6.z*p_branches.x - p3.z*p4.x*p5.z*p6.x*p_branches.x + \ p3.z*p4.y*p5.x*p6.z*p_branches.y - p3.z*p4.y*p5.z*p6.x*p_branches.y), R13*p4.z*p5.x*p6.y - R13*p4.z*p5.y*p6.x - R14*p3.z*p5.x*p6.y + R14*p3.z*p5.y*p6.x + \ R25*p3.x*p4.z*p6.y - R25*p3.y*p4.z*p6.x - R25*p3.z*p4.x*p6.y + R25*p3.z*p4.y*p6.x - \ R26*p3.x*p4.z*p5.y + R26*p3.y*p4.z*p5.x + R26*p3.z*p4.x*p5.y - R26*p3.z*p4.y*p5.x - \ p3.x*p4.z*p5.x*p6.y*p_branches.x + p3.x*p4.z*p5.y*p6.x*p_branches.x - \ p3.y*p4.z*p5.x*p6.y*p_branches.y + p3.y*p4.z*p5.y*p6.x*p_branches.y + \ p3.z*p4.x*p5.x*p6.y*p_branches.x - p3.z*p4.x*p5.y*p6.x*p_branches.x + \ p3.z*p4.y*p5.x*p6.y*p_branches.y - p3.z*p4.y*p5.y*p6.x*p_branches.y], dtype=np.float ) b2 = PF * np.array([ -p3.E * p4.z * p5.y * p6.z + p3.E * p4.z * p5.z * p6.y + p3.z * p4.E * p5.y * p6.z - p3.z * p4.E * p5.z * p6.y, -(-p3.E * p4.z * p5.x * p6.z + p3.E * p4.z * p5.z * p6.x + p3.z * p4.E * p5.x * p6.z - p3.z * p4.E * p5.z * p6.x), -p3.E * p4.z * p5.x * p6.y + p3.E * p4.z * p5.y * p6.x + p3.z * p4.E * p5.x * p6.y - p3.z * p4.E * p5.y * p6.x ], dtype=np.float) c2 = PF*np.array( [-p3.y*p4.z*p5.E*p6.z + p3.y*p4.z*p5.z*p6.E + p3.z*p4.y*p5.E*p6.z - p3.z*p4.y*p5.z*p6.E, -(-p3.x*p4.z*p5.E*p6.z + p3.x*p4.z*p5.z*p6.E + p3.z*p4.x*p5.E*p6.z - p3.z*p4.x*p5.z*p6.E), -p3.x*p4.z*p5.E*p6.y + p3.x*p4.z*p5.y*p6.E + p3.y*p4.z*p5.E*p6.x - p3.y*p4.z*p5.x*p6.E + \ p3.z*p4.x*p5.E*p6.y - p3.z*p4.x*p5.y*p6.E - p3.z*p4.y*p5.E*p6.x + p3.z*p4.y*p5.x*p6.E], dtype=np.float ) # Enforcing the mass-shell equation for p1: # E1^2 = m1^2 + p1·p1 # 0 = A*E1^2 + (B0 + B1*E2)*E1 + C0 + C1*E2 + C2*E2^2 A = np.dot(b1, b1) - 1 B0 = 2 * np.dot(a1, b1) B1 = 2 * np.dot(b1, c1) C0 = np.dot(a1, a1) + m1**2 C1 = 2 * np.dot(a1, c1) C2 = np.dot(c1, c1) # 0 = D*E^2 + (F0 + F1*E1)*E2 + G0 + G1*E1 + G2*E1^2 D = np.dot(c2, c2) - 1 F0 = 2 * np.dot(a2, c2) F1 = 2 * np.dot(b2, c2) G0 = np.dot(a2, a2) + m2**2 G1 = 2 * np.dot(a2, b2) G2 = np.dot(b2, b2) E2_sols = np.roots(np.nan_to_num([(-A**2*D**2 + A*(B1*D*F1 + 2*C2*D*G2 - C2*F1**2) + \ G2*(-B1**2*D + B1*C2*F1 - C2**2*G2))/A**2, (-2*A**2*D*F0 + A*(B0*D*F1 + B1*D*G1 + B1*F0*F1 + 2*C1*D*G2 - C1*F1**2 + \ 2*C2*F0*G2 - 2*C2*F1*G1) + G2*(-2*B0*B1*D + B0*C2*F1 - B1**2*F0 + B1*C1*F1 + \ B1*C2*G1 - 2*C1*C2*G2))/A**2, (-A**2*(2*D*G0 + F0**2) + A*(B0*D*G1 + B0*F0*F1 + B1*F0*G1 + B1*F1*G0 + \ 2*C0*D*G2 - C0*F1**2 + 2*C1*F0*G2 - 2*C1*F1*G1 + 2*C2*G0*G2 - C2*G1**2) + \ G2*(-B0**2*D - 2*B0*B1*F0 + B0*C1*F1 + B0*C2*G1 - B1**2*G0 + B1*C0*F1 + B1*C1*G1 - \ 2*C0*C2*G2 - C1**2*G2))/A**2, (-2*A**2*F0*G0 + A*(B0*F0*G1 + B0*F1*G0 + B1*G0*G1 + 2*C0*F0*G2 - 2*C0*F1*G1 + \ 2*C1*G0*G2 - C1*G1**2) + G2*(-B0**2*F0 - 2*B0*B1*G0 + B0*C0*F1 + B0*C1*G1 + B1*C0*G1 - 2*C0*C1*G2))/A**2, (-A**2*G0**2 + A*(B0*G0*G1 + 2*C0*G0*G2 - C0*G1**2) + G2*(-B0**2*G0 + B0*C0*G1 - C0**2*G2))/A**2])) E2_sols = remove_complex(E2_sols) # For each E2, there will be 2 p1's, one will have the wrong mass for E2_sol in E2_sols: if not valid_energy(E2_sol): continue for pm in [-1, 1]: E1_sol = (-B0 - B1 * E2_sol + pm * ( ((B0 + B1 * E2_sol)**2 - 4 * A * (C0 + C1 * E2_sol + C2 * E2_sol**2))**0.5)) / (2 * A) p1_sol = FourMomentum(E1_sol, *(a1 + E1_sol * b1 + E2_sol * c1)) if abs(p1_sol.m2 - m1**2) > FP_TOLERANCE or not valid_energy(E1_sol): continue p2_sol = FourMomentum(E2_sol, *(a2 + E1_sol * b2 + E2_sol * c2)) if abs(p2_sol.m2 - m2**2) > FP_TOLERANCE: continue x1 = (p1_sol.E + p1_sol.z + p_branches.E + p_branches.z + p2_sol.E + p2_sol.z) / event.sqrt_s x2 = (p1_sol.E - p1_sol.z + p_branches.E - p_branches.z + p2_sol.E - p2_sol.z) / event.sqrt_s if x1 < 0.0 or x2 < 0.0 or x1 > 1.0 or x2 > 1.0: continue output_event = deepcopy(event) output_event.set_momentum(particle_keys[0], p1_sol) output_event.set_momentum(particle_keys[1], p2_sol) output_event.x1 = x1 output_event.x2 = x2 solutions.append(output_event) return solutions