20#include<boost/container/static_vector.hpp>
24constexpr double invsqrt2PI =
25 M_2_SQRTPI / (2. * M_SQRT2);
31 ~Component() =
default;
37 Component(
double aWeight,
double aMean,
double aSigma)
47using VecOfComponents =
48 boost::container::static_vector<Component,
60gaus(
double x,
double mean,
double sigma)
62 const double invertsigma = 1. /
sigma;
63 const double z = (
x -
mean) * invertsigma;
64 return (invsqrt2PI * invertsigma) *
exp(-0.5 *
z *
z);
69pdf(
double x,
int i,
const std::array<VecOfComponents, 5>& mixture)
72 auto component = mixture[
i].begin();
73 for (; component != mixture[
i].end(); ++component) {
74 pdf += component->weight * gaus(
x, component->mean, component->sigma);
82fullPdf(
double x,
int i,
const std::array<VecOfComponents, 5>& mixture)
85 auto component = mixture[
i].begin();
86 for (; component != mixture[
i].end(); ++component) {
87 const double componentgaus = gaus(
x, component->mean, component->sigma);
88 pdf.value += component->weight * componentgaus;
89 const double invertSigma = 1. / component->sigma;
90 const double z = (
x - component->mean) * invertSigma;
91 pdf.deriv1 += -1. * component->weight *
z * componentgaus * invertSigma;
92 pdf.deriv2 += component->weight * invertSigma * invertSigma * (
z *
z - 1.) *
101width(
int i,
const std::array<VecOfComponents, 5>& mixture)
104 auto component = mixture[
i].begin();
105 for (; component != mixture[
i].end(); ++component) {
106 pdf += component->weight * component->sigma;
113 std::array<VecOfComponents, 5>& mixture)
123 for (
size_t i = 0;
i < 5; ++
i) {
125 const AmgSymMatrix(5)* measuredCov = componentParameters->covariance();
131 double weight = component.weight;
132 double mean = componentParameters->parameters()[parameter[
i]];
135 double sigma = sqrt(std::abs((*measuredCov)(parameter[i], parameter[i])));
140 multiComponentState.begin()->params->parameters()[2] -
mean;
147 mixture[
i].emplace_back(weight,
mean, sigma);
153findMode(
double xStart,
155 const std::array<VecOfComponents, 5>& mixture)
158 bool converged =
false;
161 double currentMode(xStart);
162 double nextMode(currentMode);
164 pdfAndDeriv currentPdf = fullPdf(currentMode, i, mixture);
167 for (
int iteration = 0; iteration < 20; ++iteration) {
169 if (currentPdf.deriv2 != 0.0) {
170 nextMode = currentMode - currentPdf.deriv1 / currentPdf.deriv2;
176 pdfAndDeriv
const nextPdf = fullPdf(nextMode, i, mixture);
178 if ((nextPdf.value + currentPdf.value) != 0.0) {
179 tolerance = std::abs(nextPdf.value - currentPdf.value) /
180 (nextPdf.value + currentPdf.value);
190 currentPdf = nextPdf;
191 currentMode = nextMode;
202findRoot(
double& result,
207 const std::array<VecOfComponents, 5>& mixture)
214 double fb =
pdf(b, i, mixture) -
value;
219 bool ac_equal(
false);
224 constexpr int MaxIterations = 20;
227 for (
int iter = 0;
iter <= MaxIterations;
iter++) {
229 if ((fb < 0 && fc < 0) || (fb > 0 && fc > 0)) {
238 if (std::abs(fc) < std::abs(fb)) {
248 const double tol = 0.5 *
tolerance * std::abs(b);
249 const double m = 0.5 * (
c -
b);
251 if (fb == 0 || std::abs(m) <= tol) {
256 if (std::abs(e) < tol || std::abs(fa) <= std::abs(fb)) {
266 throw std::runtime_error{
"findRoot: divisor fa is zero."};
268 const double s = fb / fa;
276 p =
s * (2 *
m *
q * (
q -
r) - (
b -
a) * (
r - 1));
277 q = (
q - 1) * (
r - 1) * (
s - 1);
286 const double min1 = 3 *
m *
q - std::abs(tol * q);
287 const double min2 = std::abs(e * q);
288 if (2 * p < (min1 < min2 ? min1 : min2)) {
302 if (std::abs(d) > tol) {
305 b += (
m > 0 ? +tol : -tol);
318std::array<double, 10>
319evaluateMode(
const std::array<VecOfComponents, 5>& mixture)
321 std::array<double, 10>
modes{};
324 for (
int i = 0;
i < 5;
i++) {
326 double largerPdfComponent = 0.0;
327 double largerMeanComponent = 0.0;
334 for (
const Component& component : mixture[i]) {
335 const double pdfValue =
pdf(component.mean, i, mixture);
336 if (pdfValue > largerPdfComponent) {
337 largerPdfComponent = pdfValue;
338 largerMeanComponent = component.mean;
341 modes[
i] = findMode(largerMeanComponent, i, mixture);
344 if (largerMeanComponent != modes[i]) {
346 const double currentWidth =
width(i, mixture);
349 const double pdfVal =
pdf(modes[i], i, mixture);
353 double upperbound =
modes[
i] + 1.5 * currentWidth;
355 if (
pdf(upperbound, i, mixture) > pdfVal * 0.5) {
356 upperbound += currentWidth;
362 const bool highXFound =
363 findRoot(highX, modes[i], upperbound, pdfVal * 0.5, i, mixture);
365 double lowerbound =
modes[
i] - 1.5 * currentWidth;
367 if (
pdf(lowerbound, i, mixture) > pdfVal * 0.5) {
368 lowerbound -= currentWidth;
373 const bool lowXFound =
374 findRoot(lowX, lowerbound, modes[i], pdfVal * 0.5, i, mixture);
375 if (highXFound && lowXFound) {
376 const double FWHM = highX - lowX;
377 modes[
i + 5] = FWHM / 2.35482;
389std::array<double, 10>
397 std::array<VecOfComponents, 5> mixture;
399 fillMixture(multiComponentState, mixture);
400 return evaluateMode(mixture);
Scalar deltaPhi(const MatrixBase< Derived > &vec) const
ElementLink & operator=(const ElementLink &)=default
#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)
constexpr 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