104HistogramY LeBailFunction::function(
const Mantid::HistogramData::HistogramX &xvalues,
bool calpeaks,
105 bool calbkgd)
const {
108 std::vector<double> out(xvalues.size(), 0);
112 for (
size_t ipk = 0; ipk <
m_numPeaks; ++ipk) {
114 vector<double> temp(xvalues.size(), 0);
116 peak->function(temp, xvalues);
117 transform(out.begin(), out.end(), temp.begin(), out.begin(), ::plus<double>());
124 throw runtime_error(
"Must define background first!");
131 size_t numpts = out.size();
132 for (
size_t i = 0; i < numpts; ++i)
136 return HistogramY(out);
323bool LeBailFunction::calculatePeaksIntensities(std::span<double const>
const vecX, std::span<double const>
const vecY,
324 vector<double> &vec_summedpeaks) {
326 std::fill(vec_summedpeaks.begin(), vec_summedpeaks.end(), 0.0);
329 vector<vector<pair<double, IPowderDiffPeakFunction_sptr>>> peakgroupvec;
330 vector<IPowderDiffPeakFunction_sptr> outboundpeakvec;
331 double xmin = vecX.front();
332 double xmax = vecX.back();
333 groupPeaks(peakgroupvec, outboundpeakvec, xmin, xmax);
336 bool allpeakheightsphysical =
true;
337 for (
size_t ig = 0; ig < peakgroupvec.size(); ++ig) {
338 g_log.
debug() <<
"[Fx351] Calculate peaks heights for (peak) group " << ig
339 <<
" : number of peaks = " << peakgroupvec[ig].size() <<
"\n";
343 if (!peakheightsphysical)
344 allpeakheightsphysical =
false;
348 for (
const auto &peak : outboundpeakvec) {
352 return allpeakheightsphysical;
366bool LeBailFunction::calculateGroupPeakIntensities(vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroup,
367 std::span<double const>
const vecX,
368 std::span<double const>
const 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 auto cviter = lower_bound(vecX.begin(), vecX.end(), leftbound);
420 size_t ileft =
static_cast<size_t>(cviter - vecX.begin());
424 cviter = lower_bound(vecX.begin(), vecX.end(), rightbound);
425 size_t iright =
static_cast<size_t>(cviter - vecX.begin());
426 if (iright <= vecX.size() - 1)
429 size_t ndata = iright - ileft;
430 if (ileft >= iright) {
432 errss <<
"[Calcualte Peak Intensity] Group range is unphysical. iLeft = " << ileft <<
", iRight = " << iright
433 <<
"; Number of peaks = " << peakgroup.size() <<
"; Left boundary = " << leftbound
434 <<
", Right boundary = " << rightbound <<
"; Left peak FWHM = " << leftpeak->fwhm()
435 <<
", Right peak FWHM = " << rightpeak->fwhm();
436 for (
size_t ipk = 0; ipk < peakgroup.size(); ++ipk) {
438 errss <<
"Peak " << ipk <<
": d_h = " << peakgroup[ipk].first <<
", TOF_h = " << thispeak->centre()
439 <<
", FWHM = " << thispeak->fwhm() <<
"\n";
440 vector<string> peakparamnames = thispeak->getParameterNames();
441 for (
auto &peakparamname : peakparamnames) {
442 errss <<
"\t" << peakparamname <<
" = " << thispeak->getParameter(peakparamname) <<
"\n";
447 throw runtime_error(errss.str());
451 vector<double> datax(vecX.begin() + ileft, vecX.begin() + iright);
452 vector<double> datay(vecY.begin() + ileft, vecY.begin() + iright);
453 if (datax.size() != ndata) {
455 errmsg <<
"Impossible: Partial peak data size = " << datax.size() <<
" != ndata = " << ndata;
457 throw runtime_error(errmsg.str());
459 g_log.
debug() <<
"[DBx356] Number of data points = " << ndata <<
" index from " << ileft <<
" to " << iright
460 <<
"; Size(datax, datay) = " << datax.size() <<
"\n";
463 vector<double> sumYs(ndata, 0.0);
464 size_t numPeaks(peakgroup.size());
465 vector<vector<double>> peakvalues(numPeaks);
468 bool datavalueinvalid =
false;
469 for (
size_t ipk = 0; ipk < numPeaks; ++ipk) {
473 peak->setHeight(1.0);
474 vector<double> localpeakvalue(ndata, 0.0);
475 peak->function(localpeakvalue, datax);
478 const auto numbadpts = std::count_if(localpeakvalue.cbegin(), localpeakvalue.cend(), [&](
const auto &pt) {
479 return (pt != 0.) && (pt < NEG_DBL_MAX || pt > DBL_MAX);
483 if (numbadpts == 0) {
485 for (
size_t i = 0; i < ndata; ++i) {
487 sumYs[i] += localpeakvalue[i];
492 peak->getMillerIndex(h, k, l);
494 warnss <<
"Peak (" << h <<
", " << k <<
", " << l <<
") @ TOF = " << peak->centre() <<
" has " << numbadpts
496 <<
"whose values exceed limit (i.e., not physical). ";
498 datavalueinvalid =
true;
500 peakvalues[ipk].assign(localpeakvalue.begin(), localpeakvalue.end());
504 bool peakheightsphysical = !datavalueinvalid;
505 if (peakheightsphysical) {
506 for (
size_t ipk = 0; ipk < peakgroup.size(); ++ipk) {
510 for (
size_t i = 0; i < ndata; ++i) {
512 if (sumYs[i] > 1.0E-5) {
514 double peaktogroupratio = peakvalues[ipk][i] / sumYs[i];
515 temp = datay[i] * peaktogroupratio;
522 deltax = datax[1] - datax[0];
524 deltax = datax[i] - datax[i - 1];
532 peakheightsphysical =
false;
535 peak->getMillerIndex(h, k, l);
536 g_log.
warning() <<
"Peak (" << h <<
", " << k <<
", " << l <<
") has unphysical intensity = NaN!\n";
538 }
else if (intensity <= -DBL_MAX || intensity >= DBL_MAX) {
541 peakheightsphysical =
false;
544 peak->getMillerIndex(h, k, l);
545 g_log.
warning() <<
"Peak (" << h <<
", " << k <<
", " << l <<
") has unphysical intensity = Infty!\n";
548 g_log.
debug() <<
"[Fx134] Set peak @ " << peak->centre() <<
"'s intensity to 0.0 instead of " <<
intensity
552 g_log.
debug() <<
"[Fx407] Peak @ " << peak->centre() <<
": Set Intensity = " <<
intensity <<
"\n";
556 for (
size_t i = ileft; i < iright; ++i) {
557 vec_summedpeaks[i] += (
intensity * peakvalues[ipk][i - ileft]);
563 return peakheightsphysical;
635void LeBailFunction::setProfileParameterValues(map<std::string, double> parammap) {
636 const double MINDIFF = 1.0E-10;
638 map<std::string, double>::iterator inpiter, curiter;
641 for (
size_t i = 0; i < numpars; ++i) {
645 inpiter = parammap.find(parname);
646 if (inpiter != parammap.end()) {
652 errmsg <<
"Parameter " << parname <<
" is in parameter name list, but not in profile "
653 <<
"parameter map. It violates the programming logic.";
655 throw runtime_error(errmsg.str());
659 double curvalue = curiter->second;
660 double newvalue = inpiter->second;
661 bool localnewvalue =
false;
662 if (
fabs(curvalue - newvalue) > MINDIFF) {
663 curiter->second = newvalue;
665 localnewvalue =
true;
673 for (
size_t ipk = 0; ipk <
m_numPeaks; ++ipk) {
675 peak->setParameter(i, newvalue);
679 g_log.
debug() <<
"Parameter " << parname <<
" is not a profile parameter. Length of string = " << parname.size()
697void LeBailFunction::groupPeaks(vector<vector<pair<double, IPowderDiffPeakFunction_sptr>>> &peakgroupvec,
698 vector<IPowderDiffPeakFunction_sptr> &outboundpeakvec,
double xmin,
double xmax) {
703 std::stringstream errmsg;
704 errmsg <<
"Group peaks: No peak is found in the peak vector. ";
706 throw std::runtime_error(errmsg.str());
710 peakgroupvec.clear();
711 outboundpeakvec.clear();
712 vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroup;
716 bool outbound =
true;
720 if (peak->centre() <= xmin) {
722 outboundpeakvec.emplace_back(peak);
735 if (thispeak->centre() < xmax) {
747 double thispeak_rightbound = thispeak->centre() + PEAKRANGECONSTANT * thispeak->fwhm();
748 double rightpeak_leftbound = rightpeak->centre() - PEAKRANGECONSTANT * rightpeak->fwhm();
750 if (thispeak_rightbound < rightpeak_leftbound) {
753 peakgroupvec.emplace_back(std::move(peakgroup));
762 peakgroupvec.emplace_back(peakgroup);
770 g_log.
information() <<
"[Fx301] Group peak: peak @ " << thispeak->centre() <<
" causes grouping "
771 <<
"peak over at maximum TOF = " << xmax <<
".\n";
773 if (!peakgroup.empty()) {
774 peakgroupvec.emplace_back(peakgroup);
785 g_log.
debug() <<
"[Calculate Peak Intensity]: Number of Peak Groups = " << peakgroupvec.size() <<
"\n";
799void LeBailFunction::addBackgroundFunction(
const string &backgroundtype,
const unsigned int &order,
800 const std::vector<std::string> &vecparnames,
801 const std::vector<double> &vecparvalues,
double startx,
double endx) {
803 if (backgroundtype != POLYNOMIAL_BACKGROUND && backgroundtype != CHEBYSHEV_BACKGROUND &&
804 backgroundtype != FULLPROF_POLYNOMIAL_BACKGROUND) {
806 warnss <<
"Cliet specified background type " << backgroundtype <<
" may not be supported properly.";
809 if (vecparnames.size() != vecparvalues.size())
810 throw runtime_error(
"Input parameter names and parameter values are not matched. ");
812 g_log.
information() <<
"Add background: type = " << backgroundtype <<
", order = " << order
813 <<
", number of parameters/attributes = " << vecparnames.size() <<
"\n";
816 auto background = FunctionFactory::Instance().createFunction(backgroundtype);
820 m_background->setAttributeValue(
"n",
static_cast<int>(order));
824 size_t numpars = vecparnames.size();
825 for (
size_t i = 0; i < numpars; ++i) {
826 const string &parname = vecparnames[i];
827 if (parname !=
"Bkpos")
829 else if (backgroundtype == FULLPROF_POLYNOMIAL_BACKGROUND)
830 m_background->setAttributeValue(
"Bkpos", vecparvalues[i]);
832 throw runtime_error(
"Bkpos should not be in the parameter list. ");
835 if (backgroundtype == CHEBYSHEV_BACKGROUND) {
Implements FunctionDomain1D with its own storage in form of a std::vector.