19#include<boost/container/static_vector.hpp>
23constexpr double invsqrt2PI =
24 M_2_SQRTPI / (2. * M_SQRT2);
30 ~Component() =
default;
32 Component& operator=(
const Component&) =
default;
34 Component& operator=(Component&&) =
default;
36 Component(
double aWeight,
double aMean,
double aSigma)
46using VecOfComponents =
47 boost::container::static_vector<Component,
59gaus(
double x,
double mean,
double sigma)
61 const double invertsigma = 1. /
sigma;
62 const double z = (
x -
mean) * invertsigma;
63 return (invsqrt2PI * invertsigma) *
exp(-0.5 *
z *
z);
68pdf(
double x,
int i,
const std::array<VecOfComponents, 5>& mixture)
71 auto component = mixture[
i].begin();
72 for (; component != mixture[
i].end(); ++component) {
73 pdf += component->weight * gaus(
x, component->mean, component->sigma);
81fullPdf(
double x,
int i,
const std::array<VecOfComponents, 5>& mixture)
84 auto component = mixture[
i].begin();
85 for (; component != mixture[
i].end(); ++component) {
86 const double componentgaus = gaus(
x, component->mean, component->sigma);
87 pdf.value += component->weight * componentgaus;
88 const double invertSigma = 1. / component->sigma;
89 const double z = (
x - component->mean) * invertSigma;
90 pdf.deriv1 += -1. * component->weight *
z * componentgaus * invertSigma;
91 pdf.deriv2 += component->weight * invertSigma * invertSigma * (
z *
z - 1.) *
100width(
int i,
const std::array<VecOfComponents, 5>& mixture)
103 auto component = mixture[
i].begin();
104 for (; component != mixture[
i].end(); ++component) {
105 pdf += component->weight * component->sigma;
112 std::array<VecOfComponents, 5>& mixture)
122 for (
size_t i = 0;
i < 5; ++
i) {
124 const AmgSymMatrix(5)* measuredCov = componentParameters->covariance();
130 double weight = component.weight;
131 double mean = componentParameters->parameters()[parameter[
i]];
134 double sigma = sqrt(std::abs((*measuredCov)(parameter[i], parameter[i])));
139 multiComponentState.begin()->params->parameters()[2] -
mean;
146 mixture[
i].emplace_back(weight,
mean, sigma);
152findMode(
double xStart,
154 const std::array<VecOfComponents, 5>& mixture)
157 bool converged =
false;
160 double currentMode(xStart);
161 double nextMode(currentMode);
163 pdfAndDeriv currentPdf = fullPdf(currentMode, i, mixture);
166 for (
int iteration = 0; iteration < 20; ++iteration) {
168 if (currentPdf.deriv2 != 0.0) {
169 nextMode = currentMode - currentPdf.deriv1 / currentPdf.deriv2;
175 pdfAndDeriv
const nextPdf = fullPdf(nextMode, i, mixture);
177 if ((nextPdf.value + currentPdf.value) != 0.0) {
178 tolerance = std::abs(nextPdf.value - currentPdf.value) /
179 (nextPdf.value + currentPdf.value);
189 currentPdf = nextPdf;
190 currentMode = nextMode;
206 const std::array<VecOfComponents, 5>& mixture)
213 double fb =
pdf(b, i, mixture) -
value;
218 bool ac_equal(
false);
223 constexpr int MaxIterations = 20;
226 for (
int iter = 0;
iter <= MaxIterations;
iter++) {
228 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) {
237 if (std::abs(fc) < std::abs(fb)) {
247 const double tol = 0.5 *
tolerance * std::abs(b);
248 const double m = 0.5 * (
c -
b);
250 if (fb == 0 || std::abs(m) <= tol) {
255 if (std::abs(e) < tol || std::abs(fa) <= std::abs(fb)) {
264 const double s = fb / fa;
272 p =
s * (2 *
m *
q * (
q -
r) - (
b -
a) * (
r - 1));
273 q = (
q - 1) * (
r - 1) * (
s - 1);
282 const double min1 = 3 *
m *
q - std::abs(tol * q);
283 const double min2 = std::abs(e * q);
284 if (2 * p < (min1 < min2 ? min1 : min2)) {
298 if (std::abs(d) > tol) {
301 b += (
m > 0 ? +tol : -tol);
314std::array<double, 10>
315evaluateMode(
const std::array<VecOfComponents, 5>& mixture)
317 std::array<double, 10>
modes{};
320 for (
int i = 0;
i < 5;
i++) {
322 double largerPdfComponent = 0.0;
323 double largerMeanComponent = 0.0;
330 for (
const Component& component : mixture[i]) {
331 const double pdfValue =
pdf(component.mean, i, mixture);
332 if (pdfValue > largerPdfComponent) {
333 largerPdfComponent = pdfValue;
334 largerMeanComponent = component.mean;
337 modes[
i] = findMode(largerMeanComponent, i, mixture);
340 if (largerMeanComponent != modes[i]) {
342 const double currentWidth =
width(i, mixture);
345 const double pdfVal =
pdf(modes[i], i, mixture);
349 double upperbound =
modes[
i] + 1.5 * currentWidth;
351 if (
pdf(upperbound, i, mixture) > pdfVal * 0.5) {
352 upperbound += currentWidth;
358 const bool highXFound =
359 findRoot(highX, modes[i], upperbound, pdfVal * 0.5, i, mixture);
361 double lowerbound =
modes[
i] - 1.5 * currentWidth;
363 if (
pdf(lowerbound, i, mixture) > pdfVal * 0.5) {
364 lowerbound -= currentWidth;
369 const bool lowXFound =
370 findRoot(lowX, lowerbound, modes[i], pdfVal * 0.5, i, mixture);
371 if (highXFound && lowXFound) {
372 const double FWHM = highX - lowX;
373 modes[
i + 5] = FWHM / 2.35482;
385std::array<double, 10>
393 std::array<VecOfComponents, 5> mixture;
395 fillMixture(multiComponentState, mixture);
396 return evaluateMode(mixture);
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
#define AmgSymMatrix(dim)
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
float modes(const std::vector< float > &mus, const std::vector< float > &log_sigma2s, const std::vector< float > &alphas)
T wrapToPi(T phi)
Wrap angle in radians to [-pi, pi].
constexpr int8_t maxNumberofStateComponents
The state is described by N Gaussian components The Beth Heitler Material effect are also described b...
bool allHaveCovariance(const MultiComponentState &in)
Check to see if all components have covariance Matrix.
std::array< double, 10 > calculateMode(const MultiComponentState &)
Method to calculate mode with MultiComponentState state as input.
std::vector< ComponentParameters > MultiComponentState
ParamDefs
This file defines the parameter enums in the Trk namespace.
ParametersBase< TrackParametersDim, Charged > TrackParameters
Helper for azimuthal angle calculations.
constexpr double tolerance