Mantid
Loading...
Searching...
No Matches
FitPowderDiffPeaks.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 +
8
12
13#include "MantidAPI/Column.h"
18#include "MantidAPI/IFunction.h"
21#include "MantidAPI/TableRow.h"
22#include "MantidAPI/TextAxis.h"
24
35
36#include <fstream>
37
38#include <cmath>
39#include <utility>
40
41#include <gsl/gsl_sf_erf.h>
42
44#define PEAKFITRANGEFACTOR 5.0
45
47#define PEAKBOUNDARYFACTOR 2.5
48
50#define EXCLUDEPEAKRANGEFACTOR 8.0
52#define WINDOWSIZE 3.0
53
54using namespace Mantid;
55using namespace Mantid::API;
56using namespace Mantid::Kernel;
57using namespace Mantid::DataObjects;
60
61using namespace std;
62
64
66
67//----------------------------------------------------------------------------------------------
71 : m_wsIndex(-1), m_tofMin(0.), m_tofMax(0.), m_useGivenTOFh(false), m_confidentInInstrumentParameters(false),
72 m_minimumHKL(), m_numPeaksLowerToMin(-1), m_indexGoodFitPeaks(), m_chi2GoodFitPeaks(), m_fitMode(ROBUSTFIT),
73 m_genPeakStartingValue(HKLCALCULATION), m_rightmostPeakHKL(), m_rightmostPeakLeftBound(0.),
74 m_rightmostPeakRightBound(0.), m_minPeakHeight(0.), m_unitCell(), m_fitPeakBackgroundComposite(false) {}
75
76//----------------------------------------------------------------------------------------------
80 // Input data workspace
81 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "Anonymous", Direction::Input),
82 "Input workspace for data (diffraction pattern). ");
83
84 // Output workspace
85 declareProperty(std::make_unique<WorkspaceProperty<Workspace2D>>("OutputWorkspace", "Anonymous2", Direction::Output),
86 "Output Workspace2D for the fitted peaks. ");
87
88 // Input/output peaks table workspace
89 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("BraggPeakParameterWorkspace", "AnonymousPeak",
91 "TableWorkspace containg all peaks' parameters.");
92
93 // Input and output instrument parameters table workspace
94 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("InstrumentParameterWorkspace",
95 "AnonymousInstrument", Direction::InOut),
96 "TableWorkspace containg instrument's parameters.");
97
98 // Workspace to output fitted peak parameters
99 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("OutputBraggPeakParameterWorkspace",
100 "AnonymousOut2", Direction::Output),
101 "Output TableWorkspace containing the fitted peak parameters for each "
102 "peak.");
103
104 // Data workspace containing fitted peak parameters
105 declareProperty(std::make_unique<WorkspaceProperty<Workspace2D>>("OutputBraggPeakParameterDataWorkspace",
106 "ParameterData", Direction::Output),
107 "Output Workspace2D containing fitted peak parameters for "
108 "further refinement.");
109
110 // Zscore table workspace
112 std::make_unique<WorkspaceProperty<TableWorkspace>>("OutputZscoreWorkspace", "ZscoreTable", Direction::Output),
113 "Output TableWorkspace containing the Zscore of the fitted "
114 "peak parameters. ");
115
116 // Workspace index of the
117 declareProperty("WorkspaceIndex", 0, "Worskpace index for the data to refine against.");
118
119 // Range of the peaks to fit
120 declareProperty("MinTOF", EMPTY_DBL(), "Minimum TOF to fit peaks. ");
121 declareProperty("MaxTOF", EMPTY_DBL(), "Maximum TOF to fit peaks. ");
122
123 vector<string> fitmodes(2);
124 fitmodes[0] = "Robust";
125 fitmodes[1] = "Confident";
126 auto fitvalidator = std::make_shared<StringListValidator>(fitmodes);
127 declareProperty("FittingMode", "Robust", fitvalidator,
128 "Fitting mode such that user can determine"
129 "whether the input parameters are trustful or not.");
130
131 // Option to calculate peak position from (HKL) and d-spacing data
132 declareProperty("UseGivenPeakCentreTOF", true,
133 "Use each Bragg peak's centre in TOF given in "
134 "BraggPeakParameterWorkspace."
135 "Otherwise, calculate each peak's centre from d-spacing.");
136
137 vector<string> genpeakoptions{"(HKL) & Calculation", "From Bragg Peak Table"};
138 auto propvalidator = std::make_shared<StringListValidator>(genpeakoptions);
139 declareProperty("PeakParametersStartingValueFrom", "(HKL) & Calculation", propvalidator,
140 "Choice of how to generate starting values of "
141 "Bragg peak profile parmeters.");
142
143 declareProperty("MinimumPeakHeight", 0.20,
144 "Minimum peak height (with background removed) "
145 "Any peak whose maximum height under this value will be "
146 "treated as zero intensity. ");
147
148 // Flag to calculate and trust peak parameters from instrument
149 // declareProperty("ConfidentInInstrumentParameters", false, "Option to
150 // calculate peak parameters from "
151 // "instrument parameters.");
152
153 // Option to denote that peaks are related
154 declareProperty("PeaksCorrelated", false,
155 "Flag for fact that all peaks' corresponding profile parameters "
156 "are correlated by an analytical function");
157
158 // Option for peak's HKL for minimum d-spacing
159 auto arrayprop = std::make_unique<ArrayProperty<int>>("MinimumHKL", "");
160 declareProperty(std::move(arrayprop), "Miller index of the left most peak (peak with "
161 "minimum d-spacing) to be fitted. ");
162
163 // Number of the peaks to fit left to peak with minimum HKL
164 declareProperty("NumberPeaksToFitBelowLowLimit", 0,
165 "Number of peaks to fit with d-spacing value "
166 "less than specified minimum. ");
167
168 // Right most peak property
169 auto righthklprop = std::make_unique<ArrayProperty<int>>("RightMostPeakHKL", "");
170 declareProperty(std::move(righthklprop), "Miller index of the right most peak. "
171 "It is only required and used in RobustFit mode.");
172
173 declareProperty("RightMostPeakLeftBound", EMPTY_DBL(),
174 "Left bound of the right most peak. "
175 "Used in RobustFit mode.");
176
177 declareProperty("RightMostPeakRightBound", EMPTY_DBL(),
178 "Right bound of the right most peak. "
179 "Used in RobustFit mode.");
180
181 // Fit option
182 declareProperty("FitCompositePeakBackground", true,
183 "Flag to do fit to both peak and background in a composite "
184 "function as last fit step.");
185}
186
187//----------------------------------------------------------------------------------------------
191 // 1. Get input
193
194 // 2. Crop input workspace
196
197 // 3. Parse input table workspace
199
200 // 4. Unit cell
201 double latticesize = getParameter("LatticeConstant");
202 if (latticesize == EMPTY_DBL())
203 throw runtime_error("Input instrument table workspace lacks LatticeConstant. "
204 "Unable to complete processing.");
205 m_unitCell.set(latticesize, latticesize, latticesize, 90.0, 90.0, 90.0);
206
207 // 5. Generate peaks
209
210 // 6. Fit peaks & get peak centers
211 m_indexGoodFitPeaks.clear();
212 m_chi2GoodFitPeaks.clear();
213 size_t numpts = m_dataWS->x(m_wsIndex).size();
214 m_peakData.resize(numpts);
215
216 g_log.information() << "[FitPeaks] Total Number of Peak = " << m_vecPeakFunctions.size() << '\n';
217 m_peakFitChi2.resize(m_vecPeakFunctions.size(), -1.0 * DBL_MIN);
218 m_goodFit.resize(m_vecPeakFunctions.size(), false);
219
220 if (m_fitMode == ROBUSTFIT) {
221 g_log.information() << "Fit (Single) Peaks In Robust Mode.\n";
223 } else if (m_fitMode == TRUSTINPUTFIT) {
224 g_log.information() << "Fit Peaks In Trust Mode. Possible to fit "
225 "overlapped "
226 "peaks.\n";
228 } else {
229 g_log.error("Unsupported fit mode!");
230 throw runtime_error("Unsupported fit mode.");
231 }
232
233 // 5. Create Output
234 // a) Create a Table workspace for peak profile
235 pair<TableWorkspace_sptr, TableWorkspace_sptr> tables = genPeakParametersWorkspace();
236 TableWorkspace_sptr outputpeaksws = tables.first;
237 TableWorkspace_sptr ztablews = tables.second;
238 setProperty("OutputBraggPeakParameterWorkspace", outputpeaksws);
239 setProperty("OutputZscoreWorkspace", ztablews);
240
241 // b) Create output data workspace (as a middle stage product)
243 setProperty("OutputWorkspace", outdataws);
244
245 // c) Create data workspace for X0, A, B and S of peak with good fit
247 setProperty("OutputBraggPeakParameterDataWorkspace", peakparamvaluews);
248}
249
250//----------------------------------------------------------------------------------------------
254 // data workspace
255 m_dataWS = this->getProperty("InputWorkspace");
256 m_wsIndex = this->getProperty("WorkspaceIndex");
257 if (m_wsIndex < 0 || m_wsIndex > static_cast<int>(m_dataWS->getNumberHistograms())) {
258 stringstream errss;
259 errss << "Input workspace = " << m_wsIndex << " is out of range [0, " << m_dataWS->getNumberHistograms();
260 g_log.error(errss.str());
261 throw std::invalid_argument(errss.str());
262 }
263
264 // table workspaces for parameters
265 m_peakParamTable = this->getProperty("BraggPeakParameterWorkspace");
266 m_profileTable = this->getProperty("InstrumentParameterWorkspace");
267
268 // fitting range
269 m_tofMin = getProperty("MinTOF");
270 m_tofMax = getProperty("MaxTOF");
271 if (m_tofMin == EMPTY_DBL())
272 m_tofMin = m_dataWS->x(m_wsIndex)[0];
273 if (m_tofMax == EMPTY_DBL())
274 m_tofMax = m_dataWS->x(m_wsIndex).back();
275
276 m_minimumHKL = getProperty("MinimumHKL");
277 m_numPeaksLowerToMin = getProperty("NumberPeaksToFitBelowLowLimit");
278
279 // fitting algorithm option
280 string fitmode = getProperty("FittingMode");
281 if (fitmode == "Robust") {
283 } else if (fitmode == "Confident") {
285 } else {
286 throw runtime_error("Input fit mode can only accept either Robust or Confident. ");
287 }
288
289 m_useGivenTOFh = getProperty("UseGivenPeakCentreTOF");
290 // m_confidentInInstrumentParameters =
291 // getProperty("ConfidentInInstrumentParameters");
292
293 // peak parameter generation option
294 string genpeakparamalg = getProperty("PeakParametersStartingValueFrom");
295 if (genpeakparamalg == "(HKL) & Calculation") {
297 } else if (genpeakparamalg == "From Bragg Peak Table") {
299 } else {
300 throw runtime_error("Input option from PeakParametersStaringValueFrom is not supported.");
301 }
302
303 // Right most peak information
304 m_rightmostPeakHKL = getProperty("RightMostPeakHKL");
305 m_rightmostPeakLeftBound = getProperty("RightMostPeakLeftBound");
306 m_rightmostPeakRightBound = getProperty("RightMostPeakRightBound");
307
308 if (m_fitMode == ROBUSTFIT) {
311 stringstream errss;
312 errss << "If fit mode is 'RobustFit', then user must specify all 3 "
313 "properties of right most peak "
314 << "(1) Miller Index (given size = " << m_rightmostPeakHKL.size() << "), "
315 << "(2) Left boundary (given value = " << m_rightmostPeakLeftBound << "), "
316 << "(3) Right boundary (given value = " << m_rightmostPeakRightBound << "). ";
317 g_log.error(errss.str());
318 throw runtime_error(errss.str());
319 }
320 }
321
322 m_minPeakHeight = getProperty("MinimumPeakHeight");
323
324 m_fitPeakBackgroundComposite = getProperty("FitCompositePeakBackground");
325}
326
327//================================= Fit Peaks In Robust Mode
328//==================================
329
330//----------------------------------------------------------------------------------------------
340 // I. Prepare
342 bool isrightmost = true;
343 size_t numpeaks = m_vecPeakFunctions.size();
344 if (numpeaks == 0)
345 throw runtime_error("There is no peak to fit!");
346
347 vector<string> peakparnames = m_vecPeakFunctions[0].second.second->getParameterNames();
348
349 // II. Create local background function.
350 Polynomial_sptr backgroundfunction = std::make_shared<Polynomial>();
351 backgroundfunction->setAttributeValue("n", 1);
352 backgroundfunction->initialize();
353
354 // III. Fit peaks
355 double chi2;
356 double refpeakshift = 0.0;
357
358 for (int peakindex = static_cast<int>(numpeaks) - 1; peakindex >= 0; --peakindex) {
359 vector<int> peakhkl = m_vecPeakFunctions[peakindex].second.first;
360 BackToBackExponential_sptr thispeak = m_vecPeakFunctions[peakindex].second.second;
361
362 stringstream infoss;
363
364 bool goodfit = false;
365
366 if (isrightmost && peakhkl == m_rightmostPeakHKL) {
367 // It is the specified right most peak. Estimate background, peak height,
368 // fwhm, ...
369 // 1. Determine the starting value of the peak
370 double peakleftbound, peakrightbound;
371 peakleftbound = m_rightmostPeakLeftBound;
372 peakrightbound = m_rightmostPeakRightBound;
373
374 double predictpeakcentre = thispeak->centre();
375
376 infoss << "[DBx102] The " << numpeaks - 1 - peakindex << "-th rightmost peak's miller index = " << peakhkl[0]
377 << ", " << peakhkl[1] << ", " << peakhkl[2] << ", predicted at TOF = " << thispeak->centre()
378 << "; User specify boundary = [" << peakleftbound << ", " << peakrightbound << "].";
379 g_log.information() << infoss.str() << '\n';
380
381 map<string, double> rightpeakparameters;
382 goodfit = fitSinglePeakRobust(thispeak, std::dynamic_pointer_cast<BackgroundFunction>(backgroundfunction),
383 peakleftbound, peakrightbound, rightpeakparameters, chi2);
384
385 m_peakFitChi2[peakindex] = chi2;
386
387 if (!goodfit)
388 throw runtime_error("Failed to fit the right most peak. Unable to process. ");
389
390 stringstream robmsgss;
391 for (auto &parname : peakparnames) {
392 robmsgss << parname << " = " << thispeak->getParameter(parname) << '\n';
393 }
394 g_log.information() << "[DB1151] Robust Fit Result: Chi^2 = " << chi2 << '\n' << robmsgss.str();
395
396 rightpeak = thispeak;
397 isrightmost = false;
398
399 // iii. Reference peak shift
400 refpeakshift = thispeak->centre() - predictpeakcentre;
401
402 g_log.notice() << "[DBx332] Peak -" << static_cast<int>(numpeaks) - peakindex - 1
403 << ": shifted = " << refpeakshift << '\n';
404 } else if (!isrightmost) {
405 // All peaks but not the right most peak
406 // 1. Validate inputs
407 if (peakindex == static_cast<int>(numpeaks) - 1)
408 throw runtime_error("Impossible to have peak index as the right most peak here!");
409
410 double predictcentre = thispeak->centre();
411
412 // 2. Determine the peak range by observation
413 double peakleftbound, peakrightbound;
414 observePeakRange(thispeak, rightpeak, refpeakshift, peakleftbound, peakrightbound);
415
416 stringstream dbxss;
417 dbxss << '\n';
418 for (int i = 0; i < 10; ++i)
419 dbxss << "==\n[DBx323] Peak (" << peakhkl[0] << ", " << peakhkl[1] << "," << peakhkl[2]
420 << "). Centre predicted @ TOF = " << predictcentre << ". Observed range = " << peakleftbound << ", "
421 << peakrightbound;
422 g_log.notice(dbxss.str());
423
424 // 3. Fit peak
425 /* Disabled and replaced by fit1PeakRobust
426 goodfit = fitSinglePeakRefRight(thispeak, backgroundfunction, rightpeak,
427 peakleftbound,
428 peakrightbound, chi2);
429 */
430
431 map<string, double> rightpeakparameters;
432 storeFunctionParameters(rightpeak, rightpeakparameters);
433 goodfit = fitSinglePeakRobust(thispeak, std::dynamic_pointer_cast<BackgroundFunction>(backgroundfunction),
434 peakleftbound, peakrightbound, rightpeakparameters, chi2);
435
436 if (goodfit) {
437 // Fit successful
438 m_peakFitChi2[peakindex] = chi2;
439 // Update right peak and reference peak shift if peak is not trivial
440 if (thispeak->height() >= m_minPeakHeight) {
441 rightpeak = thispeak;
442 refpeakshift = thispeak->centre() - predictcentre;
443 }
444
445 } else {
446 // Bad fit
447 m_peakFitChi2[peakindex] = -1.0;
448 g_log.warning() << "Fitting peak @ " << thispeak->centre() << " failed. \n";
449 }
450
451 } else {
452 // It is right to the specified right most peak. Skip to next peak
453 double peakleftbound, peakrightbound;
454 peakleftbound = m_rightmostPeakLeftBound;
455 peakrightbound = m_rightmostPeakRightBound;
456
457 infoss << "[DBx102] The " << numpeaks - 1 - peakindex << "-th rightmost peak's miller index = " << peakhkl[0]
458 << ", " << peakhkl[1] << ", " << peakhkl[2] << ", predicted at TOF = " << thispeak->centre() << "; "
459 << "User specify right most peak's miller index = " << m_rightmostPeakHKL[0] << ", "
460 << m_rightmostPeakHKL[1] << ", " << m_rightmostPeakHKL[2] << " User specify boundary = [" << peakleftbound
461 << ", " << peakrightbound << "].";
462 g_log.information() << infoss.str() << '\n';
463 continue;
464 }
465
466 } // ENDFOR Peaks
467}
468
469//----------------------------------------------------------------------------------------------
474 const BackToBackExponential_sptr &rightpeak, double refpeakshift,
475 double &peakleftbound, double &peakrightbound) {
476 double predictcentre = thispeak->centre();
477 double rightfwhm = rightpeak->fwhm();
478
479 // 1. Roughly determine the peak range from this peak's starting values and
480 // right peak' fitted
481 // parameters values
482 if (refpeakshift > 0) {
483 // tend to shift to right
484 peakleftbound = predictcentre - rightfwhm;
485 peakrightbound = predictcentre + rightfwhm + refpeakshift;
486 } else {
487 // tendency to shift to left
488 peakleftbound = predictcentre - rightfwhm + refpeakshift;
489 peakrightbound = predictcentre + rightfwhm;
490 }
491 if (peakrightbound > rightpeak->centre() - 3 * rightpeak->fwhm()) {
492 // the search of peak's right end shouldn't exceed the left tail of its real
493 // right peak!
494 // Remember this is robust mode. Any 2 adjacent peaks should be faw enough.
495 peakrightbound = rightpeak->centre() - 3 * rightpeak->fwhm();
496 }
497
498 // 2. Search for maximum
499 const auto &vecX = m_dataWS->x(m_wsIndex);
500
501 size_t icentre = findMaxValue(m_dataWS, m_wsIndex, peakleftbound, peakrightbound);
502 double peakcentre = vecX[icentre];
503
504 // 3. Narrow now the peak range
505 peakleftbound = vecX[icentre] - 4.0 * rightfwhm;
506 peakrightbound = vecX[icentre] + 4.0 * rightfwhm;
507
508 double rightpeakleftbound = rightpeak->centre() - 3 * rightfwhm;
509 if (peakrightbound > rightpeakleftbound) {
510 peakrightbound = rightpeakleftbound;
511 if (peakrightbound < 2.0 * rightfwhm + peakcentre)
512 g_log.warning() << "Peak @ " << peakcentre << "'s right boundary is too close to its right peak!\n";
513 }
514}
515
516//----------------------------------------------------------------------------------------------
556 const BackgroundFunction_sptr &backgroundfunction, double peakleftbound,
557 double peakrightbound, const map<string, double> &rightpeakparammap,
558 double &finalchi2) {
559 // 1. Build partial workspace
560 Workspace2D_sptr peakws = buildPartialWorkspace(m_dataWS, m_wsIndex, peakleftbound, peakrightbound);
561 g_log.debug() << "[DB1208] Build partial workspace for peak @ " << peak->centre() << " (predicted).\n";
562
563 // 2. Estimate and remove background
564 size_t rawdata_wsindex = 0;
565 size_t estbkgd_wsindex = 2;
566 size_t peak_wsindex = 1;
567 estimateBackgroundCoarse(peakws, backgroundfunction, rawdata_wsindex, estbkgd_wsindex, peak_wsindex);
568
569 stringstream dbss;
570 dbss << "[DBx203] Removed background peak data: \n";
571 for (size_t i = 0; i < peakws->x(peak_wsindex).size(); ++i)
572 dbss << peakws->x(peak_wsindex)[i] << "\t\t" << peakws->y(peak_wsindex)[i] << "\t\t" << peakws->e(peak_wsindex)[i]
573 << '\n';
574 g_log.debug(dbss.str());
575
576 // 3. Estimate FWHM, peak centre, and height
577 double centre, fwhm, height;
578 string errmsg;
579 bool pass = observePeakParameters(peakws, 1, centre, height, fwhm, errmsg);
580 if (!pass) {
581// If estiamtion fails, quit b/c first/rightmost peak must be fitted.
582#if 0
583 g_log.error(errmsg);
584 throw runtime_error(errmsg);
585#else
586 g_log.notice("Unable to observe peak parameters. Proceed to next peak.");
587 return false;
588#endif
589 } else if (height < m_minPeakHeight) {
590 g_log.notice() << "[FLAGx409] Peak proposed @ TOF = " << peak->centre() << " has a trivial "
591 << "peak height = " << height << " by observation. Skipped.\n";
592 return false;
593 } else {
594 g_log.information() << "[DBx201] Peak Predicted @ TOF = " << peak->centre()
595 << ", Estimated (observation) Centre = " << centre << ", FWHM = " << fwhm
596 << " Height = " << height << '\n';
597 }
598
599 // 4. Fit by Gaussian to get some starting value
600 double tof_h, sigma;
601 doFitGaussianPeak(peakws, peak_wsindex, centre, fwhm, fwhm, tof_h, sigma, height);
602
603 // 5. Fit by various methods
604 // Set all parameters for fit
605 vector<string> peakparnames = peak->getParameterNames();
606 for (size_t i = 0; i < peakparnames.size(); ++i)
607 peak->unfix(i);
608
609 // Set up the universal starting parameter
610 peak->setParameter("I", height * fwhm);
611 peak->setParameter("X0", tof_h);
612
613 size_t numsteps = 2;
614 vector<string> minimizers(numsteps);
615 minimizers[0] = "Simplex";
616 minimizers[1] = "Levenberg-Marquardt";
617 vector<size_t> maxiterations(numsteps, 10000);
618 vector<double> dampfactors(numsteps, 0.0);
619
620 // Record the start value
621 map<string, double> origparammap;
622 storeFunctionParameters(peak, origparammap);
623
624 vector<double> chi2s;
625 vector<bool> goodfits;
626 vector<map<string, double>> solutions;
627
628 // a) Fit by using input peak parameters
629 string peakinfoa0 = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(peak));
630 g_log.notice() << "[DBx533A] Approach A: Starting Peak Function Information: \n" << peakinfoa0 << '\n';
631
632 double chi2a;
633 bool fitgooda = doFit1PeakSequential(peakws, peak_wsindex, peak, minimizers, maxiterations, dampfactors, chi2a);
634 map<string, double> solutiona;
635 storeFunctionParameters(peak, solutiona);
636
637 chi2s.emplace_back(chi2a);
638 goodfits.emplace_back(fitgooda);
639 solutions.emplace_back(solutiona);
640
641 string peakinfoa1 = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(peak));
642 g_log.notice() << "[DBx533A] Approach A: Fit Successful = " << fitgooda << ", Chi2 = " << chi2a
643 << ", Peak Function Information: \n"
644 << peakinfoa1 << '\n';
645
646 // b) Fit by using Gaussian result (Sigma)
647 restoreFunctionParameters(peak, origparammap);
648 peak->setParameter("S", sigma);
649
650 string peakinfob0 = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(peak));
651 g_log.notice() << "[DBx533B] Approach B: Starting Peak Function Information: \n" << peakinfob0 << '\n';
652
653 double chi2b;
654 bool fitgoodb = doFit1PeakSequential(peakws, peak_wsindex, peak, minimizers, maxiterations, dampfactors, chi2b);
655
656 map<string, double> solutionb;
657 storeFunctionParameters(peak, solutionb);
658
659 chi2s.emplace_back(chi2b);
660 goodfits.emplace_back(fitgoodb);
661 solutions.emplace_back(solutionb);
662
663 string peakinfob1 = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(peak));
664 g_log.notice() << "[DBx533B] Approach 2: Fit Successful = " << fitgoodb << ", Chi2 = " << chi2b
665 << ", Peak Function Information: \n"
666 << peakinfob1 << '\n';
667
668 // c) Fit peak parameters by the value from right peak
669 if (!rightpeakparammap.empty()) {
670 restoreFunctionParameters(peak, rightpeakparammap);
671 peak->setParameter("X0", tof_h);
672 peak->setParameter("I", height * fwhm);
673
674 string peakinfoc0 = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(peak));
675 g_log.notice() << "[DBx533C] Approach C: Starting Peak Function Information: \n" << peakinfoc0 << '\n';
676
677 double chi2c;
678 bool fitgoodc = doFit1PeakSequential(peakws, peak_wsindex, peak, minimizers, maxiterations, dampfactors, chi2c);
679 map<string, double> solutionc;
680 storeFunctionParameters(peak, solutionc);
681
682 chi2s.emplace_back(chi2c);
683 goodfits.emplace_back(fitgoodc);
684 solutions.emplace_back(solutionc);
685
686 string peakinfoc1 = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(peak));
687 g_log.notice() << "[DBx533C] Approach C: Fit Successful = " << fitgoodc << ", Chi2 = " << chi2c
688 << ", Peak Function Information: \n"
689 << peakinfoc1 << '\n';
690 } else {
691 // No right peak information: set a error entry
692 chi2s.emplace_back(DBL_MAX);
693 goodfits.emplace_back(false);
694 solutions.emplace_back(rightpeakparammap);
695 }
696
697 // 6. Summarize the above 3 approach
698 size_t bestapproach = goodfits.size() + 1;
699 double bestchi2 = DBL_MAX;
700 for (size_t i = 0; i < goodfits.size(); ++i) {
701 if (goodfits[i] && chi2s[i] < bestchi2) {
702 bestapproach = i;
703 bestchi2 = chi2s[i];
704 }
705 }
706
707 stringstream fitsumss;
708 fitsumss << "Best fit result is obtained by approach " << bestapproach << " of total " << goodfits.size()
709 << " approaches. Best Chi^2 = " << bestchi2 << ", Peak Height = " << peak->height();
710 g_log.notice() << "[DB1127] " << fitsumss.str() << '\n';
711
712 bool fitgood = true;
713 if (bestapproach < goodfits.size()) {
714 restoreFunctionParameters(peak, solutions[bestapproach]);
715 } else {
716 fitgood = false;
717 }
718
719 // 7. Fit by Monte Carlo if previous failed
720 if (!fitgood) {
721 peak->setParameter("S", sigma);
722 peak->setParameter("I", height * fwhm);
723 peak->setParameter("X0", tof_h);
724
725 vector<string> paramsinmc{"A", "B"};
726
727 fitSinglePeakSimulatedAnnealing(peak, paramsinmc);
728 }
729
730 // 8. Fit with background
732 // Fit peak + background
733 double chi2compf;
734 bool fitcompfunsuccess = doFit1PeakBackground(peakws, rawdata_wsindex, peak, backgroundfunction, chi2compf);
735 if (fitcompfunsuccess) {
736 finalchi2 = chi2compf;
737 } else {
738 finalchi2 = bestchi2;
739 g_log.warning("Fit peak-background composite function failed! Need to "
740 "find out how this case peak value is changed from best "
741 "fit.");
742 }
743 } else {
744 // Flag is turned off
745 finalchi2 = bestchi2;
746 }
747
748 // 9. Plot function
749 FunctionDomain1DVector domain(peakws->x(0).rawData());
750 plotFunction(peak, backgroundfunction, domain);
751
752 return fitgood;
753}
754
755//----------------------------------------------------------------------------------------------
760 const BackToBackExponential_sptr &peak,
761 const BackgroundFunction_sptr &backgroundfunction, double &chi2) {
762 // 0. Set fit parameters
763 string minimzername("Levenberg-MarquardtMD");
764 double startx = peak->centre() - 3.0 * peak->fwhm();
765 double endx = peak->centre() + 3.0 * peak->fwhm();
766
767 // 1. Create composite function
769 compfunc->addFunction(peak);
770 compfunc->addFunction(backgroundfunction);
771
772 // 2. Unfix all parameters
773 vector<string> comparnames = compfunc->getParameterNames();
774 for (size_t ipar = 0; ipar < comparnames.size(); ++ipar)
775 compfunc->unfix(ipar);
776
777 // 3. Fit
778 string cominfoa = getFunctionInfo(compfunc);
779 g_log.notice() << "[DBx533X-0] Fit All: Starting Peak Function Information: \n"
780 << cominfoa << "Fit range = " << startx << ", " << endx << '\n';
781
782 // 3. Set
783 auto fitalg = createChildAlgorithm("Fit", -1, -1, true);
784 fitalg->initialize();
785
786 fitalg->setProperty("Function", std::dynamic_pointer_cast<API::IFunction>(compfunc));
787 fitalg->setProperty("InputWorkspace", dataws);
788 fitalg->setProperty("WorkspaceIndex", static_cast<int>(wsindex));
789 fitalg->setProperty("Minimizer", minimzername);
790 fitalg->setProperty("CostFunction", "Least squares");
791 fitalg->setProperty("MaxIterations", 1000);
792 fitalg->setProperty("Output", "FitPeakBackground");
793 fitalg->setProperty("StartX", startx);
794 fitalg->setProperty("EndX", endx);
795
796 // 3. Execute and parse the result
797 bool isexecute = fitalg->execute();
798 bool fitsuccess;
799 chi2 = DBL_MAX;
800
801 if (isexecute) {
802 std::string fitresult = parseFitResult(fitalg, chi2, fitsuccess);
803
804 // Figure out result
805 stringstream cominfob;
806 cominfob << "[DBx533X] Fit All: Fit Successful = " << fitsuccess << ", Chi^2 = " << chi2 << '\n';
807 cominfob << "Detailed info = " << fitresult << '\n';
808 string fitinfo = getFunctionInfo(compfunc);
809 cominfob << fitinfo;
810
811 g_log.notice(cominfob.str());
812 } else {
813 g_log.notice() << "[DB1203B] Failed To Fit Peak+Background @ " << peak->centre() << '\n';
814 fitsuccess = false;
815 }
816
817 return fitsuccess;
818}
819
820//----------------------------------------------------------------------------------------------
824 const vector<string> &paramtodomc) {
825 UNUSED_ARG(peak);
826 UNUSED_ARG(paramtodomc);
827 throw runtime_error("To Be Implemented Soon!");
828
829 /*
830 // 6. Fit peak by the result from Gaussian
831 pair<bool, double> fitresult;
832
833 double varA = 1.0;
834 double varB = 1.0;
835
836
837 // a) Get initial chi2
838 double startchi2 = DBL_MAX;
839 doFit1PeakSimple(peakws, 1, peak, "Levenberg-MarquardtMD", 0, newchi2);
840 g_log.debug() << "[DBx401] Peak @ TOF = " << peak->centre() << ", Starting
841 Chi^2 = "
842 << newchi2 << '\n';
843
844 bool continuetofit = true;
845 bool goodfit;
846
847 int count = 0;
848 size_t numfittohave = 5;
849 int maxnumloops = 100;
850 vector<pair<double, map<string, double> > > fitparammaps; // <chi2,
851 <parameter, value> >
852
853 map<string, double> curparammap;
854 double curchi2 = startchi2;
855
856 srand(0);
857 size_t reject = 0;
858 size_t count10 = 0;
859 double stepratio = 1.0;
860 while(continuetofit)
861 {
862 // a) Store
863 storeFunctionParameters(peak, curparammap);
864
865 // b) Monte Carlo
866 double aorb = static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5;
867 double change =
868 static_cast<double>(rand())/static_cast<double>(RAND_MAX)-0.5;
869 if (aorb > 0)
870 {
871 // A
872 varA = varA*(1+stepratio*change);
873 if (varA <= DBL_MIN)
874 varA = fabs(varA) + DBL_MIN;
875 }
876 else
877 {
878 // B
879 varB = varB*(1+stepratio*change);
880 if (varB <= DBL_MIN)
881 varB = fabs(varB) + DBL_MIN;
882 }
883
884 // b) Set A and B
885 peak->setParameter("A", varA);
886 peak->setParameter("B", varB);
887
888 // b) Fit
889 g_log.debug() << "DBx329: Proposed A = " << varA << ", B = " << varB <<
890 '\n';
891 fitresult = doFitPeak(peakws, peak, fwhm);
892
893 // c) Get fit result
894 goodfit = fitresult.first;
895 newchi2 = fitresult.second;
896
897 // d) Take it or not!
898 ++ count10;
899 if (!goodfit)
900 {
901 // Bad fit, reverse
902 restoreFunctionParameters(peak, curparammap);
903 ++ reject;
904 }
905 else if (newchi2 < curchi2)
906 {
907 // Good. Take it
908 curchi2 = newchi2;
909 }
910 else
911 {
912 // Toss the dice again
913 double bar = exp(-(newchi2-curchi2)/curchi2);
914 double dice = static_cast<double>(rand())/static_cast<double>(RAND_MAX);
915 if (dice < bar)
916 {
917 // Take it
918 curchi2 = newchi2;
919 }
920 else
921 {
922 // Reject it
923 restoreFunctionParameters(peak, curparammap);
924 ++ reject;
925 }
926 }
927
928 // Adjust step size
929 if (count10 >=10 && reject >= 8)
930 {
931 reject = 10;
932 count10 = 0;
933 stepratio *= 5;
934 }
935
936 // e) Record
937 if (goodfit && newchi2 < startchi2)
938 {
939 // i. Store parameters;
940 map<string,double> parammap;
941 for (size_t i = 0; i < peakparnames.size(); ++i)
942 parammap.emplace(peakparnames[i],
943 peak->getParameter(peakparnames[i]));
944 fitparammaps.emplace_back(newchi2, parammap);
945
946 // ii. sort
947 sort(fitparammaps.begin(), fitparammaps.end());
948
949 // iii. keep size
950 if (fitparammaps.size() > numfittohave)
951 fitparammaps.pop_back();
952 }
953
954 // f) Loop control & MC
955 count += 1;
956 if (count >= maxnumloops)
957 {
958 continuetofit = false;
959 }
960 } // ENDWHILE For Fit
961
962 // 7. Process MC fit results
963 if (fitparammaps.size() > 0)
964 {
965 // Good results
966 goodfit = true;
967 sort(fitparammaps.begin(), fitparammaps.end());
968 newchi2 = fitparammaps[0].first;
969
970 // Set the best result to peak
971 for (size_t i = 0; i < peakparnames.size(); ++i)
972 {
973 string& parname = peakparnames[i];
974 map<string, double>& thisparams = fitparammaps[0].second;
975 map<string, double>::iterator liter = thisparams.find(parname);
976 if (liter == thisparams.end())
977 {
978 stringstream errmsg;
979 errmsg << "In parameter value map, there is no key named " << parname <<
980 '\n';
981 throw runtime_error(errmsg.str());
982 }
983 peak->setParameter(parname, liter->second);
984 }
985
986 // Plot the peak
987 FunctionDomain1DVector domain(peakws->x(1));
988 plotFunction(peak, backgroundfunction, domain);
989
990 // Debug print the best solutions
991 for (size_t i = 0; i < fitparammaps.size(); ++i)
992 {
993 double thischi2 = fitparammaps[i].first;
994 map<string, double>& thisparams = fitparammaps[i].second;
995
996 g_log.information() << "[DB1055] Chi2 = " << thischi2 << ", A = " <<
997 thisparams["A"]
998 << ", B = " << thisparams["B"] << '\n';
999 }
1000 }
1001 else
1002 {
1003 // Bad result
1004 goodfit = false;
1005 stringstream errmsg;
1006 errmsg << "Failed to fit peak @ " << tof_h << " in robust mode!\n";
1007 g_log.error(errmsg.str());
1008 }
1009
1010 return goodfit;
1011 */
1012
1013 return false;
1014}
1015
1016//============================== Fit Peaks With Good Starting Values
1017//==========================
1018
1019//----------------------------------------------------------------------------------------------
1028 // 1. Initialize (local) background function
1029 Polynomial_sptr backgroundfunction = std::make_shared<Polynomial>();
1030 backgroundfunction->setAttributeValue("n", 1);
1031 backgroundfunction->initialize();
1032
1033 // 2. Fit peak / peaks group
1034 int ipeak = static_cast<int>(m_vecPeakFunctions.size()) - 1;
1035 double chi2;
1036
1037 // BackToBackExponential_sptr rightpeak = m_peaks[ipeak].second.second;
1038
1039 while (ipeak >= 0) {
1040 // 1. Make a peak group
1041 vector<size_t> indexpeakgroup;
1042
1043 bool makegroup = true;
1044 // Loop over 2nd level: peak groups: 1 peak or overlapped peaks
1045 while (makegroup) {
1046 // There is no need to worry about its right neighbor, b/c
1047 // this situation is already considered as its right neighbor is
1048 // treated;
1049
1050 // a) Add this peak,
1051 BackToBackExponential_sptr thispeak = m_vecPeakFunctions[ipeak].second.second;
1052 indexpeakgroup.emplace_back(ipeak);
1053
1054 // b) update the peak index
1055 --ipeak;
1056
1057 if (ipeak < 0) {
1058 // this is last peak. next peak does not exist
1059 makegroup = false;
1060 } else {
1061 // this is not the last peak. search the left one.
1062 double thispeakleftbound = thispeak->centre() - thispeak->fwhm() * 2.5;
1063 BackToBackExponential_sptr leftpeak = m_vecPeakFunctions[ipeak].second.second;
1064 double leftpeakrightbound = leftpeak->centre() + leftpeak->fwhm() * 2.5;
1065 if (thispeakleftbound > leftpeakrightbound) {
1066 // This peak and next peak is faw enough!
1067 makegroup = false;
1068 }
1069 }
1070 } // while
1071
1072 if (indexpeakgroup.size() == 1) {
1073 // Fit a single peak
1074 const size_t ifit = indexpeakgroup[0];
1075 double peakfitleftbound, peakfitrightbound;
1076 calculatePeakFitBoundary(ifit, ifit, peakfitleftbound, peakfitrightbound);
1077
1078 g_log.information() << "\n[T] Fit Peak Indexed " << ifit << " (" << m_vecPeakFunctions.size() - 1 - ifit
1079 << ")\t----------------------------------\n";
1080
1081 BackToBackExponential_sptr thispeak = m_vecPeakFunctions[ifit].second.second;
1082 bool annihilatedpeak;
1083 m_goodFit[ifit] = fitSinglePeakConfident(thispeak, backgroundfunction, peakfitleftbound, peakfitrightbound, chi2,
1084 annihilatedpeak);
1085 m_peakFitChi2[ifit] = chi2;
1086 if (annihilatedpeak)
1087 thispeak->setHeight(0.0);
1088
1089 // Debug output
1090 vector<int> &hkl = m_vecPeakFunctions[ifit].second.first;
1091 stringstream dbss;
1092 dbss << "Peak [" << hkl[0] << ", " << hkl[1] << ", " << hkl[2] << "] expected @ TOF = " << thispeak->centre()
1093 << ": \t";
1094 if (annihilatedpeak)
1095 dbss << "Annihilated!";
1096 else
1097 dbss << "Fit Status = " << m_goodFit[ifit] << ", Chi2 = " << chi2;
1098 g_log.information() << "[DB531] " << dbss.str() << '\n';
1099 } else {
1100 // Fit overlapped peaks
1101 vector<BackToBackExponential_sptr> peaksgroup;
1102 for (auto ipk : indexpeakgroup) {
1103 BackToBackExponential_sptr temppeak = m_vecPeakFunctions[ipk].second.second;
1104 peaksgroup.emplace_back(temppeak);
1105 }
1106
1107 fitOverlappedPeaks(peaksgroup, backgroundfunction, -1.0);
1108 // rightpeak = indexpeaksgroup[0];
1109 }
1110 } // ENDWHILE
1111
1112 // 2. Output
1113
1114 g_log.information() << "DBx415: Number of good fit peaks = " << m_indexGoodFitPeaks.size() << '\n';
1115
1116 // 3. Clean up
1117 g_log.information() << "[FitPeaks] Number of peak of good chi2 = " << m_chi2GoodFitPeaks.size() << '\n';
1118}
1119
1120//----------------------------------------------------------------------------------------------
1130 const BackgroundFunction_sptr &backgroundfunction, double leftbound,
1131 double rightbound, double &chi2, bool &annhilatedpeak) {
1132 // 1. Build the partial workspace
1133 // a) Determine boundary if necessary
1134 if (leftbound < 0 || leftbound >= peak->centre())
1135 leftbound = peak->centre() - 5 * peak->fwhm();
1136 if (rightbound < 0 || rightbound <= peak->centre())
1137 rightbound = peak->centre() + 5 * peak->fwhm();
1138
1139 // b) Build partial
1140 Workspace2D_sptr peakdataws = buildPartialWorkspace(m_dataWS, m_wsIndex, leftbound, rightbound);
1141
1142 // 2. Remove background
1143 estimateBackgroundCoarse(peakdataws, backgroundfunction, 0, 2, 1);
1144
1145 stringstream dbss2;
1146 dbss2 << "[T] Partial workspace No Background: \n";
1147 for (size_t i = 0; i < peakdataws->x(1).size(); ++i)
1148 dbss2 << peakdataws->x(1)[i] << "\t\t" << peakdataws->y(1)[i] << "\t\t" << peakdataws->e(1)[i] << "\t\t"
1149 << peakdataws->y(0)[i] << '\n';
1150 g_log.notice(dbss2.str());
1151
1152 // 3. Estimate peak heights
1153 size_t imaxheight = findMaxValue(peakdataws->y(1).rawData());
1154 double maxheight = peakdataws->y(1)[imaxheight];
1155 if (maxheight <= m_minPeakHeight) {
1156 // Max height / peak height is smaller than user defined minimum height. No
1157 // fit, Zero
1158 annhilatedpeak = true;
1159 return false;
1160 } else {
1161 // Max hieght is larger than user defined minimum. Fit it
1162 annhilatedpeak = false;
1163 }
1164
1165 // 4. Set the constraint and height
1166 // a) Peak centre
1167 double peakcentreleftbound = peak->centre() - peak->fwhm();
1168 double peakcentrerightbound = peak->centre() + peak->fwhm();
1169 auto x0bc = std::make_unique<BoundaryConstraint>(peak.get(), "X0", peakcentreleftbound, peakcentrerightbound);
1170 peak->addConstraint(std::move(x0bc));
1171
1172 // b) A
1173 auto abc = std::make_unique<BoundaryConstraint>(peak.get(), "A", 1.0E-10, false);
1174 peak->addConstraint(std::move(abc));
1175
1176 // c) B
1177 auto bbc = std::make_unique<BoundaryConstraint>(peak.get(), "B", 1.0E-10, false);
1178 peak->addConstraint(std::move(bbc));
1179
1180 // d) Guessed height
1181 peak->setHeight(maxheight);
1182
1183 /* Debug information */
1184 stringstream dbss0;
1185 dbss0 << "[DBx100] Peak @" << peak->centre() << ", FWHM = " << peak->fwhm() << '\n';
1186 vector<string> peakparams = peak->getParameterNames();
1187 for (size_t i = 0; i < peakparams.size(); ++i)
1188 dbss0 << peakparams[i] << " = " << peak->getParameter(i) << '\n';
1189 g_log.notice(dbss0.str());
1190
1191 // 5. Fit peak with simple scheme
1192 vector<string> peakparamnames = peak->getParameterNames();
1193 vector<map<string, double>> fitparamvaluemaps;
1194 vector<pair<double, size_t>> chi2indexvec;
1195
1196 // a) Fit peak height
1197 for (size_t iparam = 0; iparam < peakparamnames.size(); ++iparam) {
1198 string &parname = peakparams[iparam];
1199 if (parname == "I")
1200 peak->unfix(iparam);
1201 else
1202 peak->fix(iparam);
1203 }
1204 double chi2height;
1205 bool goodfit1 = doFit1PeakSimple(peakdataws, 1, peak, "Levenberg-MarquardtMD", 10000, chi2height);
1206
1207 // Store parameters
1208 map<string, double> step1params;
1209 storeFunctionParameters(peak, step1params);
1210 fitparamvaluemaps.emplace_back(step1params);
1211 if (!goodfit1)
1212 chi2height = 1.0E20;
1213 chi2indexvec.emplace_back(chi2height, 0);
1214
1215 // Fix background
1216 vector<string> bkgdparnames = backgroundfunction->getParameterNames();
1217 for (size_t iname = 0; iname < bkgdparnames.size(); ++iname)
1218 backgroundfunction->fix(iname);
1219
1220 // b) Plan A: fit all parameters
1221 double chi2planA;
1222 for (size_t iparam = 0; iparam < peakparamnames.size(); ++iparam)
1223 peak->unfix(iparam);
1224 bool goodfitA = doFit1PeakSimple(peakdataws, 1, peak, "Simplex", 10000, chi2planA);
1225
1226 // Store A's result
1227 map<string, double> planAparams;
1228 storeFunctionParameters(peak, planAparams);
1229 if (!goodfitA)
1230 chi2planA = 1.0E20;
1231 fitparamvaluemaps.emplace_back(planAparams);
1232 chi2indexvec.emplace_back(chi2planA, 1);
1233
1234 // c) Plan B: fit parameters in two groups in 2 steps
1235 // i. Restore step 1's result
1236 restoreFunctionParameters(peak, step1params);
1237
1238 // ii. Fit peak height and everything else but "A"
1239 double chi2planB;
1240 for (size_t iparam = 0; iparam < peakparamnames.size(); ++iparam) {
1241 string parname = peakparams[iparam];
1242 if (parname == "A")
1243 peak->fix(iparam);
1244 else
1245 peak->unfix(iparam);
1246 }
1247 bool goodfitB1 = doFit1PeakSimple(peakdataws, 1, peak, "Levenberg-MarquardtMD", 10000, chi2planB);
1248
1249 // iii. Fit "A" only
1250 for (size_t iparam = 0; iparam < peakparamnames.size(); ++iparam) {
1251 string parname = peakparams[iparam];
1252 if (parname == "A" || parname == "I")
1253 peak->unfix(iparam);
1254 else
1255 peak->fix(iparam);
1256 }
1257 bool goodfitB2 = doFit1PeakSimple(peakdataws, 1, peak, "Levenberg-MarquardtMD", 10000, chi2planB);
1258
1259 bool goodfitB = goodfitB1 || goodfitB2;
1260 map<string, double> planBparams;
1261 storeFunctionParameters(peak, planBparams);
1262 if (!goodfitB)
1263 chi2planB = 1.0E20;
1264 fitparamvaluemaps.emplace_back(planBparams);
1265 chi2indexvec.emplace_back(chi2planB, 2);
1266
1267 // d) Plan C: fit parameters in two groups in 2 steps in alternate order
1268 // i. Restore step 1's result
1269 restoreFunctionParameters(peak, step1params);
1270
1271 // ii. Fit "A"
1272 double chi2planC;
1273 for (size_t iparam = 0; iparam < peakparamnames.size(); ++iparam) {
1274 string parname = peakparams[iparam];
1275 if (parname != "A")
1276 peak->fix(iparam);
1277 else
1278 peak->unfix(iparam);
1279 }
1280 bool goodfitC1 = doFit1PeakSimple(peakdataws, 1, peak, "Levenberg-MarquardtMD", 10000, chi2planC);
1281
1282 // iii. Fit peak height and everything else but "A"
1283 for (size_t iparam = 0; iparam < peakparamnames.size(); ++iparam) {
1284 string parname = peakparams[iparam];
1285 if (parname == "A")
1286 peak->fix(iparam);
1287 else
1288 peak->unfix(iparam);
1289 }
1290 bool goodfitC2 = doFit1PeakSimple(peakdataws, 1, peak, "Levenberg-MarquardtMD", 10000, chi2planB);
1291
1292 bool goodfitC = goodfitC1 || goodfitC2;
1293 map<string, double> planCparams;
1294 storeFunctionParameters(peak, planCparams);
1295 if (!goodfitC)
1296 chi2planC = 1.0E20;
1297 fitparamvaluemaps.emplace_back(planCparams);
1298 chi2indexvec.emplace_back(chi2planC, 3);
1299
1300 // d) Summarize and compare result
1301 stringstream sumss;
1302 sumss << "[DBx833] Confident fit on peak summary: \n";
1303 for (size_t i = 0; i < 4; ++i)
1304 sumss << "Index " << i << ": chi^2 = " << chi2indexvec[i].first << '\n';
1305 g_log.notice(sumss.str());
1306
1307 sort(chi2indexvec.begin(), chi2indexvec.end());
1308
1309 bool goodfit;
1310 if (chi2indexvec[0].first < 1.0E19) {
1311 // There is good fit.
1312 size_t goodindex = chi2indexvec[0].second;
1313 restoreFunctionParameters(peak, fitparamvaluemaps[goodindex]);
1314 chi2 = chi2indexvec[0].first;
1315 goodfit = true;
1316 } else {
1317 // There is no good fit
1318 chi2 = DBL_MAX;
1319 goodfit = false;
1320 }
1321
1322 // 6. Plot the peak in the output workspace data
1323 if (goodfit) {
1324 FunctionDomain1DVector domain(peakdataws->x(1).rawData());
1325 plotFunction(peak, backgroundfunction, domain);
1326 } else {
1327 // Throw exception if fit peak bad. This is NOT a PERMANANT solution.
1328 stringstream errss;
1329 errss << "Fit Peak @ " << peak->centre() << " Error! Chi^2 (false) = " << chi2
1330 << ". Do Not Know How To Proceed To Next Peak!";
1331 g_log.error(errss.str());
1332 throw runtime_error(errss.str());
1333 }
1334
1335 // 7. Debug output
1336 vector<string> parnames = peak->getParameterNames();
1337 stringstream debugss;
1338 debugss << "DB1251 Single Peak Confident Fit Result: Chi^2 = " << chi2 << '\n';
1339 for (auto &parname : parnames) {
1340 debugss << parname << " = " << peak->getParameter(parname) << '\n';
1341 }
1342 g_log.notice(debugss.str());
1343
1344 return goodfit;
1345}
1346
1347//----------------------------------------------------------------------------------------------
1359void FitPowderDiffPeaks::calculatePeakFitBoundary(size_t ileftpeak, size_t irightpeak, double &peakleftboundary,
1360 double &peakrightboundary) {
1361 BackToBackExponential_sptr leftpeak = m_vecPeakFunctions[ileftpeak].second.second;
1362 BackToBackExponential_sptr rightpeak = m_vecPeakFunctions[irightpeak].second.second;
1363
1364 // 1. Determine its left boundary
1365 peakleftboundary = leftpeak->centre() - PEAKFITRANGEFACTOR * leftpeak->fwhm();
1366
1367 int ileftneighbor = static_cast<int>(ileftpeak) - 1;
1368 if (ileftneighbor < 0) {
1369 // a) No left neighbor, compare to TOF_Min
1370 if (peakleftboundary < m_tofMin)
1371 peakleftboundary = m_tofMin;
1372 } else {
1373 // b) Compare to the right peak boundary of its left neighbor
1374 BackToBackExponential_sptr leftneighbor = m_vecPeakFunctions[ileftneighbor].second.second;
1375 double leftneighborrightbound = leftneighbor->centre() + PEAKBOUNDARYFACTOR * leftneighbor->fwhm();
1376 if (leftneighborrightbound > peakleftboundary)
1377 peakleftboundary = leftneighborrightbound;
1378 }
1379
1380 // 2. Determine its right boundary
1381 peakrightboundary = rightpeak->centre() + PEAKFITRANGEFACTOR * rightpeak->fwhm();
1382
1383 size_t irightneighbor = irightpeak + 1;
1384 if (irightneighbor < m_vecPeakFunctions.size()) {
1385 // a) right peak exists
1386 BackToBackExponential_sptr rightneighbor = m_vecPeakFunctions[irightneighbor].second.second;
1387 double rightneighborleftbound = rightneighbor->centre() - PEAKBOUNDARYFACTOR * rightneighbor->fwhm();
1388 if (rightneighborleftbound < peakrightboundary)
1389 peakrightboundary = rightneighborleftbound;
1390 }
1391}
1392
1393//======================= Fit 1 Set of Overlapped Peaks ======================
1394
1395//----------------------------------------------------------------------------
1407std::pair<bool, double> FitPowderDiffPeaks::doFitPeak(const Workspace2D_sptr &dataws,
1408 const BackToBackExponential_sptr &peakfunction,
1409 double guessedfwhm) {
1410 // 1. Set up boundary
1411 if (guessedfwhm > 0) {
1412 double tof_h = peakfunction->centre();
1413 double centerleftend = tof_h - guessedfwhm * 3.0;
1414 double centerrightend = tof_h + guessedfwhm * 3.0;
1415 auto centerbound =
1416 std::make_unique<BoundaryConstraint>(peakfunction.get(), "X0", centerleftend, centerrightend, false);
1417 peakfunction->addConstraint(std::move(centerbound));
1418
1419 g_log.debug() << "[DoFitPeak] Peak Center Boundary = " << centerleftend << ", " << centerrightend << '\n';
1420 }
1421
1422 // A > 0, B > 0, S > 0
1423 auto abound = std::make_unique<BoundaryConstraint>(peakfunction.get(), "A", 0.0000001, DBL_MAX, false);
1424 peakfunction->addConstraint(std::move(abound));
1425
1426 auto bbound = std::make_unique<BoundaryConstraint>(peakfunction.get(), "B", 0.0000001, DBL_MAX, false);
1427 peakfunction->addConstraint(std::move(bbound));
1428
1429 auto sbound = std::make_unique<BoundaryConstraint>(peakfunction.get(), "S", 0.0001, DBL_MAX, false);
1430 peakfunction->addConstraint(std::move(sbound));
1431
1432 // 2. Unfix all parameters
1433 vector<string> paramnames = peakfunction->getParameterNames();
1434 size_t numparams = paramnames.size();
1435 for (size_t i = 0; i < numparams; ++i)
1436 peakfunction->unfix(i);
1437
1438 // 3. Set up the fitting scheme
1439 vector<vector<string>> vecMinimizers;
1440 vector<vector<size_t>> vecMaxIterations;
1441 vector<vector<double>> vecDampings;
1442
1443 // a) Scheme 1: Levenberg and Levenger
1444 /*
1445 vector<string> minimizers(2);
1446 minimizers[0] = "Levenberg-MarquardtMD";
1447 minimizers[1] = "Levenberg-Marquardt";
1448 vector<size_t> maxiterations(2, 1000);
1449 vector<double> dampings(2, 0.0);
1450 vecMinimizers.emplace_back(minimizers);
1451 vecMaxIterations.emplace_back(maxiterations);
1452 vecDampings.emplace_back(dampings);
1453 */
1454
1455 vector<string> minimizers2(3);
1456 minimizers2[0] = "Simplex";
1457 minimizers2[1] = "Levenberg-MarquardtMD";
1458 minimizers2[2] = "Levenberg-Marquardt";
1459 vector<size_t> maxiterations2(3, 1000);
1460 maxiterations2[0] = 10000;
1461 vector<double> dampings2(3, 0.0);
1462 vecMinimizers.emplace_back(minimizers2);
1463 vecMaxIterations.emplace_back(maxiterations2);
1464 vecDampings.emplace_back(dampings2);
1465
1466 // 4. Fit in different sequential
1467 bool goodfit = false;
1468 size_t numschemes = vecMinimizers.size();
1469
1470 map<string, double> origparams, bestparams;
1471 storeFunctionParameters(peakfunction, origparams);
1472 bestparams = origparams;
1473 double bestchi2 = DBL_MAX;
1474
1475 for (size_t is = 0; is < numschemes; ++is) {
1476 // a) Restore the starting value
1477 restoreFunctionParameters(peakfunction, origparams);
1478
1479 // b) Fit in multiple steps
1480 double thischi2;
1481 bool localgoodfit = doFit1PeakSequential(dataws, 1, peakfunction, vecMinimizers[is], vecMaxIterations[is],
1482 vecDampings[is], thischi2);
1483
1484 // c) Book keep
1485 if (localgoodfit && !goodfit) {
1486 // First local good fit
1487 bestchi2 = thischi2;
1488 storeFunctionParameters(peakfunction, bestparams);
1489 goodfit = true;
1490 } else if (localgoodfit && goodfit) {
1491 // Not the first time to have a good fit
1492 if (thischi2 < bestchi2) {
1493 bestchi2 = thischi2;
1494 storeFunctionParameters(peakfunction, bestparams);
1495 }
1496 }
1497 } // ENDFOR
1498
1499 pair<bool, double> returnvalue = make_pair(goodfit, bestchi2);
1500
1501 return returnvalue;
1502}
1503
1504//----------------------------------------------------------------------------
1507void FitPowderDiffPeaks::storeFunctionParameters(const IFunction_sptr &function, std::map<string, double> &parammaps) {
1508 vector<string> paramnames = function->getParameterNames();
1509 parammaps.clear();
1510 for (auto &paramname : paramnames)
1511 parammaps.emplace(paramname, function->getParameter(paramname));
1512}
1513
1514//----------------------------------------------------------------------------
1517void FitPowderDiffPeaks::restoreFunctionParameters(const IFunction_sptr &function, map<string, double> parammap) {
1518 vector<string> paramnames = function->getParameterNames();
1519 for (auto &parname : paramnames) {
1520 auto miter = parammap.find(parname);
1521 if (miter != parammap.end())
1522 function->setParameter(parname, miter->second);
1523 }
1524}
1525
1526//----------------------------------------------------------------------------
1539bool FitPowderDiffPeaks::doFit1PeakSimple(const Workspace2D_sptr &dataws, size_t workspaceindex,
1540 const BackToBackExponential_sptr &peakfunction, const string &minimzername,
1541 size_t maxiteration, double &chi2) {
1542 stringstream dbss;
1543 dbss << peakfunction->asString() << '\n';
1544 dbss << "Starting Value: ";
1545 vector<string> names = peakfunction->getParameterNames();
1546 for (auto &name : names)
1547 dbss << name << "= " << peakfunction->getParameter(name) << ", \t";
1548 for (size_t i = 0; i < dataws->x(workspaceindex).size(); ++i)
1549 dbss << dataws->x(workspaceindex)[i] << "\t\t" << dataws->y(workspaceindex)[i] << "\t\t"
1550 << dataws->e(workspaceindex)[i] << '\n';
1551 g_log.debug() << "DBx430 " << dbss.str() << '\n';
1552
1553 // 1. Peak height
1554 if (peakfunction->height() < 1.0E-5)
1555 peakfunction->setHeight(4.0);
1556
1557 // 2. Create fit
1558 Algorithm_sptr fitalg = createChildAlgorithm("Fit", -1, -1, true);
1559 fitalg->initialize();
1560
1561 // 3. Set
1562 fitalg->setProperty("Function", std::dynamic_pointer_cast<API::IFunction>(peakfunction));
1563 fitalg->setProperty("InputWorkspace", dataws);
1564 fitalg->setProperty("WorkspaceIndex", static_cast<int>(workspaceindex));
1565 fitalg->setProperty("Minimizer", minimzername);
1566 fitalg->setProperty("CostFunction", "Least squares");
1567 fitalg->setProperty("MaxIterations", static_cast<int>(maxiteration));
1568 fitalg->setProperty("Output", "FitPeak");
1569
1570 // 3. Execute and parse the result
1571 bool isexecute = fitalg->execute();
1572 bool fitsuccess = false;
1573 chi2 = DBL_MAX;
1574
1575 if (isexecute) {
1576 std::string fitresult = parseFitResult(fitalg, chi2, fitsuccess);
1577
1578 // Figure out result
1579 g_log.information() << "[DBx138A] Fit Peak @ " << peakfunction->centre() << " Result:" << fitsuccess << "\n"
1580 << "Detailed info = " << fitresult << ", Chi^2 = " << chi2 << '\n';
1581
1582 // Debug information output
1583 API::ITableWorkspace_sptr paramws = fitalg->getProperty("OutputParameters");
1584 std::string infofit = parseFitParameterWorkspace(paramws);
1585 g_log.information() << "Fitted Parameters: \n" << infofit << '\n';
1586 } else {
1587 g_log.error() << "[DBx128B] Failed to execute fitting peak @ " << peakfunction->centre() << '\n';
1588 }
1589
1590 return fitsuccess;
1591}
1592
1593//----------------------------------------------------------------------------------------------
1603bool FitPowderDiffPeaks::doFit1PeakSequential(const Workspace2D_sptr &dataws, size_t workspaceindex,
1604 const BackToBackExponential_sptr &peakfunction,
1605 vector<string> minimzernames, vector<size_t> maxiterations,
1606 const vector<double> &dampfactors, double &chi2) {
1607 // 1. Check
1608 if (minimzernames.size() != maxiterations.size() && minimzernames.size() != dampfactors.size()) {
1609 throw runtime_error("doFit1PeakSequential should have the input vectors of same size.");
1610 }
1611
1612 // 2. Start Chi2
1613 map<string, double> parambeforefit;
1614 storeFunctionParameters(peakfunction, parambeforefit);
1615
1616 double startchi2;
1617 doFit1PeakSimple(dataws, workspaceindex, peakfunction, "Levenberg-MarquardtMD", 0, startchi2);
1618
1619 restoreFunctionParameters(peakfunction, parambeforefit);
1620
1621 double currchi2 = startchi2;
1622 bool goodfit = false;
1623
1624 // 3. Fit sequentially
1625 for (size_t i = 0; i < minimzernames.size(); ++i) {
1626 string minimizer = minimzernames[i];
1627 size_t maxiteration = maxiterations[i];
1628 g_log.notice() << "DBx315 Start Chi2 = " << startchi2 << ", Minimizer = " << minimizer
1629 << ", Max Iterations = " << maxiteration << ", Workspace Index = " << workspaceindex
1630 << ", Data Range = " << dataws->x(workspaceindex)[0] << ", " << dataws->x(workspaceindex).back()
1631 << '\n';
1632
1633 storeFunctionParameters(peakfunction, parambeforefit);
1634
1635 double newchi2;
1636 bool localgoodfit = doFit1PeakSimple(dataws, workspaceindex, peakfunction, minimizer, maxiteration, newchi2);
1637
1638 if (localgoodfit && newchi2 < currchi2) {
1639 // A better solution
1640 currchi2 = newchi2;
1641 goodfit = true;
1642 } else {
1643 // A same of worse one
1644 restoreFunctionParameters(peakfunction, parambeforefit);
1645 g_log.information() << "DBx315C Fit Failed. Fit Good = " << localgoodfit << '\n';
1646 }
1647 }
1648
1649 // 4. Return
1650 chi2 = currchi2;
1651
1652 return goodfit;
1653}
1654
1655//----------------------------------------------------------------------------
1659 double in_center, double leftfwhm, double rightfwhm, double &center,
1660 double &sigma, double &height) {
1661 // 1. Estimate
1662 const auto &X = dataws->x(workspaceindex);
1663 const auto &Y = dataws->y(workspaceindex);
1664
1665 height = 0;
1666 for (size_t i = 1; i < X.size(); ++i) {
1667 height += (X[i] - X[i - 1]) * Y[i];
1668 }
1669 sigma = (leftfwhm + rightfwhm) * 0.5;
1670
1671 // 2. Use factory to generate Gaussian
1672 auto temppeak = API::FunctionFactory::Instance().createFunction("Gaussian");
1673 auto gaussianpeak = std::dynamic_pointer_cast<API::IPeakFunction>(temppeak);
1674 gaussianpeak->setHeight(height);
1675 gaussianpeak->setCentre(in_center);
1676 gaussianpeak->setFwhm(sigma);
1677
1678 // b) Constraint
1679 double centerleftend = in_center - leftfwhm * 0.5;
1680 double centerrightend = in_center + rightfwhm * 0.5;
1681 auto centerbound =
1682 std::make_unique<BoundaryConstraint>(gaussianpeak.get(), "PeakCentre", centerleftend, centerrightend, false);
1683 gaussianpeak->addConstraint(std::move(centerbound));
1684
1685 // 3. Fit
1686 auto fitalg = createChildAlgorithm("Fit", -1, -1, true);
1687 fitalg->initialize();
1688
1689 fitalg->setProperty("Function", std::dynamic_pointer_cast<API::IFunction>(gaussianpeak));
1690 fitalg->setProperty("InputWorkspace", dataws);
1691 fitalg->setProperty("WorkspaceIndex", 1);
1692 fitalg->setProperty("Minimizer", "Levenberg-MarquardtMD");
1693 fitalg->setProperty("CostFunction", "Least squares");
1694 fitalg->setProperty("MaxIterations", 1000);
1695 fitalg->setProperty("Output", "FitGaussianPeak");
1696
1697 // iv) Result
1698 bool successfulfit = fitalg->execute();
1699 if (!fitalg->isExecuted() || !successfulfit) {
1700 // Early return due to bad fit
1701 g_log.warning() << "Fitting Gaussian peak for peak around " << gaussianpeak->centre() << '\n';
1702 return false;
1703 }
1704
1705 double chi2;
1706 bool fitsuccess;
1707 std::string fitresult = parseFitResult(fitalg, chi2, fitsuccess);
1708 g_log.information() << "[Fit Gaussian Peak] Successful = " << fitsuccess << ", Result:\n" << fitresult << '\n';
1709
1710 // 4. Get result
1711 center = gaussianpeak->centre();
1712 height = gaussianpeak->height();
1713 double fwhm = gaussianpeak->fwhm();
1714 if (fwhm <= 0.0) {
1715 return false;
1716 }
1717 sigma = fwhm / 2.35;
1718
1719 // 5. Debug output
1720 API::ITableWorkspace_sptr paramws = fitalg->getProperty("OutputParameters");
1721 std::string infofit = parseFitParameterWorkspace(paramws);
1722 g_log.information() << "[DBx133] Fitted Gaussian Parameters: \n" << infofit << '\n';
1723
1724 return true;
1725}
1726
1727//----------------------------------------------------------------------------------------------
1733bool FitPowderDiffPeaks::fitOverlappedPeaks(vector<BackToBackExponential_sptr> peaks,
1734 const BackgroundFunction_sptr &backgroundfunction, double gfwhm) {
1735 // 1. Sort peak if necessary
1736 vector<pair<double, BackToBackExponential_sptr>> tofpeakpairs(peaks.size());
1737 for (size_t i = 0; i < peaks.size(); ++i)
1738 tofpeakpairs[i] = make_pair(peaks[i]->centre(), peaks[i]);
1739 sort(tofpeakpairs.begin(), tofpeakpairs.end());
1740
1741 // 2. Determine range of the data
1742 BackToBackExponential_sptr leftpeak = tofpeakpairs[0].second;
1743 BackToBackExponential_sptr rightpeak = tofpeakpairs.back().second;
1744 double peaksleftboundary, peaksrightboundary;
1745 if (gfwhm <= 0) {
1746 // Use peaks' preset value
1747 peaksleftboundary = leftpeak->centre() - 4 * leftpeak->fwhm();
1748 peaksrightboundary = rightpeak->centre() + 4 * rightpeak->fwhm();
1749 } else {
1750 // Use user input's guess fwhm
1751 peaksleftboundary = leftpeak->centre() - 4 * gfwhm;
1752 peaksrightboundary = rightpeak->centre() + 4 * gfwhm;
1753 }
1754
1755 // 3. Build partial data workspace
1756 Workspace2D_sptr peaksws = buildPartialWorkspace(m_dataWS, m_wsIndex, peaksleftboundary, peaksrightboundary);
1757
1758 // 4. Remove background
1759 estimateBackgroundCoarse(peaksws, backgroundfunction, 0, 2, 1);
1760
1761 // [DB] Debug output
1762 stringstream piss;
1763 piss << peaks.size() << "-Peaks Group Information: \n";
1764 for (size_t ipk = 0; ipk < tofpeakpairs.size(); ++ipk) {
1765 BackToBackExponential_sptr tmppeak = tofpeakpairs[ipk].second;
1766 piss << "Peak " << ipk << " @ TOF = " << tmppeak->centre() << ", A = " << tmppeak->getParameter("A")
1767 << ", B = " << tmppeak->getParameter("B") << ", S = " << tmppeak->getParameter("S")
1768 << ", FWHM = " << tmppeak->fwhm() << '\n';
1769 }
1770 g_log.information() << "[DB1034] " << piss.str();
1771
1772 stringstream datass;
1773 datass << "Partial workspace for peaks: \n";
1774 for (size_t i = 0; i < peaksws->x(0).size(); ++i)
1775 datass << peaksws->x(1)[i] << "\t\t" << peaksws->y(1)[i] << "\t\t" << peaksws->e(1)[i] << "\t\t" << peaksws->y(0)[i]
1776 << '\n';
1777 g_log.information() << "[DB1042] " << datass.str();
1778
1779 // 5. Estimate peak height according to pre-set peak value
1780 estimatePeakHeightsLeBail(peaksws, 1, peaks);
1781
1782 // 6. Set bundaries
1784
1785 // 7. Set up the composite function
1786 CompositeFunction_sptr peaksfunction(new CompositeFunction());
1787 for (auto &peak : peaks)
1788 peaksfunction->addFunction(peak);
1789
1790 // 8. Fit multiple peaks
1791 vector<double> chi2s;
1792 vector<bool> fitgoods;
1793 bool fitsuccess = doFitMultiplePeaks(peaksws, 1, peaksfunction, peaks, fitgoods, chi2s);
1794
1795 // 9. Plot peaks
1796 if (fitsuccess) {
1797 FunctionDomain1DVector domain(peaksws->x(1).rawData());
1798 plotFunction(peaksfunction, backgroundfunction, domain);
1799 }
1800
1801 return fitsuccess;
1802}
1803
1804//----------------------------------------------------------------------------------------------
1808 const CompositeFunction_sptr &peaksfunc,
1809 vector<BackToBackExponential_sptr> peakfuncs, vector<bool> &vecfitgood,
1810 vector<double> &vecchi2s) {
1811 // 0. Pre-debug output
1812 stringstream dbss;
1813 dbss << "[DBx529] Composite Function: " << peaksfunc->asString();
1814 g_log.notice(dbss.str());
1815
1816 // 1. Fit peaks intensities first
1817 const size_t numpeaks = peakfuncs.size();
1818 map<string, double> peaksfuncparams;
1819
1820 // a) Set up fit/fix
1821 vector<string> peakparnames = peakfuncs[0]->getParameterNames();
1822 for (size_t ipn = 0; ipn < peakparnames.size(); ++ipn) {
1823 bool isI = peakparnames[ipn] == "I";
1824
1825 for (size_t ipk = 0; ipk < numpeaks; ++ipk) {
1826 BackToBackExponential_sptr thispeak = peakfuncs[ipk];
1827 if (isI)
1828 thispeak->unfix(ipn);
1829 else
1830 thispeak->fix(ipn);
1831 }
1832 }
1833
1834 stringstream dbss1;
1835 dbss1 << "[DBx529A] Composite Function: " << peaksfunc->asString();
1836 g_log.notice(dbss1.str());
1837
1838 // b) Fit
1839 double chi2;
1840 bool fitgood = doFitNPeaksSimple(dataws, wsindex, peaksfunc, peakfuncs, "Levenberg-MarquardtMD", 1000, chi2);
1841 bool evergood = fitgood;
1842
1843 // c) Process result; possibly early return
1844 if (!fitgood) {
1845 vecfitgood.resize(numpeaks, false);
1846 vecchi2s.resize(numpeaks, -1.0);
1847 return false;
1848 } else {
1849 vecfitgood.resize(numpeaks, true);
1850 vecchi2s.resize(numpeaks, chi2);
1851 }
1852
1853 // 2. Fit A/B/S peak by peak
1854 for (size_t ipkfit = 0; ipkfit < numpeaks; ++ipkfit) {
1855 // a) Fix / unfix parameters
1856 for (size_t ipk = 0; ipk < numpeaks; ++ipk) {
1857 BackToBackExponential_sptr thispeak = peakfuncs[ipk];
1858 for (size_t iparam = 0; iparam < peakparnames.size(); ++iparam) {
1859 if (ipk == ipkfit) {
1860 // Peak to have parameters fit
1861 thispeak->unfix(iparam);
1862 } else {
1863 // Not the peak to fit, fix all
1864 thispeak->fix(iparam);
1865 }
1866 }
1867 }
1868
1869 // b) Fit
1870 storeFunctionParameters(peaksfunc, peaksfuncparams);
1871
1872 fitgood = doFitNPeaksSimple(dataws, wsindex, peaksfunc, peakfuncs, "Levenberg-MarquardtMD", 1000, chi2);
1873
1874 // not required. before loop starts, evergood=fitgood WITH fitgood==true
1875 // evergood = evergood || fitgood;
1876
1877 // c) Process the result
1878 if (!fitgood)
1879 restoreFunctionParameters(peaksfunc, peaksfuncparams);
1880 } // END OF FIT ALL SINGLE PEAKS
1881
1882 // 3. Fit all parameters (dangerous)
1883 for (size_t ipk = 0; ipk < numpeaks; ++ipk) {
1884 BackToBackExponential_sptr thispeak = peakfuncs[ipk];
1885 for (size_t iparam = 0; iparam < peakparnames.size(); ++iparam)
1886 thispeak->unfix(iparam);
1887 }
1888
1889 storeFunctionParameters(peaksfunc, peaksfuncparams);
1890 fitgood = doFitNPeaksSimple(dataws, wsindex, peaksfunc, peakfuncs, "Levenberg-MarquardtMD", 1000, chi2);
1891 // not required. before, evergood=fitgood WITH fitgood==true
1892 // evergood = evergood || fitgood;
1893
1894 if (!fitgood)
1895 restoreFunctionParameters(peaksfunc, peaksfuncparams);
1896
1897 // -1. Final debug output
1898 FunctionDomain1DVector domain(dataws->x(wsindex).rawData());
1899 FunctionValues values(domain);
1900 peaksfunc->function(domain, values);
1901 stringstream rss;
1902 for (size_t i = 0; i < domain.size(); ++i)
1903 rss << domain[i] << "\t\t" << values[i] << '\n';
1904 g_log.information() << "[T] Multiple peak fitting pattern:\n" << rss.str();
1905
1906 return evergood;
1907}
1908
1909//----------------------------------------------------------------------------------------------
1916 vector<BackToBackExponential_sptr> peaks) {
1917 // 1. Build data structures
1918 FunctionDomain1DVector domain(dataws->x(wsindex).rawData());
1919 FunctionValues values(domain);
1920 vector<vector<double>> peakvalues;
1921 for (size_t i = 0; i < (peaks.size() + 1); ++i) {
1922 vector<double> peakvalue(domain.size(), 0.0);
1923 peakvalues.emplace_back(peakvalue);
1924 }
1925
1926 // 2. Calcualte peak values
1927 size_t isum = peaks.size();
1928 for (size_t ipk = 0; ipk < peaks.size(); ++ipk) {
1929 BackToBackExponential_sptr thispeak = peaks[ipk];
1930 thispeak->setHeight(1.0);
1931 thispeak->function(domain, values);
1932 for (size_t j = 0; j < domain.size(); ++j) {
1933 peakvalues[ipk][j] = values[j];
1934 peakvalues[isum][j] += values[j];
1935 }
1936 }
1937
1938 // 3. Calculate peak height
1939 const auto &vecY = dataws->y(wsindex);
1940 for (size_t ipk = 0; ipk < peaks.size(); ++ipk) {
1941 double height = 0.0;
1942 for (size_t j = 0; j < domain.size() - 1; ++j) {
1943 if (vecY[j] > 0.0 && peakvalues[isum][j] > 1.0E-5) {
1944 double dtof = domain[j + 1] - domain[j];
1945 double temp = vecY[j] * peakvalues[ipk][j] / peakvalues[isum][j] * dtof;
1946 height += temp;
1947 }
1948 }
1949
1950 BackToBackExponential_sptr thispeak = peaks[ipk];
1951 thispeak->setHeight(height);
1952
1953 g_log.information() << "[DBx256] Peak @ " << thispeak->centre()
1954 << " Set Guessed Height (LeBail) = " << thispeak->height() << '\n';
1955 }
1956}
1957
1958//----------------------------------------------------------------------------------------------
1961void FitPowderDiffPeaks::setOverlappedPeaksConstraints(const vector<BackToBackExponential_sptr> &peaks) {
1962 for (const auto &thispeak : peaks) {
1963 // 1. Set constraint on X.
1964 double fwhm = thispeak->fwhm();
1965 double centre = thispeak->centre();
1966 double leftcentrebound = centre - 0.5 * fwhm;
1967 double rightcentrebound = centre + 0.5 * fwhm;
1968
1969 auto bc = std::make_unique<BoundaryConstraint>(thispeak.get(), "X0", leftcentrebound, rightcentrebound, false);
1970 thispeak->addConstraint(std::move(bc));
1971 }
1972}
1973
1974//----------------------------------------------------------------------------------------------
1978 const CompositeFunction_sptr &peaksfunc,
1979 const vector<BackToBackExponential_sptr> &peakfuncs,
1980 const string &minimizername, size_t maxiteration, double &chi2) {
1981 // 1. Debug output
1982 stringstream dbss0;
1983 dbss0 << "Starting Value: ";
1984 vector<string> names = peaksfunc->getParameterNames();
1985 for (auto &name : names)
1986 dbss0 << name << "= " << peaksfunc->getParameter(name) << ", \t";
1987 g_log.information() << "DBx430 " << dbss0.str() << '\n';
1988
1989 // 2. Create fit
1990 Algorithm_sptr fitalg = createChildAlgorithm("Fit", -1, -1, true);
1991 fitalg->initialize();
1992
1993 // 3. Set
1994 fitalg->setProperty("Function", std::dynamic_pointer_cast<API::IFunction>(peaksfunc));
1995 fitalg->setProperty("InputWorkspace", dataws);
1996 fitalg->setProperty("WorkspaceIndex", static_cast<int>(wsindex));
1997 fitalg->setProperty("Minimizer", minimizername);
1998 fitalg->setProperty("CostFunction", "Least squares");
1999 fitalg->setProperty("MaxIterations", static_cast<int>(maxiteration));
2000 fitalg->setProperty("Output", "FitPeak");
2001
2002 // 3. Execute and parse the result
2003 bool isexecute = fitalg->execute();
2004 bool fitsuccess = false;
2005 chi2 = DBL_MAX;
2006
2007 // 4. Output
2008 stringstream dbss;
2009 dbss << "Fit N-Peaks @ ";
2010 for (auto &peakfunc : peakfuncs)
2011 dbss << peakfunc->centre() << ", ";
2012
2013 if (isexecute) {
2014 // Figure out result
2015 std::string fitresult = parseFitResult(fitalg, chi2, fitsuccess);
2016
2017 dbss << " Result:" << fitsuccess << "\n"
2018 << "Detailed info = " << fitresult;
2019
2020 g_log.information() << "[DBx149A] " << dbss.str() << '\n';
2021
2022 // Debug information output
2023 API::ITableWorkspace_sptr paramws = fitalg->getProperty("OutputParameters");
2024 std::string infofit = parseFitParameterWorkspace(paramws);
2025 g_log.information() << "[DBx149B] Fitted Parameters: \n" << infofit << '\n';
2026 } else {
2027 dbss << ": Failed ";
2028 g_log.error() << "[DBx149C] " << dbss.str() << '\n';
2029 }
2030
2031 return fitsuccess;
2032}
2033
2034//=================================== Process Fit Result
2035//=====================================
2036//----------------------------------------------------------------------------------------------
2039std::string FitPowderDiffPeaks::parseFitResult(const API::IAlgorithm_sptr &fitalg, double &chi2, bool &fitsuccess) {
2040 stringstream rss;
2041
2042 chi2 = fitalg->getProperty("OutputChi2overDoF");
2043 string fitstatus = fitalg->getProperty("OutputStatus");
2044
2045 fitsuccess = (fitstatus == "success");
2046
2047 rss << " [Algorithm Fit]: Chi^2 = " << chi2 << "; Fit Status = " << fitstatus;
2048
2049 return rss.str();
2050}
2051
2052//----------------------------------------------------------------------------------------------
2056 // 1. Check
2057 if (!paramws) {
2058 g_log.warning() << "Input table workspace is NULL. \n";
2059 return "";
2060 }
2061
2062 // 2. Parse
2063 std::stringstream msgss;
2064 size_t numrows = paramws->rowCount();
2065 for (size_t i = 0; i < numrows; ++i) {
2066 API::TableRow row = paramws->getRow(i);
2067 std::string parname;
2068 double parvalue, parerror;
2069 row >> parname >> parvalue >> parerror;
2070
2071 msgss << parname << " = " << setw(10) << setprecision(5) << parvalue << " +/- " << setw(10) << setprecision(5)
2072 << parerror << '\n';
2073 }
2074
2075 return msgss.str();
2076}
2077
2078//================================ Process Input/Output
2079//======================================
2080//----------------------------------------------------------------------------------------------
2085 // 1. Check column orders
2086 std::vector<std::string> colnames = parameterWS->getColumnNames();
2087 if (colnames.size() < 2) {
2088 stringstream errss;
2089 errss << "Input parameter table workspace does not have enough number of "
2090 "columns. "
2091 << " Number of columns = " << colnames.size() << " >= 2 as required. ";
2092 g_log.error(errss.str());
2093 throw std::runtime_error(errss.str());
2094 }
2095
2096 if (colnames[0] != "Name" || colnames[1] != "Value") {
2097 stringstream errss;
2098 errss << "Input parameter table workspace does not have the columns in "
2099 "order as "
2100 << "Name, Value and etc. ";
2101 g_log.error(errss.str());
2102 throw std::runtime_error(errss.str());
2103 }
2104
2105 size_t numrows = parameterWS->rowCount();
2106
2107 g_log.notice() << "[DBx409] Import TableWorkspace " << parameterWS->getName() << " containing " << numrows
2108 << " instrument profile parameters\n";
2109
2110 // 2. Import data to maps
2111 std::string parname;
2112 double value;
2113 m_instrumentParmaeters.clear();
2114
2115 for (size_t ir = 0; ir < numrows; ++ir) {
2116 API::TableRow trow = parameterWS->getRow(ir);
2117 trow >> parname >> value;
2118 m_instrumentParmaeters.emplace(parname, value);
2119 g_log.notice() << "[DBx211] Import parameter " << parname << ": " << value << '\n';
2120 }
2121}
2122
2125void FitPowderDiffPeaks::parseBraggPeakTable(const TableWorkspace_sptr &peakws, vector<map<string, double>> &parammaps,
2126 vector<map<string, int>> &hklmaps) {
2127 // 1. Get columns' types and names
2128 vector<string> paramnames = peakws->getColumnNames();
2129 size_t numcols = paramnames.size();
2130 vector<string> coltypes(numcols);
2131 for (size_t i = 0; i < numcols; ++i) {
2132 Column_sptr col = peakws->getColumn(i);
2133 string coltype = col->type();
2134 coltypes[i] = coltype;
2135 }
2136
2137 // 2. Parse table rows
2138 size_t numrows = peakws->rowCount();
2139 for (size_t irow = 0; irow < numrows; ++irow) {
2140 // 1. Create map
2141 map<string, int> intmap;
2142 map<string, double> doublemap;
2143
2144 // 2. Parse
2145 for (size_t icol = 0; icol < numcols; ++icol) {
2146 string coltype = coltypes[icol];
2147 string colname = paramnames[icol];
2148
2149 if (coltype == "int") {
2150 // Integer
2151 int temp = peakws->cell<int>(irow, icol);
2152 intmap.emplace(colname, temp);
2153 } else if (coltype == "double") {
2154 // Double
2155 double temp = peakws->cell<double>(irow, icol);
2156 doublemap.emplace(colname, temp);
2157 }
2158
2159 } // ENDFOR Column
2160
2161 parammaps.emplace_back(doublemap);
2162 hklmaps.emplace_back(intmap);
2163
2164 } // ENDFOR Row
2165
2166 g_log.information() << "Import " << hklmaps.size() << " entries from Bragg peak TableWorkspace " << peakws->getName()
2167 << '\n';
2168}
2169
2170//----------------------------------------------------------------------------
2174Workspace2D_sptr FitPowderDiffPeaks::genOutputFittedPatternWorkspace(std::vector<double> pattern, int workspaceindex) {
2175 // 1. Init
2176 const auto &X = m_dataWS->x(workspaceindex);
2177
2178 if (pattern.size() != X.size()) {
2179 stringstream errmsg;
2180 errmsg << "Input pattern (" << pattern.size() << ") and algorithm's input workspace (" << X.size()
2181 << ") have different size. ";
2182 g_log.error() << errmsg.str() << '\n';
2183 throw std::logic_error(errmsg.str());
2184 }
2185
2186 size_t numpts = X.size();
2187
2188 // 2. Create data workspace
2189 Workspace2D_sptr dataws = std::dynamic_pointer_cast<Workspace2D>(
2190 WorkspaceFactory::Instance().create("Workspace2D", 5, pattern.size(), pattern.size()));
2191
2192 // 3. Set up
2193 for (size_t iw = 0; iw < 5; ++iw) {
2194 dataws->setSharedX(iw, m_dataWS->sharedX(workspaceindex));
2195 }
2196
2197 dataws->setSharedY(0, m_dataWS->sharedY(workspaceindex));
2198 dataws->mutableY(1) = pattern;
2199 dataws->mutableY(2) = m_dataWS->y(workspaceindex) - pattern;
2200
2201 // 4. Debug
2202 // FIXME Remove this section after unit test is finished.
2203 std::ofstream ofile;
2204 ofile.open("fittedpeaks.dat");
2205 for (size_t i = 0; i < numpts; ++i) {
2206 ofile << setw(12) << setprecision(5) << X[i] << setw(12) << setprecision(5) << pattern[i] << setw(12)
2207 << setprecision(5) << dataws->y(0)[i] << setw(12) << setprecision(5) << dataws->y(2)[i] << '\n';
2208 }
2209 ofile.close();
2210
2211 return dataws;
2212}
2213
2214//----------------------------------------------------------------------------
2218 // 1. Check and prepare
2219 if (m_vecPeakFunctions.size() != m_peakFitChi2.size()) {
2220 throw runtime_error("Wrong definition of m_peakFitChi2");
2221 }
2222
2223 size_t numpeaks = m_vecPeakFunctions.size();
2224
2225 // 2. Collect parameters of peak fitted good
2226 vector<double> vecdh, vectofh, vecalpha, vecbeta, vecsigma, vecchi2;
2227 for (size_t i = 0; i < numpeaks; ++i) {
2228 double &chi2 = m_peakFitChi2[i];
2229 if (chi2 > 0) {
2230 // a) Get values
2231 double dh = m_vecPeakFunctions[i].first;
2232 BackToBackExponential_sptr peak = m_vecPeakFunctions[i].second.second;
2233
2234 double p_a = peak->getParameter("A");
2235 double p_b = peak->getParameter("B");
2236 double p_x = peak->getParameter("X0");
2237 double p_s = peak->getParameter("S");
2238
2239 // b) To vectors
2240 vecchi2.emplace_back(chi2);
2241 vecdh.emplace_back(dh);
2242 vectofh.emplace_back(p_x);
2243 vecalpha.emplace_back(p_a);
2244 vecbeta.emplace_back(p_b);
2245 vecsigma.emplace_back(p_s);
2246 }
2247 } // ENDFOR i(peak)
2248
2249 // 3. Create workspace2D
2250 size_t numgoodpeaks = vecdh.size();
2251 Workspace2D_sptr paramws = std::dynamic_pointer_cast<Workspace2D>(
2252 WorkspaceFactory::Instance().create("Workspace2D", 4, numgoodpeaks, numgoodpeaks));
2253 for (size_t j = 0; j < 4; ++j) {
2254 paramws->mutableX(j) = vecdh;
2255 paramws->mutableE(j) = vecchi2;
2256 }
2257 paramws->mutableY(0) = vectofh;
2258 paramws->mutableY(1) = vecalpha;
2259 paramws->mutableY(2) = vecbeta;
2260 paramws->mutableY(3) = vecsigma;
2261
2262 // 4. Set Axis label
2263 paramws->getAxis(0)->setUnit("dSpacing");
2264
2265 auto tAxis = std::make_unique<TextAxis>(4);
2266 tAxis->setLabel(0, "X0");
2267 tAxis->setLabel(1, "A");
2268 tAxis->setLabel(2, "B");
2269 tAxis->setLabel(3, "S");
2270
2271 paramws->replaceAxis(1, std::move(tAxis));
2272
2273 return paramws;
2274}
2275
2276//----------------------------------------------------------------------------
2281pair<TableWorkspace_sptr, TableWorkspace_sptr> FitPowderDiffPeaks::genPeakParametersWorkspace() {
2282 // 1. Debug/Test Output
2283 for (size_t i = 0; i < m_vecPeakFunctions.size(); ++i) {
2284 g_log.debug() << "Peak @ d = " << m_vecPeakFunctions[i].first << ": Chi^2 = " << m_peakFitChi2[i] << '\n';
2285 }
2286
2287 if (m_vecPeakFunctions.size() != m_peakFitChi2.size()) {
2288 throw runtime_error("Wrong definition of m_peakFitChi2");
2289 }
2290
2291 size_t numpeaks = m_vecPeakFunctions.size();
2292 vector<double> vectofh(numpeaks), vecalpha(numpeaks), vecbeta(numpeaks), vecsigma(numpeaks);
2293
2294 // 2. Generate the TableWorkspace for peak parameters
2295 auto tablewsptr = new TableWorkspace();
2296 TableWorkspace_sptr tablews = TableWorkspace_sptr(tablewsptr);
2297
2298 tablews->addColumn("int", "H");
2299 tablews->addColumn("int", "K");
2300 tablews->addColumn("int", "L");
2301
2302 tablews->addColumn("double", "d_h");
2303 tablews->addColumn("double", "TOF_h");
2304 tablews->addColumn("double", "Height");
2305 tablews->addColumn("double", "Alpha");
2306 tablews->addColumn("double", "Beta");
2307 tablews->addColumn("double", "Sigma");
2308 tablews->addColumn("double", "Chi2");
2309
2310 /*
2311 stringstream outbuf;
2312 outbuf << setw(10) << "H" << setw(10) << "K" << setw(10) << "L"
2313 << setw(10) << "d_h" << setw(10) << "X0" << setw(10) << "I"
2314 << setw(10) << "A" << setw(10) << "B" << setw(10) << "S" << setw(10) <<
2315 "Chi2\n";
2316 */
2317
2318 for (size_t i = 0; i < numpeaks; ++i) {
2319 double &chi2 = m_peakFitChi2[i];
2320 if (chi2 > 0) {
2321 // Bad fit peak has chi^2 < 0;
2322 double dh = m_vecPeakFunctions[i].first;
2323 vector<int> &hkl = m_vecPeakFunctions[i].second.first;
2324 BackToBackExponential_sptr peak = m_vecPeakFunctions[i].second.second;
2325
2326 TableRow newrow = tablews->appendRow();
2327
2328 // i. H, K, L, d_h
2329 newrow << hkl[0] << hkl[1] << hkl[2] << dh;
2330
2331 // ii. A, B, I, S, X0
2332 double p_a = peak->getParameter("A");
2333 double p_b = peak->getParameter("B");
2334 double p_i = peak->getParameter("I");
2335 double p_x = peak->getParameter("X0");
2336 double p_s = peak->getParameter("S");
2337 newrow << p_x << p_i << p_a << p_b << p_s;
2338
2339 // iii. Chi^2
2340 newrow << chi2;
2341
2342 // iv. Prepare for Z-score
2343 // vectofh.emplace_back(p_x);
2344 // vecalpha.emplace_back(p_a);
2345 // vecbeta.emplace_back(p_b);
2346 // vecsigma.emplace_back(p_s);
2347 vectofh[i] = p_x;
2348 vecalpha[i] = p_a;
2349 vecbeta[i] = p_b;
2350 vecsigma[i] = p_s;
2351
2352 /*
2353 outbuf << setw(10) << setprecision(5) << chi2 << '\n';
2354 outbuf << setw(10) << hkl[0] << setw(10) << hkl[1] << setw(10) << hkl[2]
2355 << setw(10) << setprecision(5) << dh;
2356 outbuf << setw(10) << setprecision(5) << p_x
2357 << setw(10) << setprecision(5) << p_i
2358 << setw(10) << setprecision(5) << p_a
2359 << setw(10) << setprecision(5) << p_b
2360 << setw(10) << setprecision(5) << p_s;
2361 */
2362 }
2363 } // ENDFOR i(peak)
2364
2365 // 3. Z-score table
2366 // i. Calculate Z-scores
2367 vector<double> zcentres = Kernel::getZscore(vectofh);
2368 vector<double> zalphas = Kernel::getZscore(vecalpha);
2369 vector<double> zbetas = Kernel::getZscore(vecbeta);
2370 vector<double> zsigma = Kernel::getZscore(vecsigma);
2371
2372 // ii. Build table workspace for Z scores
2373 auto ztablewsptr = new TableWorkspace();
2374 TableWorkspace_sptr ztablews = TableWorkspace_sptr(ztablewsptr);
2375
2376 ztablews->addColumn("int", "H");
2377 ztablews->addColumn("int", "K");
2378 ztablews->addColumn("int", "L");
2379
2380 ztablews->addColumn("double", "d_h");
2381 ztablews->addColumn("double", "Z_TOF_h");
2382 ztablews->addColumn("double", "Z_Alpha");
2383 ztablews->addColumn("double", "Z_Beta");
2384 ztablews->addColumn("double", "Z_Sigma");
2385
2386 // iii. Set values
2387 for (size_t i = 0; i < m_vecPeakFunctions.size(); ++i) {
2388 double chi2 = m_peakFitChi2[i];
2389 if (chi2 > 0) {
2390 // A good fit has chi^2 larger than 0
2391 double dh = m_vecPeakFunctions[i].first;
2392 vector<int> &hkl = m_vecPeakFunctions[i].second.first;
2393
2394 TableRow newrow = ztablews->appendRow();
2395 newrow << hkl[0] << hkl[1] << hkl[2] << dh;
2396
2397 // ii. Z scores
2398 double p_x = zcentres[i];
2399 double p_a = zalphas[i];
2400 double p_b = zbetas[i];
2401 double p_s = zsigma[i];
2402
2403 newrow << p_x << p_a << p_b << p_s;
2404 }
2405 } // ENDFOR i(peak)
2406
2407 return make_pair(tablews, ztablews);
2408}
2409
2410//----------------------------------------------------------------------------------------------
2416 // Check and clear input and output
2417 if (!peakparamws) {
2418 stringstream errss;
2419 errss << "Input tableworkspace for peak parameters is invalid!";
2420 g_log.error(errss.str());
2421 throw std::invalid_argument(errss.str());
2422 }
2423
2424 m_vecPeakFunctions.clear();
2425
2426 // Give name to peak parameters
2427 BackToBackExponential tempeak;
2428 tempeak.initialize();
2430 mPeakParameterNames.emplace_back("S2");
2431
2432 // Parse TableWorkspace
2433 vector<map<std::string, double>> peakparametermaps;
2434 vector<map<std::string, int>> peakhkls;
2435 this->parseBraggPeakTable(peakparamws, peakparametermaps, peakhkls);
2436
2437 // Create a map to convert the Bragg peak Table paramter name to Back to back
2438 // exponential+pseudo-voigt
2439 map<string, string> bk2bk2braggmap{{"A", "Alpha"}, {"B", "Beta"}, {"X0", "TOF_h"},
2440 {"I", "Height"}, {"S", "Sigma"}, {"S2", "Sigma2"}};
2441
2442 // Generate Peaks
2443 size_t numbadrows = 0;
2444 size_t numrows = peakparamws->rowCount();
2445 for (size_t ir = 0; ir < numrows; ++ir) {
2446 double d_h;
2447 vector<int> hkl;
2448 bool good;
2449 BackToBackExponential_sptr newpeak = genPeak(peakhkls[ir], peakparametermaps[ir], bk2bk2braggmap, good, hkl, d_h);
2450
2451 if (good) {
2452 m_vecPeakFunctions.emplace_back(d_h, make_pair(hkl, newpeak));
2453 } else {
2454 ++numbadrows;
2455 }
2456 } // ENDFOR Each potential peak
2457
2458 // Sort by peaks' centre in d-space
2459 sort(m_vecPeakFunctions.begin(), m_vecPeakFunctions.end());
2460
2461 // Remove all peaks outside of tof_min and tof_max
2462 double tofmin = m_dataWS->x(m_wsIndex)[0];
2463 double tofmax = m_dataWS->x(m_wsIndex).back();
2464
2465 stringstream dbss;
2466 dbss << "Specified range for peaks in TOF: " << tofmin << ", " << tofmax << "\n";
2467
2468 vector<pair<double, pair<vector<int>, BackToBackExponential_sptr>>>::iterator deliter;
2469 for (deliter = m_vecPeakFunctions.begin(); deliter != m_vecPeakFunctions.end(); ++deliter) {
2470 double d_h = deliter->first;
2471 vector<int> &hkl = deliter->second.first;
2472 BackToBackExponential_sptr peak = deliter->second.second;
2473 double tofh = peak->getParameter("X0");
2474
2475 dbss << "\tPeak (" << hkl[0] << ", " << hkl[1] << ", " << hkl[2] << ") @ d = " << d_h
2476 << " (calculated TOF) = " << tofh << " ";
2477
2478 if (tofh < tofmin || tofh > tofmax) {
2479 // Remove peak from vector
2480 deliter = m_vecPeakFunctions.erase(deliter);
2481 dbss << ": Delete due to out of range. \n";
2482 if (deliter == m_vecPeakFunctions.end()) {
2483 break;
2484 }
2485 } else {
2486 dbss << ": Kept. \n";
2487 }
2488 }
2489
2490 g_log.notice() << "[DBx453] " << dbss.str() << "\n";
2491
2492 // Remove peaks lower than minimum
2493 if (m_minimumHKL.size() == 3) {
2494 // Only keep peaks from and above minimum HKL
2495 for (deliter = m_vecPeakFunctions.begin(); deliter != m_vecPeakFunctions.end(); ++deliter) {
2496 vector<int> hkl = deliter->second.first;
2497 if (hkl == m_minimumHKL) {
2498 break;
2499 }
2500 }
2501 if (deliter != m_vecPeakFunctions.end()) {
2502 // Find the real minum
2503 int indminhkl = static_cast<int>(deliter - m_vecPeakFunctions.begin());
2504 int ind1stpeak = indminhkl - m_numPeaksLowerToMin;
2505 if (ind1stpeak > 0) {
2506 deliter = m_vecPeakFunctions.begin() + ind1stpeak;
2507 m_vecPeakFunctions.erase(m_vecPeakFunctions.begin(), deliter);
2508 }
2509 } else {
2510 // Miminum HKL peak does not exist
2511 vector<int> hkl = m_minimumHKL;
2512 g_log.warning() << "Minimum peak " << hkl[0] << ", " << hkl[1] << ", " << hkl[2] << " does not exit. \n";
2513 }
2514 }
2515
2516 // Keep some input information
2517 stringstream dbout;
2518 for (deliter = m_vecPeakFunctions.begin(); deliter != m_vecPeakFunctions.end(); ++deliter) {
2519 vector<int> hkl = deliter->second.first;
2520 double d_h = deliter->first;
2521 double tof_h = deliter->second.second->centre();
2522 dbout << "Peak (" << hkl[0] << ", " << hkl[1] << ", " << hkl[2] << ") @ d = " << d_h << ", TOF = " << tof_h << '\n';
2523 }
2524 g_log.information() << "[DBx531] Peaks To Fit: Number of peaks = " << m_vecPeakFunctions.size() << "\n"
2525 << dbout.str();
2526}
2527
2528//-----------------------------------------------------------------------------------------
2539BackToBackExponential_sptr FitPowderDiffPeaks::genPeak(map<string, int> hklmap, map<string, double> parammap,
2540 map<string, string> bk2bk2braggmap, bool &good, vector<int> &hkl,
2541 double &d_h) {
2542 // Generate a peak function
2543 BackToBackExponential_sptr newpeakptr = std::make_shared<BackToBackExponential>();
2544 newpeakptr->initialize();
2545
2546 // Check miller index (HKL) is a valid value in a miller indexes pool (hklmap)
2547 good = getHKLFromMap(std::move(hklmap), hkl);
2548 if (!good) {
2549 // Ignore and return
2550 return newpeakptr;
2551 }
2552
2553 // Set the peak parameters either by calculating or from table workspace
2554 string peakcalmode;
2556 // a) Use Bragg peak table's (HKL) and calculate the peak parameters
2557 double alph0 = getParameter("Alph0");
2558 double alph1 = getParameter("Alph1");
2559 double alph0t = getParameter("Alph0t");
2560 double alph1t = getParameter("Alph1t");
2561 double beta0 = getParameter("Beta0");
2562 double beta1 = getParameter("Beta1");
2563 double beta0t = getParameter("Beta0t");
2564 double beta1t = getParameter("Beta1t");
2565 double sig0 = getParameter("Sig0");
2566 double sig1 = getParameter("Sig1");
2567 double sig2 = getParameter("Sig2");
2568 double tcross = getParameter("Tcross");
2569 double width = getParameter("Width");
2570 double dtt1 = getParameter("Dtt1");
2571 double dtt1t = getParameter("Dtt1t");
2572 double dtt2t = getParameter("Dtt2t");
2573 double zero = getParameter("Zero");
2574 double zerot = getParameter("Zerot");
2575
2576 // b) Check validity and make choice
2577 if (tcross == EMPTY_DBL() || width == EMPTY_DBL() || dtt1 == EMPTY_DBL() || dtt1t == EMPTY_DBL() ||
2578 dtt2t == EMPTY_DBL() || zero == EMPTY_DBL() || zerot == EMPTY_DBL()) {
2579 stringstream errss;
2580 errss << "In input InstrumentParameterTable, one of the following is not "
2581 "given. Unable to process. \n";
2582 errss << "Tcross = " << tcross << "; Width = " << width << ", Dtt1 = " << dtt1 << ", Dtt1t = " << dtt1t << '\n';
2583 errss << "Dtt2t = " << dtt2t << ", Zero = " << zero << ", Zerot = " << zerot;
2584
2585 g_log.error(errss.str());
2586 throw runtime_error(errss.str());
2587 }
2588
2589 bool caltofonly = false;
2590 if (alph0 == EMPTY_DBL() || alph1 == EMPTY_DBL() || alph0t == EMPTY_DBL() || alph1t == EMPTY_DBL() ||
2591 beta0 == EMPTY_DBL() || beta1 == EMPTY_DBL() || beta0t == EMPTY_DBL() || beta1t == EMPTY_DBL() ||
2592 sig0 == EMPTY_DBL() || sig1 == EMPTY_DBL() || sig2 == EMPTY_DBL()) {
2593 caltofonly = true;
2594 g_log.warning() << "[DBx343] At least one of the input instrument-peak "
2595 "profile parameters is not given. "
2596 << "Use (HKL) only!\n";
2597 g_log.warning() << "Alph0 = " << alph0 << ", Alph1 = " << alph1 << ", Alph0t = " << alph0t
2598 << ", Alph1t = " << alph1t << '\n';
2599 g_log.warning() << "Beta0 = " << beta0 << ", Beta1 = " << beta1 << ", Beta0t = " << beta0t
2600 << ", Beta1t = " << beta1t << '\n';
2601 g_log.warning() << "Sig0 = " << sig0 << ", Sig1 = " << sig1 << ", Sig2 = " << sig2 << '\n';
2602 }
2603
2604 if (caltofonly) {
2605 // c) Calcualte d->TOF only
2606 // Calcualte d-spacing
2607 d_h = m_unitCell.d(hkl[0], hkl[1], hkl[2]);
2608 // d_h = calCubicDSpace(latticesize, hkl[0], hkl[1],
2609 // hkl[2]);
2610 if ((d_h != d_h) || (d_h < -DBL_MAX) || (d_h > DBL_MAX)) {
2611 stringstream warnss;
2612 warnss << "Peak with Miller Index = " << hkl[0] << ", " << hkl[1] << ", " << hkl[2]
2613 << " has unphysical d-spacing value = " << d_h;
2614 g_log.warning(warnss.str());
2615 good = false;
2616 return newpeakptr;
2617 }
2618
2619 // Calcualte TOF_h
2620 double tof_h = calThermalNeutronTOF(d_h, dtt1, dtt1t, dtt2t, zero, zerot, width, tcross);
2621 newpeakptr->setCentre(tof_h);
2622 } else {
2623 // d) Calculate a lot of peak parameters
2624 // Initialize the function
2626 tnb2bfunc.initialize();
2627 tnb2bfunc.setMillerIndex(hkl[0], hkl[1], hkl[2]);
2628
2629 vector<string> tnb2bfuncparnames = tnb2bfunc.getParameterNames();
2630
2631 // Set peak parameters
2632 for (const auto &parname : tnb2bfuncparnames) {
2633 if (parname != "Height") {
2634 auto miter = m_instrumentParmaeters.find(parname);
2635 if (miter == m_instrumentParmaeters.end()) {
2636 stringstream errss;
2637 errss << "Cannot find peak parameter " << parname << " in input instrument parameter "
2638 << "TableWorkspace. This mode is unable to execute. Quit!";
2639 g_log.error(errss.str());
2640 throw runtime_error(errss.str());
2641 }
2642 double parvalue = miter->second;
2643 tnb2bfunc.setParameter(parname, parvalue);
2644 }
2645 }
2646
2647 // Calculate peak parameters A, B, S, and X0
2648 tnb2bfunc.calculateParameters(false);
2649 d_h = tnb2bfunc.getPeakParameter("d_h");
2650 double alpha = tnb2bfunc.getPeakParameter("Alpha");
2651 double beta = tnb2bfunc.getPeakParameter("Beta");
2652 double sigma2 = tnb2bfunc.getPeakParameter("Sigma2");
2653 double tof_h = tnb2bfunc.centre();
2654
2655 newpeakptr->setParameter("A", alpha);
2656 newpeakptr->setParameter("B", beta);
2657 newpeakptr->setParameter("S", sqrt(sigma2));
2658 newpeakptr->setParameter("X0", tof_h);
2659 }
2660
2661 peakcalmode = "Calculate all parameters by thermal neutron peak function.";
2662
2663 } // Calculate peak variable from Profile function
2665 // e) Import from input table workspace
2666 vector<string>::iterator nameiter;
2667 for (nameiter = mPeakParameterNames.begin(); nameiter != mPeakParameterNames.end(); ++nameiter) {
2668 // BackToBackExponential parameter name
2669 string b2bexpname = *nameiter;
2670 // Map to instrument parameter
2671 map<string, string>::iterator refiter;
2672 refiter = bk2bk2braggmap.find(b2bexpname);
2673 if (refiter == bk2bk2braggmap.end())
2674 throw runtime_error("Programming error!");
2675 string instparname = refiter->second;
2676
2677 // Search in Bragg peak table
2678 map<string, double>::iterator miter;
2679 miter = parammap.find(instparname);
2680 if (miter != parammap.end()) {
2681 // Parameter exist in input
2682 double parvalue = miter->second;
2683 if (b2bexpname == "S2") {
2684 newpeakptr->setParameter("S", sqrt(parvalue));
2685 } else {
2686 newpeakptr->setParameter(b2bexpname, parvalue);
2687 }
2688 }
2689 } // FOR PEAK TABLE CELL
2690
2691 peakcalmode = "Import from Bragg peaks table";
2692 }
2693
2694 // Debug output
2695 stringstream infoss;
2696 string peakinfo = getFunctionInfo(std::dynamic_pointer_cast<IFunction>(newpeakptr));
2697
2698 infoss << "Generate Peak (" << hkl[0] << ", " << hkl[1] << ", " << hkl[2] << ") Of Mode " << peakcalmode << ".\n";
2699 g_log.notice(infoss.str());
2700 g_log.information() << "[DBx426B] " << peakinfo << ".\n";
2701
2702 good = true;
2703
2704 return newpeakptr;
2705}
2706
2707//----------------------------------------------------------------------------------------------
2716 const FunctionDomain1DVector &domain) {
2717 // 1. Determine range
2718 const auto &vecX = m_dataWS->x(m_wsIndex);
2719 double x0 = domain[0];
2720 auto viter = lower_bound(vecX.cbegin(), vecX.cend(), x0);
2721 int ix0 = static_cast<int>(std::distance(vecX.cbegin(), viter));
2722
2723 // Check boundary
2724 if ((static_cast<int>(domain.size()) + ix0) > static_cast<int>(m_peakData.size()))
2725 throw runtime_error("Plot single peak out of boundary error!");
2726
2727 // 2. Calculation of peaks
2728 FunctionValues values1(domain);
2729 peakfunction->function(domain, values1);
2730
2731 for (int i = 0; i < static_cast<int>(domain.size()); ++i)
2732 m_peakData[i + ix0] = values1[i];
2733
2734 // 3.Calculation of background
2735 FunctionValues values2(domain);
2736 background->function(domain, values2);
2737
2738 for (int i = 0; i < static_cast<int>(domain.size()); ++i)
2739 m_peakData[i + ix0] += values2[i];
2740}
2741
2742//===================================== Auxiliary Functions
2743//===================================
2744//----------------------------------------------------------------------------------------------
2750bool FitPowderDiffPeaks::getHKLFromMap(map<string, int> intmap, vector<int> &hkl) {
2751 vector<string> strhkl(3);
2752 strhkl[0] = "H";
2753 strhkl[1] = "K";
2754 strhkl[2] = "L";
2755
2756 hkl.clear();
2757
2758 map<string, int>::iterator miter;
2759 for (size_t i = 0; i < 3; ++i) {
2760 string parname = strhkl[i];
2761 miter = intmap.find(parname);
2762 if (miter == intmap.end())
2763 return false;
2764
2765 hkl.emplace_back(miter->second);
2766 }
2767
2768 return true;
2769}
2770
2771//----------------------------------------------------------------------------------------------
2776void FitPowderDiffPeaks::cropWorkspace(double tofmin, double tofmax) {
2777 auto cropalg = createChildAlgorithm("CropWorkspace", -1, -1, true);
2778 cropalg->initialize();
2779
2780 cropalg->setProperty("InputWorkspace", m_dataWS);
2781 cropalg->setPropertyValue("OutputWorkspace", "MyData");
2782 cropalg->setProperty("XMin", tofmin);
2783 cropalg->setProperty("XMax", tofmax);
2784
2785 bool cropstatus = cropalg->execute();
2786
2787 std::stringstream errmsg;
2788 if (!cropstatus) {
2789 errmsg << "DBx309 Cropping workspace unsuccessful. Fatal Error. Quit!";
2790 g_log.error() << errmsg.str() << '\n';
2791 throw std::runtime_error(errmsg.str());
2792 }
2793
2794 m_dataWS = cropalg->getProperty("OutputWorkspace");
2795 if (!m_dataWS) {
2796 errmsg << "Unable to retrieve a Workspace2D object from ChildAlgorithm Crop.";
2797 g_log.error(errmsg.str());
2798 throw std::runtime_error(errmsg.str());
2799 } else {
2800 g_log.information() << "[DBx211] Cropped Workspace Range: " << m_dataWS->x(m_wsIndex)[0] << ", "
2801 << m_dataWS->x(m_wsIndex).back() << '\n';
2802 }
2803}
2804
2805//----------------------------------------------------------------------------------------------
2810double FitPowderDiffPeaks::getParameter(const string &parname) {
2811 map<string, double>::iterator mapiter;
2812 mapiter = m_instrumentParmaeters.find(parname);
2813
2814 if (mapiter == m_instrumentParmaeters.end()) {
2815 stringstream errss;
2816 errss << "Instrument parameter map (having " << m_instrumentParmaeters.size() << " entries) "
2817 << "does not have parameter " << parname << ". ";
2818 g_log.debug(errss.str());
2819 return (EMPTY_DBL());
2820 }
2821
2822 return mapiter->second;
2823}
2824
2825//----------------------------------------------------------------------------------------------
2833 size_t workspaceindex, double leftbound, double rightbound) {
2834 // 1. Check
2835 const auto &X = sourcews->x(workspaceindex);
2836 const auto &Y = sourcews->y(workspaceindex);
2837 const auto &E = sourcews->e(workspaceindex);
2838
2839 if (leftbound >= rightbound) {
2840 stringstream errmsg;
2841 errmsg << "[BuildPartialWorkspace] Input left boundary = " << leftbound << " is larger than input right boundary "
2842 << rightbound << ". It is not allowed. ";
2843 throw std::invalid_argument(errmsg.str());
2844 }
2845 if (leftbound >= X.back() || rightbound <= X[0]) {
2846 throw std::invalid_argument("Boundary is out side of the input data set. ");
2847 }
2848
2849 // 2. Determine the size of the "partial" workspace
2850 int ileft = static_cast<int>(std::lower_bound(X.begin(), X.end(), leftbound) - X.begin());
2851 if (ileft > 0)
2852 --ileft;
2853 int iright = static_cast<int>(std::lower_bound(X.begin(), X.end(), rightbound) - X.begin());
2854 if (iright >= static_cast<int>(X.size()))
2855 iright = static_cast<int>(X.size() - 1);
2856
2857 auto wssize = static_cast<size_t>(iright - ileft + 1);
2858
2859 // 3. Build the partial workspace
2860 size_t nspec = 6;
2861 Workspace2D_sptr partws = std::dynamic_pointer_cast<Workspace2D>(
2862 API::WorkspaceFactory::Instance().create("Workspace2D", nspec, wssize, wssize));
2863
2864 // 4. Put data there
2865 // TODO: Try to use vector copier
2866 for (size_t iw = 0; iw < partws->getNumberHistograms(); ++iw) {
2867 MantidVec &nX = partws->dataX(iw);
2868 for (size_t i = 0; i < wssize; ++i) {
2869 nX[i] = X[i + ileft];
2870 }
2871 }
2872 auto &nY = partws->mutableY(0);
2873 auto &nE = partws->mutableE(0);
2874 for (size_t i = 0; i < wssize; ++i) {
2875 nY[i] = Y[i + ileft];
2876 nE[i] = E[i + ileft];
2877 }
2878
2879 return partws;
2880}
2881
2882//----------------------------------------------------------------------------------------------
2886string getFunctionInfo(const IFunction_sptr &function) {
2887 stringstream outss;
2888 vector<string> parnames = function->getParameterNames();
2889 size_t numpars = parnames.size();
2890 outss << "Number of Parameters = " << numpars << '\n';
2891 for (size_t i = 0; i < numpars; ++i)
2892 outss << parnames[i] << " = " << function->getParameter(i) << ", \t\tFitted = " << function->isActive(i) << '\n';
2893
2894 return outss.str();
2895}
2896
2897//----------------------------------------------------------------------------------------------
2910 size_t wsindexraw, size_t wsindexbkgd, size_t wsindexpeak) {
2911 // 1. Get prepared
2912 if (dataws->getNumberHistograms() < 3) {
2913 stringstream errss;
2914 errss << "Function estimateBackgroundCoase() requires input Workspace2D "
2915 "has at least 3 spectra."
2916 << "Present input has " << dataws->getNumberHistograms() << " spectra.";
2917 throw runtime_error(errss.str());
2918 }
2919 const auto &X = dataws->x(wsindexraw);
2920 const auto &Y = dataws->y(wsindexraw);
2921
2922 // TODO: This is a magic number!
2923 size_t numsamplepts = 2;
2924 if (X.size() <= 10) {
2925 // Make it at minimum to estimate background
2926 numsamplepts = 1;
2927 }
2928
2929 // 2. Average the first and last three data points
2930 double y0 = 0;
2931 double x0 = 0;
2932
2933 for (size_t i = 0; i < numsamplepts; ++i) {
2934 x0 += X[i];
2935 y0 += Y[i];
2936 }
2937 x0 = x0 / static_cast<double>(numsamplepts);
2938 y0 = y0 / static_cast<double>(numsamplepts);
2939
2940 double xf = 0;
2941 double yf = 0;
2942 for (size_t i = X.size() - numsamplepts; i < X.size(); ++i) {
2943 xf += X[i];
2944 yf += Y[i];
2945 }
2946 xf = xf / static_cast<double>(numsamplepts);
2947 yf = yf / static_cast<double>(numsamplepts);
2948
2949 // 3. Calculate B(x) = B0 + B1*x
2950 double b1 = (yf - y0) / (xf - x0);
2951 double b0 = yf - b1 * xf;
2952
2953 background->setParameter("A0", b0);
2954 background->setParameter("A1", b1);
2955
2956 // 4. Calcualte background
2957 FunctionDomain1DVector domain(X.rawData());
2958 FunctionValues values(domain);
2959 background->function(domain, values);
2960
2961 dataws->mutableY(wsindexbkgd) = values.toVector();
2962 dataws->mutableY(wsindexpeak) = dataws->y(wsindexraw) - dataws->y(wsindexbkgd);
2963 dataws->mutableE(wsindexpeak) = dataws->e(wsindexraw);
2964}
2965
2966//-----------------------------------------------------------------------------------------------------------
2980bool observePeakParameters(const Workspace2D_sptr &dataws, size_t wsindex, double &centre, double &height, double &fwhm,
2981 string &errmsg) {
2982 // 1. Get the value of the Max Height
2983 const auto &X = dataws->x(wsindex);
2984 const auto &Y = dataws->y(wsindex);
2985
2986 // 2. The highest peak should be the centre
2987 size_t icentre = findMaxValue(Y.rawData());
2988 centre = X[icentre];
2989 height = Y[icentre];
2990
2991 if (icentre <= 1 || icentre > X.size() - 2) {
2992 stringstream errss;
2993 errss << "Peak center = " << centre << " is at the edge of the input workspace [" << X[0] << ", " << X.back()
2994 << ". It is unable to proceed the estimate of FWHM. Quit with error!.";
2995 errmsg = errss.str();
2996 return false;
2997 }
2998 if (height <= 0) {
2999 stringstream errss;
3000 errss << "Max height = " << height << " in input workspace [" << X[0] << ", " << X.back()
3001 << " is negative. Fatal error is design of the algorithm.";
3002 errmsg = errss.str();
3003 return false;
3004 }
3005
3006 // 3. Calculate FWHM
3007 double halfMax = height * 0.5;
3008
3009 // a) Deal with left side
3010 bool continueloop = true;
3011 size_t index = icentre - 1;
3012 while (continueloop) {
3013 if (Y[index] <= halfMax) {
3014 // Located the data points
3015 continueloop = false;
3016 } else if (index == 0) {
3017 // Reach the end of the boundary, but haven't found. return with error.
3018 stringstream errss;
3019 errss << "The peak is not complete (left side) in the given data range.";
3020 errmsg = errss.str();
3021 return false;
3022 } else {
3023 // Contineu to locate
3024 --index;
3025 }
3026 }
3027 double x0 = X[index];
3028 double xf = X[index + 1];
3029 double y0 = Y[index];
3030 double yf = Y[index + 1];
3031
3032 // Formular for linear iterpolation: X = [(xf-x0)*Y - (xf*y0-x0*yf)]/(yf-y0)
3033 double xl = linearInterpolateX(x0, xf, y0, yf, halfMax);
3034
3035 double lefthalffwhm = centre - xl;
3036
3037 // 3. Deal with right side
3038 continueloop = true;
3039 index = icentre + 1;
3040 while (continueloop) {
3041 if (Y[index] <= halfMax) {
3042 // Located the data points
3043 continueloop = false;
3044 } else if (index == Y.size() - 1) {
3045 // Reach the end of the boundary, but haven't found. return with error.
3046 stringstream errss;
3047 errss << "The peak is not complete (right side) in the given data range.";
3048 errmsg = errss.str();
3049 return false;
3050 } else {
3051 ++index;
3052 }
3053 }
3054 x0 = X[index - 1];
3055 xf = X[index];
3056 y0 = Y[index - 1];
3057 yf = Y[index];
3058
3059 // Formula for linear iterpolation: X = [(xf-x0)*Y - (xf*y0-x0*yf)]/(yf-y0)
3060 double xr = linearInterpolateX(x0, xf, y0, yf, halfMax);
3061
3062 double righthalffwhm = xr - centre;
3063
3064 // Final
3065 fwhm = lefthalffwhm + righthalffwhm;
3066
3067 return true;
3068}
3069
3070//-----------------------------------------------------------------------------------------------------------
3075size_t findMaxValue(const std::vector<double> &Y) {
3076
3077 auto maxIt = std::max_element(Y.begin(), Y.end());
3078 return std::distance(Y.begin(), maxIt);
3079}
3080
3081//----------------------------------------------------------------------------------------------
3089size_t findMaxValue(const MatrixWorkspace_sptr &dataws, size_t wsindex, double leftbound, double rightbound) {
3090 const auto &X = dataws->x(wsindex);
3091 const auto &Y = dataws->y(wsindex);
3092
3093 // 1. Determine xmin, xmax range
3094 std::vector<double>::const_iterator viter;
3095
3096 viter = std::lower_bound(X.begin(), X.end(), leftbound);
3097 size_t ixmin = size_t(viter - X.begin());
3098 if (ixmin != 0)
3099 --ixmin;
3100 viter = std::lower_bound(X.begin(), X.end(), rightbound);
3101 size_t ixmax = size_t(viter - X.begin());
3102
3103 // 2. Search imax
3104 size_t imax = ixmin;
3105 double maxY = Y[ixmin];
3106 for (size_t i = ixmin + 1; i <= ixmax; ++i) {
3107 if (Y[i] > maxY) {
3108 maxY = Y[i];
3109 imax = i;
3110 }
3111 }
3112
3113 return imax;
3114}
3115
3116} // namespace Mantid::CurveFitting::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double value
The value of the point.
Definition: FitMW.cpp:51
#define PEAKFITRANGEFACTOR
Factor on FWHM for fitting a peak.
#define PEAKBOUNDARYFACTOR
Factor on FWHM for defining a peak's range.
double sigma
Definition: GetAllEi.cpp:156
double height
Definition: GetAllEi.cpp:155
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Definition: System.h:64
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Definition: Algorithm.cpp:842
Kernel::Logger & g_log
Definition: Algorithm.h:451
A composite function is a function containing other functions.
Implements FunctionDomain1D with its own storage in form of a std::vector.
size_t size() const override
Return the number of arguments in the domain.
A class to store values calculated by a function.
std::vector< double > toVector() const
Return the calculated values as a vector.
virtual void initialize()
Iinialize the function.
Definition: IFunction.h:422
std::vector< std::string > getParameterNames() const
Return a vector with all parameter names.
Definition: IFunction.cpp:551
virtual void setMillerIndex(int h, int k, int l)
Set Miller Indicies.
virtual double centre() const
Overwrite IFunction base class methods.
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
A property class for workspaces.
FitPowderDiffPeaks : Fit peaks in powder diffraction pattern.
double m_rightmostPeakLeftBound
Right most peak's left boundary.
void init() override
Implement abstract Algorithm methods.
void restoreFunctionParameters(const API::IFunction_sptr &function, std::map< std::string, double > parammap)
Restore the function's parameter values from a map.
bool doFit1PeakSequential(const DataObjects::Workspace2D_sptr &dataws, size_t workspaceindex, const Functions::BackToBackExponential_sptr &peakfunction, std::vector< std::string > minimzernames, std::vector< size_t > maxiterations, const std::vector< double > &dampfactors, double &chi2)
Fit 1 peak by using a sequential of minimizer.
void observePeakRange(const Functions::BackToBackExponential_sptr &thispeak, const Functions::BackToBackExponential_sptr &rightpeak, double refpeakshift, double &peakleftbound, double &peakrightbound)
Observe peak range with hint from right peak's properties.
void storeFunctionParameters(const API::IFunction_sptr &function, std::map< std::string, double > &parammaps)
Store the function's parameter values to a map.
double getParameter(const std::string &parname)
Get parameter value from m_instrumentParameters.
bool doFitMultiplePeaks(const DataObjects::Workspace2D_sptr &dataws, size_t wsindex, const API::CompositeFunction_sptr &peaksfunc, std::vector< Functions::BackToBackExponential_sptr > peakfuncs, std::vector< bool > &vecfitgood, std::vector< double > &vecchi2s)
Fit multiple (overlapped) peaks.
bool doFitGaussianPeak(const DataObjects::Workspace2D_sptr &dataws, size_t workspaceindex, double in_center, double leftfwhm, double rightfwhm, double &center, double &sigma, double &height)
Fit background-removed peak by Gaussian.
std::vector< int > m_rightmostPeakHKL
Right most peak HKL.
std::string parseFitResult(const API::IAlgorithm_sptr &fitalg, double &chi2, bool &fitsuccess)
Parse the fitting result.
enum Mantid::CurveFitting::Algorithms::FitPowderDiffPeaks::@0 m_fitMode
Fit mode.
std::pair< DataObjects::TableWorkspace_sptr, DataObjects::TableWorkspace_sptr > genPeakParametersWorkspace()
Generate output peak parameters workspace.
bool getHKLFromMap(std::map< std::string, int > intmap, std::vector< int > &hkl)
Get (HKL) from a map; Return false if the information is incomplete.
double m_rightmostPeakRightBound
Right most peak's right boundary.
std::vector< bool > m_goodFit
Peak fitting status.
std::vector< double > m_peakFitChi2
Peak fitting information.
double m_minPeakHeight
Minimum peak height for peak to be refined.
bool doFit1PeakSimple(const DataObjects::Workspace2D_sptr &dataws, size_t workspaceindex, const Functions::BackToBackExponential_sptr &peakfunction, const std::string &minimzername, size_t maxiteration, double &chi2)
Fit 1 peak by 1 minimizer of 1 call of minimzer (simple version)
void exec() override
Implement abstract Algorithm methods.
bool m_fitPeakBackgroundComposite
Fit peak + background as the last step.
void importInstrumentParameterFromTable(const DataObjects::TableWorkspace_sptr &parameterWS)
Import instrument parameters from (input) table workspace.
void setOverlappedPeaksConstraints(const std::vector< Functions::BackToBackExponential_sptr > &peaks)
Set constraints on a group of overlapped peaks for fitting.
DataObjects::TableWorkspace_sptr m_profileTable
Instrument profile parameter table workspace.
void genPeaksFromTable(const DataObjects::TableWorkspace_sptr &peakparamws)
Generate peaks from input table workspace.
void calculatePeakFitBoundary(size_t ileftpeak, size_t irightpeak, double &peakleftboundary, double &peakrightboundary)
Calculate the range to fit peak/peaks group.
Geometry::UnitCell m_unitCell
Unit cell of powder crystal.
std::pair< bool, double > doFitPeak(const DataObjects::Workspace2D_sptr &dataws, const Functions::BackToBackExponential_sptr &peakfunction, double guessedfwhm)
Fit peak with flexiblity in multiple steps Prerequisit:
DataObjects::Workspace2D_sptr genOutputFittedPatternWorkspace(std::vector< double > pattern, int workspaceindex)
Create a Workspace2D for fitted peaks (pattern)
std::vector< double > m_peakData
Data for each individual peaks. (HKL)^2, vector index, function values.
void parseBraggPeakTable(const DataObjects::TableWorkspace_sptr &peakws, std::vector< std::map< std::string, double > > &parammaps, std::vector< std::map< std::string, int > > &hklmaps)
Import Bragg peak table workspace.
void cropWorkspace(double tofmin, double tofmax)
Crop data workspace.
enum Mantid::CurveFitting::Algorithms::FitPowderDiffPeaks::@1 m_genPeakStartingValue
Choice to generate peak profile paramter starting value.
DataObjects::Workspace2D_sptr genPeakParameterDataWorkspace()
Create data workspace for X0, A, B and S of peak with good fit.
DataObjects::TableWorkspace_sptr m_peakParamTable
Bragg peak parameter.
Functions::BackToBackExponential_sptr genPeak(std::map< std::string, int > hklmap, std::map< std::string, double > parammap, std::map< std::string, std::string > bk2bk2braggmap, bool &good, std::vector< int > &hkl, double &d_h)
Generate a peak.
std::vector< std::string > mPeakParameterNames
Peak parmeter names.
bool fitOverlappedPeaks(std::vector< Functions::BackToBackExponential_sptr > peaks, const Functions::BackgroundFunction_sptr &backgroundfunction, double gfwhm)
Fit peaks with confidence in fwhm and etc.
std::map< std::string, double > m_instrumentParmaeters
Map for function (instrument parameter)
std::vector< std::pair< double, std::pair< std::vector< int >, Functions::BackToBackExponential_sptr > > > m_vecPeakFunctions
Sorted vector for peaks. double = d_h, vector = (HKL), peak.
int m_numPeaksLowerToMin
Number of peaks to fit lower to minimum HKL.
bool doFit1PeakBackground(const DataObjects::Workspace2D_sptr &dataws, size_t wsindex, const Functions::BackToBackExponential_sptr &peak, const Functions::BackgroundFunction_sptr &backgroundfunction, double &chi2)
Fit 1 peak and background.
void plotFunction(const API::IFunction_sptr &peakfunction, const Functions::BackgroundFunction_sptr &background, const API::FunctionDomain1DVector &domain)
Plot a single peak to output vector.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
std::string parseFitParameterWorkspace(const API::ITableWorkspace_sptr &paramws)
Parse Fit() output parameter workspace.
DataObjects::Workspace2D_sptr buildPartialWorkspace(const API::MatrixWorkspace_sptr &sourcews, size_t workspaceindex, double leftbound, double rightbound)
Build partial workspace for fitting.
bool m_useGivenTOFh
Flag to use given Bragg peaks' centre in TOF.
bool fitSinglePeakRobust(const Functions::BackToBackExponential_sptr &peak, const Functions::BackgroundFunction_sptr &backgroundfunction, double peakleftbound, double peakrightbound, const std::map< std::string, double > &rightpeakparammap, double &finalchi2)
Fit single peak in robust mode (no hint)
void fitPeaksRobust()
Fit peaks in robust algorithm.
void estimatePeakHeightsLeBail(const DataObjects::Workspace2D_sptr &dataws, size_t wsindex, std::vector< Functions::BackToBackExponential_sptr > peaks)
Use Le Bail method to estimate and set the peak heights.
bool fitSinglePeakConfident(const Functions::BackToBackExponential_sptr &peak, const Functions::BackgroundFunction_sptr &backgroundfunction, double leftbound, double rightbound, double &chi2, bool &annhilatedpeak)
Fit peak with trustful peak parameters.
int m_wsIndex
TOF vector of data workspace to process with.
bool doFitNPeaksSimple(const DataObjects::Workspace2D_sptr &dataws, size_t wsindex, const API::CompositeFunction_sptr &peaksfunc, const std::vector< Functions::BackToBackExponential_sptr > &peakfuncs, const std::string &minimizername, size_t maxiteration, double &chi2)
Fit N overlapped peaks in a simple manner.
bool fitSinglePeakSimulatedAnnealing(const Functions::BackToBackExponential_sptr &peak, const std::vector< std::string > &paramtodomc)
Fit signle peak by Monte Carlo/simulated annealing.
Provide BackToBackExponential peak shape function interface to IPeakFunction.
ThermalNeutronBk2BkExpConvPVoigt : Back-to-back exponential convoluted with pseudo Voigt for thermal ...
double getPeakParameter(const std::string &) override
Overwrite IPeakFunction base class methods.
void setParameter(size_t i, const double &value, bool explicitlySet=true) override
Core function to calcualte peak values for whole region.
void calculateParameters(bool explicitoutput) const override
Calculate peak parameters (alpha, beta, sigma2..)
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
void set(double _a, double _b, double _c, double _alpha, double _beta, double _gamma, const int angleunit=angDegrees)
Set lattice parameters.
Definition: UnitCell.cpp:303
double d(double h, double k, double l) const
Return d-spacing ( ) for a given h,k,l coordinate.
Definition: UnitCell.cpp:700
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< Column > Column_sptr
Definition: Column.h:228
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
Definition: Algorithm.h:61
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
double linearInterpolateX(double x0, double xf, double y0, double yf, double y)
Formular for linear iterpolation: X = [(xf-x0)*Y - (xf*y0-x0*yf)]/(yf-y0)
size_t findMaxValue(const std::vector< double > &Y)
Find maximum value.
bool observePeakParameters(const DataObjects::Workspace2D_sptr &dataws, size_t wsindex, double &centre, double &height, double &fwhm, std::string &errmsg)
Estimate peak parameters;.
void estimateBackgroundCoarse(const DataObjects::Workspace2D_sptr &dataws, const Functions::BackgroundFunction_sptr &background, size_t wsindexraw, size_t wsindexbkgd, size_t wsindexpeak)
Estimate background for a pattern in a coarse mode.
std::string getFunctionInfo(const API::IFunction_sptr &function)
Get function parameter name, value and etc information in string.
double calThermalNeutronTOF(double dh, double dtt1, double dtt1t, double dtt2t, double zero, double zerot, double width, double tcross)
Calcualte TOF from d-spacing value for thermal neutron.
std::shared_ptr< Polynomial > Polynomial_sptr
Definition: Polynomial.h:53
std::shared_ptr< BackToBackExponential > BackToBackExponential_sptr
std::shared_ptr< BackgroundFunction > BackgroundFunction_sptr
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
std::vector< double > getZscore(const std::vector< TYPE > &data)
Return the Z score values for a dataset.
Definition: Statistics.cpp:81
Helper class which provides the Collimation Length for SANS instruments.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition: cow_ptr.h:172
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
STL namespace.
@ InOut
Both an input & output workspace.
Definition: Property.h:55
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54