104HistogramY LeBailFunction::function(
const Mantid::HistogramData::HistogramX &xvalues,
bool calpeaks,
105 bool calbkgd)
const {
108 std::vector<double> out(xvalues.size(), 0);
109 const auto &xvals = xvalues.rawData();
113 for (
size_t ipk = 0; ipk <
m_numPeaks; ++ipk) {
115 vector<double> temp(xvalues.size(), 0);
117 peak->function(temp, xvals);
118 transform(out.begin(), out.end(), temp.begin(), out.begin(), ::plus<double>());
125 throw runtime_error(
"Must define background first!");
132 size_t numpts = out.size();
133 for (
size_t i = 0; i < numpts; ++i)
137 return HistogramY(out);
324bool LeBailFunction::calculatePeaksIntensities(
const vector<double> &vecX,
const vector<double> &vecY,
325 vector<double> &vec_summedpeaks) {
327 std::fill(vec_summedpeaks.begin(), vec_summedpeaks.end(), 0.0);
330 vector<vector<pair<double, IPowderDiffPeakFunction_sptr>>> peakgroupvec;
331 vector<IPowderDiffPeakFunction_sptr> outboundpeakvec;
332 double xmin = vecX.front();
333 double xmax = vecX.back();
334 groupPeaks(peakgroupvec, outboundpeakvec, xmin, xmax);
337 bool allpeakheightsphysical =
true;
338 for (
size_t ig = 0; ig < peakgroupvec.size(); ++ig) {
339 g_log.
debug() <<
"[Fx351] Calculate peaks heights for (peak) group " << ig
340 <<
" : number of peaks = " << peakgroupvec[ig].size() <<
"\n";
344 if (!peakheightsphysical)
345 allpeakheightsphysical =
false;
349 for (
const auto &peak : outboundpeakvec) {
353 return allpeakheightsphysical;
367bool LeBailFunction::calculateGroupPeakIntensities(vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroup,
368 const vector<double> &vecX,
const vector<double> &vecY,
369 vector<double> &vec_summedpeaks) {
371 if (peakgroup.empty()) {
372 throw runtime_error(
"Programming error such that input peak group cannot be empty!");
374 g_log.
debug() <<
"[Fx155] Peaks group size = " << peakgroup.size() <<
"\n";
376 if (peakgroup.size() > 1)
377 sort(peakgroup.begin(), peakgroup.end());
380 if (vec_summedpeaks.size() != vecY.size()) {
382 errss <<
"Input vector 'allpeaksvalues' has wrong size = " << vec_summedpeaks.size()
383 <<
" != data workspace Y's size = " << vecY.size();
385 throw runtime_error(errss.str());
390 double leftbound = leftpeak->centre() - PEAKRANGECONSTANT * leftpeak->fwhm();
391 if (leftbound < vecX.front()) {
394 leftpeak->getMillerIndex(h, k, l);
395 msg <<
"Peak group (containing " << peakgroup.size() <<
" peaks) has its left boundary (TOF = " << leftbound
396 <<
") out side of input data workspace's left boundary (" << vecX.front()
397 <<
"). Accuracy of its peak intensity might be affected. "
398 <<
"Group's left boundary is determined by its leftmost peak (" << h <<
", " << k <<
", " << l
399 <<
") at TOF = " << leftpeak->centre() <<
" with FWHM = " << leftpeak->fwhm() <<
". ";
403 leftbound = vecX[0] + 0.1;
406 double rightbound = rightpeak->centre() + PEAKRANGECONSTANT * rightpeak->fwhm();
407 if (rightbound > vecX.back()) {
409 msg <<
"Peak group's right boundary " << rightbound <<
" is out side of "
410 <<
"input data workspace's right bound (" << vecX.back()
411 <<
")! Accuracy of its peak intensity might be affected. ";
415 rightbound = vecX.back() - 0.1;
419 vector<double>::const_iterator cviter;
421 cviter = lower_bound(vecX.begin(), vecX.end(), leftbound);
422 size_t ileft =
static_cast<size_t>(cviter - vecX.begin());
426 cviter = lower_bound(vecX.begin(), vecX.end(), rightbound);
427 size_t iright =
static_cast<size_t>(cviter - vecX.begin());
428 if (iright <= vecX.size() - 1)
431 size_t ndata = iright - ileft;
432 if (ileft >= iright) {
434 errss <<
"[Calcualte Peak Intensity] Group range is unphysical. iLeft = " << ileft <<
", iRight = " << iright
435 <<
"; Number of peaks = " << peakgroup.size() <<
"; Left boundary = " << leftbound
436 <<
", Right boundary = " << rightbound <<
"; Left peak FWHM = " << leftpeak->fwhm()
437 <<
", Right peak FWHM = " << rightpeak->fwhm();
438 for (
size_t ipk = 0; ipk < peakgroup.size(); ++ipk) {
440 errss <<
"Peak " << ipk <<
": d_h = " << peakgroup[ipk].first <<
", TOF_h = " << thispeak->centre()
441 <<
", FWHM = " << thispeak->fwhm() <<
"\n";
442 vector<string> peakparamnames = thispeak->getParameterNames();
443 for (
auto &peakparamname : peakparamnames) {
444 errss <<
"\t" << peakparamname <<
" = " << thispeak->getParameter(peakparamname) <<
"\n";
449 throw runtime_error(errss.str());
453 vector<double> datax(vecX.begin() + ileft, vecX.begin() + iright);
454 vector<double> datay(vecY.begin() + ileft, vecY.begin() + iright);
455 if (datax.size() != ndata) {
457 errmsg <<
"Impossible: Partial peak data size = " << datax.size() <<
" != ndata = " << ndata;
459 throw runtime_error(errmsg.str());
461 g_log.
debug() <<
"[DBx356] Number of data points = " << ndata <<
" index from " << ileft <<
" to " << iright
462 <<
"; Size(datax, datay) = " << datax.size() <<
"\n";
465 vector<double> sumYs(ndata, 0.0);
466 size_t numPeaks(peakgroup.size());
467 vector<vector<double>> peakvalues(numPeaks);
470 bool datavalueinvalid =
false;
471 for (
size_t ipk = 0; ipk < numPeaks; ++ipk) {
475 peak->setHeight(1.0);
476 vector<double> localpeakvalue(ndata, 0.0);
477 peak->function(localpeakvalue, datax);
480 const auto numbadpts = std::count_if(localpeakvalue.cbegin(), localpeakvalue.cend(), [&](
const auto &pt) {
481 return (pt != 0.) && (pt < NEG_DBL_MAX || pt > DBL_MAX);
485 if (numbadpts == 0) {
487 for (
size_t i = 0; i < ndata; ++i) {
489 sumYs[i] += localpeakvalue[i];
494 peak->getMillerIndex(h, k, l);
496 warnss <<
"Peak (" << h <<
", " << k <<
", " << l <<
") @ TOF = " << peak->centre() <<
" has " << numbadpts
498 <<
"whose values exceed limit (i.e., not physical). ";
500 datavalueinvalid =
true;
502 peakvalues[ipk].assign(localpeakvalue.begin(), localpeakvalue.end());
506 bool peakheightsphysical = !datavalueinvalid;
507 if (peakheightsphysical) {
508 for (
size_t ipk = 0; ipk < peakgroup.size(); ++ipk) {
510 double intensity = 0.0;
512 for (
size_t i = 0; i < ndata; ++i) {
514 if (sumYs[i] > 1.0E-5) {
516 double peaktogroupratio = peakvalues[ipk][i] / sumYs[i];
517 temp = datay[i] * peaktogroupratio;
524 deltax = datax[1] - datax[0];
526 deltax = datax[i] - datax[i - 1];
528 intensity += temp * deltax;
531 if (intensity != intensity) {
534 peakheightsphysical =
false;
537 peak->getMillerIndex(h, k, l);
538 g_log.
warning() <<
"Peak (" << h <<
", " << k <<
", " << l <<
") has unphysical intensity = NaN!\n";
540 }
else if (intensity <= -DBL_MAX || intensity >= DBL_MAX) {
543 peakheightsphysical =
false;
546 peak->getMillerIndex(h, k, l);
547 g_log.
warning() <<
"Peak (" << h <<
", " << k <<
", " << l <<
") has unphysical intensity = Infty!\n";
548 }
else if (intensity < 0.0) {
550 g_log.
debug() <<
"[Fx134] Set peak @ " << peak->centre() <<
"'s intensity to 0.0 instead of " << intensity
554 g_log.
debug() <<
"[Fx407] Peak @ " << peak->centre() <<
": Set Intensity = " << intensity <<
"\n";
555 peak->setHeight(intensity);
558 for (
size_t i = ileft; i < iright; ++i) {
559 vec_summedpeaks[i] += (intensity * peakvalues[ipk][i - ileft]);
565 return peakheightsphysical;
637void LeBailFunction::setProfileParameterValues(map<std::string, double> parammap) {
638 const double MINDIFF = 1.0E-10;
640 map<std::string, double>::iterator inpiter, curiter;
643 for (
size_t i = 0; i < numpars; ++i) {
647 inpiter = parammap.find(parname);
648 if (inpiter != parammap.end()) {
654 errmsg <<
"Parameter " << parname <<
" is in parameter name list, but not in profile "
655 <<
"parameter map. It violates the programming logic.";
657 throw runtime_error(errmsg.str());
661 double curvalue = curiter->second;
662 double newvalue = inpiter->second;
663 bool localnewvalue =
false;
664 if (
fabs(curvalue - newvalue) > MINDIFF) {
665 curiter->second = newvalue;
667 localnewvalue =
true;
675 for (
size_t ipk = 0; ipk <
m_numPeaks; ++ipk) {
677 peak->setParameter(i, newvalue);
681 g_log.
debug() <<
"Parameter " << parname <<
" is not a profile parameter. Length of string = " << parname.size()
699void LeBailFunction::groupPeaks(vector<vector<pair<double, IPowderDiffPeakFunction_sptr>>> &peakgroupvec,
700 vector<IPowderDiffPeakFunction_sptr> &outboundpeakvec,
double xmin,
double xmax) {
705 std::stringstream errmsg;
706 errmsg <<
"Group peaks: No peak is found in the peak vector. ";
708 throw std::runtime_error(errmsg.str());
712 peakgroupvec.clear();
713 outboundpeakvec.clear();
714 vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroup;
718 bool outbound =
true;
722 if (peak->centre() <= xmin) {
724 outboundpeakvec.emplace_back(peak);
737 if (thispeak->centre() < xmax) {
749 double thispeak_rightbound = thispeak->centre() + PEAKRANGECONSTANT * thispeak->fwhm();
750 double rightpeak_leftbound = rightpeak->centre() - PEAKRANGECONSTANT * rightpeak->fwhm();
752 if (thispeak_rightbound < rightpeak_leftbound) {
755 peakgroupvec.emplace_back(std::move(peakgroup));
764 peakgroupvec.emplace_back(peakgroup);
772 g_log.
information() <<
"[Fx301] Group peak: peak @ " << thispeak->centre() <<
" causes grouping "
773 <<
"peak over at maximum TOF = " << xmax <<
".\n";
775 if (!peakgroup.empty()) {
776 peakgroupvec.emplace_back(peakgroup);
787 g_log.
debug() <<
"[Calculate Peak Intensity]: Number of Peak Groups = " << peakgroupvec.size() <<
"\n";
801void LeBailFunction::addBackgroundFunction(
const string &backgroundtype,
const unsigned int &order,
802 const std::vector<std::string> &vecparnames,
803 const std::vector<double> &vecparvalues,
double startx,
double endx) {
805 if (backgroundtype != POLYNOMIAL_BACKGROUND && backgroundtype != CHEBYSHEV_BACKGROUND &&
806 backgroundtype != FULLPROF_POLYNOMIAL_BACKGROUND) {
808 warnss <<
"Cliet specified background type " << backgroundtype <<
" may not be supported properly.";
811 if (vecparnames.size() != vecparvalues.size())
812 throw runtime_error(
"Input parameter names and parameter values are not matched. ");
814 g_log.
information() <<
"Add background: type = " << backgroundtype <<
", order = " << order
815 <<
", number of parameters/attributes = " << vecparnames.size() <<
"\n";
818 auto background = FunctionFactory::Instance().createFunction(backgroundtype);
819 m_background = std::dynamic_pointer_cast<Functions::BackgroundFunction>(background);
822 m_background->setAttributeValue(
"n",
static_cast<int>(order));
826 size_t numpars = vecparnames.size();
827 for (
size_t i = 0; i < numpars; ++i) {
828 const string &parname = vecparnames[i];
829 if (parname !=
"Bkpos")
831 else if (backgroundtype == FULLPROF_POLYNOMIAL_BACKGROUND)
832 m_background->setAttributeValue(
"Bkpos", vecparvalues[i]);
834 throw runtime_error(
"Bkpos should not be in the parameter list. ");
837 if (backgroundtype == CHEBYSHEV_BACKGROUND) {
Implements FunctionDomain1D with its own storage in form of a std::vector.