152 specnum_t mon1 = monitor1_spec, mon2 = monitor2_spec;
154 const auto &componentInfo =
m_input_ws->componentInfo();
156 const auto firstComponent = componentInfo.children(componentInfo.root()).front();
159 if (componentInfo.hasParameter(firstComponent,
"t0_formula")) {
160 std::string formula = componentInfo.getParameterAsString(firstComponent,
"t0_formula");
161 std::stringstream guess;
162 guess << initial_guess;
164 while (formula.find(
"incidentEnergy") != std::string::npos) {
166 size_t found = formula.find(
"incidentEnergy");
167 formula.replace(found, 14, guess.str());
173 double tzero = p.Eval();
177 return initial_guess;
178 }
catch (mu::Parser::exception_type &e) {
180 "Equation attribute for t0 formula. Muparser error message is: " + e.GetMsg());
184 if (mon1 ==
EMPTY_INT() && componentInfo.hasParameter(firstComponent,
"ei-mon1-spec")) {
185 mon1 = boost::lexical_cast<specnum_t>(componentInfo.getParameterAsString(firstComponent,
"ei-mon1-spec"));
187 if (mon2 ==
EMPTY_INT() && componentInfo.hasParameter(firstComponent,
"ei-mon2-spec")) {
188 mon2 = boost::lexical_cast<specnum_t>(componentInfo.getParameterAsString(firstComponent,
"ei-mon2-spec"));
191 throw std::invalid_argument(
"Could not determine spectrum number to use. Try to set it explicitly");
194 std::vector<specnum_t> spec_nums(2, mon1);
197 auto mon_indices =
m_input_ws->getIndicesFromSpectra(spec_nums);
199 if (mon_indices.size() != 2) {
200 g_log.
error() <<
"Error retrieving monitor spectra from input workspace. "
201 "Check input properties.\n";
202 throw std::runtime_error(
"Error retrieving monitor spectra spectra from input workspace.");
206 double peak_times[2] = {0.0, 0.0};
207 double det_distances[2] = {0.0, 0.0};
208 const auto &spectrumInfo =
m_input_ws->spectrumInfo();
209 for (
unsigned int i = 0; i < 2; ++i) {
210 size_t ws_index = mon_indices[i];
212 const double peak_guess = det_distances[i] * std::sqrt(
m_t_to_mev / initial_guess);
215 g_log.
information() <<
"Time-of-flight window for peak " << (i + 1) <<
": tmin = " << t_min
216 <<
" microseconds, tmax = " << t_max <<
" microseconds\n";
219 g_log.
information() <<
"Peak for monitor " << (i + 1) <<
" (at " << det_distances[i]
220 <<
" metres) = " << peak_times[i] <<
" microseconds\n";
221 }
catch (std::invalid_argument &) {
224 throw std::invalid_argument(
"No peak found for the monitor with spectra num: " +
std::to_string(spec_nums[i]) +
225 " (at " + boost::lexical_cast<std::string>(det_distances[i]) +
226 " metres from source).\n");
228 peak_times[i] = peak_guess;
229 g_log.
warning() <<
"No peak found for monitor with spectra num " << spec_nums[i] <<
" (at " << det_distances[i]
231 g_log.
warning() <<
"Using guess time found from energy estimate of Peak = " << peak_times[i]
232 <<
" microseconds\n";
236 m_peak1_pos = std::make_pair(
static_cast<int>(ws_index), peak_times[i]);
243 g_log.
notice() <<
"Incident energy fixed at Ei=" << initial_guess <<
" meV\n";
244 return initial_guess;
246 double mean_speed = (det_distances[1] - det_distances[0]) / (peak_times[1] - peak_times[0]);
247 double tzero = peak_times[1] - ((1.0 / mean_speed) * det_distances[1]);
249 g_log.
debug() <<
"Mean Speed = " << mean_speed <<
'\n';
253 g_log.
notice() <<
"Incident energy calculated at Ei= " <<
energy <<
" meV from initial guess = " << initial_guess
364 std::vector<double> &peak_x, std::vector<double> &peak_y,
365 std::vector<double> &peak_e)
const {
368 auto Xs = data_ws->points(0);
369 const auto &Ys = data_ws->y(0);
370 const auto &Es = data_ws->e(0);
372 auto peakIt = std::max_element(Ys.cbegin(), Ys.cend());
373 double bkg_val = *std::min_element(Ys.begin(), Ys.end());
374 if (*peakIt == bkg_val) {
375 throw std::invalid_argument(
"No peak in the range specified as minimal and "
376 "maximal values of the function are equal ");
378 auto iPeak = peakIt - Ys.begin();
379 double peakY = Ys[iPeak] - bkg_val;
380 double peakE = Es[iPeak];
382 const std::vector<double>::size_type nxvals = Xs.size();
386 auto im =
static_cast<int64_t
>(iPeak - 1);
387 for (; im >= 0; --im) {
388 const double ratio = (Ys[im] - bkg_val) / peakY;
389 const double ratio_err = std::sqrt(std::pow(Es[im], 2) + std::pow(ratio * peakE, 2)) / peakY;
390 if (ratio < (1.0 / prominence -
m_peak_signif * ratio_err)) {
395 std::vector<double>::size_type ip = iPeak + 1;
396 for (; ip < nxvals; ip++) {
397 const double ratio = (Ys[ip] - bkg_val) / peakY;
398 const double ratio_err = std::sqrt(std::pow(Es[ip], 2) + std::pow(ratio * peakE, 2)) / peakY;
399 if (ratio < (1.0 / prominence -
m_peak_signif * ratio_err)) {
404 if (ip == nxvals || im < 0) {
405 throw std::invalid_argument(
"No peak found in data that satisfies prominence criterion");
421 double deriv = -1000.0;
424 double dtp = Xs[ip + 1] - Xs[ip];
425 double dtm = Xs[ip] - Xs[ip - 1];
426 deriv = 0.5 * (((Ys[ip + 1] - Ys[ip]) / dtp) + ((Ys[ip] - Ys[ip - 1]) / dtm));
427 error = 0.5 * std::sqrt(((std::pow(Es[ip + 1], 2) + std::pow(Es[ip], 2)) / std::pow(dtp, 2)) +
428 ((std::pow(Es[ip], 2) + std::pow(Es[ip - 1], 2)) / std::pow(dtm, 2)) -
429 2.0 * (std::pow(Es[ip], 2) / (dtp * dtm)));
434 if (deriv < -
error) {
440 double deriv = 1000.0;
443 double dtp = Xs[im + 1] - Xs[im];
444 double dtm = Xs[im] - Xs[im - 1];
445 deriv = 0.5 * (((Ys[im + 1] - Ys[im]) / dtp) + ((Ys[im] - Ys[im - 1]) / dtm));
446 error = 0.5 * std::sqrt(((std::pow(Es[im + 1], 2) + std::pow(Es[im], 2)) / std::pow(dtp, 2)) +
447 ((std::pow(Es[im], 2) + std::pow(Es[im - 1], 2)) / std::pow(dtm, 2)) -
448 2.0 * std::pow(Es[im], 2) / (dtp * dtm));
455 double pk_min = Xs[im];
456 double pk_max = Xs[ip];
457 double pk_width = Xs[ip] - Xs[im];
463 double bkgd_range = 0.0;
464 double bkgd_min = std::max(Xs.front(), pk_min -
m_bkgd_frac * pk_width);
465 double bkgd_max = std::min(Xs.back(), pk_max +
m_bkgd_frac * pk_width);
468 double bkgd_m, bkgd_err_m;
469 integrate(bkgd_m, bkgd_err_m, Xs.rawData(), Ys, Es, bkgd_min, pk_min);
470 bkgd = bkgd + bkgd_m;
471 bkgd_range = bkgd_range + (pk_min - bkgd_min);
474 if (ip < nxvals - 1) {
475 double bkgd_p, bkgd_err_p;
476 integrate(bkgd_p, bkgd_err_p, Xs.rawData(), Ys, Es, pk_max, bkgd_max);
477 bkgd = bkgd + bkgd_p;
478 bkgd_range = bkgd_range + (bkgd_max - pk_max);
481 if (im > 0 || ip < nxvals - 1)
483 bkgd = bkgd / bkgd_range;
487 const std::vector<double>::size_type nvalues = ip - im + 1;
488 peak_x.resize(nvalues);
489 std::copy(Xs.begin() + im, Xs.begin() + ip + 1, peak_x.begin());
490 peak_y.resize(nvalues);
491 using std::placeholders::_1;
492 std::transform(Ys.begin() + im, Ys.begin() + ip + 1, peak_y.begin(), std::bind(std::minus<double>(), _1, bkgd));
493 peak_e.resize(nvalues);
494 std::copy(Es.begin() + im, Es.begin() + ip + 1, peak_e.begin());
497 int64_t ipk_int =
static_cast<int64_t
>(iPeak) - im;
498 double hby2 = 0.5 * peak_y[ipk_int];
501 auto nyvals =
static_cast<int64_t
>(peak_y.size());
502 if (peak_y[nyvals - 1] < hby2) {
503 int64_t ip1(0), ip2(0);
505 auto it1 = std::find_if(peak_y.cbegin() + ipk_int, peak_y.cend(), [hby2](
double const y) { return y < hby2; });
506 if (it1 != peak_y.cend())
507 ip1 =
static_cast<int64_t
>(std::distance(peak_y.cbegin(), it1)) - 1;
509 int64_t
const rend2 = nyvals - ipk_int;
510 auto it2 = std::find_if(peak_y.crbegin(), peak_y.crbegin() + rend2, [hby2](
double const y) { return y > hby2; });
511 if (it2 != peak_y.crbegin() + rend2)
512 ip2 = nyvals -
static_cast<int64_t
>(std::distance(peak_y.crbegin(), it2));
517 if (peak_y[ip1] == peak_y[ip2]) {
518 g_log.
warning() <<
"A peak with a local maxima on the trailing edge has "
519 "been found. The estimation of the "
520 <<
"half-height point will not be as accurate.\n";
522 while (peak_y[ip1] == peak_y[ip2]) {
525 throw std::invalid_argument(
"Trailing edge values are equal until up to the peak centre.");
529 xp_hh = peak_x[ip2] + (peak_x[ip1] - peak_x[ip2]) * ((hby2 - peak_y[ip2]) / (peak_y[ip1] - peak_y[ip2]));
531 xp_hh = peak_x[nyvals - 1];
535 if (peak_y[0] < hby2) {
536 int64_t im1(0), im2(0);
538 int64_t
const rstart3 = nyvals - 1 - ipk_int;
539 auto it3 = std::find_if(peak_y.crbegin() + rstart3, peak_y.crend(), [hby2](
double const y) { return y < hby2; });
540 if (it3 != peak_y.crend())
541 im1 = nyvals -
static_cast<int64_t
>(std::distance(peak_y.crbegin(), it3));
544 std::find_if(peak_y.cbegin(), peak_y.cbegin() + ipk_int + 1, [hby2](
double const y) { return y > hby2; });
545 if (it4 != peak_y.cbegin() + ipk_int + 1)
546 im2 =
static_cast<int64_t
>(std::distance(peak_y.cbegin(), it4)) - 1;
551 if (peak_y[im1] == peak_y[im2]) {
552 g_log.
warning() <<
"A peak with a local maxima on the rising edge has "
553 "been found. The estimation of the "
554 <<
"half-height point will not be as accurate.\n";
556 while (peak_y[im1] == peak_y[im2]) {
559 throw std::invalid_argument(
"The rising edge values are equal up to the peak centre.");
563 xm_hh = peak_x[im2] + (peak_x[im1] - peak_x[im2]) * ((hby2 - peak_y[im2]) / (peak_y[im1] - peak_y[im2]));
565 xm_hh = peak_x.front();
567 return (xp_hh - xm_hh);
622void GetEi2::integrate(
double &integral_val,
double &integral_err,
const HistogramData::HistogramX &
x,
623 const HistogramData::HistogramY &s,
const HistogramData::HistogramE &e,
const double xmin,
624 const double xmax)
const {
628 auto lowit = std::lower_bound(
x.cbegin(),
x.cend(), xmin);
629 auto ml = std::distance(
x.cbegin(), lowit);
630 auto highit = std::upper_bound(lowit,
x.cend(), xmax);
631 auto mu = std::distance(
x.cbegin(), highit);
638 unsigned int ilo = std::max<unsigned int>(
static_cast<unsigned int>(ml) - 1, 0);
639 unsigned int ihi = std::min<unsigned int>(
static_cast<unsigned int>(
mu) + 1,
static_cast<unsigned int>(nx));
640 double fraction = (xmax - xmin) / (
x[ihi] -
x[ilo]);
642 0.5 * fraction * (s[ihi] * ((xmax -
x[ilo]) + (xmin -
x[ilo])) + s[ilo] * ((
x[ihi] - xmax) + (
x[ihi] - xmin)));
643 double err_hi = e[ihi] * ((xmax -
x[ilo]) + (xmin -
x[ilo]));
644 double err_lo = e[ilo] * ((
x[ihi] - xmax) + (
x[ihi] - xmin));
645 integral_err = 0.5 * fraction * std::sqrt(err_hi * err_hi + err_lo * err_lo);
649 double x1eff(0.0), s1eff(0.0), e1eff(0.0);
651 x1eff = (xmin * (xmin -
x[ml - 1]) +
x[ml - 1] * (
x[ml] - xmin)) / (
x[ml] -
x[ml - 1]);
652 double fraction = (
x[ml] - xmin) / ((
x[ml] -
x[ml - 1]) + (xmin -
x[ml - 1]));
653 s1eff = s[ml - 1] * fraction;
654 e1eff = e[ml - 1] * fraction;
660 double xneff(0.0), sneff(0.0), eneff;
661 if (
mu <
static_cast<int>(nx - 1)) {
662 xneff = (xmax * (
x[
mu + 1] - xmax) +
x[
mu + 1] * (xmax -
x[
mu])) / (
x[
mu + 1] -
x[
mu]);
663 const double fraction = (xmax -
x[
mu]) / ((
x[
mu + 1] -
x[
mu]) + (
x[
mu + 1] - xmax));
664 sneff = s[
mu + 1] * fraction;
665 eneff = e[
mu + 1] * fraction;
673 integral_val = (
x[ml] - x1eff) * (s[ml] + s1eff);
674 integral_err = e1eff * (
x[ml] - x1eff);
675 integral_err *= integral_err;
678 double ierr = e[ml] * (xneff - x1eff);
679 integral_err += ierr * ierr;
680 }
else if (
mu == ml + 1) {
681 integral_val += (s[
mu] + s[ml]) * (
x[
mu] -
x[ml]);
682 double err_lo = e[ml] * (
x[ml + 1] - x1eff);
683 double err_hi = e[
mu] * (
x[
mu - 1] - xneff);
684 integral_err += err_lo * err_lo + err_hi * err_hi;
686 for (
auto i =
static_cast<int>(ml); i <
mu; ++i) {
687 integral_val += (s[i + 1] + s[i]) * (
x[i + 1] -
x[i]);
689 double ierr = e[i + 1] * (
x[i + 2] -
x[i]);
690 integral_err += ierr * ierr;
696 integral_val += (xneff -
x[
mu]) * (s[
mu] + sneff);
697 double err_tmp = eneff * (xneff -
x[
mu]);
698 integral_err += err_tmp * err_tmp;
701 integral_err = 0.5 * sqrt(integral_err);