phasespace package#
phasespace.phasespace module#
Implementation of the Raubold and Lynch method to generate n-body events.
The code is based on the GENBOD function (W515 from CERNLIB), documented in:
James, Monte Carlo Phase Space, CERN 68-15 (1968)
- class phasespace.phasespace.GenParticle(name: str, mass: Callable | int | float | ArrayLike)[source]#
Bases:
objectRepresentation of a particle.
Instances of this class can be combined with each other to build decay chains, which can then be used to generate phase space events through the
generateorgenerate_tensormethod.- A
GenParticlemust have - a
name, which is ensured not to clash with any others in the decay chain.
- a
- a
mass, which can be either a number or a function to generate it according to a certain distribution. The returned
~tf.Tensorneeds to have shape(nevents,). In this case, the particle is not considered as having a fixed mass and thehas_fixed_massmethod will return False.
- a
It may also have:
Children, ie, decay products, which are also
GenParticleinstances.
- Parameters:
name (str) – Name of the particle.
mass (float, array-like, callable) – Mass of the particle. If it’s a float, it gets converted to array-like.
- generate(n_events: int | tf.Tensor | tf.Variable, boost_to: tf.Tensor | vector.Momentum | None = None, normalize_weights: bool = True, seed: SeedLike = None, *, as_vectors: bool | None = None) tuple[tf.Tensor, dict[str, tf.Tensor]][source]#
Generate normalized n-body phase space as tensorflow tensors.
Any TensorFlow tensor can always be converted to a numpy array with the method
numpy().Events are generated in the rest frame of the particle, unless
boost_tois given.Notes
In this method, the event weights are returned normalized to their maximum.
- Parameters:
n_events (int) – Number of events to generate.
boost_to (optional) – Momentum vector of shape
(x, 4), where x is optional, to where the resulting events will be boosted in the (px, py, pz, E) format. Can also be avectormomentum Lorentz vector. If not specified, events are generated in the rest frame of the particle.normalize_weights (bool, optional) – Normalize the event weight to its max?
seed (
SeedLike) – The seed can be a number or atf.random.Generatorthat are used as a seed to create a random number generator inside the function or directly as the random number generator instance, respectively.as_vectors (bool, optional) – If True, the output momenta are returned as
vectorobjects.
- Returns:
Result of the generation, which varies with the value of
normalize_weights:If True, the tuple elements are the normalized event weights as a tensor of shape
(n_events,), and the momenta generated particles as a dictionary of tensors of shape(4, n_events)with particle names as keys.If False, the tuple weights are the unnormalized event weights as a tensor of shape
(n_events,), the maximum per-event weights as a tensor of shape(n_events,)and the momenta generated particles as a dictionary of tensors of shape(4, n_events)with particle names as keys.
- Return type:
tuple
- Raises:
tf.errors.InvalidArgumentError – If the the decay is kinematically forbidden.
ValueError – If
n_eventsand the size ofboost_todon’t match.See GenParticle.generate_unnormalized. –
- generate_tensor(n_events: int, boost_to=None, normalize_weights: bool = True)[source]#
Generate normalized n-body phase space as numpy arrays.
Events are generated in the rest frame of the particle, unless
boost_tois given.Notes
In this method, the event weights are returned normalized to their maximum.
- Parameters:
n_events (int) – Number of events to generate.
boost_to (optional) – Momentum vector of shape
(x, 4), where x is optional, to where the resulting events will be boosted. If not specified, events are generated in the rest frame of the particle.normalize_weights (bool, optional) – Normalize the event weight to its max
- Returns:
Result of the generation, which varies with the value of
normalize_weights:If True, the tuple elements are the normalized event weights as an array of shape
(n_events,), and the momenta generated particles as a dictionary of arrays of shape(4, n_events)with particle names as keys.If False, the tuple weights are the unnormalized event weights as an array of shape
(n_events,), the maximum per-event weights as an array of shape(n_events,)and the momenta generated particles as a dictionary of arrays of shape(4, n_events)with particle names as keys.
- Return type:
tuple
- Raises:
tf.errors.InvalidArgumentError – If the the decay is kinematically forbidden.
ValueError – If
n_eventsand the size ofboost_todon’t match.See GenParticle.generate_unnormalized. –
- get_mass(min_mass: tf.Tensor = None, max_mass: tf.Tensor = None, n_events: tf.Tensor | tf.Variable = None, seed: SeedLike = None) tf.Tensor[source]#
Get the particle mass.
If the particle is resonant, the mass function will be called with the
min_mass,max_mass,n_eventsand optionally aseedparameter.- Parameters:
min_mass (tensor) – Lower mass range. Defaults to None, which is only valid in the case of fixed mass.
max_mass (tensor) – Upper mass range. Defaults to None, which is only valid in the case of fixed mass.
() (n_events) – Number of events to produce. Has to be specified if the particle is resonant.
seed (
SeedLike) – The seed can be a number or atf.random.Generatorthat are used as a seed to create a random number generator inside the function or directly as the random number generator instance, respectively.
- Returns:
Mass of the particles, either a scalar or shape
(nevents,)- Return type:
~tf.Tensor- Raises:
ValueError – If the mass is requested and has not been set.
- property has_children#
Does the particle have children?
- Type:
bool
- property has_fixed_mass#
Is the mass a callable function?
- Type:
bool
- property has_grandchildren#
Does the particle have grandchildren?
- Type:
bool
- set_children(*children)[source]#
Assign children.
- Parameters:
children (GenParticle) – Two or more children to assign to the current particle.
- Returns:
self
- Raises:
ValueError – If there is an inconsistency in the parent/children relationship, ie,
if children were already set, if their parent was or if less than two children were given. –
KeyError – If there is a particle name clash.
RuntimeError – If
generatewas already called before.
- A
- class phasespace.phasespace.Particle[source]#
Bases:
objectDeprecated Particle class.
Renamed to GenParticle.
- phasespace.phasespace.nbody_decay(mass_top: float, masses: list, top_name: str = '', names: list = None)[source]#
Shortcut to build an n-body decay of a GenParticle.
If the particle names are not given, the top particle is called ‘top’ and the children ‘p_{i}’, where i corresponds to their position in the
massessequence.- Parameters:
mass_top (tensor, list) – Mass of the top particle. Can be a list of 4-vectors.
masses (list) – Masses of the child particles.
top_name (str, optional) – Name of the top particle. If not given, the top particle is named top.
names (list, optional) – Names of the child particles. If not given, they are build as ‘p_{i}’, where i is given by their ordering in the
masseslist.
- Returns:
Particle decay.
- Return type:
GenParticle- Raises:
ValueError – If the length of
massesandnamesdoesn’t match.
- phasespace.phasespace.pdk(a, b, c)[source]#
Calculate the PDK (2-body phase space) function.
Based on Eq. (9.17) in CERN 68-15 (1968).
- Parameters:
a (
~tf.Tensor) – \(M_{i+1}\) in Eq. (9.17).b (
~tf.Tensor) – \(M_{i}\) in Eq. (9.17).c (
~tf.Tensor) – \(m_{i+1}\) in Eq. (9.17).
- Returns:
~tf.Tensor
- phasespace.phasespace.process_list_to_tensor(lst)[source]#
Convert a list to a tensor.
The list is converted to a tensor and transposed to get the proper shape.
Notes
If
lstis a tensor, nothing is done to it other than convert it totf.float64.- Parameters:
lst (list) – List to convert.
- Returns:
~tf.Tensor
- phasespace.phasespace.to_vectors(particles: dict[str, tf.Tensor]) dict[str, vector.Momentum][source]#
Convert a dictionary of particles to a dictionary of
vector.Momentuminstances.- Parameters:
particles (dict) – Dictionary of particles, with the keys being the particle names and the values being the momenta.
- Returns:
Dictionary of
vector.Momentuminstances with numpy arrays- Return type:
dict
phasespace.kinematics module#
Basic kinematics.
- phasespace.kinematics.beta(vector)[source]#
Calculate beta of a given 4-vector.
- Parameters:
vector – Input Lorentz momentum vector.
- Returns:
Beta (v/c) of the Lorentz momentum vector.
- phasespace.kinematics.boost_components(vector)[source]#
Get the boost components of a given 4-vector.
- Parameters:
vector – Input Lorentz momentum vector.
- Returns:
Boost components (3-vector) of the Lorentz momentum vector.
- phasespace.kinematics.lorentz_boost(vector, boostvector)[source]#
Perform Lorentz boost.
- Parameters:
vector – 4-vector to be boosted
boostvector – Boost vector. Can be either 3-vector or 4-vector, since only spatial components are used.
- Returns:
Boosted 4-vector.
- phasespace.kinematics.lorentz_vector(space, time)[source]#
Make a Lorentz vector from spatial and time components.
- Parameters:
space – 3-vector of spatial components.
time – Time component.
- Returns:
Lorentz 4-vector combining spatial and time components.
- phasespace.kinematics.mass(vector)[source]#
Calculate mass scalar for Lorentz 4-momentum.
- Parameters:
vector – Input Lorentz momentum vector.
- Returns:
Mass of the Lorentz 4-momentum vector.
- phasespace.kinematics.metric_tensor()[source]#
Metric tensor for Lorentz space (constant).
- Returns:
Metric tensor for Lorentz space with signature (-1, -1, -1, 1).
- phasespace.kinematics.scalar_product(vec1, vec2)[source]#
Calculate scalar product of two 3-vectors.
- Parameters:
vec1 – First vector.
vec2 – Second vector.
- Returns:
Scalar product of the two vectors.
- phasespace.kinematics.spatial_component(vector)[source]#
Extract spatial components of the input Lorentz vector.
- Parameters:
vector – Input Lorentz vector (where indexes 0-2 are space, index 3 is time).
- Returns:
Spatial components (3-vector) of the input Lorentz vector.
- phasespace.kinematics.time_component(vector)[source]#
Extract time component of the input Lorentz vector.
- Parameters:
vector – Input Lorentz vector (where indexes 0-2 are space, index 3 is time).
- Returns:
Time component of the input Lorentz vector.
- phasespace.kinematics.x_component(vector)[source]#
Extract spatial X component of the input Lorentz or 3-vector.
- Parameters:
vector – Input vector.
- Returns:
X component of the input vector.
phasespace.fromdecay module#
- class phasespace.fromdecay.genmultidecay.GenMultiDecay(gen_particles: list[tuple[float, GenParticle]])[source]#
Bases:
objectA
GenParticle-type container that can handle multiple decays.- Parameters:
gen_particles – All the GenParticles and their corresponding probabilities. The list must be of the format [[probability, GenParticle instance], [probability, …
- DEFAULT_MASS_FUNC = 'relbw'#
- MASS_WIDTH_TOLERANCE = 0.01#
- classmethod from_dict(dec_dict: dict, mass_converter: dict[str, Callable] = None, tolerance: float = None, particle_model_map: dict[str, str] = None)[source]#
Create a
GenMultiDecayinstance from a dict in theDecayLanguagepackage format.- Parameters:
dec_dict – The input dict from which the GenMultiDecay object will be created from. A dec_dict has the same structure as the dicts used in DecayLanguage, see the examples below.
mass_converter – A dict with mass function names and their corresponding mass functions. These functions should take the particle mass and the mass width as inputs and return a mass function that phasespace can understand. This dict will be combined with the predefined mass functions in this package. See the Example below or the tutorial for how to use this parameter.
tolerance – Minimum mass width of the particle to use a mass function instead of assuming the mass to be constant. If None, the default value, defined by the class variable
MASS_WIDTH_TOLERANCE, will be used. This value can be customized if desired.particle_model_map – A dict where the key is a particle name and the value is a mass function name. If a particle is specified in the particle_model_map, then all appearances of this particle in dec_dict will get the same mass function. This way, one doesn’t have to manually add the zfit parameter to every place where this particle appears in dec_dict. If the zfit parameter is specified for a particle which is also included in particle_model_map, the zfit parameter mass function name will be prioritized.
- Returns:
The created GenMultiDecay object.
Examples
Basic Usage
DecayLanguage is usually used to create a dict that can be understood by GenMultiDecay:
from decaylanguage import DecFileParser from phasespace.fromdecay import GenMultiDecay # Parse a .dec file to create a DecayLanguage dict describing a D*+ particle # that can decay in 2 different ways: D*+ -> D0(->K- pi+) pi+ or D*+ -> D+ gamma parser = DecFileParser('example_decays.dec') parser.parse() dst_chain = parser.build_decay_chains("D*+") # dst_chain will be: # {'D*+': [{'bf': 0.984, # 'fs': [{'D0': [{'bf': 1.0, # 'fs': ['K-', 'pi+']}]}, # 'pi+']}, # {'bf': 0.016, # 'fs': ['D+', 'gamma']}]}
Using particle_model_map
If the D0 particle should have a mass distribution of a gaussian when it decays, one can pass the
particle_model_mapparameter tofrom_dict:dst_gen = GenMultiDecay.from_dict(dst_chain, particle_model_map={"D0": "gauss"})
This will then set the mass function of D0 to a gaussian for all its decays.
Using the zfit parameter
If more custom control is required, e.g., if D0 can decay in multiple ways and one of the decays should have a specific mass function, a
zfitparameter can be added to its decay dict:dst_chain["D*+"][0]["fs"][0]["D0"][0]["zfit"] = "gauss" dst_gen = GenMultiDecay.from_dict(dst_chain)
This will now make the D0 particle have a gaussian mass function, only when it decays into K- and pi+. In this case, there are no other ways that D0 can decay, so using
particle_model_mapis a cleaner and easier option.Custom Mass Functions
If the decay of the D0 particle should be modelled by a mass distribution that does not come with the package, a custom distribution can be created:
def custom_gauss(mass, width): particle_mass = tf.cast(mass, tf.float64) particle_width = tf.cast(width, tf.float64) def mass_func(min_mass, max_mass, n_events): min_mass = tf.cast(min_mass, tf.float64) max_mass = tf.cast(max_mass, tf.float64) # Use a zfit PDF pdf = zfit.pdf.Gauss(mu=particle_mass, sigma=particle_width, obs="") iterator = tf.stack([min_mass, max_mass], axis=-1) return tf.vectorized_map( lambda lim: pdf.sample(1, limits=(lim[0], lim[1])), iterator ) return mass_func # Change the distribution in the dst_chain dict dst_chain["D*+"][0]["fs"][0]["D0"][0]["zfit"] = "custom_gauss" # Pass the custom_gauss function to from_dict dst_gen = GenMultiDecay.from_dict(dst_chain, mass_converter={"custom_gauss": custom_gauss})
Notes
For a more in-depth tutorial, see the tutorial on GenMultiDecay in the documentation.
- generate(n_events: int, normalize_weights: bool = True, **kwargs) tuple[list[Tensor], list[Tensor]] | tuple[list[Tensor], list[Tensor], list[Tensor]][source]#
Generate four-momentum vectors from the decay(s).
- Parameters:
n_events – Total number of events combined, for all the decays.
normalize_weights – Normalize weights according to all events generated. This also changes the return values. See the phasespace documentation for more details.
kwargs – Additional parameters passed to all calls of
GenParticle.generate
- Returns:
The arguments returned by
GenParticle.generateare returned. See the phasespace documentation for details. However, instead of being 2 or 3 tensors, it is 2 or 3 lists of tensors, each entry in the lists corresponding to the return arguments from the corresponding GenParticle instances inself.gen_particles. Note that whennormalize_weightsis True, the weights are normalized to the maximum of all returned events.
Mass distribution functions for resonant particles.
This module provides factory functions that create mass distribution functions for resonant particles. These functions use zfit PDFs to sample masses from various distributions (Gaussian, Breit-Wigner, etc.) within specified limits.
- phasespace.fromdecay.mass_functions.breitwigner_factory(mass, width)[source]#
Create a Breit-Wigner (Cauchy) mass distribution function.
- Parameters:
mass – Central mass (m) of the particle.
width – Width (gamma) of the Breit-Wigner distribution.
- Returns:
Callable that generates masses from a Breit-Wigner distribution. The returned function accepts
min_mass,max_mass, andn_eventsparameters and returns sampled masses as a tensor of shape(n_events,).
- phasespace.fromdecay.mass_functions.gauss_factory(mass, width)[source]#
Create a Gaussian mass distribution function.
- Parameters:
mass – Mean mass of the particle.
width – Width (sigma) of the Gaussian distribution.
- Returns:
Callable that generates masses from a Gaussian distribution. The returned function accepts
min_mass,max_mass, andn_eventsparameters and returns sampled masses as a tensor of shape(n_events,).
- phasespace.fromdecay.mass_functions.relativistic_breitwigner_factory(mass, width)[source]#
Create a relativistic Breit-Wigner mass distribution function.
- Parameters:
mass – Central mass (m) of the particle.
width – Width (gamma) of the relativistic Breit-Wigner distribution.
- Returns:
Callable that generates masses from a relativistic Breit-Wigner distribution. The returned function accepts
min_mass,max_mass, andn_eventsparameters and returns sampled masses as a tensor of shape(n_events,).
Notes
This uses
tf.map_fninstead oftf.vectorized_mapas no analytic sampling is available for the relativistic Breit-Wigner distribution.