Mantid
Loading...
Searching...
No Matches
LeBailFit.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 +
10#include "MantidAPI/TableRow.h"
11#include "MantidAPI/TextAxis.h"
15#include "MantidHistogramData/HistogramX.h"
16#include "MantidHistogramData/HistogramY.h"
20
21#include <boost/algorithm/string.hpp>
22#include <boost/algorithm/string/split.hpp>
23
24#include <cctype>
25#include <fstream>
26#include <iomanip>
27
28const int OBSDATAINDEX(0);
29const int CALDATAINDEX(1);
30const int DATADIFFINDEX(2);
31const int CALPUREPEAKINDEX(3);
32// Output workspace background at ws index 4
33const int CALBKGDINDEX(4);
34// Input background
35const int INPUTBKGDINDEX(6);
36// Output workspace: pure peak (data with background removed)
37const int INPUTPUREPEAKINDEX(7);
38
39const double NOBOUNDARYLIMIT(1.0E10);
40const double EPSILON(1.0E-10);
41
42using namespace Mantid;
43using namespace Mantid::CurveFitting;
44using namespace Mantid::DataObjects;
45using namespace Mantid::API;
46using namespace Mantid::Kernel;
47using Mantid::HistogramData::HistogramX;
48using Mantid::HistogramData::HistogramY;
49
50using namespace std;
51
53
54const Rfactor badR(DBL_MAX, DBL_MAX);
55
57
58//----------------------------------------------------------------------------------------------
62 : m_lebailFunction(), m_dataWS(), m_outputWS(), parameterWS(), reflectionWS(), m_wsIndex(0), m_startX(DBL_MAX),
63 m_endX(DBL_MIN), m_inputPeakInfoVec(), m_backgroundFunction(), m_funcParameters(), m_origFuncParameters(),
64 m_peakType(), m_backgroundType(), m_backgroundParameters(), m_backgroundParameterNames(), m_bkgdorder(0),
65 mPeakRadius(0), m_lebailFitChi2(0.), m_lebailCalChi2(0.), mMinimizer(), m_dampingFactor(0.),
66 m_inputParameterPhysical(false), m_fitMode(), m_indicatePeakHeight(0.), m_MCGroups(), m_numMCGroups(0),
67 m_bestRwp(0.), m_bestRp(0.), m_bestParameters(), m_bestBackgroundData(), m_bestMCStep(0), m_numMinimizeSteps(0),
68 m_Temperature(DBL_MIN), m_useAnnealing(false), m_walkStyle(RANDOMWALK), m_minimumPeakHeight(DBL_MAX),
69 m_tolerateInputDupHKL2Peaks(false), m_bkgdParameterNames(), m_numberBkgdParameters(0), m_bkgdParameterBuffer(),
70 m_bestBkgdParams(), m_roundBkgd(0), m_bkgdParameterStepVec(), m_peakCentreTol(0.) {}
71
72//----------------------------------------------------------------------------------------------
76 // -------------- Input and output Workspaces -----------------
77
78 // Input Data Workspace
79 this->declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
80 "Input workspace containing the data to fit by LeBail algorithm.");
81
82 // Output Result Data/Model Workspace
83 this->declareProperty(std::make_unique<WorkspaceProperty<Workspace2D>>("OutputWorkspace", "", Direction::Output),
84 "Output workspace containing calculated pattern or "
85 "calculated background. ");
86
87 // Instrument profile Parameters
88 this->declareProperty(
89 std::make_unique<WorkspaceProperty<TableWorkspace>>("InputParameterWorkspace", "", Direction::Input),
90 "Input table workspace containing the parameters "
91 "required by LeBail fit. ");
92
93 // Output instrument profile parameters
94 auto tablewsprop1 = std::make_unique<WorkspaceProperty<TableWorkspace>>(
95 "OutputParameterWorkspace", "", Direction::Output, API::PropertyMode::Optional);
96 this->declareProperty(std::move(tablewsprop1), "Input table workspace containing the "
97 "parameters required by LeBail fit. ");
98
99 // Single peak: Reflection (HKL) Workspace, PeaksWorkspace
100 this->declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("InputHKLWorkspace", "", Direction::Input),
101 "Input table workspace containing the list of reflections (HKL). ");
102
103 // Bragg peaks profile parameter output table workspace
104 auto tablewsprop2 = std::make_unique<WorkspaceProperty<TableWorkspace>>("OutputPeaksWorkspace", "", Direction::Output,
106 this->declareProperty(std::move(tablewsprop2), "Optional output table workspace "
107 "containing all peaks' peak "
108 "parameters. ");
109
110 // WorkspaceIndex
111 this->declareProperty("WorkspaceIndex", 0, "Workspace index of the spectrum to fit by LeBail.");
112
113 // Interested region
114 this->declareProperty(std::make_unique<Kernel::ArrayProperty<double>>("FitRegion"),
115 "Region of data (TOF) for LeBail fit. Default is whole range. ");
116
117 // Functionality: Fit/Calculation/Background
118 std::vector<std::string> functions{"LeBailFit", "Calculation", "MonteCarlo", "RefineBackground"};
119 auto validator = std::make_shared<Kernel::StringListValidator>(functions);
120 this->declareProperty("Function", "LeBailFit", validator, "Functionality");
121
122 // Peak type
123 vector<string> peaktypes{"ThermalNeutronBk2BkExpConvPVoigt", "NeutronBk2BkExpConvPVoigt"};
124 auto peaktypevalidator = std::make_shared<StringListValidator>(peaktypes);
125 declareProperty("PeakType", "ThermalNeutronBk2BkExpConvPVoigt", peaktypevalidator, "Peak profile type.");
126
127 /*------------------------ Background Related Properties
128 * ---------------------------------*/
129 // About background: Background type, input (table workspace or array)
130 std::vector<std::string> bkgdtype{"Polynomial", "Chebyshev", "FullprofPolynomial"};
131 auto bkgdvalidator = std::make_shared<Kernel::StringListValidator>(bkgdtype);
132 declareProperty("BackgroundType", "Polynomial", bkgdvalidator, "Background type");
133
134 // Input background parameters (array)
135 this->declareProperty(std::make_unique<Kernel::ArrayProperty<double>>("BackgroundParameters"),
136 "Optional: enter a comma-separated list of background order parameters "
137 "from order 0. ");
138
139 // Input background parameters (tableworkspace)
140 auto tablewsprop3 = std::make_unique<WorkspaceProperty<TableWorkspace>>(
141 "BackgroundParametersWorkspace", "", Direction::InOut, API::PropertyMode::Optional);
142 this->declareProperty(std::move(tablewsprop3), "Optional table workspace containing the fit result for background.");
143
144 // Peak Radius
145 this->declareProperty("PeakRadius", 5, "Range (multiplier relative to FWHM) for a full peak. ");
146
147 /*------------------------ Properties for Calculation Mode
148 * --------------------------------*/
149 // Output option to plot each individual peak
150 declareProperty("PlotIndividualPeaks", false, "Option to output each individual peak in mode Calculation.");
151 setPropertySettings("PlotIndividualPeaks",
152 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "Calculation"));
153
154 // Make each reflection visible
155 declareProperty("IndicationPeakHeight", 0.0,
156 "Heigh of peaks (reflections) if its calculated height is "
157 "smaller than user-defined minimum.");
158 setPropertySettings("IndicationPeakHeight",
159 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "Calculation"));
160
161 // UseInputPeakHeights
162 declareProperty("UseInputPeakHeights", true,
163 "For 'Calculation' mode only, use peak heights specified in "
164 "ReflectionWorkspace. "
165 "Otherwise, calcualte peaks' heights. ");
166 setPropertySettings("UseInputPeakHeights",
167 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "Calculation"));
168
169 /*--------------------------- Properties for Fitting Mode
170 * ---------------------------------*/
171 // Minimizer
172 std::vector<std::string> minimizerOptions = API::FuncMinimizerFactory::Instance().getKeys(); // :Instance().getKeys();
173 declareProperty("Minimizer", "Levenberg-MarquardtMD",
175 "The minimizer method applied to do the fit, default is "
176 "Levenberg-Marquardt",
178 setPropertySettings("Minimizer", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "LeBailFit"));
179
180 declareProperty("Damping", 1.0, "Damping factor if minimizer is 'Damped Gauss-Newton'");
181 setPropertySettings("Damping", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "LeBailFit"));
182 setPropertySettings("Damping", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
183
184 declareProperty("NumberMinimizeSteps", 100, "Number of Monte Carlo random walk steps.");
185 setPropertySettings("NumberMinimizeSteps",
186 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "LeBailFit"));
187 setPropertySettings("NumberMinimizeSteps",
188 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
189 setPropertySettings("NumberMinimizeSteps",
190 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "RefineBackground"));
191
192 //----------------- Parameters for Monte Carlo Simulated Annealing
193 //--------------------------
194 auto mcwsprop = std::make_unique<WorkspaceProperty<TableWorkspace>>("MCSetupWorkspace", "", Direction::Input,
196 declareProperty(std::move(mcwsprop), "Name of table workspace containing parameters' "
197 "setup for Monte Carlo simualted annearling. ");
198 setPropertySettings("MCSetupWorkspace", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
199
200 declareProperty("RandomSeed", 1, "Random number seed.");
201 setPropertySettings("RandomSeed", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
202
203 declareProperty("AnnealingTemperature", 1.0,
204 "Temperature used Monte Carlo. "
205 "Negative temperature is for simulated annealing. ");
206 setPropertySettings("AnnealingTemperature",
207 std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
208
209 declareProperty("UseAnnealing", true, "Allow annealing temperature adjusted automatically.");
210 setPropertySettings("UseAnnealing", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
211
212 declareProperty("DrunkenWalk", false,
213 "Flag to use drunken walk algorithm. "
214 "Otherwise, random walk algorithm is used. ");
215 setPropertySettings("DrunkenWalk", std::make_unique<VisibleWhenProperty>("Function", IS_EQUAL_TO, "MonteCarlo"));
216
217 declareProperty("MinimumPeakHeight", 0.01,
218 "Minimum height of a peak to be counted "
219 "during smoothing background by exponential smooth algorithm. ");
220
221 // Flag to allow input hkl file containing degenerated peaks
222 declareProperty("AllowDegeneratedPeaks", false,
223 "Flag to allow degenerated peaks in input .hkl file. "
224 "Otherwise, an exception will be thrown if this situation occurs.");
225
226 // Tolerance of imported peak's position comparing to data range
227 declareProperty("ToleranceToImportPeak", EMPTY_DBL(),
228 "Tolerance in TOF to import peak from Bragg "
229 "peaks list. If it specified, all peaks within Xmin-Tol and "
230 "Xmax+Tol will be imported. "
231 "It is used in the case that the geometry parameters are "
232 "close to true values. ");
233}
234
235//----------------------------------------------------------------------------------------------
239 // Process input properties
241
242 // Import parameters from table workspace
245
246 // Background function and calculation on it
248
249 // Create Le Bail function
251
252 // Create output workspace/workspace
254
255 // 5. Adjust function mode according to input values
256 if (m_lebailFunction->isParameterValid()) {
257 // All peaks within range are physical and good to refine
259 } else {
260 // Some peaks within range have unphysical parameters. Just calcualtion for
261 // reference
263 g_log.warning() << "Input instrument parameters values cause some peaks to have "
264 "unphysical profile parameters.\n";
265 if (m_fitMode == FIT || m_fitMode == MONTECARLO) {
266 g_log.warning() << "Function mode FIT is disabled. Convert to Calculation mode.\n";
268 }
269 }
270
271 // 7. Do calculation or fitting
272 m_lebailFitChi2 = -1; // Initialize
273 m_lebailCalChi2 = -1;
274
275 switch (m_fitMode) {
276 case CALCULATION:
277 // Calculation
278 g_log.notice() << "Function: Pattern Calculation.\n";
280 break;
281
282 case FIT:
283 // LeBail Fit
284 g_log.notice() << "Function: Do LeBail Fit ==> Monte Carlo.\n";
285 // fall through
286 case MONTECARLO:
287 // Monte carlo Le Bail refinement
288 g_log.notice("Function: Do LeBail Fit By Monte Carlo Random Walk.");
290
291 break;
292
294 // Calculating background
295 // FIXME : Determine later whether this functionality is kept or removed!
296 g_log.notice() << "Function: Refine Background (Precisely).\n";
298 break;
299
300 default:
301 // Impossible
302 std::stringstream errmsg;
303 errmsg << "FunctionMode = " << m_fitMode << " is not supported in exec().";
304 g_log.error() << errmsg.str() << "\n";
305 throw std::runtime_error(errmsg.str());
306
307 break;
308 }
309
310 // 7. Output peak (table) and parameter workspace
313
314 setProperty("OutputWorkspace", m_outputWS);
315
316 // 8. Final statistic
317 Rfactor finalR = getRFactor(m_outputWS->y(0).rawData(), m_outputWS->y(1).rawData(), m_outputWS->e(0).rawData());
318 g_log.notice() << "\nFinal R factor: Rwp = " << finalR.Rwp << ", Rp = " << finalR.Rp
319 << ", Data points = " << m_outputWS->y(1).size() << ", Range = " << m_outputWS->x(0)[0] << ", "
320 << m_outputWS->x(0).back() << "\n";
321}
322
323//----------------------------------------------------------------------------------------------
328 // FIXME - Need to think of FullprofPolynomial
329 // Type
330 m_backgroundType = getPropertyValue("BackgroundType");
331
332 // Parameters
333 m_backgroundParameters = getProperty("BackgroundParameters");
334 TableWorkspace_sptr bkgdparamws = getProperty("BackgroundParametersWorkspace");
335
336 // Determine where the background parameters are from
337 if (!bkgdparamws) {
338 // Set up parameter name
340 size_t i0 = 0;
341 if (m_backgroundType == "FullprofPolynomial") {
342 // TODO - Add this special case to Wiki
343 m_backgroundParameterNames.emplace_back("Bkpos");
345 g_log.warning("Bkpos is out side of data range. It MIGHT NOT BE RIGHT. ");
346 i0 = 1;
347 }
348
349 size_t numparams = m_backgroundParameters.size();
350 for (size_t i = i0; i < numparams; ++i) {
351 stringstream parss;
352 parss << "A" << (i - i0);
353 m_backgroundParameterNames.emplace_back(parss.str());
354 }
355
356 g_log.information() << "[Input] Use background specified with vector with "
357 "input vector sized "
358 << numparams << ".\n";
359 } else {
360 g_log.information() << "[Input] Use background specified by table workspace.\n";
362 }
363
364 // Set up background order
365 m_bkgdorder = static_cast<unsigned int>(m_backgroundParameterNames.size());
366 if (m_backgroundType == "FullprofPolynomial") {
367 // Consider 1 extra Bkpos
368 if (m_bkgdorder == 0)
369 throw runtime_error("FullprofPolynomial: Bkpos must be given! ");
370 else if (m_bkgdorder <= 7)
371 m_bkgdorder = 6;
372 else if (m_bkgdorder <= 13)
373 m_bkgdorder = 12;
374 else
375 throw runtime_error("There is something wrong to set up FullprofPolynomial. ");
376 } else {
377 // order n will have n+1 parameters
378 if (m_bkgdorder == 0)
379 throw runtime_error("Polynomial and Chebyshev at least be order 0 (1 parameter). ");
380 --m_bkgdorder;
381 }
382}
383
384//=================================== Pattern Calculation & Minimizing
385//=======================
386
387//----------------------------------------------------------------------------------------------
395 // Generate domain and values vectors
396 const auto &vecX = m_dataWS->x(m_wsIndex).rawData();
397 std::vector<double> vecY(m_outputWS->y(CALDATAINDEX).size(), 0);
398
399 // Calculate diffraction pattern
400 Rfactor rfactor(-DBL_MAX, -DBL_MAX);
401 // FIXME - It should be a new ticket to turn on this option (use
402 // user-specified peak height)
403 bool useinputpeakheights = this->getProperty("UseInputPeakHeights");
404 if (useinputpeakheights)
405 g_log.warning("UseInputPeakHeights is temporarily turned off now. ");
406
407 // Set the parameters to LeBailFunction
408 map<string, double> profilemap = convertToDoubleMap(m_funcParameters);
409 m_lebailFunction->setProfileParameterValues(profilemap);
410
411 // Calculate peak intensities and diffraction pattern
412 vector<double> emptyvec;
413 bool resultphysical =
414 calculateDiffractionPattern(m_dataWS->x(m_wsIndex), m_dataWS->y(m_wsIndex), true, true, emptyvec, vecY, rfactor);
415 m_outputWS->mutableY(CALDATAINDEX) = vecY;
416
417 // Calculate background
418 m_outputWS->mutableY(INPUTBKGDINDEX) = m_lebailFunction->function(vecX, false, true);
419
421
422 // Set up output workspaces
424
425 // Calcualte individual peaks
426 bool ploteachpeak = this->getProperty("PlotIndividualPeaks");
427 g_log.information() << "Output individual peaks = " << ploteachpeak << ".\n";
428 if (ploteachpeak) {
429 for (size_t ipk = 0; ipk < m_lebailFunction->getNumberOfPeaks(); ++ipk) {
430 m_outputWS->mutableY(9 + ipk) = m_lebailFunction->calPeak(ipk, vecX, m_outputWS->y(9 + ipk).size());
431 }
432 }
433
434 // Record for output
435 Parameter par_rwp;
436 par_rwp.name = "Rwp";
437 par_rwp.curvalue = rfactor.Rwp;
438 m_funcParameters["Rwp"] = par_rwp;
439
440 g_log.notice() << "Rwp = " << rfactor.Rwp << ", Rp = " << rfactor.Rp << "\n";
441
442 if (!resultphysical) {
443 g_log.warning() << "Input parameters are unable to generate peaks that are physical."
444 << ".\n";
445 }
446}
447
448//==================================== Refine background
449//====================================
450//----------------------------------------------------------------------------------------------
459 // Set up class variables for background
460 m_bkgdParameterNames = m_backgroundFunction->getParameterNames();
464 m_roundBkgd = 0;
466 for (size_t i = 1; i < m_numberBkgdParameters; ++i) {
468 }
469
470 // 1. Generate domain and value
471 const auto &vecX = m_dataWS->x(m_wsIndex).rawData();
472 const auto &vecY = m_dataWS->y(m_wsIndex);
473 vector<double> valueVec(vecX.size(), 0);
474 size_t numpts = vecX.size();
475
476 API::FunctionDomain1DVector domain(vecX);
477 API::FunctionValues values(domain);
478
479 // 2. Calculate diffraction pattern
480 Rfactor currR(DBL_MAX, DBL_MAX);
481 m_backgroundFunction->function(domain, values);
482 vector<double> backgroundvalues = values.toVector();
483 for (size_t i = 0; i < numpts; ++i) {
484 m_outputWS->mutableY(INPUTPUREPEAKINDEX)[i] = m_dataWS->y(m_wsIndex)[i] - values[i];
485 }
486 m_outputWS->setSharedE(INPUTPUREPEAKINDEX, m_dataWS->sharedE(m_wsIndex));
487 map<string, double> parammap = convertToDoubleMap(m_funcParameters);
488 m_lebailFunction->setProfileParameterValues(parammap);
490 backgroundvalues, valueVec, currR);
491 Rfactor bestR = currR;
493 stringstream bufss;
494 bufss << "Starting background parameter ";
495 for (size_t i = 0; i < m_bestBkgdParams.size(); ++i)
496 bufss << "[" << i << "] = " << m_bestBkgdParams[i] << ", ";
497 bufss << ". Starting Rwp = " << currR.Rwp;
498 g_log.notice(bufss.str());
499
500 for (size_t istep = 0; istep < m_numMinimizeSteps; ++istep) {
501 // a) Store current setup
503
504 // b) Propose new values and evalulate
506 Rfactor newR(DBL_MAX, DBL_MAX);
507 m_backgroundFunction->function(domain, values);
508 backgroundvalues = values.toVector();
509 for (size_t i = 0; i < numpts; ++i) {
510 m_outputWS->mutableY(INPUTPUREPEAKINDEX)[i] = m_dataWS->y(m_wsIndex)[i] - values[i];
511 }
513 m_lebailFunction->setProfileParameterValues(parammap);
515 backgroundvalues, valueVec, newR);
516
517 g_log.information() << "[DBx800] New Rwp = " << newR.Rwp << ", Rp = " << newR.Rp << ".\n";
518
519 bool accept = acceptOrDeny(currR, newR);
520
521 // c) Process result
522 if (!accept) {
523 // Not accept. Restore original
525 } else {
526 // Accept
527 currR = newR;
528 if (newR.Rwp < bestR.Rwp) {
529 // Is it the best?
530 bestR = newR;
532
533 stringstream ss;
534 ss << "Temp best background parameter ";
535 for (size_t i = 0; i < m_bestBkgdParams.size(); ++i)
536 ss << "[" << i << "] = " << m_bestBkgdParams[i] << ", ";
537 g_log.information(ss.str());
538 }
539 }
540
541 // d) Progress
542 progress(static_cast<double>(istep) / static_cast<double>(m_numMinimizeSteps));
543 }
544
545 // 3. Recover the best
547
548 stringstream bufss1;
549 bufss1 << "Best background parameter ";
550 for (size_t i = 0; i < m_bkgdParameterStepVec.size(); ++i)
551 bufss1 << "[" << i << "] = " << m_backgroundFunction->getParameter(i) << ", ";
552 g_log.notice(bufss1.str());
553
554 Rfactor outputR(-DBL_MAX, -DBL_MAX);
555 m_backgroundFunction->function(domain, values);
556 backgroundvalues = values.toVector();
557 for (size_t i = 0; i < numpts; ++i) {
558 m_outputWS->mutableY(INPUTPUREPEAKINDEX)[i] = m_dataWS->y(m_wsIndex)[i] - values[i];
559 }
561 m_lebailFunction->setProfileParameterValues(parammap);
563 backgroundvalues, valueVec, outputR);
564
565 g_log.notice() << "[RefineBackground] Best Rwp = " << bestR.Rwp << ", vs. recovered best Rwp = " << outputR.Rwp
566 << ".\n";
567
568 // 4. Add data (0: experimental, 1: calcualted, 2: difference)
569 auto &vecY1 = m_outputWS->mutableY(1);
570 auto &vecY2 = m_outputWS->mutableY(2);
571 for (size_t i = 0; i < numpts; ++i) {
572 vecY1[i] = valueVec[i] + backgroundvalues[i];
573 vecY2[i] = vecY[i] - (valueVec[i] + backgroundvalues[i]);
574 }
575
576 // (3: peak without background, 4: input background)
577 // m_backgroundFunction->function(domain, values);
578 m_outputWS->mutableY(CALBKGDINDEX) = backgroundvalues;
579 m_outputWS->mutableY(CALPUREPEAKINDEX) = valueVec;
580
581 // 5. Output background to table workspace
582 auto outtablews = std::make_shared<TableWorkspace>();
583 outtablews->addColumn("str", "Name");
584 outtablews->addColumn("double", "Value");
585 outtablews->addColumn("double", "Error");
586
587 for (const auto &parname : m_bkgdParameterNames) {
588 double parvalue = m_backgroundFunction->getParameter(parname);
589
590 TableRow newrow = outtablews->appendRow();
591 newrow << parname << parvalue << 1.0;
592 }
593
594 setProperty("BackgroundParametersWorkspace", outtablews);
595}
596
597//----------------------------------------------------------------------------------------------
602void LeBailFit::storeBackgroundParameters(vector<double> &bkgdparamvec) {
603 for (size_t i = 0; i < m_numberBkgdParameters; ++i) {
604 bkgdparamvec[i] = m_backgroundFunction->getParameter(i);
605 }
606}
607
612void LeBailFit::recoverBackgroundParameters(const vector<double> &bkgdparamvec) {
613 for (size_t i = 0; i < m_numberBkgdParameters; ++i) {
614 m_backgroundFunction->setParameter(i, bkgdparamvec[i]);
615 }
616}
617
621 int iparam = m_roundBkgd % static_cast<int>(m_numberBkgdParameters);
622
623 double currvalue = m_backgroundFunction->getParameter(static_cast<int>(iparam));
624 double r = 2 * (static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 0.5);
625 double newvalue = currvalue + r * m_bkgdParameterStepVec[iparam];
626
627 g_log.information() << "[DBx804] Background " << iparam << " propose new value = " << newvalue << " from "
628 << currvalue << ".\n";
629
630 m_backgroundFunction->setParameter(static_cast<size_t>(iparam), newvalue);
631
632 ++m_roundBkgd;
633}
634
635//=================================== Set up the Le Bail Fit
636//================================
637//----------------------------------------------------------------------------------------------
642 // Generate Le Bail function
643 m_lebailFunction = std::make_shared<LeBailFunction>(LeBailFunction(m_peakType));
644
645 // Set up profile parameters
646 if (m_funcParameters.empty())
647 throw runtime_error("Function parameters must be set up by this point.");
648
649 map<string, double> pardblmap = convertToDoubleMap(m_funcParameters);
650 m_lebailFunction->setProfileParameterValues(pardblmap);
651
652 // Add peaks
653 if (!isEmpty(m_peakCentreTol)) {
654 const auto &vecx = m_dataWS->x(m_wsIndex);
655 m_lebailFunction->setPeakCentreTolerance(m_peakCentreTol, vecx.front(), vecx.back());
656 }
657
658 vector<vector<int>> vecHKL;
659 vector<pair<vector<int>, double>>::iterator piter;
660 for (piter = m_inputPeakInfoVec.begin(); piter != m_inputPeakInfoVec.end(); ++piter)
661 vecHKL.emplace_back(piter->first);
662 m_lebailFunction->addPeaks(vecHKL);
663
664 // Add background
667}
668
669//----------------------------------------------------------------------------------------------
675 // Process input property 'FitRegion' for range of data to fit/calculate
676 std::vector<double> fitrange = this->getProperty("FitRegion");
677
678 double tof_min, tof_max;
679 if (fitrange.empty()) {
680 tof_min = inpws->x(wsindex)[0];
681 tof_max = inpws->x(wsindex).back();
682 } else if (fitrange.size() == 2) {
683 tof_min = fitrange[0];
684 tof_max = fitrange[1];
685 } else {
686 g_log.warning() << "Input FitRegion has more than 2 entries. Using "
687 "default in stread.\n";
688
689 tof_min = inpws->x(wsindex)[0];
690 tof_max = inpws->x(wsindex).back();
691 }
692
693 // Crop workspace
694 auto cropalg = createChildAlgorithm("CropWorkspace", -1, -1, true);
695 cropalg->initialize();
696
697 cropalg->setProperty("InputWorkspace", inpws);
698 cropalg->setPropertyValue("OutputWorkspace", "MyData");
699 cropalg->setProperty("XMin", tof_min);
700 cropalg->setProperty("XMax", tof_max);
701
702 bool cropstatus = cropalg->execute();
703 if (!cropstatus) {
704 std::stringstream errmsg;
705 errmsg << "DBx309 Cropping workspace unsuccessful. Fatal Error. Quit!";
706 g_log.error() << errmsg.str() << "\n";
707 throw std::runtime_error(errmsg.str());
708 }
709
710 API::MatrixWorkspace_sptr cropws = cropalg->getProperty("OutputWorkspace");
711 if (!cropws) {
712 g_log.error("Unable to retrieve a Workspace2D object from ChildAlgorithm "
713 "CropWorkspace");
714 throw runtime_error("Unable to retrieve a Workspace2D object from "
715 "ChildAlgorithm CropWorkspace");
716 } else {
717 g_log.debug() << "DBx307: Cropped Workspace... Range From " << cropws->x(wsindex)[0] << " To "
718 << cropws->x(wsindex).back() << " of size " << cropws->x(wsindex).size() << "\n";
719 }
720
721 return cropws;
722}
723
724//================================= Import/Parse and Output
725//===================================
726//----------------------------------------------------------------------------------------------
730 // Peak type
731 m_peakType = getPropertyValue("PeakType");
732
733 // 1. Get input and perform some check
734 // a) Import data workspace and related, do crop
735 API::MatrixWorkspace_sptr inpWS = this->getProperty("InputWorkspace");
736
737 int tempindex = this->getProperty("WorkspaceIndex");
738 m_wsIndex = size_t(tempindex);
739
740 if (m_wsIndex >= inpWS->getNumberHistograms()) {
741 // throw if workspace index is not correct
742 stringstream errss;
743 errss << "Input WorkspaceIndex " << tempindex << " is out of boundary [0, " << inpWS->getNumberHistograms()
744 << "). ";
745 g_log.error(errss.str());
746 throw runtime_error(errss.str());
747 }
748
749 m_dataWS = this->cropWorkspace(inpWS, m_wsIndex);
750 m_startX = m_dataWS->x(0).front();
751 m_endX = m_dataWS->x(0).back();
752
753 // b) Minimizer
754 std::string minim = getProperty("Minimizer");
755 mMinimizer = minim;
756
757 // c) Peak parameters and related.
758 parameterWS = this->getProperty("InputParameterWorkspace");
759 reflectionWS = this->getProperty("InputHKLWorkspace");
760 mPeakRadius = this->getProperty("PeakRadius");
761
762 // d) Determine Functionality (function mode)
763 std::string function = this->getProperty("Function");
764 m_fitMode = FIT; // Default: LeBailFit
765 if (function == "Calculation") {
766 // peak calculation
768 } else if (function == "CalculateBackground") {
769 // automatic background points selection
771 } else if (function == "MonteCarlo") {
772 // Monte Carlo random walk refinement
774 } else if (function == "LeBailFit") {
775 // Le Bail Fit mode
776 m_fitMode = FIT;
777 } else if (function == "RefineBackground") {
778 // Refine background mode
780 } else {
781 stringstream errss;
782 errss << "Function mode " << function << " is not supported by LeBailFit().";
783 g_log.error(errss.str());
784 throw invalid_argument(errss.str());
785 }
786
787 m_dampingFactor = getProperty("Damping");
788
789 tempindex = getProperty("NumberMinimizeSteps");
790 if (tempindex > 0)
791 m_numMinimizeSteps = static_cast<size_t>(tempindex);
792 else {
794 stringstream errss;
795 errss << "Input number of random walk steps (" << m_numMinimizeSteps << ") cannot be less and equal to zero.";
796 g_log.error(errss.str());
797 throw invalid_argument(errss.str());
798 }
799
800 m_minimumPeakHeight = getProperty("MinimumPeakHeight");
801 m_indicatePeakHeight = getProperty("IndicationPeakHeight");
802
803 // Tolerate duplicated input peak or not?
804 m_tolerateInputDupHKL2Peaks = getProperty("AllowDegeneratedPeaks");
805
806 // Tolerance in peak positions to import peak
807 m_peakCentreTol = getProperty("ToleranceToImportPeak");
808}
809
810//----------------------------------------------------------------------------------------------
815 // 1. Check column orders
816 if (parameterWS->columnCount() < 3) {
817 g_log.error() << "Input parameter table workspace does not have enough "
818 "number of columns. "
819 << " Number of columns (Input =" << parameterWS->columnCount() << ") >= 3 as required.\n";
820 throw std::invalid_argument("Input parameter workspace is wrong. ");
821 } else {
822 g_log.information() << "[DB] Starting to parse instrument parameter table workspace " << parameterWS->getName()
823 << ".\n";
824 }
825
826 // 2. Import data to maps
827 size_t numrows = parameterWS->rowCount();
828 std::vector<std::string> colnames = parameterWS->getColumnNames();
829 size_t numcols = colnames.size();
830
831 std::map<std::string, double> tempdblmap;
832 std::map<std::string, std::string> tempstrmap;
833 std::map<std::string, double>::iterator dbliter;
834 std::map<string, string>::iterator striter;
835
836 std::string colname;
837 double dblvalue;
838 std::string strvalue;
839
840 for (size_t ir = 0; ir < numrows; ++ir) {
841 // a) Clear the map
842 tempdblmap.clear();
843 tempstrmap.clear();
844
845 // b) Get the row
846 API::TableRow trow = parameterWS->getRow(ir);
847
848 // c) Parse each term
849 for (size_t icol = 0; icol < numcols; ++icol) {
850 colname = colnames[icol];
851 if (colname != "FitOrTie" && colname != "Name") {
852 // double data
853 g_log.debug() << "Col-name = " << colname << ", ";
854 trow >> dblvalue;
855 g_log.debug() << "Value = " << dblvalue << ".\n";
856 ;
857 tempdblmap.emplace(colname, dblvalue);
858 } else {
859 // string data
860 g_log.debug() << "Col-name = " << colname << ", ";
861 trow >> strvalue;
862 strvalue.erase(std::find_if(strvalue.rbegin(), strvalue.rend(), std::not_fn(::isspace)).base(), strvalue.end());
863
864 g_log.debug() << "Value = " << strvalue << ".\n";
865 tempstrmap.emplace(colname, strvalue);
866 }
867 }
868
869 // d) Construct a Parameter instance
870 Parameter newparameter;
871 // i. name
872 striter = tempstrmap.find("Name");
873 if (striter != tempstrmap.end()) {
874 newparameter.name = striter->second;
875 } else {
876 std::stringstream errmsg;
877 errmsg << "Parameter (table) workspace " << parameterWS->getName()
878 << " does not contain column 'Name'. It is not a valid input. "
879 "Quit ";
880 g_log.error() << errmsg.str() << "\n";
881 throw std::invalid_argument(errmsg.str());
882 }
883
884 // ii. fit
885 striter = tempstrmap.find("FitOrTie");
886 if (striter != tempstrmap.end()) {
887 std::string fitortie = striter->second;
888 bool tofit = true;
889 if (fitortie.length() > 0) {
890 char fc = fitortie.c_str()[0];
891 if (fc == 't' || fc == 'T') {
892 tofit = false;
893 }
894 }
895 newparameter.fit = tofit;
896 } else {
897 std::stringstream errmsg;
898 errmsg << "Parameter (table) workspace " << parameterWS->getName()
899 << " does not contain column 'FitOrTie'. It is not a valid "
900 "input. Quit ";
901 g_log.error() << errmsg.str() << "\n";
902 throw std::invalid_argument(errmsg.str());
903 }
904
905 // iii. value
906 dbliter = tempdblmap.find("Value");
907 if (dbliter != tempdblmap.end()) {
908 newparameter.curvalue = dbliter->second;
909 } else {
910 std::stringstream errmsg;
911 errmsg << "Parameter (table) workspace " << parameterWS->getName()
912 << " does not contain column 'Value'. It is not a valid input. "
913 "Quit ";
914 g_log.error() << errmsg.str() << "\n";
915 throw std::invalid_argument(errmsg.str());
916 }
917
918 // iv. min
919 dbliter = tempdblmap.find("Min");
920 if (dbliter != tempdblmap.end()) {
921 newparameter.minvalue = dbliter->second;
922 } else {
923 newparameter.minvalue = -1.0E10;
924 }
925
926 // v. max
927 dbliter = tempdblmap.find("Max");
928 if (dbliter != tempdblmap.end()) {
929 newparameter.maxvalue = dbliter->second;
930 } else {
931 newparameter.maxvalue = 1.0E10;
932 }
933
934 // vi. stepsize
935 dbliter = tempdblmap.find("StepSize");
936 if (dbliter != tempdblmap.end()) {
937 newparameter.stepsize = dbliter->second;
938 } else {
939 newparameter.stepsize = 1.0;
940 }
941
942 // vii. error
943 newparameter.fiterror = 1.0E10;
944
945 // viii. some historical records
946 // FIXME : Consider to move parameter value's min/max to Monte Carlo table
947 newparameter.minrecordvalue = newparameter.maxvalue + 1.0;
948 newparameter.maxrecordvalue = newparameter.minvalue - 1.0;
949
950 m_funcParameters.emplace(newparameter.name, newparameter);
951 m_origFuncParameters.emplace(newparameter.name, newparameter.curvalue);
952
953 g_log.information() << "Inserting Parameter " << newparameter.name << " = " << newparameter.curvalue << ".\n";
954
955 if (newparameter.fit) {
956 g_log.debug() << "[Input]: " << newparameter.name << ": value = " << newparameter.curvalue << " Range: ["
957 << newparameter.minvalue << ", " << newparameter.maxvalue
958 << "], MC Step = " << newparameter.stepsize << ", Fit? = " << newparameter.fit << "\n";
959 }
960 } // ENDFOR rows in Table
961
962 g_log.information() << "[DB]: Successfully Imported Peak Parameters TableWorkspace " << parameterWS->getName()
963 << ". Imported " << m_funcParameters.size() << " parameters. "
964 << "\n";
965}
966
967//----------------------------------------------------------------------------------------------
973 // 1. Check column orders
974 std::vector<std::string> colnames = reflectionWS->getColumnNames();
975 if (colnames.size() < 3) {
976 g_log.error() << "Input parameter table workspace does not have enough "
977 "number of columns. "
978 << " Number of columns = " << colnames.size() << " < 3 as required.\n";
979 throw std::runtime_error("Input parameter workspace is wrong. ");
980 }
981 if (colnames[0] != "H" || colnames[1] != "K" || colnames[2] != "L") {
982 stringstream errss;
983 errss << "Input Bragg peak parameter TableWorkspace does not have the "
984 "columns in order. "
985 << "It must be H, K, L. for the first 3 columns.";
986 g_log.error(errss.str());
987 throw std::runtime_error(errss.str());
988 }
989
990 // Has peak height?
991 bool hasPeakHeight = false;
992 if (colnames.size() >= 4 && colnames[3] == "PeakHeight") {
993 // Has a column for peak height
994 hasPeakHeight = true;
995 }
996
997 /* FIXME This section is disabled. It should be a new ticket to turn on this
998 option.
999 bool userexcludepeaks = false;
1000 if (colnames.size() >= 5 && colnames[4] == "Include/Exclude")
1001 {
1002 userexcludepeaks = true;
1003 }
1004 */
1005
1006 // 2. Import data to maps
1007 int h, k, l;
1008
1009 size_t numrows = reflectionWS->rowCount();
1010 for (size_t ir = 0; ir < numrows; ++ir) {
1011 // 1. Get from table row
1012 API::TableRow trow = reflectionWS->getRow(ir);
1013 trow >> h >> k >> l;
1014
1015 // 3. Insert related data structure
1016 std::vector<int> hkl;
1017 hkl.emplace_back(h);
1018 hkl.emplace_back(k);
1019 hkl.emplace_back(l);
1020
1021 // optional peak height
1022 double peakheight = 1.0;
1023 if (hasPeakHeight) {
1024 trow >> peakheight;
1025 }
1026
1027 m_inputPeakInfoVec.emplace_back(hkl, peakheight);
1028 } // ENDFOR row
1029
1030 g_log.information() << "Imported HKL TableWorkspace. Size of Rows = " << numrows << "\n";
1031}
1032
1033//----------------------------------------------------------------------------------------------
1037void LeBailFit::parseBackgroundTableWorkspace(const TableWorkspace_sptr &bkgdparamws, vector<string> &bkgdparnames,
1038 vector<double> &bkgdorderparams) {
1039 g_log.debug() << "DB1105A Parsing background TableWorkspace.\n";
1040
1041 // Clear (output) map
1042 bkgdorderparams.clear();
1043
1044 // Check background parameter table workspace
1045 std::vector<std::string> colnames = bkgdparamws->getColumnNames();
1046 if (colnames.size() < 2) {
1047 stringstream errss;
1048 errss << "Input background parameter table workspace " << bkgdparamws->getName() << " has only " << colnames.size()
1049 << " columns, which is fewer than 2 columns as required. ";
1050 g_log.error(errss.str());
1051 throw runtime_error(errss.str());
1052 } else {
1053 if (!(boost::starts_with(colnames[0], "Name") && boost::starts_with(colnames[1], "Value"))) {
1054 // Column 0 and 1 must be Name and Value (at least started with)
1055 stringstream errss;
1056 errss << "Input parameter table workspace have wrong column definition. "
1057 << "Column 0 should be Name. And column 1 should be Value. "
1058 "Current input is: \n";
1059 for (size_t i = 0; i < 2; ++i)
1060 errss << "Column " << i << ": " << colnames[0] << "\n";
1061 g_log.error(errss.str());
1062 throw runtime_error(errss.str());
1063 }
1064 }
1065
1066 // Parse input table workspace to a map. Valid parameter names must start
1067 // with A.
1068 std::map<std::string, double> parmap;
1069 for (size_t ir = 0; ir < bkgdparamws->rowCount(); ++ir) {
1070 API::TableRow row = bkgdparamws->getRow(ir);
1071 std::string parname;
1072 double parvalue;
1073 row >> parname >> parvalue;
1074
1075 // Remove extra white spaces
1076 boost::algorithm::trim(parname);
1077
1078 if (!parname.empty() && (parname[0] == 'A' || parname == "Bkpos")) {
1079 // Insert parameter name starting with A or Bkpos (special case for
1080 // FullprofPolynomial)
1081 parmap.emplace(parname, parvalue);
1082 }
1083 }
1084
1085 // Add pair to vector
1086 bkgdparnames.reserve(parmap.size());
1087 bkgdorderparams.reserve(parmap.size());
1088
1089 std::map<std::string, double>::iterator mit;
1090 for (mit = parmap.begin(); mit != parmap.end(); ++mit) {
1091 std::string parname = mit->first;
1092 double parvalue = mit->second;
1093 bkgdparnames.emplace_back(parname);
1094 bkgdorderparams.emplace_back(parvalue);
1095 }
1096
1097 // Debug output
1098 std::stringstream msg;
1099 msg << "Finished importing background TableWorkspace. "
1100 << "Background Order = " << bkgdorderparams.size() << ": ";
1101 for (size_t iod = 0; iod < bkgdorderparams.size(); ++iod) {
1102 msg << bkgdparnames[iod] << " = " << bkgdorderparams[iod] << "; ";
1103 }
1104 g_log.information(msg.str());
1105}
1106
1107//----------------------------------------------------------------------------------------------
1113 // Create peaks workspace
1115
1116 // Add columns to table/peak workspace
1117 peakWS->addColumn("int", "H");
1118 peakWS->addColumn("int", "K");
1119 peakWS->addColumn("int", "L");
1120 peakWS->addColumn("double", "Height");
1121 peakWS->addColumn("double", "TOF_h");
1122 peakWS->addColumn("double", "Alpha");
1123 peakWS->addColumn("double", "Beta");
1124 peakWS->addColumn("double", "Sigma2");
1125 peakWS->addColumn("double", "Gamma");
1126 peakWS->addColumn("double", "FWHM");
1127 peakWS->addColumn("int", "PeakGroup");
1128 peakWS->addColumn("double", "Chi^2");
1129 peakWS->addColumn("str", "FitStatus");
1130
1131 // Add each peak in LeBailFunction to peak/table workspace
1132 for (size_t ipk = 0; ipk < m_lebailFunction->getNumberOfPeaks(); ++ipk) {
1133
1134 // Miller index and peak parameters
1136
1137 int h, k, l;
1138 peak->getMillerIndex(h, k, l);
1139 double tof_h = peak->centre();
1140 double height = peak->height();
1141 double alpha = peak->getPeakParameter("Alpha");
1142 double beta = peak->getPeakParameter("Beta");
1143 double sigma2 = peak->getPeakParameter("Sigma2");
1144 double gamma = peak->getPeakParameter("Gamma");
1145 double fwhm = peak->fwhm();
1146
1147 // New row
1148 API::TableRow newrow = peakWS->appendRow();
1149 newrow << h << k << l << height << tof_h << alpha << beta << sigma2 << gamma << fwhm << -1 << -1.0 << "N/A";
1150
1151 if (tof_h < 0) {
1152 stringstream errss;
1153 errss << "Peak (" << h << ", " << k << ", " << l << "): TOF_h (=" << tof_h << ") is NEGATIVE!";
1154 g_log.error(errss.str());
1155 }
1156 }
1157
1158 // Set property
1159 this->setProperty("OutputPeaksWorkspace", peakWS);
1160}
1161
1162//----------------------------------------------------------------------------------------------
1168void LeBailFit::exportInstrumentParameterToTable(std::map<std::string, Parameter> parammap) {
1169 // 1. Create table workspace
1171
1172 tablews = new DataObjects::TableWorkspace();
1173 DataObjects::TableWorkspace_sptr parameterws(tablews);
1174
1175 tablews->addColumn("str", "Name");
1176 tablews->addColumn("double", "Value");
1177 tablews->addColumn("str", "FitOrTie");
1178 tablews->addColumn("double", "chi^2");
1179 tablews->addColumn("double", "Min");
1180 tablews->addColumn("double", "Max");
1181 tablews->addColumn("double", "StepSize");
1182 tablews->addColumn("double", "StartValue");
1183 tablews->addColumn("double", "Diff");
1184
1185 // 2. Add profile parameter value
1186 std::map<std::string, Parameter>::iterator paramiter;
1187 std::map<std::string, double>::iterator opiter;
1188 for (paramiter = parammap.begin(); paramiter != parammap.end(); ++paramiter) {
1189 std::string parname = paramiter->first;
1190 if (parname != "Height") {
1191 // Export every parameter except "Height"
1192
1193 // a) current value
1194 double parvalue = paramiter->second.curvalue;
1195
1196 // b) fit or tie?
1197 char fitortie = 't';
1198 if (paramiter->second.fit) {
1199 fitortie = 'f';
1200 }
1201 std::stringstream ss;
1202 ss << fitortie;
1203 std::string fit_tie = ss.str();
1204
1205 // c) starting value
1206 opiter = m_origFuncParameters.find(parname);
1207 double origparvalue = -1.0E100;
1208 if (opiter != m_origFuncParameters.end()) {
1209 origparvalue = opiter->second;
1210 }
1211 double diff = origparvalue - parvalue;
1212
1213 // d. (standard) error
1214 double paramerror = paramiter->second.fiterror;
1215
1216 // e. create the row
1217 double min = paramiter->second.minvalue;
1218 double max = paramiter->second.maxvalue;
1219 double step = paramiter->second.stepsize;
1220
1221 API::TableRow newparam = tablews->appendRow();
1222 newparam << parname << parvalue << fit_tie << paramerror << min << max << step << origparvalue << diff;
1223 } // ENDIF
1224 }
1225
1226 // 3. Add chi^2
1228 // Impossible mode
1229 throw runtime_error("Impossible to have this situation happen. Flag 541.");
1230 } else if (!m_inputParameterPhysical) {
1231 // Input instrument profile parameters are not physical
1232 m_lebailCalChi2 = DBL_MAX;
1233 m_lebailFitChi2 = DBL_MAX;
1234 }
1235
1236 if (m_fitMode == FIT) {
1237 // Do this for FIT mode only
1238 API::TableRow fitchi2row = tablews->appendRow();
1239 fitchi2row << "FitChi2" << m_lebailFitChi2 << "t" << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
1240 API::TableRow chi2row = tablews->appendRow();
1241 chi2row << "Chi2" << m_lebailCalChi2 << "t" << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
1242 }
1243
1244 // 4. Add to output peroperty
1245 setProperty("OutputParameterWorkspace", parameterws);
1246}
1247
1248//----------------------------------------------------------------------------------------------
1264 // 1. Determine number of output spectra
1265 size_t nspec = 9;
1266
1267 if (m_fitMode == CALCULATION) {
1268 bool plotindpeak = this->getProperty("PlotIndividualPeaks");
1269 if (plotindpeak) {
1270 nspec += m_lebailFunction->getNumberOfPeaks();
1271 g_log.information() << "Number of peaks to add to output data = " << m_lebailFunction->getNumberOfPeaks()
1272 << ".\n";
1273 }
1274 }
1275
1276 // 2. Create workspace2D and set the data to spectrum 0 (common among all)
1277 size_t nbinx = m_dataWS->x(m_wsIndex).size();
1278 size_t nbiny = m_dataWS->y(m_wsIndex).size();
1279 m_outputWS = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
1280 API::WorkspaceFactory::Instance().create("Workspace2D", nspec, nbinx, nbiny));
1281
1282 // 3. Add values
1283 // All X.
1284 for (size_t j = 0; j < m_outputWS->getNumberHistograms(); ++j)
1285 m_outputWS->setSharedX(j, m_dataWS->sharedX(m_wsIndex));
1286
1287 // Observation
1288 m_outputWS->setSharedY(OBSDATAINDEX, m_dataWS->sharedY(m_wsIndex));
1289 m_outputWS->setSharedE(OBSDATAINDEX, m_dataWS->sharedE(m_wsIndex));
1290
1291 // 4. Set axis
1292 m_outputWS->getAxis(0)->setUnit("TOF");
1293
1294 auto tAxis = std::make_unique<API::TextAxis>(nspec);
1295 tAxis->setLabel(0, "Data");
1296 tAxis->setLabel(1, "Calc");
1297 tAxis->setLabel(2, "Diff");
1298 tAxis->setLabel(3, "CalcNoBkgd");
1299 tAxis->setLabel(4, "OutBkgd");
1300 tAxis->setLabel(5, "InpCalc");
1301 tAxis->setLabel(6, "InBkgd");
1302 tAxis->setLabel(7, "DataNoBkgd");
1303 tAxis->setLabel(8, "SmoothedBkgd");
1304
1305 if (m_fitMode == CALCULATION) {
1306 // Set the single peak labels
1307 for (size_t i = 0; i < (nspec - 9); ++i) {
1308 std::stringstream ss;
1309 ss << "Peak_" << i;
1310 tAxis->setLabel(9 + i, ss.str());
1311 }
1312 }
1313
1314 m_outputWS->replaceAxis(1, std::move(tAxis));
1315}
1316
1317// ====================================== Random Walk Suite
1318// ====================================
1319//----------------------------------------------------------------------------------------------
1325void LeBailFit::execRandomWalkMinimizer(size_t maxcycles, map<string, Parameter> &parammap) {
1326 // Set up random walk parameters
1327 const auto &vecX = m_dataWS->x(m_wsIndex);
1328 const auto &vecInY = m_dataWS->y(m_wsIndex);
1329
1330 const auto &domain = m_dataWS->x(m_wsIndex).rawData();
1331 std::vector<double> vecCalPurePeaks(domain.size(), 0.0);
1332
1333 // Strategy and map
1334 TableWorkspace_sptr mctablews = getProperty("MCSetupWorkspace");
1335 if (mctablews) {
1337 } else {
1339 }
1340 // Walking style/algorithm
1341 bool usedrunkenwalk = getProperty("DrunkenWalk");
1342 if (usedrunkenwalk)
1344 else
1346 // Annealing temperature
1347 m_Temperature = getProperty("AnnealingTemperature");
1348 if (m_Temperature < 0)
1350 m_useAnnealing = getProperty("UseAnnealing");
1351 // Random seed
1352 int randomseed = getProperty("RandomSeed");
1353
1354 // R-factors used for MC procedure
1355 Rfactor startR(-DBL_MAX, -DBL_MAX);
1356
1357 // Process background to make a pure peak spectrum in output workspace
1358 HistogramY vecBkgd = m_lebailFunction->function(vecX.rawData(), false, true);
1359 m_outputWS->mutableY(INPUTBKGDINDEX) = vecBkgd;
1360 m_outputWS->mutableY(INPUTPUREPEAKINDEX) = vecInY - vecBkgd;
1361
1362 // Calcualte starting Rwp and etc
1363 const auto &vecPurePeak = m_outputWS->y(INPUTPUREPEAKINDEX);
1364
1365 map<string, double> pardblmap = convertToDoubleMap(parammap);
1366 m_lebailFunction->setProfileParameterValues(pardblmap);
1367 bool startvaluevalid = calculateDiffractionPattern(vecX, vecPurePeak, false, false, vecBkgd, vecCalPurePeaks, startR);
1368 if (!startvaluevalid) {
1369 // Throw exception if starting values are not valid for all
1370 throw runtime_error("Starting value of instrument profile parameters can "
1371 "generate peaks with"
1372 " unphyiscal parameters values.");
1373 }
1374
1375 doMarkovChain(parammap, vecX, vecPurePeak, vecBkgd.rawData(), maxcycles, startR, randomseed);
1376
1377 // 5. Sum up: retrieve the best result from class variable: m_bestParameters
1378 Rfactor finalR(-DBL_MAX, -DBL_MAX);
1379 map<string, double> bestparams = convertToDoubleMap(m_bestParameters);
1380 m_lebailFunction->setProfileParameterValues(bestparams);
1381 calculateDiffractionPattern(vecX, vecPurePeak, false, false, vecBkgd, vecCalPurePeaks, finalR);
1382
1383 auto &vecCalY = m_outputWS->mutableY(CALDATAINDEX);
1384 auto &vecDiff = m_outputWS->mutableY(DATADIFFINDEX);
1385 auto &vecCalPurePeak = m_outputWS->mutableY(CALPUREPEAKINDEX);
1386 auto &vecCalBkgd = m_outputWS->mutableY(CALBKGDINDEX);
1387 // Calculated (refined) data
1388 vecCalY = vecCalPurePeaks;
1389 vecCalY += vecBkgd;
1390 // Diff
1391 vecDiff = vecInY - vecCalY;
1392 // Calcualted without background (pure peaks)
1393 vecCalPurePeak = vecCalPurePeaks;
1394 // Different between calculated peaks and raw data
1395 vecCalBkgd = vecInY - vecCalPurePeaks;
1396
1397 // c) Apply the best parameters to param
1399 Parameter par_rwp;
1400 par_rwp.name = "Rwp";
1401 par_rwp.curvalue = m_bestRwp;
1402 parammap["Rwp"] = par_rwp;
1403} // Main Exec MC
1404
1405//----------------------------------------------------------------------------------------------
1408void LeBailFit::doMarkovChain(const map<string, Parameter> &parammap, const Mantid::HistogramData::HistogramX &vecX,
1409 const Mantid::HistogramData::HistogramY &vecPurePeak, const vector<double> &vecBkgd,
1410 size_t maxcycles, const Rfactor &startR, int randomseed) {
1411
1412 // Rfactors in loop
1413 Rfactor currR(-DBL_MAX, -DBL_MAX), newR(-DBL_MAX, -DBL_MAX);
1414 // parameter map for newly proposed values
1415 map<string, Parameter> mapCurrParameter = parammap;
1416 map<string, Parameter> newparammap = mapCurrParameter;
1417 // Output vector from
1418 std::vector<double> veccalpurepeaks(vecX.size(), 0.0);
1419
1420 // Set starting parameters
1421 currR = startR;
1422 m_bestRwp = currR.Rwp + EPSILON;
1423 m_bestRp = currR.Rp + EPSILON;
1424 bookKeepBestMCResult(mapCurrParameter, vecBkgd, currR, 0);
1425
1426 g_log.notice() << "[MC-Start] Random-walk Starting Rwp = " << currR.Rwp << ", Rp = " << currR.Rp << "\n";
1427
1428 // Random walk loops
1429 // generate some MC trace structure
1430 vector<double> vecIndex(maxcycles + 1);
1431 vector<Rfactor> vecR(maxcycles + 1);
1432 size_t numinvalidmoves = 0;
1433 size_t numacceptance = 0;
1434 bool prevcyclebetterR = true;
1435
1436 // Annealing record
1437 int numRecentAcceptance = 0;
1438 int numRecentSteps = 0;
1439 int numConsecutiveInvalid = 0;
1440
1441 // FIXME - It seems that annealing cannot work together with reset invalid if
1442 // in the region of invalid.
1443 // Need to write down the procedure to think it over.
1444 int numMaxConsecutiveInvalid = 5;
1445 int m_numStepsCheckTemperature = 10;
1446
1447 // Loop start
1448 srand(randomseed);
1449
1450 for (size_t icycle = 1; icycle <= maxcycles; ++icycle) {
1451 // Refine parameters (for all parameters in turn) to data with background
1452 // removed
1453 for (auto &MCGroup : m_MCGroups) {
1454 // Propose new value for ONE AND ONLY ONE Monte Carlo parameter group
1455 /*
1456 int igroup = giter->first; // group id
1457 g_log.debug() << "BigTrouble: Group " << igroup << "\n";
1458 */
1459 bool hasnewvalues = proposeNewValues(MCGroup.second, currR, mapCurrParameter, newparammap, prevcyclebetterR);
1460
1461 if (!hasnewvalues) {
1462 // No parameter to have value updated in this MC group. Skip evaluation
1463 // of LeBail function.
1464 continue;
1465 }
1466
1467 // Evaluate LeBail function
1468 map<string, double> newpardblmap = convertToDoubleMap(newparammap);
1469 m_lebailFunction->setProfileParameterValues(newpardblmap);
1470 bool validparams = calculateDiffractionPattern(vecX, vecPurePeak, false, false, vecBkgd, veccalpurepeaks, newR);
1471 g_log.debug() << "[Calculation] Rwp = " << newR.Rwp << ", Rp = " << newR.Rp << ".\n";
1472
1473 // Determine whether to take the change or not
1474 bool acceptchange;
1475 if (!validparams) {
1476 ++numinvalidmoves;
1477 acceptchange = false;
1478 prevcyclebetterR = false;
1479 ++numConsecutiveInvalid;
1480 } else {
1481 acceptchange = acceptOrDeny(currR, newR);
1482
1483 prevcyclebetterR = newR.Rwp < currR.Rwp;
1484 }
1485
1486 g_log.debug() << "[DBx317] Step " << icycle << ": New Rwp = " << setprecision(10) << newR.Rwp
1487 << ", Rp = " << setprecision(5) << newR.Rp << "; Accepted = " << acceptchange
1488 << "; Proposed parameters valid =" << validparams << "\n";
1489
1490 // Apply change and book keeping
1491 if (acceptchange) {
1492 // Apply the change to current
1493 applyParameterValues(newparammap, mapCurrParameter);
1494 currR = newR;
1495
1496 // All tim ebest
1497 // FIXME - [RPRWP] Use Rp now
1498 if (currR.Rwp < m_bestRwp) {
1499 // Book keep the best
1500 bookKeepBestMCResult(mapCurrParameter, vecBkgd, currR, icycle);
1501 }
1502 // FIXME - After determining to use Rp or Rwp, this should be got into
1503 // bookKeepBestMCResult
1504 if (currR.Rp < m_bestRp)
1505 m_bestRp = currR.Rp;
1506 if (currR.Rwp < m_bestRwp)
1507 m_bestRwp = currR.Rwp;
1508
1509 // Statistic
1510 ++numacceptance;
1511 ++numRecentAcceptance;
1512 }
1513 ++numRecentSteps;
1514
1515 // Annealing or start over
1516 if (numConsecutiveInvalid >= numMaxConsecutiveInvalid) {
1517 // Exceeds the limit of consecutive invalid proposed new values. Start
1518 // over
1519 mapCurrParameter = m_bestParameters;
1520
1521 // Reset counters
1522 numConsecutiveInvalid = 0;
1523 numRecentAcceptance = 0;
1524 numRecentSteps = 0;
1525
1526 } else if (m_useAnnealing) {
1527 // Annealing: change temperature to tune the acceptance rate
1528 // FIXME : Here are some magic numbers
1529 if (numRecentSteps == m_numStepsCheckTemperature) {
1530 // i. Change temperature
1531 if (numRecentAcceptance <= 2) {
1532 m_Temperature *= 2.0;
1533 } else if (numRecentAcceptance >= 8) {
1534 m_Temperature /= 2.0;
1535 }
1536 // ii Reset counters
1537 numRecentAcceptance = 0;
1538 numRecentSteps = 0;
1539 }
1540 }
1541
1542 // e) Debug output?
1543
1544 } // END FOR Group
1545
1546 // v. Improve the background
1547 // FIXME - [RPRWP] Use Rp now
1548 if (currR.Rwp < m_bestRwp) {
1549 // FIXME - Fit background is disabled at this moment
1550 // fitBackground(m_wsIndex, domainB, valuesB, background);
1551 }
1552
1553 // vi. Record some information
1554 vecIndex[icycle] = static_cast<double>(icycle);
1555 if (currR.Rwp < 1.0E5)
1556 vecR[icycle] = currR;
1557 else {
1558 Rfactor dum(-1, -1);
1559 vecR[icycle] = dum;
1560 }
1561
1562 // vii. progress
1563 if (icycle % 10 == 0)
1564 progress(double(icycle) / double(maxcycles));
1565
1566 } // ENDFOR MC Cycles
1567
1568 progress(1.0);
1569
1570 // a) Summary output
1571 g_log.notice() << "[SUMMARY] Random-walk R-factor: Best step @ " << m_bestMCStep
1572 << ", Acceptance ratio = " << double(numacceptance) / double(maxcycles * m_numMCGroups) << ".\n"
1573 << "Rwp: Starting = " << startR.Rwp << ", Best = " << m_bestRwp << ", Ending = " << currR.Rwp << "\n"
1574 << "Rp : Starting = " << startR.Rp << ", Best = " << m_bestRp << ", Ending = " << currR.Rp << "\n";
1575
1576 map<string, Parameter>::iterator mapiter;
1577 for (mapiter = mapCurrParameter.begin(); mapiter != mapCurrParameter.end(); ++mapiter) {
1578 Parameter &param = mapiter->second;
1579 if (param.fit) {
1580 g_log.notice() << setw(10) << param.name << "\t: Average Stepsize = " << setw(10) << setprecision(5)
1581 << param.sumstepsize / double(maxcycles) << ", Max Step Size = " << setw(10) << setprecision(5)
1582 << param.maxabsstepsize << ", Number of Positive Move = " << setw(4) << param.numpositivemove
1583 << ", Number of Negative Move = " << setw(4) << param.numnegativemove
1584 << ", Number of No Move = " << setw(4) << param.numnomove << ", Minimum tried value = " << setw(4)
1585 << param.minrecordvalue << ", Maximum tried value = " << setw(4) << param.maxrecordvalue << "\n";
1586 }
1587 }
1588 g_log.notice() << "Number of invalid proposed moves = " << numinvalidmoves << "\n";
1589
1590 // b) Export trace of R
1591 stringstream filenamess;
1592 filenamess << "r_trace_" << vecR.size() << ".dat";
1593 writeRfactorsToFile(vecIndex, vecR, filenamess.str());
1594}
1595
1596//----------------------------------------------------------------------------------------------
1601 g_log.information("Set up random walk strategy from table.");
1602
1603 // Scan the table
1604 size_t numrows = tablews->rowCount();
1605 for (size_t i = 0; i < numrows; ++i) {
1606 // 1. Get a row and pass out
1607 TableRow temprow = tablews->getRow(i);
1608 string parname;
1609 double a0, a1;
1610 int nonnegative, group;
1611
1612 temprow >> parname >> a0 >> a1 >> nonnegative >> group;
1613
1614 // 2. MC group
1615 map<int, vector<string>>::iterator giter;
1616 giter = m_MCGroups.find(group);
1617 if (giter != m_MCGroups.end()) {
1618 giter->second.emplace_back(parname);
1619 } else {
1620 // First instance in the new group.
1621 m_MCGroups.emplace(group, std::initializer_list<std::string>{parname});
1622 }
1623
1624 // 3. Set up MC parameters, A0, A1, non-negative
1625 auto piter = m_funcParameters.find(parname);
1626 if (piter != m_funcParameters.end()) {
1627 piter->second.mcA0 = a0;
1628 piter->second.mcA1 = a1;
1629 piter->second.nonnegative = (nonnegative != 0);
1630 }
1631 }
1632
1633 m_numMCGroups = m_MCGroups.size();
1634
1635 // 4. Reset
1636 map<string, Parameter>::iterator mapiter;
1637 for (mapiter = m_funcParameters.begin(); mapiter != m_funcParameters.end(); ++mapiter) {
1638 mapiter->second.movedirection = 1;
1639 mapiter->second.sumstepsize = 0.0;
1640 mapiter->second.numpositivemove = 0;
1641 mapiter->second.numnegativemove = 0;
1642 mapiter->second.numnomove = 0;
1643 mapiter->second.maxabsstepsize = -0.0;
1644 }
1645}
1646
1647//----------------------------------------------------------------------------------------------
1651 g_log.information("Set up random walk strategy from build-in. ");
1652
1653 stringstream dboutss;
1654 dboutss << "Monte Carlo minimizer refines: ";
1655
1656 // 1. Monte Carlo groups
1657 // a. Instrument gemetry
1658 vector<string> geomparams;
1659 addParameterToMCMinimize(geomparams, "Dtt1");
1660 addParameterToMCMinimize(geomparams, "Dtt1t");
1661 addParameterToMCMinimize(geomparams, "Dtt2t");
1662 addParameterToMCMinimize(geomparams, "Zero");
1663 addParameterToMCMinimize(geomparams, "Zerot");
1664 addParameterToMCMinimize(geomparams, "Width");
1665 addParameterToMCMinimize(geomparams, "Tcross");
1666 m_MCGroups.emplace(0, geomparams);
1667
1668 dboutss << "Geometry parameters: ";
1669 for (auto &geomparam : geomparams)
1670 dboutss << geomparam << "\t\t";
1671 dboutss << "\n";
1672
1673 // b. Alphas
1674 vector<string> alphs;
1675 addParameterToMCMinimize(alphs, "Alph0");
1676 addParameterToMCMinimize(alphs, "Alph1");
1677 addParameterToMCMinimize(alphs, "Alph0t");
1678 addParameterToMCMinimize(alphs, "Alph1t");
1679 m_MCGroups.emplace(1, alphs);
1680
1681 dboutss << "Alpha parameters";
1682 for (auto &alph : alphs)
1683 dboutss << alph << "\t\t";
1684 dboutss << "\n";
1685
1686 // c. Beta
1687 vector<string> betas;
1688 addParameterToMCMinimize(betas, "Beta0");
1689 addParameterToMCMinimize(betas, "Beta1");
1690 addParameterToMCMinimize(betas, "Beta0t");
1691 addParameterToMCMinimize(betas, "Beta1t");
1692 m_MCGroups.emplace(2, betas);
1693
1694 dboutss << "Beta parameters";
1695 for (auto &beta : betas)
1696 dboutss << beta << "\t\t";
1697 dboutss << "\n";
1698
1699 // d. Sig
1700 vector<string> sigs;
1701 addParameterToMCMinimize(sigs, "Sig0");
1702 addParameterToMCMinimize(sigs, "Sig1");
1703 addParameterToMCMinimize(sigs, "Sig2");
1704 m_MCGroups.emplace(3, sigs);
1705
1706 dboutss << "Sig parameters";
1707 for (auto &sig : sigs)
1708 dboutss << sig << "\t\t";
1709 dboutss << "\n";
1710
1711 g_log.notice(dboutss.str());
1712
1713 m_numMCGroups = m_MCGroups.size();
1714
1715 // 2. Dictionary for each parameter for non-negative, mcX0, mcX1
1716 // a) Sig0, Sig1, Sig2
1717 for (const auto &parname : sigs) {
1718 m_funcParameters[parname].mcA0 = 2.0;
1719 m_funcParameters[parname].mcA1 = 1.0;
1720 m_funcParameters[parname].nonnegative = true;
1721 }
1722
1723 // b) Alpha
1724 for (const auto &parname : alphs) {
1725 m_funcParameters[parname].mcA1 = 1.0;
1726 m_funcParameters[parname].nonnegative = false;
1727 }
1728 m_funcParameters["Alph0"].mcA0 = 0.05;
1729 m_funcParameters["Alph1"].mcA0 = 0.02;
1730 m_funcParameters["Alph0t"].mcA0 = 0.1;
1731 m_funcParameters["Alph1t"].mcA0 = 0.05;
1732
1733 // c) Beta
1734 for (const auto &parname : betas) {
1735 m_funcParameters[parname].mcA1 = 1.0;
1736 m_funcParameters[parname].nonnegative = false;
1737 }
1738 m_funcParameters["Beta0"].mcA0 = 0.5;
1739 m_funcParameters["Beta1"].mcA0 = 0.05;
1740 m_funcParameters["Beta0t"].mcA0 = 0.5;
1741 m_funcParameters["Beta1t"].mcA0 = 0.05;
1742
1743 // d) Geometry might be more complicated
1744 m_funcParameters["Width"].mcA0 = 0.0;
1745 m_funcParameters["Width"].mcA1 = 0.1;
1746 m_funcParameters["Width"].nonnegative = true;
1747
1748 m_funcParameters["Tcross"].mcA0 = 0.0;
1749 m_funcParameters["Tcross"].mcA1 = 1.0;
1750 m_funcParameters["Tcross"].nonnegative = true;
1751
1752 m_funcParameters["Zero"].mcA0 = 5.0; // 5.0
1753 m_funcParameters["Zero"].mcA1 = 0.0;
1754 m_funcParameters["Zero"].nonnegative = false;
1755
1756 m_funcParameters["Zerot"].mcA0 = 5.0; // 5.0
1757 m_funcParameters["Zerot"].mcA1 = 0.0;
1758 m_funcParameters["Zerot"].nonnegative = false;
1759
1760 m_funcParameters["Dtt1"].mcA0 = 5.0; // 20.0
1761 m_funcParameters["Dtt1"].mcA1 = 0.0;
1762 m_funcParameters["Dtt1"].nonnegative = true;
1763
1764 m_funcParameters["Dtt1t"].mcA0 = 5.0; // 20.0
1765 m_funcParameters["Dtt1t"].mcA1 = 0.0;
1766 m_funcParameters["Dtt1t"].nonnegative = true;
1767
1768 m_funcParameters["Dtt2t"].mcA0 = 0.1;
1769 m_funcParameters["Dtt2t"].mcA1 = 1.0;
1770 m_funcParameters["Dtt2t"].nonnegative = false;
1771
1772 // 4. Reset
1773 map<string, Parameter>::iterator mapiter;
1774 for (mapiter = m_funcParameters.begin(); mapiter != m_funcParameters.end(); ++mapiter) {
1775 mapiter->second.movedirection = 1;
1776 mapiter->second.sumstepsize = 0.0;
1777 mapiter->second.numpositivemove = 0;
1778 mapiter->second.numnegativemove = 0;
1779 mapiter->second.numnomove = 0;
1780 mapiter->second.maxabsstepsize = -0.0;
1781 }
1782}
1783
1784//----------------------------------------------------------------------------------------------
1792void LeBailFit::addParameterToMCMinimize(vector<string> &parnamesforMC, const string &parname) {
1793 map<string, Parameter>::iterator pariter;
1794 pariter = m_funcParameters.find(parname);
1795 if (pariter == m_funcParameters.end()) {
1796 stringstream errss;
1797 errss << "Parameter " << parname << " does not exisit Le Bail function parameters. ";
1798 g_log.error(errss.str());
1799 throw runtime_error(errss.str());
1800 }
1801
1802 if (pariter->second.fit)
1803 parnamesforMC.emplace_back(parname);
1804}
1805
1806//----------------------------------------------------------------------------------------------
1826bool LeBailFit::calculateDiffractionPattern(const HistogramX &vecX, const HistogramY &vecY, bool inputraw,
1827 bool outputwithbkgd, const HistogramY &vecBkgd, std::vector<double> &values,
1828 Rfactor &rfactor) {
1829 HistogramY veccalbkgd(vecX.size());
1830 bool veccalbkgdIsEmpty = true;
1831
1832 // Examine whether all peaks are valid
1833 double maxfwhm = vecX.back() - vecX.front();
1834 bool peaksvalid = m_lebailFunction->isParameterValid(maxfwhm);
1835
1836 // If not valid, then return error message
1837 if (!peaksvalid) {
1838 g_log.information() << "Proposed new instrument profile values cause peak(s) to have "
1839 << "unphysical parameter values.\n";
1840 rfactor = badR;
1841 return false;
1842 }
1843
1844 // Calculate peaks' height
1845 if (inputraw) {
1846 // Remove background
1847 vector<double> vecPureY(vecY.size(), 0.);
1848 if (vecBkgd.size() == vecY.size()) {
1849 // Use input background
1850 g_log.information() << "Calculate diffraction pattern from raw and input "
1851 "background vector. "
1852 << ".\n";
1853 ::transform(vecY.begin(), vecY.end(), vecBkgd.begin(), vecPureY.begin(), ::minus<double>());
1854 } else {
1855 // Calculate background
1856 g_log.information() << "Calculate diffraction pattern from input data "
1857 "and newly calculated background. "
1858 << ".\n";
1859 veccalbkgd = m_lebailFunction->function(vecX.rawData(), false, true);
1860 ::transform(vecY.begin(), vecY.end(), veccalbkgd.begin(), vecPureY.begin(), ::minus<double>());
1861 veccalbkgdIsEmpty = false;
1862 }
1863
1864 // Calculate peak intensity
1865 peaksvalid = m_lebailFunction->calculatePeaksIntensities(vecX.rawData(), vecPureY, values);
1866 } // [input is raw]
1867 else {
1868 // Calculate peaks intensities
1869 g_log.debug() << "Calculate diffraction pattern from input data with "
1870 "background removed. "
1871 << ".\n";
1872 peaksvalid = m_lebailFunction->calculatePeaksIntensities(vecX.rawData(), vecY.rawData(), values);
1873 }
1874
1875 // Calculate Le Bail function
1876 if (values.size() != vecY.size()) {
1877 g_log.error() << "Input/output vector 'values' has a wrong size = " << values.size() << ". Resize it to "
1878 << vecY.size() << ".\n";
1879 throw runtime_error("Impossible...");
1880 }
1881
1882 // Integrated with background if required
1883 if (outputwithbkgd) {
1884 if (vecBkgd.size() == vecY.size()) {
1885 ::transform(values.begin(), values.end(), vecBkgd.begin(), values.begin(), ::plus<double>());
1886 } else {
1887 if (veccalbkgdIsEmpty)
1888 throw runtime_error("Programming logic error.");
1889 ::transform(values.begin(), values.end(), veccalbkgd.begin(), values.begin(), ::plus<double>());
1890 }
1891 rfactor = getRFactor(m_dataWS->y(m_wsIndex).rawData(), values, m_dataWS->e(m_wsIndex).rawData());
1892 } else {
1893 vector<double> caldata(values.size(), 0.0);
1894 if (vecBkgd.size() == vecY.size()) {
1895 // Use input background vector
1896 std::transform(values.begin(), values.end(), vecBkgd.begin(), caldata.begin(), std::plus<double>());
1897 } else {
1898 // Re-calculate background
1899 if (veccalbkgdIsEmpty)
1900 throw runtime_error("Programming logic error (2). ");
1901 std::transform(values.begin(), values.end(), veccalbkgd.begin(), caldata.begin(), std::plus<double>());
1902 }
1903 rfactor = getRFactor(m_dataWS->y(m_wsIndex).rawData(), caldata, m_dataWS->e(m_wsIndex).rawData());
1904 }
1905
1906 if (!peaksvalid) {
1907 g_log.information("LeBailFit: Some peaks have unphysical peak value. ");
1908 rfactor = badR;
1909 return false;
1910 }
1911
1912 return true;
1913}
1914
1915//----------------------------------------------------------------------------------------------
1929bool LeBailFit::proposeNewValues(const vector<string> &mcgroup, Rfactor r, map<string, Parameter> &curparammap,
1930 map<string, Parameter> &newparammap, bool prevBetterRwp) {
1931 // TODO: Study the possibility to merge curparammap and newparammap
1932
1933 // Initialize some flags
1934 bool anyparamtorefine = false;
1935
1936 // Find out parameters to refine in this step/MC group
1937 g_log.debug() << "Parameter Number In Group = " << mcgroup.size() << "\n";
1938 for (const auto &paramname : mcgroup) {
1939 // Find out the i-th parameter to be refined or not
1940 auto mapiter = curparammap.find(paramname);
1941 if (mapiter == curparammap.end()) {
1942 stringstream errmsg;
1943 errmsg << "Parameter to update (" << paramname << ") is not in the pool of parameters to get updated. "
1944 << ".\n"
1945 << "Number of parameters to update in this group = " << curparammap.size() << ". They are ";
1946 for (mapiter = curparammap.begin(); mapiter != curparammap.end(); ++mapiter) {
1947 errmsg << mapiter->first << ", ";
1948 }
1949 g_log.error(errmsg.str());
1950 throw runtime_error(errmsg.str());
1951 }
1952 Parameter &param = mapiter->second;
1953
1954 if (param.fit)
1955 anyparamtorefine = true;
1956 else
1957 continue;
1958
1959 // Pick a random number between -1 and 1 and calculate step size
1960 double randomnumber = 2 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0;
1961
1962 // FIXME - [RPRWP] Try using Rp this time.
1963 double weight = r.Rwp;
1964 if (weight > 1.0)
1965 weight = 1.0;
1966 double stepsize = m_dampingFactor * weight * (param.curvalue * param.mcA1 + param.mcA0) * randomnumber;
1967 if (fabs(stepsize) > 0.5 * (param.maxvalue - param.minvalue))
1968 stepsize = fabs(stepsize) / stepsize * 0.5 * (param.maxvalue - param.minvalue);
1969
1970 // Direction of new value: drunk walk or random walk
1971 double newvalue;
1972 if (m_walkStyle == RANDOMWALK) {
1973 // Random walk. No preference on direction
1974 newvalue = param.curvalue + stepsize;
1975 } else if (m_walkStyle == DRUNKENWALK) {
1976 // Drunken walk. Prefer to previous successful move direction
1977 int prevRightDirection;
1978 if (prevBetterRwp)
1979 prevRightDirection = 1;
1980 else
1981 prevRightDirection = -1;
1982
1983 double randirint = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
1984 g_log.debug() << "[TestRandom] random = " << randirint << "\n";
1985
1986 // FIXME Here are some MAGIC numbers
1987 if (randirint < 0.1) {
1988 // Negative direction to previous direction
1989 stepsize = -1.0 * fabs(stepsize) * static_cast<double>(param.movedirection * prevRightDirection);
1990 } else if (randirint < 0.4) {
1991 // No preferance and thus do nothing
1992 } else {
1993 // Positive direction to previous direction
1994 stepsize = fabs(stepsize) * static_cast<double>(param.movedirection * prevRightDirection);
1995 }
1996
1997 newvalue = param.curvalue + stepsize;
1998 } else {
1999 throw runtime_error("Unrecoganized walk style. ");
2000 }
2001
2002 // Restriction on the new value: non-negative
2003 if (param.nonnegative && newvalue < 0) {
2004 // If not allowed to be negative
2005 newvalue = fabs(newvalue);
2006 }
2007
2008 // Restriction on the new value: keep the new value in the boundary
2009 if (newvalue < param.minvalue) {
2010 int toss = rand() % 2;
2011 double direction = -1.0;
2012 newvalue = limitProposedValueInBound(param, newvalue, direction, toss);
2013 } else if (newvalue > param.maxvalue) {
2014 int toss = rand() % 2;
2015 double direction = 1.0;
2016 newvalue = limitProposedValueInBound(param, newvalue, direction, toss);
2017 }
2018
2019 // Apply to new parameter map
2020 auto newmiter = newparammap.find(paramname);
2021 if (newmiter == newparammap.end())
2022 throw runtime_error("New parameter map does not contain parameter that is updated.");
2023 newmiter->second.curvalue = newvalue;
2024 g_log.debug() << "[ProposeNewValue] " << paramname << " --> " << newvalue << "; random number = " << randomnumber
2025 << "\n";
2026
2027 // g) record some trace
2028 Parameter &p = param;
2029 if (stepsize > 0) {
2030 p.movedirection = 1;
2031 ++p.numpositivemove;
2032 } else if (stepsize < 0) {
2033 p.movedirection = -1;
2034 ++p.numnegativemove;
2035 } else {
2036 p.movedirection = -1;
2037 ++p.numnomove;
2038 }
2039 p.sumstepsize += fabs(stepsize);
2040 if (fabs(stepsize) > p.maxabsstepsize)
2041 p.maxabsstepsize = fabs(stepsize);
2042
2043 if (newvalue > p.maxrecordvalue)
2044 p.maxrecordvalue = newvalue;
2045 else if (newvalue < p.minrecordvalue)
2046 p.minrecordvalue = newvalue;
2047
2048 g_log.debug() << "[DBx257] " << paramname << "\t"
2049 << "Proposed value = " << setw(15) << newvalue << " (orig = " << param.curvalue
2050 << ", step = " << stepsize << "), totRwp = " << r.Rwp << "\n";
2051 } // ENDFOR (i): Each parameter in this MC group/step
2052
2053 return anyparamtorefine;
2054}
2055
2056//-----------------------------------------------------------------------------------------------
2068double LeBailFit::limitProposedValueInBound(const Parameter &param, double newvalue, double direction, int choice) {
2069 if (choice == 0) {
2070 // Half distance
2071 if (direction > 0) {
2072 newvalue = (param.maxvalue - param.curvalue) * 0.5 + param.curvalue;
2073 } else {
2074 newvalue = param.minvalue + 0.5 * (param.curvalue - param.minvalue);
2075 }
2076 } else {
2077 double deltaX = param.maxvalue - param.minvalue;
2078
2079 if (deltaX < NOBOUNDARYLIMIT) {
2080 choice = 1; // periodic
2081 } else {
2082 choice = 2; // reflection
2083 }
2084
2085 if (choice == 1) {
2086 // Periodic boundary
2087 if (direction > 0) {
2088 // newvalue = param.minvalue + (newvalue - param.maxvalue) % deltaX;
2089 double dval = (newvalue - param.maxvalue) / deltaX;
2090 newvalue = param.minvalue + deltaX * (dval - floor(dval));
2091 } else {
2092 // newvalue = param.maxvalue - (param.minvalue - newvalue) % deltaX;
2093 double dval = (param.minvalue - newvalue) / deltaX;
2094 newvalue = param.maxvalue - deltaX * (dval - floor(dval));
2095 }
2096 } else {
2097 // Reflective boundary
2098 if (direction > 0) {
2099 newvalue = param.maxvalue - (newvalue - param.maxvalue);
2100 } else {
2101 newvalue = param.minvalue + (param.maxvalue - newvalue);
2102 }
2103 }
2104 }
2105
2106 return newvalue;
2107}
2108
2109//-----------------------------------------------------------------------------------------------
2116 bool accept;
2117
2118 // FIXME - [RPRWP] Using Rp for peak fitting
2119 double new_goodness = newR.Rwp;
2120 double cur_goodness = currR.Rwp;
2121
2122 if (new_goodness < cur_goodness) {
2123 // Lower Rwp. Take the change
2124 accept = true;
2125 } else if (new_goodness > 1.0 - 1.0E-9) {
2126 // Too high
2127 g_log.debug() << "Goodness > " << 1.0 - 1.0E-9 << ". Reject!"
2128 << ".\n";
2129 accept = false;
2130 } else {
2131 // Higher Rwp/Rp. Take a chance to accept
2132 double dice = static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
2133 g_log.debug() << "[TestRandom] dice " << dice << "\n";
2134 double bar = exp(-(new_goodness - cur_goodness) / (cur_goodness * m_Temperature));
2135
2136 accept = dice < bar;
2137 }
2138
2139 return accept;
2140}
2141
2142//----------------------------------------------------------------------------------------------
2151void LeBailFit::bookKeepBestMCResult(map<string, Parameter> parammap, const vector<double> &bkgddata, Rfactor rfactor,
2152 size_t istep) {
2153 // TODO : [RPRWP] Here is a metric of goodness of it.
2154 double goodness = rfactor.Rwp;
2155 bool better = goodness < m_bestRwp;
2156
2157 if (better) {
2158 // In case obtain the best solution so far
2159
2160 // a) Record goodness and step
2161 m_bestRwp = rfactor.Rwp;
2162 m_bestRp = rfactor.Rp;
2163 m_bestMCStep = istep;
2164
2165 // b) Record parameters
2166 if (m_bestParameters.empty()) {
2167 // If not be initialized, initialize it!
2168 m_bestParameters = parammap;
2169 } else {
2170 // in case initialized, copy the value over
2172 }
2173
2174 // c) Background
2175 m_bestBackgroundData = bkgddata;
2176 } else {
2177 // In code calling this function, it should be better always.
2178 g_log.warning("[Book keep best MC result] Shouldn't be here as it is found "
2179 "that it is not the best solution ");
2180 }
2181}
2182
2183//------------------------------------------------------------------------------------------------
2189void LeBailFit::applyParameterValues(map<string, Parameter> &srcparammap, map<string, Parameter> &tgtparammap) {
2190 map<string, Parameter>::iterator srcmapiter;
2191 map<string, Parameter>::iterator tgtmapiter;
2192 for (srcmapiter = srcparammap.begin(); srcmapiter != srcparammap.end(); ++srcmapiter) {
2193 string parname = srcmapiter->first;
2194 Parameter srcparam = srcmapiter->second;
2195
2196 tgtmapiter = tgtparammap.find(parname);
2197 if (tgtmapiter == tgtparammap.end()) {
2198 stringstream errss;
2199 errss << "Parameter " << parname << " cannot be found in target Parameter map containing " << tgtparammap.size()
2200 << " entries. ";
2201 g_log.error(errss.str());
2202 throw runtime_error("Programming or memory error! This situation cannot happen!");
2203 }
2204
2205 tgtmapiter->second.curvalue = srcparam.curvalue;
2206 }
2207}
2208
2210std::map<std::string, double> LeBailFit::convertToDoubleMap(std::map<std::string, Parameter> &inmap) {
2211 std::map<std::string, double> outmap;
2212 std::map<std::string, Parameter>::iterator miter;
2213 for (miter = inmap.begin(); miter != inmap.end(); ++miter) {
2214 outmap.emplace(miter->first, miter->second.curvalue);
2215 }
2216
2217 return outmap;
2218}
2219
2220// ============================ External Auxiliary Functions
2221// =================================
2222
2225void writeRfactorsToFile(vector<double> vecX, vector<Rfactor> vecR, const string &filename) {
2226 ofstream ofile;
2227 ofile.open(filename.c_str());
2228
2229 for (size_t i = 0; i < vecX.size(); ++i)
2230 ofile << setw(15) << setprecision(5) << vecX[i] << setw(15) << setprecision(5) << vecR[i].Rwp << setw(15)
2231 << setprecision(5) << vecR[i].Rp << "\n";
2232
2233 ofile.close();
2234}
2235
2236} // namespace Mantid::CurveFitting::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double height
Definition: GetAllEi.cpp:155
const double EPSILON(1.0E-10)
const int DATADIFFINDEX(2)
const int CALDATAINDEX(1)
const int INPUTPUREPEAKINDEX(7)
const int OBSDATAINDEX(0)
const int CALBKGDINDEX(4)
const double NOBOUNDARYLIMIT(1.0E10)
const int CALPUREPEAKINDEX(3)
const int INPUTBKGDINDEX(6)
#define fabs(x)
Definition: Matrix.cpp:22
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
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
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
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
Implements FunctionDomain1D with its own storage in form of a std::vector.
A class to store values calculated by a function.
std::vector< double > toVector() const
Return the calculated values as a vector.
TableRowHelper appendRow()
Appends a row.
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
A property class for workspaces.
bool calculateDiffractionPattern(const Mantid::HistogramData::HistogramX &vecX, const Mantid::HistogramData::HistogramY &vecY, bool inputraw, bool outputwithbkgd, const Mantid::HistogramData::HistogramY &vecBkgd, std::vector< double > &values, Kernel::Rfactor &rfactor)
Calculate diffraction pattern in Le Bail algorithm for MC Random walk.
Definition: LeBailFit.cpp:1826
void bookKeepBestMCResult(std::map< std::string, Parameter > parammap, const std::vector< double > &bkgddata, Kernel::Rfactor rfactor, size_t istep)
Book keep the (sopposed) best MC result.
Definition: LeBailFit.cpp:2151
void proposeNewBackgroundValues()
Propose new background parameters.
Definition: LeBailFit.cpp:620
bool acceptOrDeny(Kernel::Rfactor currR, Kernel::Rfactor newR)
Determine whether the proposed value should be accepted or denied.
Definition: LeBailFit.cpp:2115
std::vector< std::pair< std::vector< int >, double > > m_inputPeakInfoVec
Input Bragg peak information for future processing;.
Definition: LeBailFit.h:200
Functions::BackgroundFunction_sptr m_backgroundFunction
Background function.
Definition: LeBailFit.h:203
bool m_tolerateInputDupHKL2Peaks
Flag to allow peaks with duplicated (HKL)^2 in input .hkl file.
Definition: LeBailFit.h:274
std::map< std::string, double > m_origFuncParameters
Input function parameters that are stored for reference.
Definition: LeBailFit.h:208
void addParameterToMCMinimize(std::vector< std::string > &parnamesforMC, const std::string &parname)
Add parameter (to a vector of string/name) for MC random walk.
Definition: LeBailFit.cpp:1792
bool m_inputParameterPhysical
Flag to show whether the input profile parameters are physical to all peaks.
Definition: LeBailFit.h:239
void exec() override
Implement abstract Algorithm methods.
Definition: LeBailFit.cpp:238
API::MatrixWorkspace_sptr cropWorkspace(const API::MatrixWorkspace_sptr &inpws, size_t wsindex)
Crop the workspace for better usage.
Definition: LeBailFit.cpp:674
void doMarkovChain(const std::map< std::string, Parameter > &parammap, const Mantid::HistogramData::HistogramX &vecX, const Mantid::HistogramData::HistogramY &vecPurePeak, const std::vector< double > &vecBkgd, size_t maxcycles, const Kernel::Rfactor &startR, int randomseed)
Work on Markov chain to 'solve' LeBail function.
Definition: LeBailFit.cpp:1408
void init() override
Declare the input properties for this algorithm.
Definition: LeBailFit.cpp:75
std::map< std::string, Parameter > m_funcParameters
Function parameters updated by fit.
Definition: LeBailFit.h:206
LeBailFunction_sptr m_lebailFunction
Le Bail Function (Composite)
Definition: LeBailFit.h:187
std::vector< double > m_backgroundParameters
Background polynomials.
Definition: LeBailFit.h:221
std::vector< double > m_bkgdParameterBuffer
Definition: LeBailFit.h:280
void parseInstrumentParametersTable()
Import peak parameters.
Definition: LeBailFit.cpp:814
std::vector< std::string > m_bkgdParameterNames
Definition: LeBailFit.h:278
void processInputBackground()
Process and calculate input background.
Definition: LeBailFit.cpp:327
void parseBraggPeaksParametersTable()
Import Miller Indices (HKL)
Definition: LeBailFit.cpp:972
double limitProposedValueInBound(const Parameter &param, double newvalue, double direction, int choice)
Limit proposed value in the specified boundary.
Definition: LeBailFit.cpp:2068
std::map< std::string, double > convertToDoubleMap(std::map< std::string, Parameter > &inmap)
Convert a map of Parameter to a map of double.
Definition: LeBailFit.cpp:2210
void execRefineBackground()
Calcualte background by fitting peak heights.
Definition: LeBailFit.cpp:458
double m_minimumPeakHeight
Minimum height of a peak to be counted in smoothing background.
Definition: LeBailFit.h:271
DataObjects::Workspace2D_sptr m_outputWS
Definition: LeBailFit.h:191
void execPatternCalculation()
Calculate LeBail pattern from from input peak parameters.
Definition: LeBailFit.cpp:394
void recoverBackgroundParameters(const std::vector< double > &bkgdparamvec)
Restore/recover the buffered background parameters to m_background function.
Definition: LeBailFit.cpp:612
std::map< int, std::vector< std::string > > m_MCGroups
Definition: LeBailFit.h:247
bool m_useAnnealing
Flag to use Annealing Simulation (i.e., use automatic adjusted temperature)
Definition: LeBailFit.h:265
API::MatrixWorkspace_sptr m_dataWS
Instance data.
Definition: LeBailFit.h:190
size_t m_numMinimizeSteps
Number of minimization steps. For both MC and regular.
Definition: LeBailFit.h:258
void setupBuiltInRandomWalkStrategy()
Set up Monte Carlo random walk strategy.
Definition: LeBailFit.cpp:1650
void storeBackgroundParameters(std::vector< double > &bkgdparamvec)
Store/buffer current background parameters.
Definition: LeBailFit.cpp:602
void exportBraggPeakParameterToTable()
Create and set up output table workspace for peaks.
Definition: LeBailFit.cpp:1112
std::map< std::string, Parameter > m_bestParameters
Definition: LeBailFit.h:253
enum Mantid::CurveFitting::Algorithms::LeBailFit::@2 m_walkStyle
Monte Carlo algorithm.
void createOutputDataWorkspace()
Create output data workspace.
Definition: LeBailFit.cpp:1263
DataObjects::TableWorkspace_sptr parameterWS
Definition: LeBailFit.h:192
std::vector< double > m_bestBackgroundData
Definition: LeBailFit.h:254
double m_Temperature
Monte Carlo temperature.
Definition: LeBailFit.h:261
void parseBackgroundTableWorkspace(const DataObjects::TableWorkspace_sptr &bkgdparamws, std::vector< std::string > &bkgdparnames, std::vector< double > &bkgdorderparams)
Parse content in a table workspace to vector for background parameters.
Definition: LeBailFit.cpp:1037
std::vector< std::string > m_backgroundParameterNames
Definition: LeBailFit.h:222
std::string m_backgroundType
Background type.
Definition: LeBailFit.h:218
void processInputProperties()
Process input properties.
Definition: LeBailFit.cpp:729
void execRandomWalkMinimizer(size_t maxcycles, std::map< std::string, Parameter > &parammap)
Main for random walk process.
Definition: LeBailFit.cpp:1325
void applyParameterValues(std::map< std::string, Parameter > &srcparammap, std::map< std::string, Parameter > &tgtparammap)
Apply the value of parameters in the source to target.
Definition: LeBailFit.cpp:2189
std::string m_peakType
============================= =========================== ///
Definition: LeBailFit.h:215
std::vector< double > m_bkgdParameterStepVec
Definition: LeBailFit.h:283
void createLeBailFunction()
Create LeBailFunction.
Definition: LeBailFit.cpp:641
void exportInstrumentParameterToTable(std::map< std::string, Parameter > parammap)
Output parameters (fitted or tied)
Definition: LeBailFit.cpp:1168
DataObjects::TableWorkspace_sptr reflectionWS
Definition: LeBailFit.h:193
bool proposeNewValues(const std::vector< std::string > &mcgroup, Kernel::Rfactor r, std::map< std::string, Parameter > &curparammap, std::map< std::string, Parameter > &newparammap, bool prevBetterRwp)
Propose new parameters.
Definition: LeBailFit.cpp:1929
void setupRandomWalkStrategyFromTable(const DataObjects::TableWorkspace_sptr &tablews)
Set up Monte Carlo random walk strategy.
Definition: LeBailFit.cpp:1600
LeBailFunction : LeBailFunction is to calculate peak intensities in a composite function including ne...
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
API::Column_sptr addColumn(const std::string &type, const std::string &name) override
Creates a new column.
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
Definition: ListValidator.h:29
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< IPowderDiffPeakFunction > IPowderDiffPeakFunction_sptr
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
const Rfactor badR(DBL_MAX, DBL_MAX)
void writeRfactorsToFile(std::vector< double > vecX, std::vector< Kernel::Rfactor > vecR, const std::string &filename)
Write a set of (XY) data to a column file.
Definition: LeBailFit.cpp:2225
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::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition: IValidator.h:26
Rfactor MANTID_KERNEL_DLL getRFactor(const std::vector< double > &obsI, const std::vector< double > &calI, const std::vector< double > &obsE)
Return the R-factors (Rwp) of a diffraction pattern data.
Definition: Statistics.cpp:229
Helper class which provides the Collimation Length for SANS instruments.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
STL namespace.
LeBailFit : Algorithm to do Le Bail Fit.
Definition: LeBailFit.h:37
@ 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
R factor for powder data analysis.
Definition: Statistics.h:52