Mantid
Loading...
Searching...
No Matches
LeBailFunction.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
12#include "MantidHistogramData/HistogramX.h"
13
14#include "MantidHistogramData/HistogramY.h"
15
16#include <sstream>
17#include <utility>
18
19#include <gsl/gsl_sf_erf.h>
20
21using namespace Mantid::API;
22using namespace Mantid::Kernel;
23using Mantid::HistogramData::HistogramY;
24
25using namespace std;
26
27const double NEG_DBL_MAX(-1. * DBL_MAX);
28
30namespace {
31const double PEAKRANGECONSTANT = 5.0;
32
33const string CHEBYSHEV_BACKGROUND("Chebyshev");
34const string POLYNOMIAL_BACKGROUND("Polynomial");
35const string FULLPROF_POLYNOMIAL_BACKGROUND("FullprofPolynomial");
36} // namespace
37
38// Get a reference to the logger
39Kernel::Logger g_log("LeBailFunction");
40
41//----------------------------------------------------------------------------------------------
44LeBailFunction::LeBailFunction(const std::string &peaktype) {
45 // Set initial values to some class variables
47 m_compsiteFunction = m_function;
48
49 m_numPeaks = 0;
50
51 m_isInputValue = false;
52 m_hasNewPeakValue = false;
53
54 // Peak type, validate and parameter name vectors
55 m_peakType = peaktype;
56 IFunction_sptr ifunc = FunctionFactory::Instance().createFunction(m_peakType);
57 if (!ifunc) {
58 stringstream errss;
59 errss << "Input peak type " << peaktype << " is not a recoganizable Mantid function.";
60 throw runtime_error(errss.str());
61 }
62 IPowderDiffPeakFunction_sptr peakfunc = std::dynamic_pointer_cast<IPowderDiffPeakFunction>(ifunc);
63 if (!peakfunc) {
64 stringstream errss;
65 errss << "Input peak type " << peaktype << " is not a IPowderDiffPeakFunction.";
66 throw runtime_error(errss.str());
67 }
68
69 m_peakParameterNameVec = peakfunc->getParameterNames();
72
73 // Peak parameter values
74 for (auto parname : m_peakParameterNameVec) {
75 m_functionParameters.emplace(parname, 0.0);
76 }
77
78 // Importing peak position tolerance
80 m_maxTOFPeakCentre = DBL_MAX;
81}
82
83//----------------------------------------------------------------------------------------------
86LeBailFunction::~LeBailFunction() = default;
87
88//----------------------------------------------------------------------------------------------
91API::IFunction_sptr LeBailFunction::getFunction() {
92 return m_compsiteFunction;
93 // return std::dynamic_pointer_cast<IFunction_sptr>(m_compsiteFunction);
94}
95
96//----------------------------------------------------------------------------------------------
104HistogramY LeBailFunction::function(const Mantid::HistogramData::HistogramX &xvalues, bool calpeaks,
105 bool calbkgd) const {
106
107 // Reset output elements to zero
108 std::vector<double> out(xvalues.size(), 0);
109 const auto &xvals = xvalues.rawData();
110
111 // Peaks
112 if (calpeaks) {
113 for (size_t ipk = 0; ipk < m_numPeaks; ++ipk) {
114 // Reset temporary vector for output
115 vector<double> temp(xvalues.size(), 0);
117 peak->function(temp, xvals);
118 transform(out.begin(), out.end(), temp.begin(), out.begin(), ::plus<double>());
119 }
120 }
121
122 // Background if required
123 if (calbkgd) {
124 if (!m_background) {
125 throw runtime_error("Must define background first!");
126 }
127
128 FunctionDomain1DVector domain(xvals);
129 FunctionValues values(domain);
130 g_log.information() << "Background function (in LeBailFunction): " << m_background->asString() << ".\n";
131 m_background->function(domain, values);
132 size_t numpts = out.size();
133 for (size_t i = 0; i < numpts; ++i)
134 out[i] += values[i];
135 }
136
137 return HistogramY(out);
138}
139
142HistogramY LeBailFunction::calPeak(size_t ipk, const std::vector<double> &xvalues, size_t ySize) const {
143
144 if (ipk >= m_numPeaks) {
145 stringstream errss;
146 errss << "Try to calculate peak indexed " << ipk << ". But number of peaks = " << m_numPeaks;
147 g_log.error(errss.str());
148 throw runtime_error(errss.str());
149 }
150
151 std::vector<double> out(ySize, 0);
153 peak->function(out, xvalues);
154 return HistogramY(out);
155}
156
157//----------------------------------------------------------------------------------------------
161bool LeBailFunction::hasProfileParameter(const std::string &paramname) {
162 auto fiter = lower_bound(m_orderedProfileParameterNames.cbegin(), m_orderedProfileParameterNames.cend(), paramname);
163
164 bool found = true;
165 if (fiter == m_orderedProfileParameterNames.end()) {
166 // End of the vector
167 found = false;
168 } else {
169 // Middle of vector
170 string matchparname = *fiter;
171 if (matchparname != paramname)
172 found = false;
173 }
174
175 return found;
176}
177
178//----------------------------------------------------------------------------------------------
183bool LeBailFunction::isParameterValid(double maxfwhm) const {
184 // Re-calculate peak parameter if there is some modification
185 if (m_hasNewPeakValue) {
187 }
188
189 // Check whether each peak has valid value
190 bool arevalid = true;
191 for (size_t i = 0; i < m_numPeaks; ++i) {
193 bool isvalid = peak->isPhysical();
194 if (isvalid && maxfwhm >= 0)
195 isvalid = peak->fwhm() < maxfwhm;
196 if (!isvalid) {
197 arevalid = false;
198
199 int h, k, l;
200 peak->getMillerIndex(h, k, l);
201 g_log.information() << "Peak [" << h << ", " << k << ", " << l << "] @ TOF = " << peak->centre()
202 << " has unphysical parameters or unreasonable large FWHM"
203 << ".\n";
204 break;
205 }
206 }
207
208 return arevalid;
209}
210
211//----------------------------------------------------------------------------------------------
214void LeBailFunction::calculatePeakParameterValues() const {
215 for (size_t i = 0; i < m_numPeaks; ++i) {
217 peak->calculateParameters(false);
218 }
219
220 m_hasNewPeakValue = false;
221}
222
223//----------------------------------------------------------------------------------------------
229void LeBailFunction::setPeakCentreTolerance(double peakpostol, double tofmin, double tofmax) {
230 // m_usePeakPosTol = true;
231 m_minTOFPeakCentre = tofmin - peakpostol;
232 m_maxTOFPeakCentre = tofmax + peakpostol;
233}
234
235//----------------------------------------------------------------------------------------------
239void LeBailFunction::addPeaks(const std::vector<std::vector<int>> &peakhkls) {
240 // Prerequisit
241 if (!m_isInputValue)
242 throw runtime_error("Client must set up profile parameter vlaues by calling "
243 "setProfileParameterValues() first! ");
244
245 // Add peaks
246 for (size_t ipk = 0; ipk < peakhkls.size(); ++ipk) {
247 vector<int> hkl = peakhkls[ipk];
248
249 // Check input Miller Index
250 if (hkl.size() != 3) {
251 stringstream errss;
252 errss << "Error of " << ipk << "-th input Miller Index. It has " << peakhkls[ipk].size()
253 << " items, but not required 3 items.";
254 g_log.error(errss.str());
255 throw runtime_error(errss.str());
256 }
257
258 // Generate new peak
259 int h = hkl[0];
260 int k = hkl[1];
261 int l = hkl[2];
263 if (!newpeak) {
264 g_log.error("Unable to generate peak. ");
265 throw runtime_error("Unable to generate peak.");
266 }
267
268 double tofh = newpeak->centre();
269 if (tofh < m_minTOFPeakCentre || tofh > m_maxTOFPeakCentre) {
270 g_log.information() << "Peak " << h << ", " << k << ", " << l << " 's centre is at TOF = " << tofh
271 << ", which is out of user specified boundary (" << m_minTOFPeakCentre << ", "
272 << m_maxTOFPeakCentre << "). "
273 << ".\n";
274 } else {
275 double dsp = newpeak->getPeakParameter("d_h");
276
277 // Add new peak to all related data storage
278 m_vecPeaks.emplace_back(newpeak);
279 // FIXME - Refining lattice size is not considered here!
280 m_dspPeakVec.emplace_back(dsp, newpeak);
281 m_mapHKLPeak.emplace(hkl, newpeak);
282 }
283 }
284
285 m_numPeaks = m_vecPeaks.size();
286
287 g_log.information() << "Total " << m_numPeaks << " after trying to add " << peakhkls.size() << " peaks. \n";
288} // END of addPeaks()
289
290//----------------------------------------------------------------------------------------------
296IPowderDiffPeakFunction_sptr LeBailFunction::generatePeak(int h, int k, int l) {
297 IFunction_sptr f = FunctionFactory::Instance().createFunction(m_peakType);
298 IPowderDiffPeakFunction_sptr peak = std::dynamic_pointer_cast<IPowderDiffPeakFunction>(f);
299
300 peak->setMillerIndex(h, k, l);
301 for (const auto &parname : m_peakParameterNameVec) {
302 double parvalue = m_functionParameters[parname];
303 peak->setParameter(parname, parvalue);
304 }
305
306 return peak;
307}
308
309//----------------------------------------------------------------------------------------------
324bool LeBailFunction::calculatePeaksIntensities(const vector<double> &vecX, const vector<double> &vecY,
325 vector<double> &vec_summedpeaks) {
326 // Clear inputs
327 std::fill(vec_summedpeaks.begin(), vec_summedpeaks.end(), 0.0);
328
329 // Divide peaks into groups from peak's parameters
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);
335
336 // Calculate each peak's intensity and set
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";
341
342 bool peakheightsphysical = calculateGroupPeakIntensities(peakgroupvec[ig], vecX, vecY, vec_summedpeaks);
343
344 if (!peakheightsphysical)
345 allpeakheightsphysical = false;
346 }
347
348 // Set zero to all peaks out of boundary
349 for (const auto &peak : outboundpeakvec) {
350 peak->setHeight(0.);
351 }
352
353 return allpeakheightsphysical;
354}
355
356//----------------------------------------------------------------------------------------------
367bool LeBailFunction::calculateGroupPeakIntensities(vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroup,
368 const vector<double> &vecX, const vector<double> &vecY,
369 vector<double> &vec_summedpeaks) {
370 // Check input peaks group and sort peak by d-spacing
371 if (peakgroup.empty()) {
372 throw runtime_error("Programming error such that input peak group cannot be empty!");
373 } else {
374 g_log.debug() << "[Fx155] Peaks group size = " << peakgroup.size() << "\n";
375 }
376 if (peakgroup.size() > 1)
377 sort(peakgroup.begin(), peakgroup.end());
378
379 // Check input vector validity
380 if (vec_summedpeaks.size() != vecY.size()) {
381 stringstream errss;
382 errss << "Input vector 'allpeaksvalues' has wrong size = " << vec_summedpeaks.size()
383 << " != data workspace Y's size = " << vecY.size();
384 g_log.error(errss.str());
385 throw runtime_error(errss.str());
386 }
387
388 // Check boundary
389 IPowderDiffPeakFunction_sptr leftpeak = peakgroup[0].second;
390 double leftbound = leftpeak->centre() - PEAKRANGECONSTANT * leftpeak->fwhm();
391 if (leftbound < vecX.front()) {
392 stringstream msg;
393 int h, k, l;
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() << ". ";
400
401 g_log.information(msg.str());
402
403 leftbound = vecX[0] + 0.1;
404 }
405 IPowderDiffPeakFunction_sptr rightpeak = peakgroup.back().second;
406 double rightbound = rightpeak->centre() + PEAKRANGECONSTANT * rightpeak->fwhm();
407 if (rightbound > vecX.back()) {
408 stringstream msg;
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. ";
412
413 g_log.information(msg.str());
414
415 rightbound = vecX.back() - 0.1;
416 }
417
418 // Determine calculation range to input workspace: [ileft, iright)
419 vector<double>::const_iterator cviter;
420
421 cviter = lower_bound(vecX.begin(), vecX.end(), leftbound);
422 size_t ileft = static_cast<size_t>(cviter - vecX.begin());
423 if (ileft > 0)
424 --ileft;
425
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)
429 ++iright;
430
431 size_t ndata = iright - ileft;
432 if (ileft >= iright) {
433 stringstream errss;
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) {
439 IPowderDiffPeakFunction_sptr thispeak = peakgroup[ipk].second;
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";
445 }
446 }
447
448 g_log.error(errss.str());
449 throw runtime_error(errss.str());
450 }
451
452 // Generate a subset of vecX and vecY to calculate peak intensities
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) {
456 stringstream errmsg;
457 errmsg << "Impossible: Partial peak data size = " << datax.size() << " != ndata = " << ndata;
458 g_log.error(errmsg.str());
459 throw runtime_error(errmsg.str());
460 }
461 g_log.debug() << "[DBx356] Number of data points = " << ndata << " index from " << ileft << " to " << iright
462 << "; Size(datax, datay) = " << datax.size() << "\n";
463
464 // Prepare to integrate dataY to calculate peak intensity
465 vector<double> sumYs(ndata, 0.0);
466 size_t numPeaks(peakgroup.size());
467 vector<vector<double>> peakvalues(numPeaks);
468
469 // Integrage peak by peak
470 bool datavalueinvalid = false;
471 for (size_t ipk = 0; ipk < numPeaks; ++ipk) {
472 // calculate peak function value. Peak height should be set to a non-zero
473 // value
474 IPowderDiffPeakFunction_sptr peak = peakgroup[ipk].second;
475 peak->setHeight(1.0);
476 vector<double> localpeakvalue(ndata, 0.0);
477 peak->function(localpeakvalue, datax);
478
479 // check data
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);
482 });
483
484 // report the problem and/or integrate data
485 if (numbadpts == 0) {
486 // Data is fine. Integrate them all
487 for (size_t i = 0; i < ndata; ++i) {
488 // If value is physical
489 sumYs[i] += localpeakvalue[i];
490 }
491 } else {
492 // Report the problem
493 int h, k, l;
494 peak->getMillerIndex(h, k, l);
495 stringstream warnss;
496 warnss << "Peak (" << h << ", " << k << ", " << l << ") @ TOF = " << peak->centre() << " has " << numbadpts
497 << " data points, "
498 << "whose values exceed limit (i.e., not physical). ";
499 g_log.debug(warnss.str());
500 datavalueinvalid = true;
501 }
502 peakvalues[ipk].assign(localpeakvalue.begin(), localpeakvalue.end());
503 } // For All peaks
504
505 // Calculate intensity of all peaks
506 bool peakheightsphysical = !datavalueinvalid;
507 if (peakheightsphysical) {
508 for (size_t ipk = 0; ipk < peakgroup.size(); ++ipk) {
509 IPowderDiffPeakFunction_sptr peak = peakgroup[ipk].second;
510 double intensity = 0.0;
511
512 for (size_t i = 0; i < ndata; ++i) {
513 double temp;
514 if (sumYs[i] > 1.0E-5) {
515 // Reasonable non-zero value
516 double peaktogroupratio = peakvalues[ipk][i] / sumYs[i];
517 temp = datay[i] * peaktogroupratio;
518 } else {
519 // SumY too smaller
520 temp = 0.0;
521 }
522 double deltax;
523 if (i == 0)
524 deltax = datax[1] - datax[0];
525 else
526 deltax = datax[i] - datax[i - 1];
527
528 intensity += temp * deltax;
529 } // for data points
530
531 if (intensity != intensity) {
532 // Unphysical intensity: NaN
533 intensity = 0.0;
534 peakheightsphysical = false;
535
536 int h, k, l;
537 peak->getMillerIndex(h, k, l);
538 g_log.warning() << "Peak (" << h << ", " << k << ", " << l << ") has unphysical intensity = NaN!\n";
539
540 } else if (intensity <= -DBL_MAX || intensity >= DBL_MAX) {
541 // Unphysical intensity: NaN
542 intensity = 0.0;
543 peakheightsphysical = false;
544
545 int h, k, l;
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) {
549 // No negative intensity
550 g_log.debug() << "[Fx134] Set peak @ " << peak->centre() << "'s intensity to 0.0 instead of " << intensity
551 << ".\n";
552 intensity = 0.0;
553 }
554 g_log.debug() << "[Fx407] Peak @ " << peak->centre() << ": Set Intensity = " << intensity << "\n";
555 peak->setHeight(intensity);
556
557 // Add peak's value to peaksvalues
558 for (size_t i = ileft; i < iright; ++i) {
559 vec_summedpeaks[i] += (intensity * peakvalues[ipk][i - ileft]);
560 }
561
562 } // ENDFOR each peak
563 }
564
565 return peakheightsphysical;
566}
567
568//----------------------------------------------------------------------------------------------
577void LeBailFunction::setPeakParameters(const IPowderDiffPeakFunction_sptr &peak, const map<string, double> &parammap,
578 double peakheight, bool setpeakheight) {
579 UNUSED_ARG(peak);
580 UNUSED_ARG(parammap);
581 UNUSED_ARG(peakheight);
582 UNUSED_ARG(setpeakheight);
583 throw runtime_error("Requiring update flag: peak value changed and etc.");
584 /*
585 // FIXME - The best solution for speeding is to have a set of peak
586 parameter listed in the order
587 // of peak function's parameters' indexed. Then no need to do
588 search anymore.
589
590 // 1. Prepare, sort parameters by name
591 std::map<std::string, double>::iterator pit;
592 vector<string> peakparamnames = peak->getParameterNames();
593
594 // 2. Apply parameters values to peak function
595 for (pit = parammap.begin(); pit != parammap.end(); ++pit)
596 {
597 // a) Check whether the parameter is a peak parameter
598 std::string parname = pit->first;
599 std::vector<std::string>::iterator ifind =
600 std::find(peakparamnames.begin(), peakparamnames.end(), parname);
601
602 // b) Set parameter value
603 if (ifind == peakparamnames.end())
604 {
605 // If not a peak profile parameter, skip
606 g_log.debug() << "Parameter '" << parname << "' in input parameter
607 table workspace "
608 << "is not for peak function " << peak->name() << ".\n";
609 }
610 else
611 {
612 // Set value
613 double value = pit->second;
614 peak->setParameter(parname, value);
615 g_log.debug() << "LeBailFit Set " << parname << "= " << value << "\n";
616 }
617 } // ENDFOR: parameter iterator
618
619 // 3. Peak height
620 if (setpeakheight)
621 peak->setHeight(peakheight);
622
623 return;*/
624}
625
626//----------------------------------------------------------------------------------------------
637void LeBailFunction::setProfileParameterValues(map<std::string, double> parammap) {
638 const double MINDIFF = 1.0E-10;
639
640 map<std::string, double>::iterator inpiter, curiter;
641
642 size_t numpars = m_peakParameterNameVec.size();
643 for (size_t i = 0; i < numpars; ++i) {
644 string &parname = m_peakParameterNameVec[i];
645
646 // Find iterator of this parameter in input parammap
647 inpiter = parammap.find(parname);
648 if (inpiter != parammap.end()) {
649 // Find iterator to parameter value in class' parameter map (parameter is
650 // found in input map)
651 curiter = m_functionParameters.find(parname);
652 if (curiter == m_functionParameters.end()) {
653 stringstream errmsg;
654 errmsg << "Parameter " << parname << " is in parameter name list, but not in profile "
655 << "parameter map. It violates the programming logic.";
656 g_log.error(errmsg.str());
657 throw runtime_error(errmsg.str());
658 }
659
660 // Set value if difference is large
661 double curvalue = curiter->second;
662 double newvalue = inpiter->second;
663 bool localnewvalue = false;
664 if (fabs(curvalue - newvalue) > MINDIFF) {
665 curiter->second = newvalue;
666 m_hasNewPeakValue = true;
667 localnewvalue = true;
668 }
669
670 // Set new value to each peak
671 if (!localnewvalue)
672 continue;
673
674 // Set new parameter to each peak
675 for (size_t ipk = 0; ipk < m_numPeaks; ++ipk) {
677 peak->setParameter(i, newvalue);
678 }
679 } // If parameter name is a profile parameter
680 else {
681 g_log.debug() << "Parameter " << parname << " is not a profile parameter. Length of string = " << parname.size()
682 << "\n";
683 }
684 } // ENDFOR [All profile parameter]
685
686 // Set the flag to indicate that client has input parameters
688 m_isInputValue = true;
689}
690
691//----------------------------------------------------------------------------------------------
699void LeBailFunction::groupPeaks(vector<vector<pair<double, IPowderDiffPeakFunction_sptr>>> &peakgroupvec,
700 vector<IPowderDiffPeakFunction_sptr> &outboundpeakvec, double xmin, double xmax) {
701 // Sort peaks
702 if (m_numPeaks > 1) {
703 sort(m_dspPeakVec.begin(), m_dspPeakVec.end());
704 } else if (m_numPeaks == 0) {
705 std::stringstream errmsg;
706 errmsg << "Group peaks: No peak is found in the peak vector. ";
707 g_log.error() << errmsg.str() << "\n";
708 throw std::runtime_error(errmsg.str());
709 }
710
711 // Set up starting value
712 peakgroupvec.clear();
713 outboundpeakvec.clear();
714 vector<pair<double, IPowderDiffPeakFunction_sptr>> peakgroup; // one group of peaks
715 size_t ipk = 0;
716
717 // Group peaks from low-d to high-d
718 bool outbound = true;
719 while (outbound && ipk < m_numPeaks) {
720 // Group peaks out of lower boundary to a separate vector of peaks
722 if (peak->centre() <= xmin) {
723 // Add peak
724 outboundpeakvec.emplace_back(peak);
725 ipk += 1;
726 } else {
727 // Get out of while loop if peak is in bound
728 outbound = false;
729 }
730 }
731
732 bool inbound = true;
733 while (inbound && ipk < m_numPeaks) {
734 // Group peaks in the boundary
735 IPowderDiffPeakFunction_sptr thispeak = m_dspPeakVec[ipk].second;
736
737 if (thispeak->centre() < xmax) {
738 // Peak is in the boundary still
739
740 // add peak to CURRENT peak group
741 peakgroup.emplace_back(m_dspPeakVec[ipk]);
742
743 if (ipk < m_numPeaks - 1) {
744 // Any peak but not the last (rightmost) peak
745
746 // test whether next peak will be in a different group
747 IPowderDiffPeakFunction_sptr rightpeak = m_dspPeakVec[ipk + 1].second;
748
749 double thispeak_rightbound = thispeak->centre() + PEAKRANGECONSTANT * thispeak->fwhm();
750 double rightpeak_leftbound = rightpeak->centre() - PEAKRANGECONSTANT * rightpeak->fwhm();
751
752 if (thispeak_rightbound < rightpeak_leftbound) {
753 // this peak and its right peak are well separated.
754 // finish this group by swapping values
755 peakgroupvec.emplace_back(std::move(peakgroup));
756 peakgroup = {};
757 } else {
758 // this peak and its right peak are close enough to be in same group.
759 // do nothing
760 ;
761 }
762 } else {
763 // Rightmost peak. Finish the current peak
764 peakgroupvec.emplace_back(peakgroup);
765 }
766
767 ++ipk;
768 } // still in bound
769 else {
770 // Peak is get out of boundary
771 inbound = false;
772 g_log.information() << "[Fx301] Group peak: peak @ " << thispeak->centre() << " causes grouping "
773 << "peak over at maximum TOF = " << xmax << ".\n";
774
775 if (!peakgroup.empty()) {
776 peakgroupvec.emplace_back(peakgroup);
777 }
778 } // FIRST out of boundary
779 } // ENDWHILE
780
781 while (ipk < m_numPeaks) {
782 // Group peaks out of uppper boundary to a separate vector of peaks
783 outboundpeakvec.emplace_back(m_dspPeakVec[ipk].second);
784 ipk += 1;
785 }
786
787 g_log.debug() << "[Calculate Peak Intensity]: Number of Peak Groups = " << peakgroupvec.size() << "\n";
788}
789
790//----------------------------------------------------------------------------------------------
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) {
804 // Check
805 if (backgroundtype != POLYNOMIAL_BACKGROUND && backgroundtype != CHEBYSHEV_BACKGROUND &&
806 backgroundtype != FULLPROF_POLYNOMIAL_BACKGROUND) {
807 stringstream warnss;
808 warnss << "Cliet specified background type " << backgroundtype << " may not be supported properly.";
809 g_log.warning(warnss.str());
810 }
811 if (vecparnames.size() != vecparvalues.size())
812 throw runtime_error("Input parameter names and parameter values are not matched. ");
813
814 g_log.information() << "Add background: type = " << backgroundtype << ", order = " << order
815 << ", number of parameters/attributes = " << vecparnames.size() << "\n";
816
817 // Create background function from factory
818 auto background = FunctionFactory::Instance().createFunction(backgroundtype);
819 m_background = std::dynamic_pointer_cast<Functions::BackgroundFunction>(background);
820
821 // Set order and initialize
822 m_background->setAttributeValue("n", static_cast<int>(order));
823 m_background->initialize();
824
825 // Set parameters & attribute
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")
830 m_background->setParameter(parname, vecparvalues[i]);
831 else if (backgroundtype == FULLPROF_POLYNOMIAL_BACKGROUND)
832 m_background->setAttributeValue("Bkpos", vecparvalues[i]);
833 else
834 throw runtime_error("Bkpos should not be in the parameter list. ");
835 }
836
837 if (backgroundtype == CHEBYSHEV_BACKGROUND) {
838 if (startx > 0.)
839 m_background->setAttributeValue("StartX", startx);
840 if (endx > 0.)
841 m_background->setAttributeValue("EndX", endx);
842 }
843}
844
845//----------------------------------------------------------------------------------------------
851void LeBailFunction::setFitProfileParameter(const string &paramname, double minvalue, double maxvalue) {
852 // Make ties in composition function
853 for (size_t ipk = 1; ipk < m_numPeaks; ++ipk) {
854 stringstream ss1, ss2;
855 ss1 << "f" << (ipk - 1) << "." << paramname;
856 ss2 << "f" << ipk << "." << paramname;
857 string tiepart1 = ss1.str();
858 string tiepart2 = ss2.str();
859 m_compsiteFunction->tie(tiepart1, tiepart2);
860 g_log.debug() << "LeBailFunction::Fit(Tie) / " << tiepart1 << " / " << tiepart2 << " /\n";
861 }
862
863 // Set contrains of the parameter on any of the tied parameter.
864 std::stringstream parss;
865 parss << "f0." << paramname;
866 string parnamef0 = parss.str();
867 auto bc = std::make_unique<Constraints::BoundaryConstraint>(m_compsiteFunction.get(), parnamef0, minvalue, maxvalue);
868 m_compsiteFunction->addConstraint(std::move(bc));
869}
870
871//----------------------------------------------------------------------------------------------
876void LeBailFunction::fixPeakParameter(const string &paramname, double paramvalue) {
877 for (size_t ipk = 0; ipk < m_numPeaks; ++ipk) {
878 stringstream ss1, ss2;
879 ss1 << "f" << ipk << "." << paramname;
880 ss2 << paramvalue;
881 string tiepart1 = ss1.str();
882 string tievalue = ss2.str();
883 m_compsiteFunction->tie(tiepart1, tievalue);
884
885 g_log.debug() << "Set up tie | " << tiepart1 << " <---> " << tievalue << " | \n";
886
887 // FIXME & TODO: Make a map between peak parameter name and index. And use
888 // fix() to replace tie
889 /*-- Code prepared to replace the existing block
890 ThermalNeutronBk2BkExpConvPVoigt_sptr thispeak = m_dspPeaks[ipk].second;
891 size_t iparam = findIndex(thispeak, funcparam.name);
892 thispeak->fix(iparam);
893 --*/
894
895 } // For each peak
896}
897
898//----------------------------------------------------------------------------------------------
901void LeBailFunction::fixBackgroundParameters() {
902 size_t numbkgdparams = m_background->nParams();
903
904 for (size_t iparam = 0; iparam < numbkgdparams; ++iparam)
905 m_background->fix(iparam);
906}
907
908//----------------------------------------------------------------------------------------------
911void LeBailFunction::setFixPeakHeights() {
912 for (size_t ipk = 0; ipk < m_numPeaks; ++ipk) {
913 // a. Get peak height
914 IPowderDiffPeakFunction_sptr thispeak = m_dspPeakVec[ipk].second;
915 thispeak->fix(0);
916 } // For each peak
917}
918
919//----------------------------------------------------------------------------------------------
923void LeBailFunction::setPeakHeights(const std::vector<double> &inheights) {
924 UNUSED_ARG(inheights);
925 throw runtime_error("It is not implemented properly.");
926 /*
927 if (inheights.size() != heights.size())
928 {
929 g_log.error() << "Input number of peaks (height) is not same as peaks. "
930 << '\n';
931 throw std::logic_error("Input number of peaks (height) is not same as
932 peaks. ");
933 }
934
935 for (size_t ih = 0; ih < inheights.size(); ++ih)
936 heights[ih] = inheights[ih];
937
938 return;*/
939}
940
941//----------------------------------------------------------------------------------------------
944IPowderDiffPeakFunction_sptr LeBailFunction::getPeak(size_t peakindex) {
945 if (peakindex >= m_numPeaks) {
946 stringstream errmsg;
947 errmsg << "Try to access peak " << peakindex << " out of range [0, " << m_numPeaks << ").";
948 g_log.error(errmsg.str());
949 throw runtime_error(errmsg.str());
950 }
951
952 IPowderDiffPeakFunction_sptr rpeak = m_vecPeaks[peakindex];
953
954 return rpeak;
955}
956
957//----------------------------------------------------------------------------------------------
960double LeBailFunction::getPeakParameter(std::vector<int> hkl, const std::string &parname) const {
961 // Search peak in map
962 map<vector<int>, IPowderDiffPeakFunction_sptr>::const_iterator fiter;
963 fiter = m_mapHKLPeak.find(hkl);
964 if (fiter == m_mapHKLPeak.end()) {
965 stringstream errss;
966 errss << "Peak with Miller index (" << hkl[0] << ", " << hkl[1] << "," << hkl[2]
967 << ") does not exist in Le Bail function.";
968 g_log.error(errss.str());
969 throw runtime_error(errss.str());
970 }
971
972 IPowderDiffPeakFunction_sptr peak = fiter->second;
973
974 double parvalue = getPeakParameterValue(peak, parname);
975
976 return parvalue;
977}
978
979//----------------------------------------------------------------------------------------------
982double LeBailFunction::getPeakParameter(size_t index, const std::string &parname) const {
983 if (index >= m_numPeaks) {
984 stringstream errss;
985 errss << "getPeakParameter() tries to reach a peak with index " << index << ", which is out of range " << m_numPeaks
986 << "/" << m_vecPeaks.size() << ".";
987 g_log.error(errss.str());
988 throw std::runtime_error(errss.str());
989 }
990
992 double value = getPeakParameterValue(peak, parname);
993
994 return value;
995}
996
997//----------------------------------------------------------------------------------------------
1002double LeBailFunction::getPeakParameterValue(const API::IPowderDiffPeakFunction_sptr &peak,
1003 const std::string &parname) const {
1004 // Locate the category of the parameter name
1005 auto vsiter = lower_bound(m_orderedProfileParameterNames.cbegin(), m_orderedProfileParameterNames.cend(), parname);
1006
1007 bool found = true;
1008 if (vsiter == m_orderedProfileParameterNames.end()) {
1009 // End of vector
1010 found = false;
1011 } else {
1012 // Middle of vector. But no match
1013 string matchparname = *vsiter;
1014 if (parname != matchparname)
1015 found = false;
1016 }
1017
1018 // Get parameter
1019 double parvalue;
1020 if (found) {
1021 // It is a native peak parameter
1022 parvalue = peak->getParameter(parname);
1023 } else {
1024 // It is a calculated peak parameter
1025 parvalue = peak->getPeakParameter(parname);
1026 }
1027
1028 return parvalue;
1029}
1030
1031//----------------------------------------------------------------------------------------------
1034double LeBailFunction::getPeakMaximumValue(std::vector<int> hkl, const std::vector<double> &xvalues, size_t &ix) {
1035 // Search peak in map
1036 map<vector<int>, IPowderDiffPeakFunction_sptr>::const_iterator fiter;
1037 fiter = m_mapHKLPeak.find(hkl);
1038 if (fiter == m_mapHKLPeak.end()) {
1039 stringstream errss;
1040 errss << "Peak with Miller index (" << hkl[0] << ", " << hkl[1] << "," << hkl[2]
1041 << ") does not exist in Le Bail function.";
1042 g_log.error(errss.str());
1043 throw runtime_error(errss.str());
1044 }
1045
1046 IPowderDiffPeakFunction_sptr peak = fiter->second;
1047
1048 double maxvalue = peak->getMaximumValue(xvalues, ix);
1049
1050 return maxvalue;
1051}
1052
1053} // namespace Mantid::CurveFitting::Algorithms
double value
The value of the point.
Definition FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
#define fabs(x)
Definition Matrix.cpp:22
const double NEG_DBL_MAX
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition System.h:48
A composite function is a function containing other functions.
Implements FunctionDomain1D with its own storage in form of a std::vector.
A class to store values calculated by a function.
std::vector< std::string > m_peakParameterNameVec
Name of peak parameter names (be same as the order in IPowderDiffPeakFunction)
void calculatePeakParameterValues() const
Calculate all peaks' parameter value.
void groupPeaks(std::vector< std::vector< std::pair< double, API::IPowderDiffPeakFunction_sptr > > > &peakgroupvec, std::vector< API::IPowderDiffPeakFunction_sptr > &outboundpeakvec, double xmin, double xmax)
Group close peaks together.
std::vector< std::pair< double, API::IPowderDiffPeakFunction_sptr > > m_dspPeakVec
Vector of pair <peak position in d-space, Peak> sortable.
bool calculateGroupPeakIntensities(std::vector< std::pair< double, API::IPowderDiffPeakFunction_sptr > > peakgroup, const std::vector< double > &vecX, const std::vector< double > &vecY, std::vector< double > &vec_summedpeaks)
Calculate the peaks intensities in same group.
Functions::BackgroundFunction_sptr m_background
Background function.
API::IPowderDiffPeakFunction_sptr generatePeak(int h, int k, int l)
Generate a peak with parameter set by.
std::vector< API::IPowderDiffPeakFunction_sptr > m_vecPeaks
Vector of all peaks.
double getPeakParameterValue(const API::IPowderDiffPeakFunction_sptr &peak, const std::string &parname) const
Retrieve peak's parameter. may be native or calculated.
API::CompositeFunction_sptr m_compsiteFunction
Composite functions for all peaks and background.
std::vector< std::string > m_orderedProfileParameterNames
Ordered profile parameter names for search.
std::map< std::vector< int >, API::IPowderDiffPeakFunction_sptr > m_mapHKLPeak
Vector of all peak's Miller indexes.
std::map< std::string, double > m_functionParameters
Parameters.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
std::shared_ptr< IPowderDiffPeakFunction > IPowderDiffPeakFunction_sptr
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition IFunction.h:743
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
Kernel::Logger g_log("DetermineSpinStateOrder")
static constexpr double h
Planck constant in J*s.
STL namespace.