151 specnum_t mon1 = monitor1_spec, mon2 = monitor2_spec;
159 std::string formula = par->asString();
160 std::stringstream guess;
161 guess << initial_guess;
163 while (formula.find(
"incidentEnergy") != std::string::npos) {
165 size_t found = formula.find(
"incidentEnergy");
166 formula.replace(found, 14, guess.str());
172 double tzero = p.Eval();
176 return initial_guess;
177 }
catch (mu::Parser::exception_type &e) {
179 "Equation attribute for t0 formula. Muparser error message is: " + e.GetMsg());
184 par =
pmap.getRecursive(instrument->getChild(0).get(),
"ei-mon1-spec");
186 mon1 = boost::lexical_cast<specnum_t>(par->asString());
190 par =
pmap.getRecursive(instrument->getChild(0).get(),
"ei-mon2-spec");
192 mon2 = boost::lexical_cast<specnum_t>(par->asString());
196 throw std::invalid_argument(
"Could not determine spectrum number to use. Try to set it explicitly");
199 std::vector<specnum_t> spec_nums(2, mon1);
202 auto mon_indices =
m_input_ws->getIndicesFromSpectra(spec_nums);
204 if (mon_indices.size() != 2) {
205 g_log.
error() <<
"Error retrieving monitor spectra from input workspace. "
206 "Check input properties.\n";
207 throw std::runtime_error(
"Error retrieving monitor spectra spectra from input workspace.");
211 double peak_times[2] = {0.0, 0.0};
212 double det_distances[2] = {0.0, 0.0};
213 const auto &spectrumInfo =
m_input_ws->spectrumInfo();
214 for (
unsigned int i = 0; i < 2; ++i) {
215 size_t ws_index = mon_indices[i];
217 const double peak_guess = det_distances[i] * std::sqrt(
m_t_to_mev / initial_guess);
220 g_log.
information() <<
"Time-of-flight window for peak " << (i + 1) <<
": tmin = " << t_min
221 <<
" microseconds, tmax = " << t_max <<
" microseconds\n";
224 g_log.
information() <<
"Peak for monitor " << (i + 1) <<
" (at " << det_distances[i]
225 <<
" metres) = " << peak_times[i] <<
" microseconds\n";
226 }
catch (std::invalid_argument &) {
229 throw std::invalid_argument(
"No peak found for the monitor with spectra num: " +
std::to_string(spec_nums[i]) +
230 " (at " + boost::lexical_cast<std::string>(det_distances[i]) +
231 " metres from source).\n");
233 peak_times[i] = peak_guess;
234 g_log.
warning() <<
"No peak found for monitor with spectra num " << spec_nums[i] <<
" (at " << det_distances[i]
236 g_log.
warning() <<
"Using guess time found from energy estimate of Peak = " << peak_times[i]
237 <<
" microseconds\n";
241 m_peak1_pos = std::make_pair(
static_cast<int>(ws_index), peak_times[i]);
248 g_log.
notice() <<
"Incident energy fixed at Ei=" << initial_guess <<
" meV\n";
249 return initial_guess;
251 double mean_speed = (det_distances[1] - det_distances[0]) / (peak_times[1] - peak_times[0]);
252 double tzero = peak_times[1] - ((1.0 / mean_speed) * det_distances[1]);
254 g_log.
debug() <<
"Mean Speed = " << mean_speed <<
'\n';
258 g_log.
notice() <<
"Incident energy calculated at Ei= " <<
energy <<
" meV from initial guess = " << initial_guess
369 std::vector<double> &peak_x, std::vector<double> &peak_y,
370 std::vector<double> &peak_e)
const {
373 auto Xs = data_ws->points(0);
374 const auto &Ys = data_ws->y(0);
375 const auto &Es = data_ws->e(0);
377 auto peakIt = std::max_element(Ys.cbegin(), Ys.cend());
378 double bkg_val = *std::min_element(Ys.begin(), Ys.end());
379 if (*peakIt == bkg_val) {
380 throw std::invalid_argument(
"No peak in the range specified as minimal and "
381 "maximal values of the function are equal ");
383 auto iPeak = peakIt - Ys.begin();
384 double peakY = Ys[iPeak] - bkg_val;
385 double peakE = Es[iPeak];
387 const std::vector<double>::size_type nxvals = Xs.size();
391 auto im =
static_cast<int64_t
>(iPeak - 1);
392 for (; im >= 0; --im) {
393 const double ratio = (Ys[im] - bkg_val) / peakY;
394 const double ratio_err = std::sqrt(std::pow(Es[im], 2) + std::pow(ratio * peakE, 2)) / peakY;
395 if (ratio < (1.0 / prominence -
m_peak_signif * ratio_err)) {
400 std::vector<double>::size_type ip = iPeak + 1;
401 for (; ip < nxvals; ip++) {
402 const double ratio = (Ys[ip] - bkg_val) / peakY;
403 const double ratio_err = std::sqrt(std::pow(Es[ip], 2) + std::pow(ratio * peakE, 2)) / peakY;
404 if (ratio < (1.0 / prominence -
m_peak_signif * ratio_err)) {
409 if (ip == nxvals || im < 0) {
410 throw std::invalid_argument(
"No peak found in data that satisfies prominence criterion");
426 double deriv = -1000.0;
429 double dtp = Xs[ip + 1] - Xs[ip];
430 double dtm = Xs[ip] - Xs[ip - 1];
431 deriv = 0.5 * (((Ys[ip + 1] - Ys[ip]) / dtp) + ((Ys[ip] - Ys[ip - 1]) / dtm));
432 error = 0.5 * std::sqrt(((std::pow(Es[ip + 1], 2) + std::pow(Es[ip], 2)) / std::pow(dtp, 2)) +
433 ((std::pow(Es[ip], 2) + std::pow(Es[ip - 1], 2)) / std::pow(dtm, 2)) -
434 2.0 * (std::pow(Es[ip], 2) / (dtp * dtm)));
439 if (deriv < -
error) {
445 double deriv = 1000.0;
448 double dtp = Xs[im + 1] - Xs[im];
449 double dtm = Xs[im] - Xs[im - 1];
450 deriv = 0.5 * (((Ys[im + 1] - Ys[im]) / dtp) + ((Ys[im] - Ys[im - 1]) / dtm));
451 error = 0.5 * std::sqrt(((std::pow(Es[im + 1], 2) + std::pow(Es[im], 2)) / std::pow(dtp, 2)) +
452 ((std::pow(Es[im], 2) + std::pow(Es[im - 1], 2)) / std::pow(dtm, 2)) -
453 2.0 * std::pow(Es[im], 2) / (dtp * dtm));
460 double pk_min = Xs[im];
461 double pk_max = Xs[ip];
462 double pk_width = Xs[ip] - Xs[im];
468 double bkgd_range = 0.0;
469 double bkgd_min = std::max(Xs.front(), pk_min -
m_bkgd_frac * pk_width);
470 double bkgd_max = std::min(Xs.back(), pk_max +
m_bkgd_frac * pk_width);
473 double bkgd_m, bkgd_err_m;
474 integrate(bkgd_m, bkgd_err_m, Xs.rawData(), Ys, Es, bkgd_min, pk_min);
475 bkgd = bkgd + bkgd_m;
476 bkgd_range = bkgd_range + (pk_min - bkgd_min);
479 if (ip < nxvals - 1) {
480 double bkgd_p, bkgd_err_p;
481 integrate(bkgd_p, bkgd_err_p, Xs.rawData(), Ys, Es, pk_max, bkgd_max);
482 bkgd = bkgd + bkgd_p;
483 bkgd_range = bkgd_range + (bkgd_max - pk_max);
486 if (im > 0 || ip < nxvals - 1)
488 bkgd = bkgd / bkgd_range;
492 const std::vector<double>::size_type nvalues = ip - im + 1;
493 peak_x.resize(nvalues);
494 std::copy(Xs.begin() + im, Xs.begin() + ip + 1, peak_x.begin());
495 peak_y.resize(nvalues);
496 using std::placeholders::_1;
497 std::transform(Ys.begin() + im, Ys.begin() + ip + 1, peak_y.begin(), std::bind(std::minus<double>(), _1, bkgd));
498 peak_e.resize(nvalues);
499 std::copy(Es.begin() + im, Es.begin() + ip + 1, peak_e.begin());
502 int64_t ipk_int =
static_cast<int64_t
>(iPeak) - im;
503 double hby2 = 0.5 * peak_y[ipk_int];
506 auto nyvals =
static_cast<int64_t
>(peak_y.size());
507 if (peak_y[nyvals - 1] < hby2) {
508 int64_t ip1(0), ip2(0);
510 auto it1 = std::find_if(peak_y.cbegin() + ipk_int, peak_y.cend(), [hby2](
double const y) { return y < hby2; });
511 if (it1 != peak_y.cend())
512 ip1 =
static_cast<int64_t
>(std::distance(peak_y.cbegin(), it1)) - 1;
514 int64_t
const rend2 = nyvals - ipk_int;
515 auto it2 = std::find_if(peak_y.crbegin(), peak_y.crbegin() + rend2, [hby2](
double const y) { return y > hby2; });
516 if (it2 != peak_y.crbegin() + rend2)
517 ip2 = nyvals -
static_cast<int64_t
>(std::distance(peak_y.crbegin(), it2));
522 if (peak_y[ip1] == peak_y[ip2]) {
523 g_log.
warning() <<
"A peak with a local maxima on the trailing edge has "
524 "been found. The estimation of the "
525 <<
"half-height point will not be as accurate.\n";
527 while (peak_y[ip1] == peak_y[ip2]) {
530 throw std::invalid_argument(
"Trailing edge values are equal until up to the peak centre.");
534 xp_hh = peak_x[ip2] + (peak_x[ip1] - peak_x[ip2]) * ((hby2 - peak_y[ip2]) / (peak_y[ip1] - peak_y[ip2]));
536 xp_hh = peak_x[nyvals - 1];
540 if (peak_y[0] < hby2) {
541 int64_t im1(0), im2(0);
543 int64_t
const rstart3 = nyvals - 1 - ipk_int;
544 auto it3 = std::find_if(peak_y.crbegin() + rstart3, peak_y.crend(), [hby2](
double const y) { return y < hby2; });
545 if (it3 != peak_y.crend())
546 im1 = nyvals -
static_cast<int64_t
>(std::distance(peak_y.crbegin(), it3));
549 std::find_if(peak_y.cbegin(), peak_y.cbegin() + ipk_int + 1, [hby2](
double const y) { return y > hby2; });
550 if (it4 != peak_y.cbegin() + ipk_int + 1)
551 im2 =
static_cast<int64_t
>(std::distance(peak_y.cbegin(), it4)) - 1;
556 if (peak_y[im1] == peak_y[im2]) {
557 g_log.
warning() <<
"A peak with a local maxima on the rising edge has "
558 "been found. The estimation of the "
559 <<
"half-height point will not be as accurate.\n";
561 while (peak_y[im1] == peak_y[im2]) {
564 throw std::invalid_argument(
"The rising edge values are equal up to the peak centre.");
568 xm_hh = peak_x[im2] + (peak_x[im1] - peak_x[im2]) * ((hby2 - peak_y[im2]) / (peak_y[im1] - peak_y[im2]));
570 xm_hh = peak_x.front();
572 return (xp_hh - xm_hh);
627void GetEi2::integrate(
double &integral_val,
double &integral_err,
const HistogramData::HistogramX &
x,
628 const HistogramData::HistogramY &s,
const HistogramData::HistogramE &e,
const double xmin,
629 const double xmax)
const {
633 auto lowit = std::lower_bound(
x.cbegin(),
x.cend(), xmin);
634 auto ml = std::distance(
x.cbegin(), lowit);
635 auto highit = std::upper_bound(lowit,
x.cend(), xmax);
636 auto mu = std::distance(
x.cbegin(), highit);
643 unsigned int ilo = std::max<unsigned int>(
static_cast<unsigned int>(ml) - 1, 0);
644 unsigned int ihi = std::min<unsigned int>(
static_cast<unsigned int>(
mu) + 1,
static_cast<unsigned int>(nx));
645 double fraction = (xmax - xmin) / (
x[ihi] -
x[ilo]);
647 0.5 * fraction * (s[ihi] * ((xmax -
x[ilo]) + (xmin -
x[ilo])) + s[ilo] * ((
x[ihi] - xmax) + (
x[ihi] - xmin)));
648 double err_hi = e[ihi] * ((xmax -
x[ilo]) + (xmin -
x[ilo]));
649 double err_lo = e[ilo] * ((
x[ihi] - xmax) + (
x[ihi] - xmin));
650 integral_err = 0.5 * fraction * std::sqrt(err_hi * err_hi + err_lo * err_lo);
654 double x1eff(0.0), s1eff(0.0), e1eff(0.0);
656 x1eff = (xmin * (xmin -
x[ml - 1]) +
x[ml - 1] * (
x[ml] - xmin)) / (
x[ml] -
x[ml - 1]);
657 double fraction = (
x[ml] - xmin) / ((
x[ml] -
x[ml - 1]) + (xmin -
x[ml - 1]));
658 s1eff = s[ml - 1] * fraction;
659 e1eff = e[ml - 1] * fraction;
665 double xneff(0.0), sneff(0.0), eneff;
666 if (
mu <
static_cast<int>(nx - 1)) {
667 xneff = (xmax * (
x[
mu + 1] - xmax) +
x[
mu + 1] * (xmax -
x[
mu])) / (
x[
mu + 1] -
x[
mu]);
668 const double fraction = (xmax -
x[
mu]) / ((
x[
mu + 1] -
x[
mu]) + (
x[
mu + 1] - xmax));
669 sneff = s[
mu + 1] * fraction;
670 eneff = e[
mu + 1] * fraction;
678 integral_val = (
x[ml] - x1eff) * (s[ml] + s1eff);
679 integral_err = e1eff * (
x[ml] - x1eff);
680 integral_err *= integral_err;
683 double ierr = e[ml] * (xneff - x1eff);
684 integral_err += ierr * ierr;
685 }
else if (
mu == ml + 1) {
686 integral_val += (s[
mu] + s[ml]) * (
x[
mu] -
x[ml]);
687 double err_lo = e[ml] * (
x[ml + 1] - x1eff);
688 double err_hi = e[
mu] * (
x[
mu - 1] - xneff);
689 integral_err += err_lo * err_lo + err_hi * err_hi;
691 for (
auto i =
static_cast<int>(ml); i <
mu; ++i) {
692 integral_val += (s[i + 1] + s[i]) * (
x[i + 1] -
x[i]);
694 double ierr = e[i + 1] * (
x[i + 2] -
x[i]);
695 integral_err += ierr * ierr;
701 integral_val += (xneff -
x[
mu]) * (s[
mu] + sneff);
702 double err_tmp = eneff * (xneff -
x[
mu]);
703 integral_err += err_tmp * err_tmp;
706 integral_err = 0.5 * sqrt(integral_err);