15#include "MantidHistogramData/HistogramX.h"
16#include "MantidHistogramData/HistogramY.h"
21#include <boost/algorithm/string.hpp>
22#include <boost/algorithm/string/split.hpp>
47using Mantid::HistogramData::HistogramX;
48using Mantid::HistogramData::HistogramY;
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.) {}
80 "Input workspace containing the data to fit by LeBail algorithm.");
84 "Output workspace containing calculated pattern or "
85 "calculated background. ");
90 "Input table workspace containing the parameters "
91 "required by LeBail fit. ");
94 auto tablewsprop1 = std::make_unique<WorkspaceProperty<TableWorkspace>>(
96 this->
declareProperty(std::move(tablewsprop1),
"Input table workspace containing the "
97 "parameters required by LeBail fit. ");
101 "Input table workspace containing the list of reflections (HKL). ");
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 "
111 this->
declareProperty(
"WorkspaceIndex", 0,
"Workspace index of the spectrum to fit by LeBail.");
115 "Region of data (TOF) for LeBail fit. Default is whole range. ");
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");
123 vector<string> peaktypes{
"ThermalNeutronBk2BkExpConvPVoigt",
"NeutronBk2BkExpConvPVoigt"};
124 auto peaktypevalidator = std::make_shared<StringListValidator>(peaktypes);
125 declareProperty(
"PeakType",
"ThermalNeutronBk2BkExpConvPVoigt", peaktypevalidator,
"Peak profile type.");
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");
136 "Optional: enter a comma-separated list of background order parameters "
140 auto tablewsprop3 = std::make_unique<WorkspaceProperty<TableWorkspace>>(
142 this->
declareProperty(std::move(tablewsprop3),
"Optional table workspace containing the fit result for background.");
145 this->
declareProperty(
"PeakRadius", 5,
"Range (multiplier relative to FWHM) for a full peak. ");
150 declareProperty(
"PlotIndividualPeaks",
false,
"Option to output each individual peak in mode Calculation.");
152 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"Calculation"));
156 "Heigh of peaks (reflections) if its calculated height is "
157 "smaller than user-defined minimum.");
159 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"Calculation"));
163 "For 'Calculation' mode only, use peak heights specified in "
164 "ReflectionWorkspace. "
165 "Otherwise, calcualte peaks' heights. ");
167 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"Calculation"));
175 "The minimizer method applied to do the fit, default is "
176 "Levenberg-Marquardt",
180 declareProperty(
"Damping", 1.0,
"Damping factor if minimizer is 'Damped Gauss-Newton'");
184 declareProperty(
"NumberMinimizeSteps", 100,
"Number of Monte Carlo random walk steps.");
186 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"LeBailFit"));
188 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"MonteCarlo"));
190 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"RefineBackground"));
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. ");
204 "Temperature used Monte Carlo. "
205 "Negative temperature is for simulated annealing. ");
207 std::make_unique<VisibleWhenProperty>(
"Function",
IS_EQUAL_TO,
"MonteCarlo"));
209 declareProperty(
"UseAnnealing",
true,
"Allow annealing temperature adjusted automatically.");
213 "Flag to use drunken walk algorithm. "
214 "Otherwise, random walk algorithm is used. ");
218 "Minimum height of a peak to be counted "
219 "during smoothing background by exponential smooth algorithm. ");
223 "Flag to allow degenerated peaks in input .hkl file. "
224 "Otherwise, an exception will be thrown if this situation occurs.");
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. ");
263 g_log.
warning() <<
"Input instrument parameters values cause some peaks to have "
264 "unphysical profile parameters.\n";
266 g_log.
warning() <<
"Function mode FIT is disabled. Convert to Calculation mode.\n";
278 g_log.
notice() <<
"Function: Pattern Calculation.\n";
284 g_log.
notice() <<
"Function: Do LeBail Fit ==> Monte Carlo.\n";
288 g_log.
notice(
"Function: Do LeBail Fit By Monte Carlo Random Walk.");
296 g_log.
notice() <<
"Function: Refine Background (Precisely).\n";
302 std::stringstream errmsg;
303 errmsg <<
"FunctionMode = " <<
m_fitMode <<
" is not supported in exec().";
305 throw std::runtime_error(errmsg.str());
318 g_log.
notice() <<
"\nFinal R factor: Rwp = " << finalR.
Rwp <<
", Rp = " << finalR.
Rp
345 g_log.
warning(
"Bkpos is out side of data range. It MIGHT NOT BE RIGHT. ");
350 for (
size_t i = i0; i < numparams; ++i) {
352 parss <<
"A" << (i - i0);
357 "input vector sized "
358 << numparams <<
".\n";
360 g_log.
information() <<
"[Input] Use background specified by table workspace.\n";
369 throw runtime_error(
"FullprofPolynomial: Bkpos must be given! ");
375 throw runtime_error(
"There is something wrong to set up FullprofPolynomial. ");
379 throw runtime_error(
"Polynomial and Chebyshev at least be order 0 (1 parameter). ");
400 Rfactor rfactor(-DBL_MAX, -DBL_MAX);
403 bool useinputpeakheights = this->
getProperty(
"UseInputPeakHeights");
404 if (useinputpeakheights)
405 g_log.
warning(
"UseInputPeakHeights is temporarily turned off now. ");
412 vector<double> emptyvec;
413 bool resultphysical =
426 bool ploteachpeak = this->
getProperty(
"PlotIndividualPeaks");
427 g_log.
information() <<
"Output individual peaks = " << ploteachpeak <<
".\n";
436 par_rwp.
name =
"Rwp";
440 g_log.
notice() <<
"Rwp = " << rfactor.
Rwp <<
", Rp = " << rfactor.
Rp <<
"\n";
442 if (!resultphysical) {
443 g_log.
warning() <<
"Input parameters are unable to generate peaks that are physical."
473 vector<double> valueVec(vecX.size(), 0);
474 size_t numpts = vecX.size();
480 Rfactor currR(DBL_MAX, DBL_MAX);
482 vector<double> backgroundvalues = values.
toVector();
483 for (
size_t i = 0; i < numpts; ++i) {
490 backgroundvalues, valueVec, currR);
494 bufss <<
"Starting background parameter ";
497 bufss <<
". Starting Rwp = " << currR.
Rwp;
506 Rfactor newR(DBL_MAX, DBL_MAX);
508 backgroundvalues = values.
toVector();
509 for (
size_t i = 0; i < numpts; ++i) {
515 backgroundvalues, valueVec, newR);
528 if (newR.
Rwp < bestR.
Rwp) {
534 ss <<
"Temp best background parameter ";
549 bufss1 <<
"Best background parameter ";
554 Rfactor outputR(-DBL_MAX, -DBL_MAX);
556 backgroundvalues = values.
toVector();
557 for (
size_t i = 0; i < numpts; ++i) {
563 backgroundvalues, valueVec, outputR);
565 g_log.
notice() <<
"[RefineBackground] Best Rwp = " << bestR.
Rwp <<
", vs. recovered best Rwp = " << outputR.
Rwp
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]);
582 auto outtablews = std::make_shared<TableWorkspace>();
583 outtablews->addColumn(
"str",
"Name");
584 outtablews->addColumn(
"double",
"Value");
585 outtablews->addColumn(
"double",
"Error");
590 TableRow newrow = outtablews->appendRow();
591 newrow << parname << parvalue << 1.0;
594 setProperty(
"BackgroundParametersWorkspace", outtablews);
624 double r = 2 * (
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX) - 0.5);
627 g_log.
information() <<
"[DBx804] Background " << iparam <<
" propose new value = " << newvalue <<
" from "
628 << currvalue <<
".\n";
647 throw runtime_error(
"Function parameters must be set up by this point.");
658 vector<vector<int>> vecHKL;
659 vector<pair<vector<int>,
double>>::iterator piter;
661 vecHKL.emplace_back(piter->first);
676 std::vector<double> fitrange = this->
getProperty(
"FitRegion");
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];
686 g_log.
warning() <<
"Input FitRegion has more than 2 entries. Using "
687 "default in stread.\n";
689 tof_min = inpws->x(wsindex)[0];
690 tof_max = inpws->x(wsindex).back();
695 cropalg->initialize();
697 cropalg->setProperty(
"InputWorkspace", inpws);
698 cropalg->setPropertyValue(
"OutputWorkspace",
"MyData");
699 cropalg->setProperty(
"XMin", tof_min);
700 cropalg->setProperty(
"XMax", tof_max);
702 bool cropstatus = cropalg->execute();
704 std::stringstream errmsg;
705 errmsg <<
"DBx309 Cropping workspace unsuccessful. Fatal Error. Quit!";
707 throw std::runtime_error(errmsg.str());
712 g_log.
error(
"Unable to retrieve a Workspace2D object from ChildAlgorithm "
714 throw runtime_error(
"Unable to retrieve a Workspace2D object from "
715 "ChildAlgorithm CropWorkspace");
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";
737 int tempindex = this->
getProperty(
"WorkspaceIndex");
740 if (
m_wsIndex >= inpWS->getNumberHistograms()) {
743 errss <<
"Input WorkspaceIndex " << tempindex <<
" is out of boundary [0, " << inpWS->getNumberHistograms()
746 throw runtime_error(errss.str());
763 std::string function = this->
getProperty(
"Function");
765 if (function ==
"Calculation") {
768 }
else if (function ==
"CalculateBackground") {
771 }
else if (function ==
"MonteCarlo") {
774 }
else if (function ==
"LeBailFit") {
777 }
else if (function ==
"RefineBackground") {
782 errss <<
"Function mode " << function <<
" is not supported by LeBailFit().";
784 throw invalid_argument(errss.str());
795 errss <<
"Input number of random walk steps (" <<
m_numMinimizeSteps <<
") cannot be less and equal to zero.";
797 throw invalid_argument(errss.str());
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. ");
828 std::vector<std::string> colnames =
parameterWS->getColumnNames();
829 size_t numcols = colnames.size();
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;
838 std::string strvalue;
840 for (
size_t ir = 0; ir < numrows; ++ir) {
849 for (
size_t icol = 0; icol < numcols; ++icol) {
850 colname = colnames[icol];
851 if (colname !=
"FitOrTie" && colname !=
"Name") {
853 g_log.
debug() <<
"Col-name = " << colname <<
", ";
855 g_log.
debug() <<
"Value = " << dblvalue <<
".\n";
857 tempdblmap.emplace(colname, dblvalue);
860 g_log.
debug() <<
"Col-name = " << colname <<
", ";
862 strvalue.erase(std::find_if(strvalue.rbegin(), strvalue.rend(), std::not_fn(::isspace)).base(), strvalue.end());
864 g_log.
debug() <<
"Value = " << strvalue <<
".\n";
865 tempstrmap.emplace(colname, strvalue);
872 striter = tempstrmap.find(
"Name");
873 if (striter != tempstrmap.end()) {
874 newparameter.
name = striter->second;
876 std::stringstream errmsg;
877 errmsg <<
"Parameter (table) workspace " <<
parameterWS->getName()
878 <<
" does not contain column 'Name'. It is not a valid input. "
881 throw std::invalid_argument(errmsg.str());
885 striter = tempstrmap.find(
"FitOrTie");
886 if (striter != tempstrmap.end()) {
887 std::string fitortie = striter->second;
889 if (fitortie.length() > 0) {
890 char fc = fitortie.c_str()[0];
891 if (fc ==
't' || fc ==
'T') {
895 newparameter.
fit = tofit;
897 std::stringstream errmsg;
898 errmsg <<
"Parameter (table) workspace " <<
parameterWS->getName()
899 <<
" does not contain column 'FitOrTie'. It is not a valid "
902 throw std::invalid_argument(errmsg.str());
906 dbliter = tempdblmap.find(
"Value");
907 if (dbliter != tempdblmap.end()) {
908 newparameter.
curvalue = dbliter->second;
910 std::stringstream errmsg;
911 errmsg <<
"Parameter (table) workspace " <<
parameterWS->getName()
912 <<
" does not contain column 'Value'. It is not a valid input. "
915 throw std::invalid_argument(errmsg.str());
919 dbliter = tempdblmap.find(
"Min");
920 if (dbliter != tempdblmap.end()) {
921 newparameter.
minvalue = dbliter->second;
927 dbliter = tempdblmap.find(
"Max");
928 if (dbliter != tempdblmap.end()) {
929 newparameter.
maxvalue = dbliter->second;
935 dbliter = tempdblmap.find(
"StepSize");
936 if (dbliter != tempdblmap.end()) {
937 newparameter.
stepsize = dbliter->second;
955 if (newparameter.
fit) {
958 <<
"], MC Step = " << newparameter.
stepsize <<
", Fit? = " << newparameter.
fit <<
"\n";
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. ");
981 if (colnames[0] !=
"H" || colnames[1] !=
"K" || colnames[2] !=
"L") {
983 errss <<
"Input Bragg peak parameter TableWorkspace does not have the "
985 <<
"It must be H, K, L. for the first 3 columns.";
987 throw std::runtime_error(errss.str());
991 bool hasPeakHeight =
false;
992 if (colnames.size() >= 4 && colnames[3] ==
"PeakHeight") {
994 hasPeakHeight =
true;
1010 for (
size_t ir = 0; ir < numrows; ++ir) {
1013 trow >> h >> k >> l;
1016 std::vector<int> hkl;
1017 hkl.emplace_back(h);
1018 hkl.emplace_back(k);
1019 hkl.emplace_back(l);
1022 double peakheight = 1.0;
1023 if (hasPeakHeight) {
1030 g_log.
information() <<
"Imported HKL TableWorkspace. Size of Rows = " << numrows <<
"\n";
1038 vector<double> &bkgdorderparams) {
1039 g_log.
debug() <<
"DB1105A Parsing background TableWorkspace.\n";
1042 bkgdorderparams.clear();
1045 std::vector<std::string> colnames = bkgdparamws->getColumnNames();
1046 if (colnames.size() < 2) {
1048 errss <<
"Input background parameter table workspace " << bkgdparamws->getName() <<
" has only " << colnames.size()
1049 <<
" columns, which is fewer than 2 columns as required. ";
1051 throw runtime_error(errss.str());
1053 if (!(boost::starts_with(colnames[0],
"Name") && boost::starts_with(colnames[1],
"Value"))) {
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";
1062 throw runtime_error(errss.str());
1068 std::map<std::string, double> parmap;
1069 for (
size_t ir = 0; ir < bkgdparamws->rowCount(); ++ir) {
1071 std::string parname;
1073 row >> parname >> parvalue;
1076 boost::algorithm::trim(parname);
1078 if (!parname.empty() && (parname[0] ==
'A' || parname ==
"Bkpos")) {
1081 parmap.emplace(parname, parvalue);
1086 bkgdparnames.reserve(parmap.size());
1087 bkgdorderparams.reserve(parmap.size());
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);
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] <<
"; ";
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");
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();
1149 newrow << h << k << l <<
height << tof_h << alpha << beta << sigma2 << gamma << fwhm << -1 << -1.0 <<
"N/A";
1153 errss <<
"Peak (" << h <<
", " << k <<
", " << l <<
"): TOF_h (=" << tof_h <<
") is NEGATIVE!";
1159 this->
setProperty(
"OutputPeaksWorkspace", peakWS);
1181 tablews->
addColumn(
"double",
"StepSize");
1182 tablews->
addColumn(
"double",
"StartValue");
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") {
1194 double parvalue = paramiter->second.curvalue;
1197 char fitortie =
't';
1198 if (paramiter->second.fit) {
1201 std::stringstream ss;
1203 std::string fit_tie = ss.str();
1207 double origparvalue = -1.0E100;
1209 origparvalue = opiter->second;
1211 double diff = origparvalue - parvalue;
1214 double paramerror = paramiter->second.fiterror;
1217 double min = paramiter->second.minvalue;
1218 double max = paramiter->second.maxvalue;
1219 double step = paramiter->second.stepsize;
1222 newparam << parname << parvalue << fit_tie << paramerror << min << max << step << origparvalue << diff;
1229 throw runtime_error(
"Impossible to have this situation happen. Flag 541.");
1239 fitchi2row <<
"FitChi2" <<
m_lebailFitChi2 <<
"t" << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
1241 chi2row <<
"Chi2" <<
m_lebailCalChi2 <<
"t" << 0.0 << 0.0 << 0.0 << 0.0 << 0.0 << 0.0;
1245 setProperty(
"OutputParameterWorkspace", parameterws);
1268 bool plotindpeak = this->
getProperty(
"PlotIndividualPeaks");
1279 m_outputWS = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
1284 for (
size_t j = 0; j <
m_outputWS->getNumberHistograms(); ++j)
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");
1307 for (
size_t i = 0; i < (nspec - 9); ++i) {
1308 std::stringstream ss;
1310 tAxis->setLabel(9 + i, ss.str());
1314 m_outputWS->replaceAxis(1, std::move(tAxis));
1331 std::vector<double> vecCalPurePeaks(domain.size(), 0.0);
1355 Rfactor startR(-DBL_MAX, -DBL_MAX);
1358 HistogramY vecBkgd =
m_lebailFunction->function(vecX.rawData(),
false,
true);
1368 if (!startvaluevalid) {
1370 throw runtime_error(
"Starting value of instrument profile parameters can "
1371 "generate peaks with"
1372 " unphyiscal parameters values.");
1375 doMarkovChain(parammap, vecX, vecPurePeak, vecBkgd.rawData(), maxcycles, startR, randomseed);
1378 Rfactor finalR(-DBL_MAX, -DBL_MAX);
1388 vecCalY = vecCalPurePeaks;
1391 vecDiff = vecInY - vecCalY;
1393 vecCalPurePeak = vecCalPurePeaks;
1395 vecCalBkgd = vecInY - vecCalPurePeaks;
1400 par_rwp.
name =
"Rwp";
1402 parammap[
"Rwp"] = par_rwp;
1409 const Mantid::HistogramData::HistogramY &vecPurePeak,
const vector<double> &vecBkgd,
1410 size_t maxcycles,
const Rfactor &startR,
int randomseed) {
1413 Rfactor currR(-DBL_MAX, -DBL_MAX), newR(-DBL_MAX, -DBL_MAX);
1415 map<string, Parameter> mapCurrParameter = parammap;
1416 map<string, Parameter> newparammap = mapCurrParameter;
1418 std::vector<double> veccalpurepeaks(vecX.size(), 0.0);
1426 g_log.
notice() <<
"[MC-Start] Random-walk Starting Rwp = " << currR.Rwp <<
", Rp = " << currR.Rp <<
"\n";
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;
1437 int numRecentAcceptance = 0;
1438 int numRecentSteps = 0;
1439 int numConsecutiveInvalid = 0;
1444 int numMaxConsecutiveInvalid = 5;
1445 int m_numStepsCheckTemperature = 10;
1450 for (
size_t icycle = 1; icycle <= maxcycles; ++icycle) {
1459 bool hasnewvalues =
proposeNewValues(MCGroup.second, currR, mapCurrParameter, newparammap, prevcyclebetterR);
1461 if (!hasnewvalues) {
1471 g_log.
debug() <<
"[Calculation] Rwp = " << newR.
Rwp <<
", Rp = " << newR.
Rp <<
".\n";
1477 acceptchange =
false;
1478 prevcyclebetterR =
false;
1479 ++numConsecutiveInvalid;
1483 prevcyclebetterR = newR.
Rwp < currR.Rwp;
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";
1511 ++numRecentAcceptance;
1516 if (numConsecutiveInvalid >= numMaxConsecutiveInvalid) {
1522 numConsecutiveInvalid = 0;
1523 numRecentAcceptance = 0;
1529 if (numRecentSteps == m_numStepsCheckTemperature) {
1531 if (numRecentAcceptance <= 2) {
1533 }
else if (numRecentAcceptance >= 8) {
1537 numRecentAcceptance = 0;
1554 vecIndex[icycle] =
static_cast<double>(icycle);
1555 if (currR.Rwp < 1.0E5)
1556 vecR[icycle] = currR;
1563 if (icycle % 10 == 0)
1564 progress(
double(icycle) /
double(maxcycles));
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";
1576 map<string, Parameter>::iterator mapiter;
1577 for (mapiter = mapCurrParameter.begin(); mapiter != mapCurrParameter.end(); ++mapiter) {
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)
1584 <<
", Number of No Move = " << setw(4) << param.
numnomove <<
", Minimum tried value = " << setw(4)
1588 g_log.
notice() <<
"Number of invalid proposed moves = " << numinvalidmoves <<
"\n";
1591 stringstream filenamess;
1592 filenamess <<
"r_trace_" << vecR.size() <<
".dat";
1604 size_t numrows = tablews->rowCount();
1605 for (
size_t i = 0; i < numrows; ++i) {
1607 TableRow temprow = tablews->getRow(i);
1610 int nonnegative, group;
1612 temprow >> parname >> a0 >> a1 >> nonnegative >> group;
1615 map<int, vector<string>>::iterator giter;
1618 giter->second.emplace_back(parname);
1621 m_MCGroups.emplace(group, std::initializer_list<std::string>{parname});
1627 piter->second.mcA0 = a0;
1628 piter->second.mcA1 = a1;
1629 piter->second.nonnegative = (nonnegative != 0);
1636 map<string, Parameter>::iterator 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;
1653 stringstream dboutss;
1654 dboutss <<
"Monte Carlo minimizer refines: ";
1658 vector<string> geomparams;
1668 dboutss <<
"Geometry parameters: ";
1669 for (
auto &geomparam : geomparams)
1670 dboutss << geomparam <<
"\t\t";
1674 vector<string> alphs;
1681 dboutss <<
"Alpha parameters";
1682 for (
auto &alph : alphs)
1683 dboutss << alph <<
"\t\t";
1687 vector<string> betas;
1694 dboutss <<
"Beta parameters";
1695 for (
auto &beta : betas)
1696 dboutss << beta <<
"\t\t";
1700 vector<string> sigs;
1706 dboutss <<
"Sig parameters";
1707 for (
auto &sig : sigs)
1708 dboutss << sig <<
"\t\t";
1717 for (
const auto &parname : sigs) {
1724 for (
const auto &parname : alphs) {
1734 for (
const auto &parname : betas) {
1773 map<string, Parameter>::iterator 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;
1793 map<string, Parameter>::iterator pariter;
1797 errss <<
"Parameter " << parname <<
" does not exisit Le Bail function parameters. ";
1799 throw runtime_error(errss.str());
1802 if (pariter->second.fit)
1803 parnamesforMC.emplace_back(parname);
1827 bool outputwithbkgd,
const HistogramY &vecBkgd, std::vector<double> &values,
1829 HistogramY veccalbkgd(vecX.size());
1830 bool veccalbkgdIsEmpty =
true;
1833 double maxfwhm = vecX.back() - vecX.front();
1838 g_log.
information() <<
"Proposed new instrument profile values cause peak(s) to have "
1839 <<
"unphysical parameter values.\n";
1847 vector<double> vecPureY(vecY.size(), 0.);
1848 if (vecBkgd.size() == vecY.size()) {
1851 "background vector. "
1853 ::transform(vecY.begin(), vecY.end(), vecBkgd.begin(), vecPureY.begin(), ::minus<double>());
1857 "and newly calculated background. "
1860 ::transform(vecY.begin(), vecY.end(), veccalbkgd.begin(), vecPureY.begin(), ::minus<double>());
1861 veccalbkgdIsEmpty =
false;
1865 peaksvalid =
m_lebailFunction->calculatePeaksIntensities(vecX.rawData(), vecPureY, values);
1869 g_log.
debug() <<
"Calculate diffraction pattern from input data with "
1870 "background removed. "
1872 peaksvalid =
m_lebailFunction->calculatePeaksIntensities(vecX.rawData(), vecY.rawData(), values);
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...");
1883 if (outputwithbkgd) {
1884 if (vecBkgd.size() == vecY.size()) {
1885 ::transform(values.begin(), values.end(), vecBkgd.begin(), values.begin(), ::plus<double>());
1887 if (veccalbkgdIsEmpty)
1888 throw runtime_error(
"Programming logic error.");
1889 ::transform(values.begin(), values.end(), veccalbkgd.begin(), values.begin(), ::plus<double>());
1893 vector<double> caldata(values.size(), 0.0);
1894 if (vecBkgd.size() == vecY.size()) {
1896 std::transform(values.begin(), values.end(), vecBkgd.begin(), caldata.begin(), std::plus<double>());
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>());
1930 map<string, Parameter> &newparammap,
bool prevBetterRwp) {
1934 bool anyparamtorefine =
false;
1937 g_log.
debug() <<
"Parameter Number In Group = " << mcgroup.size() <<
"\n";
1938 for (
const auto ¶mname : mcgroup) {
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. "
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 <<
", ";
1950 throw runtime_error(errmsg.str());
1955 anyparamtorefine =
true;
1960 double randomnumber = 2 *
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX) - 1.0;
1963 double weight = r.
Rwp;
1974 newvalue = param.
curvalue + stepsize;
1977 int prevRightDirection;
1979 prevRightDirection = 1;
1981 prevRightDirection = -1;
1983 double randirint =
static_cast<double>(rand()) /
static_cast<double>(RAND_MAX);
1984 g_log.
debug() <<
"[TestRandom] random = " << randirint <<
"\n";
1987 if (randirint < 0.1) {
1989 stepsize = -1.0 *
fabs(stepsize) *
static_cast<double>(param.
movedirection * prevRightDirection);
1990 }
else if (randirint < 0.4) {
1994 stepsize =
fabs(stepsize) *
static_cast<double>(param.
movedirection * prevRightDirection);
1997 newvalue = param.
curvalue + stepsize;
1999 throw runtime_error(
"Unrecoganized walk style. ");
2005 newvalue =
fabs(newvalue);
2010 int toss = rand() % 2;
2011 double direction = -1.0;
2013 }
else if (newvalue > param.
maxvalue) {
2014 int toss = rand() % 2;
2015 double direction = 1.0;
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
2032 }
else if (stepsize < 0) {
2048 g_log.
debug() <<
"[DBx257] " << paramname <<
"\t"
2049 <<
"Proposed value = " << setw(15) << newvalue <<
" (orig = " << param.
curvalue
2050 <<
", step = " << stepsize <<
"), totRwp = " << r.
Rwp <<
"\n";
2053 return anyparamtorefine;
2071 if (direction > 0) {
2087 if (direction > 0) {
2089 double dval = (newvalue - param.
maxvalue) / deltaX;
2090 newvalue = param.
minvalue + deltaX * (dval - floor(dval));
2093 double dval = (param.
minvalue - newvalue) / deltaX;
2094 newvalue = param.
maxvalue - deltaX * (dval - floor(dval));
2098 if (direction > 0) {
2119 double new_goodness = newR.
Rwp;
2120 double cur_goodness = currR.
Rwp;
2122 if (new_goodness < cur_goodness) {
2125 }
else if (new_goodness > 1.0 - 1.0E-9) {
2127 g_log.
debug() <<
"Goodness > " << 1.0 - 1.0E-9 <<
". Reject!"
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));
2136 accept = dice < bar;
2154 double goodness = rfactor.
Rwp;
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 ");
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;
2196 tgtmapiter = tgtparammap.find(parname);
2197 if (tgtmapiter == tgtparammap.end()) {
2199 errss <<
"Parameter " << parname <<
" cannot be found in target Parameter map containing " << tgtparammap.size()
2202 throw runtime_error(
"Programming or memory error! This situation cannot happen!");
2205 tgtmapiter->second.curvalue = srcparam.
curvalue;
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);
2227 ofile.open(filename.c_str());
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";
#define DECLARE_ALGORITHM(classname)
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)
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
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.
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.
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.
std::string mMinimizer
Minimizer.
void proposeNewBackgroundValues()
Propose new background parameters.
bool acceptOrDeny(Kernel::Rfactor currR, Kernel::Rfactor newR)
Determine whether the proposed value should be accepted or denied.
std::vector< std::pair< std::vector< int >, double > > m_inputPeakInfoVec
Input Bragg peak information for future processing;.
Functions::BackgroundFunction_sptr m_backgroundFunction
Background function.
bool m_tolerateInputDupHKL2Peaks
Flag to allow peaks with duplicated (HKL)^2 in input .hkl file.
std::map< std::string, double > m_origFuncParameters
Input function parameters that are stored for reference.
void addParameterToMCMinimize(std::vector< std::string > &parnamesforMC, const std::string &parname)
Add parameter (to a vector of string/name) for MC random walk.
bool m_inputParameterPhysical
Flag to show whether the input profile parameters are physical to all peaks.
void exec() override
Implement abstract Algorithm methods.
API::MatrixWorkspace_sptr cropWorkspace(const API::MatrixWorkspace_sptr &inpws, size_t wsindex)
Crop the workspace for better usage.
void doMarkovChain(const std::map< std::string, Parameter > ¶mmap, 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.
FunctionMode m_fitMode
Fit mode.
void init() override
Declare the input properties for this algorithm.
std::map< std::string, Parameter > m_funcParameters
Function parameters updated by fit.
LeBailFunction_sptr m_lebailFunction
Le Bail Function (Composite)
std::vector< double > m_backgroundParameters
Background polynomials.
std::vector< double > m_bkgdParameterBuffer
void parseInstrumentParametersTable()
Import peak parameters.
std::vector< std::string > m_bkgdParameterNames
void processInputBackground()
Process and calculate input background.
std::vector< double > m_bestBkgdParams
int mPeakRadius
Peak Radius.
void parseBraggPeaksParametersTable()
Import Miller Indices (HKL)
double limitProposedValueInBound(const Parameter ¶m, double newvalue, double direction, int choice)
Limit proposed value in the specified boundary.
double m_indicatePeakHeight
std::map< std::string, double > convertToDoubleMap(std::map< std::string, Parameter > &inmap)
Convert a map of Parameter to a map of double.
void execRefineBackground()
Calcualte background by fitting peak heights.
double m_dampingFactor
Damping factor.
double m_minimumPeakHeight
Minimum height of a peak to be counted in smoothing background.
DataObjects::Workspace2D_sptr m_outputWS
void execPatternCalculation()
Calculate LeBail pattern from from input peak parameters.
void recoverBackgroundParameters(const std::vector< double > &bkgdparamvec)
Restore/recover the buffered background parameters to m_background function.
std::map< int, std::vector< std::string > > m_MCGroups
bool m_useAnnealing
Flag to use Annealing Simulation (i.e., use automatic adjusted temperature)
API::MatrixWorkspace_sptr m_dataWS
Instance data.
size_t m_numMinimizeSteps
Number of minimization steps. For both MC and regular.
void setupBuiltInRandomWalkStrategy()
Set up Monte Carlo random walk strategy.
void storeBackgroundParameters(std::vector< double > &bkgdparamvec)
Store/buffer current background parameters.
double m_lebailFitChi2
Fit Chi^2.
void exportBraggPeakParameterToTable()
Create and set up output table workspace for peaks.
std::map< std::string, Parameter > m_bestParameters
enum Mantid::CurveFitting::Algorithms::LeBailFit::@2 m_walkStyle
Monte Carlo algorithm.
void createOutputDataWorkspace()
Create output data workspace.
DataObjects::TableWorkspace_sptr parameterWS
std::vector< double > m_bestBackgroundData
double m_Temperature
Monte Carlo temperature.
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.
std::vector< std::string > m_backgroundParameterNames
std::string m_backgroundType
Background type.
void processInputProperties()
Process input properties.
void execRandomWalkMinimizer(size_t maxcycles, std::map< std::string, Parameter > ¶mmap)
Main for random walk process.
void applyParameterValues(std::map< std::string, Parameter > &srcparammap, std::map< std::string, Parameter > &tgtparammap)
Apply the value of parameters in the source to target.
std::string m_peakType
============================= =========================== ///
std::vector< double > m_bkgdParameterStepVec
size_t m_numberBkgdParameters
void createLeBailFunction()
Create LeBailFunction.
void exportInstrumentParameterToTable(std::map< std::string, Parameter > parammap)
Output parameters (fitted or tied)
DataObjects::TableWorkspace_sptr reflectionWS
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.
void setupRandomWalkStrategyFromTable(const DataObjects::TableWorkspace_sptr &tablews)
Set up Monte Carlo random walk strategy.
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.
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...
void debug(const std::string &msg)
Logs at debug level.
void notice(const std::string &msg)
Logs at notice level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
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.
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.
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.
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.
LeBailFit : Algorithm to do Le Bail Fit.
@ InOut
Both an input & output workspace.
@ Input
An input workspace.
@ Output
An output workspace.
R factor for powder data analysis.