This page demonstrates deserialization and evaluation of an amplitude model for the decay \(\Lambda_c^+ \to p K^- \pi^+\). The amplitude analysis is performed based on roughly half a million of \(\Lambda_c^{\pm}\) decay candidates by the LHCb collaboration, INSPIRE-HEP 2683025. Details on the mapped of the amplitude model onto the standard helicity formalism can be found in appendix of INSPIRE-HEP 2623821.
Model components are deserialized from a JSON file into computational objects within a workspace for further manipulation. First, functions representing lineshapes and form factors are built. Following this, distributions are processed and added to the workspace.
┌ Warning: parameters are not used in HadronicUnpolarizedIntensity
└ @ ThreeBodyDecaysIO ~/.julia/packages/ThreeBodyDecaysIO/bNt1V/src/HadronicUnpolarizedIntensity.jl:18
Validation
The integrity of the model is checked by validating the value of distributions at a few phase space points. The table lists the validation checks and their status. The marks “🟢”, “🟡”, and “🔴” indicate an accuracy of \(<10^{-10}\), \(<10^{-2}\), or \(\ge10^{-2}\), respectively, for the difference between the reference and computed values.
A loop over validation points
let@unpack misc, parameter_points = input@unpack amplitude_model_checksums = miscmap(amplitude_model_checksums) do check_point_info@unpack point, value, distribution = check_point_info## pull distribution dist = workspace[distribution]# pull correct parameter point parameter_points_dict =array2dict(parameter_points; key="name")# find the point in the list of points parameter_point = parameter_points_dict[point]# compute, compare _parameters =array2dict(parameter_point["parameters"]; key="name", apply=v -> v["value"])# computed_value =dist(_parameters)#tonumber(X::Number) = Xtonumber(X::String) =string2complex(X) reference_value =tonumber(value) status =label_diff(reference_value - computed_value)# (; Distribution=distribution, Point=point, Status=status)end|> DataFrameend
11×3 DataFrame
Row
Distribution
Point
Status
String
String
Char
1
default_model
validation_point
🟡
2
L1405_Flatte
validation_point_m31sq
🟢
3
L1690_BW
validation_point_m31sq
🟢
4
D1232_BW
validation_point_m12sq
🟢
5
L1520_BW
validation_point_m31sq
🟢
6
L1600_BW
validation_point_m31sq
🟢
7
L2000_BW
validation_point_m31sq
🟢
8
D1600_BW
validation_point_m12sq
🟢
9
D1700_BW
validation_point_m12sq
🟢
10
K892_BW
validation_point_m23sq
🟢
11
L1670_BW
validation_point_m31sq
🟢
Visualization
The model describing the decay is fetched from the workspace
model_dist = [v for (k, v) in workspace if v isa HadronicUnpolarizedIntensity] |> first;
Dalitz plot
The Dalitz plot shows the probability distribution across two dimensional phase space of the decay.
The projection of the model onto a mass variable is shown by black line. Contributions from individual resonances are shown by the colored lines.
Computation of projections
let k =2 i, j =ij_from_k(k) xlab ="m($i$j) [GeV]" model = model_dist.model# mlims =sqrt.(lims(k, masses(model))) mv =range(mlims..., 150) |> shift_by_half#plot()plot!(mv, lab="Total") do m I =Base.Fix1(unpolarized_intensity, model) m *quadgk(projection_integrand(I, masses(model), m^2; k), 0, 1)[1]end chain_names =Set(model.names) |> collect |> sortfor name in chain_names _model = model[model.names.==name]plot!(mv, lab=name) do m I =Base.Fix1(unpolarized_intensity, _model) m *quadgk(projection_integrand(I, masses(_model), m^2; k), 0, 1)[1]endendplot!(; xlab)end
Fit Fractions
The contribution of different resonances to the overall decay process is quantitatively assessed using numerical evaluation on a finite-size sample. Statistical uncertainty in the reported values only reflects the precision of these calculations. For a understanding of model uncertainties, refer to the original publications.
Computation of fit fractions
let model = model_dist.model ms =masses(model)# x2 =rand(10000, 2) data =map(eachslice(x2; dims=1)) do (x, y) σ1=lims1(ms)[1] + x *diff(lims1(ms) |> collect)[1] σ2=lims2(ms)[1] + y *diff(lims2(ms) |> collect)[1] σs =Invariants(ms; σ1, σ2)endfilter!(data) do σsKibble(σs, ms^2) <0end# chain_names =Set(model.names) |> collect |> sort _int_i =map(chain_names) do name _intensities =unpolarized_intensity.(model[model.names.==name] |>Ref, data) _value =mean(_intensities) _err =sqrt(cov(_intensities, _intensities) /length(data)) _value ± _errend _int0 =sum(unpolarized_intensity.(model |>Ref, data)) /length(data) ff =round.(_int_i ./ _int0 .*100; digits=2)DataFrame("Resonance"=> chain_names, "Fit Fraction [%]"=> ff)end