1 #include <framework/logging/Logger.h>
2 #include <svd/reconstruction/WaveFitter.h>
6 #include <boost/math/tools/minima.hpp>
20 array<double, 6> waves;
21 double sumTemplateByTemplate = 0;
22 for (
int i = 0; i < 6; ++i) {
23 waves[i] = m_wave(m_times[i] - t0);
24 sumTemplateByTemplate += waves[i] * waves[i];
27 vector<double> amplitudes(m_data.size());
28 for (
unsigned int row = 0; row < m_data.size(); ++row) {
29 double sumDataByTemplate = 0;
30 for (
int i = 0; i < 6; i++) {
31 sumDataByTemplate += m_data[row][i] * waves[i];
33 amplitudes[row] = sumDataByTemplate / sumTemplateByTemplate;
36 for (
unsigned int row = 0; row < m_data.size(); ++row)
37 for (
int i = 0; i < 6; i++) {
39 (m_data[row][i] - amplitudes[row] * waves[i]) / m_noises[row];
40 result += diff * diff;
42 return result / m_ndf;
49 for (
int i = 0; i < 6; ++i) w[i] = m_wave(m_times[i] - t);
51 for (
int i = 0; i < 6; ++i) sum_w2 += w[i] * w[i];
52 double lognorm = 0.5 * m_data.size() * log(sum_w2);
54 for (
unsigned int row = 0; row < m_data.size(); ++row) {
56 for (
int i = 1; i < 6; ++i)
57 for (
int j = 0; j < i; ++j) {
58 double cross = w[i] * m_data[row][j] - w[j] * m_data[row][i];
63 return lognorm + 0.5 * sum_ksi / sum_w2;
70 m_ndf = 6 * m_data.size() - m_data.size() - 2;
72 B2ERROR(
"SVD::WaveFitterter : Fit required with no data provided.");
74 m_fittedTimeError = 0;
75 m_fittedAmplitudes.clear();
76 m_fittedAmplitudeErrors.clear();
85 auto result_low = boost::math::tools::brent_find_minima(
86 [
this](
double t)->
double {
return negLogLikelihood(t); }, -m_dt, 0.0, s_minimizer_precision
88 double t0_low = result_low.first;
89 double lik_low = result_low.second;
90 auto result_hi = boost::math::tools::brent_find_minima(
91 [
this](
double t)->
double {
return negLogLikelihood(t); }, 0.0, m_dt, s_minimizer_precision
93 double t0_hi = result_hi.first;
94 double lik_hi = result_hi.second;
95 if (lik_low < lik_hi) {
96 m_fittedTime = t0_low;
97 m_fittedLik = lik_low;
100 m_fittedLik = lik_hi;
102 calculateAmplitudes();
103 calculateFitErrors();
104 calculateFittedData();
111 array<double, 6> waves;
112 double sumTemplateByTemplate = 0;
113 for (
int i = 0; i < 6; ++i) {
114 waves[i] = m_wave(m_times[i] - m_fittedTime);
115 sumTemplateByTemplate += waves[i] * waves[i];
118 for (
unsigned int row = 0; row < m_data.size(); ++row) {
119 double sumDataByTemplate = 0;
120 for (
int i = 0; i < 6; i++) {
121 sumDataByTemplate += m_data[row][i] * waves[i];
123 m_fittedAmplitudes.push_back(sumDataByTemplate / sumTemplateByTemplate);
131 for (
int i = 0; i < 6; ++i) {
132 double wave = m_wave(m_times[i] - m_fittedTime);
133 sum_w2 += wave * wave;
135 double one_by_sqrtSumw2 = 1.0 / sqrt(sum_w2);
136 for (
unsigned int row = 0; row < m_data.size(); ++row)
137 m_fittedAmplitudeErrors.push_back(one_by_sqrtSumw2 * m_noises[row]);
140 double timestep = 0.1 * m_dt;
142 for (
int i = 0; i < 6; ++i) {
143 double dwave = (wave(m_times[i] - m_fittedTime + 0.5 * timestep) - wave(m_times[i] - m_fittedTime - 0.5 * timestep)) / timestep;
144 dwave_sq += dwave * dwave;
147 for (
unsigned int row = 0; row < m_data.size(); ++row) {
148 double sn = m_fittedAmplitudes[row] / m_noises[row];
151 m_fittedTimeError = 1.0 / sqrt(sn_sq * dwave_sq);
156 m_fittedData.resize(m_data.size());
157 for (
int i = 0; i < 6; ++i) {
158 double wave = m_wave(m_times[i] - m_fittedTime);
159 for (
unsigned int row = 0; row < m_data.size(); ++row)
160 m_fittedData[row][i] = m_fittedAmplitudes[row] * wave;
166 const unsigned int half_order = 6;
167 const double knots[half_order] = {
168 0.1252334085114689154724414,
169 0.3678314989981801937526915,
170 0.5873179542866174472967024,
171 0.7699026741943046870368938,
172 0.9041172563704748566784659,
173 0.9815606342467192506905491
175 const double weights[half_order] = {
176 0.2491470458134027850005624,
177 0.2334925365383548087608499,
178 0.2031674267230659217490645,
179 0.1600783285433462263346525,
180 0.1069393259953184309602547,
181 0.0471753363865118271946160
183 double span = 0.5 * (upper - lower);
184 double center = 0.5 * (upper + lower);
186 for (
unsigned int iknot = 0; iknot < half_order; ++iknot) {
187 result += weights[iknot] * f(center + span * knots[iknot]);
188 result += weights[iknot] * f(center - span * knots[iknot]);
196 const unsigned int half_order = 10;
197 const double knots[half_order] = {
209 const double weights[half_order] = {
221 double span = 0.5 * (upper - lower);
222 double center = 0.5 * (upper + lower);
224 for (
unsigned int iknot = 0; iknot < half_order; ++iknot) {
225 result += weights[iknot] * f(center + span * knots[iknot]);
226 result += weights[iknot] * f(center - span * knots[iknot]);
234 const double outer = m_dt;
235 const double inner = 5;
236 if (!m_hasFit) doFit();
237 auto integrand = [
this](
double t)->
double {
return exp(-negLogLikelihood(t));};
239 double i1 = integral20(-outer, -inner, integrand);
240 double i2 = integral20(-inner, 0, integrand);
241 double i3 = integral20(0, inner, integrand);
242 double i4 = integral20(inner, outer, integrand);
243 double L_background = 1.0 / (2 * outer) * (i1 + i2 + i3 + i4);
244 double L_signal = 1.0 / (2 * inner) * (i2 + i3);
245 double prob = (L_signal / (L_background + L_signal));
252 const double outer = m_dt;
253 if (!m_hasFit) doFit();
254 auto integrand = [
this](
double t)->
double {
return exp(-negLogLikelihood(t));};
256 double int_total = integral20(-outer, 0, integrand);
257 int_total += integral20(0, outer, integrand);
258 double int_inner = 0;
259 if (low * high < 0) {
260 int_inner += integral20(low, 0, integrand);
261 int_inner += integral20(0, high, integrand);
263 int_inner += integral20(low, high, integrand);
265 double int_outer = int_total - int_inner;
266 double LR = int_inner / int_outer;