def test_eq(): particle = Particle( name="MyParticle", pid=123, mass=1.2, spin=1, charge=0, isospin=Spin(1, 0), ) assert particle != Particle( "MyParticle", pid=123, mass=1.5, width=0.2, spin=1) same_particle = deepcopy(particle) assert particle is not same_particle assert particle == same_particle assert hash(particle) == hash(same_particle) different_labels = Particle( name="Different name, same QNs", pid=753, mass=1.2, spin=1, charge=0, isospin=Spin(1, 0), ) assert particle == different_labels assert hash(particle) == hash(different_labels) assert particle.name != different_labels.name assert particle.pid != different_labels.pid
def test_exceptions(): with pytest.raises(FrozenInstanceError): test_state = Particle( "MyParticle", 123, mass=1.2, width=0.1, spin=1, charge=0, isospin=Spin(1, 0), ) test_state.charge = 1 # type: ignore with pytest.raises(ValueError): Particle( name="Fails Gell-Mann–Nishijima formula", pid=666, mass=0.0, spin=1, charge=0, parity=Parity(-1), c_parity=Parity(-1), g_parity=Parity(-1), isospin=Spin(0.0, 0.0), charmness=1, )
def test_hash(): spin1 = Spin(0.0, 0.0) spin2 = Spin(1.5, -0.5) assert {spin2, spin1, deepcopy(spin1), deepcopy(spin2)} == { spin1, spin2, }
class TestGellmannNishijima: @staticmethod @pytest.mark.parametrize( "state", [ Particle( "p1", 1, spin=0.0, mass=1, charge=1, isospin=Spin(1.0, 0.0), strangeness=2, ), Particle( "p1", 1, spin=1.0, mass=1, charge=1, isospin=Spin(1.5, 0.5), charmness=1, ), Particle( "p1", 1, spin=0.5, mass=1, charge=1.5, # type: ignore isospin=Spin(1.0, 1.0), baryon_number=1, ), ], ) def test_computations(state: Particle): assert GellmannNishijima.compute_charge(state) == state.charge assert (GellmannNishijima.compute_isospin_projection( charge=state.charge, baryon_number=state.baryon_number, strangeness=state.strangeness, charmness=state.charmness, bottomness=state.bottomness, topness=state.topness, ) == state.isospin.projection # type: ignore ) @staticmethod def test_isospin_none(): state = Particle("p1", 1, mass=1, spin=0.0, charge=1, isospin=None) assert GellmannNishijima.compute_charge(state) is None
class TestSpin: @staticmethod def test_init_and_eq(): isospin = Spin(1.5, -0.5) assert isospin == 1.5 assert float(isospin) == 1.5 assert isospin.magnitude == 1.5 assert isospin.projection == -0.5 @staticmethod def test_hash(): spin1 = Spin(0.0, 0.0) spin2 = Spin(1.5, -0.5) assert {spin2, spin1, deepcopy(spin1), deepcopy(spin2)} == { spin1, spin2, } @staticmethod def test_neg(): isospin = Spin(1.5, -0.5) flipped_spin = -isospin assert flipped_spin.magnitude == isospin.magnitude assert flipped_spin.projection == -isospin.projection @pytest.mark.parametrize("spin", [Spin(2.5, -0.5), Spin(1, 0)]) def test_repr(self, spin): from_repr = eval(repr(spin)) # pylint: disable=eval-used assert from_repr == spin @pytest.mark.parametrize( "magnitude, projection", [(0.3, 0.3), (1.0, 0.5), (0.5, 0.0), (-0.5, 0.5)], ) def test_exceptions(self, magnitude, projection): with pytest.raises(ValueError): print(Spin(magnitude, projection))
def test_particle(): state = Particle( "MyParticle", pid=123, mass=2.5, width=0.3, spin=1.5, isospin=Spin(1.0, -1.0), charge=-1, ) converted_dict = io._xml.object_to_dict(state) quantum_numbers = converted_dict["QuantumNumber"] spin_dict = quantum_numbers[0] charge_dict = quantum_numbers[1] assert spin_dict["Value"] == 1.5 assert charge_dict["Value"] == -1
def build_spin(definition: Union[dict, float, int, str]) -> Spin: def check_missing_projection(magnitude: float) -> None: if magnitude != 0.0: raise ValueError( "Can only have a spin without projection if magnitude = 0") if isinstance(definition, (float, int)): magnitude = float(definition) check_missing_projection(magnitude) projection = 0.0 elif not isinstance(definition, dict): raise ValueError(f"Cannot create Spin from definition {definition}") else: magnitude = float(definition["Value"]) if "Projection" not in definition: check_missing_projection(magnitude) projection = definition.get("Projection", 0.0) return Spin(magnitude, projection)
def __create_two_body_decay_spin_data( in_spin: Optional[Spin] = None, out_spin1: Optional[Spin] = None, out_spin2: Optional[Spin] = None, angular_momentum: Optional[Spin] = None, coupled_spin: Optional[Spin] = None, ) -> _SpinRuleInputType: spin_zero = Spin(0, 0) if in_spin is None: in_spin = spin_zero if out_spin1 is None: out_spin1 = spin_zero if out_spin2 is None: out_spin2 = spin_zero if angular_momentum is None: angular_momentum = spin_zero if coupled_spin is None: coupled_spin = spin_zero return ( [ SpinEdgeInput( EdgeQuantumNumbers.spin_magnitude(in_spin.magnitude), EdgeQuantumNumbers.spin_projection(in_spin.projection), ) ], [ SpinEdgeInput( EdgeQuantumNumbers.spin_magnitude(out_spin1.magnitude), EdgeQuantumNumbers.spin_projection(out_spin1.projection), ), SpinEdgeInput( EdgeQuantumNumbers.spin_magnitude(out_spin2.magnitude), EdgeQuantumNumbers.spin_projection(out_spin2.projection), ), ], SpinNodeInput( NodeQuantumNumbers.l_magnitude(angular_momentum.magnitude), NodeQuantumNumbers.l_projection(angular_momentum.projection), NodeQuantumNumbers.s_magnitude(coupled_spin.magnitude), NodeQuantumNumbers.s_projection(coupled_spin.projection), ), )
def test_exceptions(self, magnitude, projection): with pytest.raises(ValueError): print(Spin(magnitude, projection))
def build_spin(definition: dict) -> Spin: magnitude = definition["Value"] projection = definition.get("Projection", 0.0) return Spin(magnitude, projection)
), ], SpinNodeInput( NodeQuantumNumbers.l_magnitude(angular_momentum.magnitude), NodeQuantumNumbers.l_projection(angular_momentum.projection), NodeQuantumNumbers.s_magnitude(coupled_spin.magnitude), NodeQuantumNumbers.s_projection(coupled_spin.projection), ), ) @pytest.mark.parametrize( "rule_input, expected", [( __create_two_body_decay_spin_data( angular_momentum=Spin(ang_mom_mag, 0)), expected, ) for ang_mom_mag, expected in [ (0, True), (1, False), (2, False), (3, False), ]] + [( __create_two_body_decay_spin_data(in_spin=Spin(spin_mag, 0), angular_momentum=Spin(spin_mag, 0)), expected, ) for spin_mag, expected in zip([0, 1, 2], [True] * 3)] + [( __create_two_body_decay_spin_data( in_spin=Spin(spin_mag, 0), out_spin1=Spin(1, -1), out_spin2=Spin(1, 1),
def test_init_and_eq(): isospin = Spin(1.5, -0.5) assert isospin == 1.5 assert float(isospin) == 1.5 assert isospin.magnitude == 1.5 assert isospin.projection == -0.5
def __create_isospin(pdg_particle: PdgDatabase) -> Optional[Spin]: if pdg_particle.I is None: return None magnitude = pdg_particle.I projection = __compute_isospin_projection(pdg_particle) return Spin(magnitude, projection)
def wrapper( # pylint: disable=too-many-locals self: Any, graph: StateTransitionGraph[ParticleWithSpin], node_id: int) -> DecayNode: amplitude = decay_generate_function(self, graph, node_id) if isinstance(amplitude, HelicityDecay): helicity_decay = amplitude else: raise TypeError( f"Can only decorate with return value {HelicityDecay.__name__}" ) node_props = graph.get_node_props(node_id) ang_mom = __get_angular_momentum(node_props) if ang_mom.projection != 0.0: raise ValueError(f"Projection of L is non-zero!: {ang_mom}") spin = __get_coupled_spin(node_props) if not isinstance(spin, Spin): raise ValueError( f"{spin.__class__.__name__} is not of type {Spin.__name__}") in_edge_ids = graph.get_edge_ids_ingoing_to_node(node_id) parent_spin = Spin( graph.get_edge_props(in_edge_ids[0])[0].spin, graph.get_edge_props(in_edge_ids[0])[1], ) daughter_spins: List[Spin] = [] for out_edge_id in graph.get_edge_ids_outgoing_from_node(node_id): daughter_spin = Spin( graph.get_edge_props(out_edge_id)[0].spin, graph.get_edge_props(out_edge_id)[1], ) if daughter_spin is not None and isinstance(daughter_spin, Spin): daughter_spins.append(daughter_spin) decay_particle_lambda = (daughter_spins[0].projection - daughter_spins[1].projection) cg_ls = ClebschGordan( j_1=ang_mom.magnitude, m_1=ang_mom.projection, j_2=spin.magnitude, m_2=decay_particle_lambda, J=parent_spin.magnitude, M=decay_particle_lambda, ) cg_ss = ClebschGordan( j_1=daughter_spins[0].magnitude, m_1=daughter_spins[0].projection, j_2=daughter_spins[1].magnitude, m_2=-daughter_spins[1].projection, J=spin.magnitude, M=decay_particle_lambda, ) return CanonicalDecay( decaying_particle=helicity_decay.decaying_particle, decay_products=helicity_decay.decay_products, recoil_system=helicity_decay.recoil_system, l_s=cg_ls, s2s3=cg_ss, )
def __get_coupled_spin(node_props: InteractionProperties) -> Spin: s_mag = node_props.s_magnitude s_proj = node_props.s_projection if s_mag is None or s_proj is None: raise TypeError("Coupled spin S not defined!") return Spin(s_mag, s_proj)
def __get_angular_momentum(node_props: InteractionProperties) -> Spin: l_mag = node_props.l_magnitude l_proj = node_props.l_projection if l_mag is None or l_proj is None: raise TypeError("Angular momentum L not defined!") return Spin(l_mag, l_proj)
isospin_conservation, spin_conservation, ) from .test_spin import __create_two_body_decay_spin_data _SpinRuleInputType = Tuple[List[SpinEdgeInput], List[SpinEdgeInput], SpinNodeInput] @pytest.mark.parametrize( "rule_input, expected", [ ( __create_two_body_decay_spin_data( Spin(1, 0), Spin(1, 0), Spin(1, 0), Spin(1, 0), Spin(0, 0), ), True, ), ( __create_two_body_decay_spin_data( Spin(1, 0), Spin(1, 0), Spin(1, 0), Spin(1, 0), Spin(1, 0), ),
def test_neg(): isospin = Spin(1.5, -0.5) flipped_spin = -isospin assert flipped_spin.magnitude == isospin.magnitude assert flipped_spin.projection == -isospin.projection