Modify amplitude model
Contents
Modify amplitude model#
import attrs
import graphviz
import qrules
import sympy as sp
from IPython.display import Math
from ampform import get_builder
from ampform.io import aslatex
Since a HelicityModel.expression
is simply a sympy.Expr
, it’s relatively easy to modify it. The HelicityModel
however also contains other attributes that need to be modified accordingly. In this notebook, we show how to do that for specific use cases using the following example decay:
result = qrules.generate_transitions(
initial_state=("J/psi(1S)", [-1, +1]),
final_state=["gamma", "pi0", "pi0"],
allowed_intermediate_particles=["f(0)(980)", "f(0)(1500)"],
allowed_interaction_types=["strong", "EM"],
formalism="helicity",
)
model_builder = get_builder(result)
original_model = model_builder.formulate()
dot = qrules.io.asdot(result, collapse_graphs=True)
graphviz.Source(dot)
Couple parameters#
We can couple parameters renaming them:
renames = {
R"C_{J/\psi(1S) \to {f_{0}(980)}_{0} \gamma_{+1}; f_{0}(980) \to \pi^{0}_{0} \pi^{0}_{0}}": (
"C"
),
R"C_{J/\psi(1S) \to {f_{0}(1500)}_{0} \gamma_{+1}; f_{0}(1500) \to \pi^{0}_{0} \pi^{0}_{0}}": (
"C"
),
}
new_model = original_model.rename_symbols(renames)
ParameterValues({ C: (1+0j), })
new_model.components[R"I_{J/\psi(1S)_{+1} \to \gamma_{+1} \pi^{0}_{0} \pi^{0}_{0}}"]
Parameter substitution#
Let’s say we want to express all coefficients as a product \(Ce^{i\phi}\) of magnitude \(C\) with phase \(\phi\).
original_coefficients = [
par for par in original_model.parameter_defaults if par.name.startswith("C")
]
original_coefficients
[C_{J/\psi(1S) \to {f_{0}(980)}_{0} \gamma_{+1}; f_{0}(980) \to \pi^{0}_{0} \pi^{0}_{0}},
C_{J/\psi(1S) \to {f_{0}(1500)}_{0} \gamma_{+1}; f_{0}(1500) \to \pi^{0}_{0} \pi^{0}_{0}}]
There are two things to note now:
These parameters appear in
HelicityModel.expression
, itsparameter_defaults
, and itscomponents
, so both these attributes should be modified accordingly.A
HelicityModel
is immutable, so we cannot directly replace its attributes. Instead, we should create a newHelicityModel
with substituted attributes usingattrs.evolve()
:
The following snippet shows how to do all this. It’s shown in full, because it could well be you want to perform some completely different substitutions (can be any kinds of subs()
). The overall procedure is comparable, however.
new_intensity = original_model.intensity
new_amplitudes = dict(original_model.amplitudes)
new_parameter_defaults = dict(original_model.parameter_defaults) # copy!
new_components = dict(original_model.components) # copy!
for coefficient in original_coefficients:
decay_description = coefficient.name[3:-1]
magnitude = sp.Symbol( # coefficient with same name, but real, not complex
coefficient.name,
nonnegative=True,
)
phase = sp.Symbol(
Rf"\phi_{{{decay_description}}}",
real=True,
)
replacement = magnitude * sp.exp(sp.I * phase)
display(replacement)
# replace parameter defaults
del new_parameter_defaults[coefficient]
new_parameter_defaults[magnitude] = 1.0
new_parameter_defaults[phase] = 0.0
# replace parameters in expression
new_intensity = new_intensity.subs(coefficient, replacement, simultaneous=True)
# replace parameters in each component
new_amplitudes = {
key: old_expression.subs(coefficient, replacement, simultaneous=True)
for key, old_expression in new_amplitudes.items()
}
new_components = {
key: old_expression.subs(coefficient, replacement, simultaneous=True)
for key, old_expression in new_components.items()
}
# create new model from the old
new_model = attrs.evolve(
original_model,
intensity=new_intensity,
amplitudes=new_amplitudes,
parameter_defaults=new_parameter_defaults,
components=new_components,
)
assert new_model != original_model
As can be seen, the parameter_defaults
have bene updated, as have the components
:
new_model.components[
R"A_{J/\psi(1S)_{-1} \to {f_{0}(980)}_{0} \gamma_{-1}; {f_{0}(980)}_{0}"
R" \to \pi^{0}_{0} \pi^{0}_{0}}"
]
Also note that the new model reduces to the old once we replace the parameters with their suggested default values:
evaluated_expr = new_model.expression.subs(new_model.parameter_defaults).doit()
evaluated_expr
assert (
original_model.expression.subs(original_model.parameter_defaults).doit()
== evaluated_expr
)