24#include "MantidHistogramData/LinearGenerator.h"
31#include <boost/math/special_functions/fpclassify.hpp>
44std::string
const DEFAULT_PDF_GROUP_NAME =
"__PDF_Workspace";
49const size_t LOWER_CONVERGENCE_LIMIT = 350;
51const size_t JUMP_CHECKING_RATE = 200;
53const double LOW_JUMP_LIMIT = 1e-25;
58 int const numberOfSpectra,
59 std::vector<std::string>
const &verticalAxisNames) {
60 auto createWorkspaceAlgorithm = AlgorithmManager::Instance().createUnmanaged(
"CreateWorkspace");
61 createWorkspaceAlgorithm->initialize();
62 createWorkspaceAlgorithm->setChild(
true);
63 createWorkspaceAlgorithm->setLogging(
false);
64 createWorkspaceAlgorithm->setProperty(
"DataX", xValues);
65 createWorkspaceAlgorithm->setProperty(
"DataY", yValues);
66 createWorkspaceAlgorithm->setProperty(
"NSpec", numberOfSpectra);
67 createWorkspaceAlgorithm->setProperty(
"VerticalAxisUnit",
"Text");
68 createWorkspaceAlgorithm->setProperty(
"VerticalAxisValues", verticalAxisNames);
69 createWorkspaceAlgorithm->setProperty(
"OutputWorkspace",
"__PDF");
70 createWorkspaceAlgorithm->execute();
71 return createWorkspaceAlgorithm->getProperty(
"OutputWorkspace");
80 : m_counter(0), m_chainIterations(0), m_changes(), m_jump(), m_parameters(), m_chain(), m_chi2(0.),
81 m_converged(false), m_convPoint(0), m_parConverged(), m_criteria(), m_maxIter(0), m_parChanged(),
82 m_temperature(0.), m_counterGlobal(0), m_simAnnealingItStep(0), m_leftRefrPoints(0), m_tempStep(0.),
83 m_overexploration(false), m_nParams(0), m_numInactiveRegenerations(), m_changesOld() {
84 declareProperty(
"ChainLength",
static_cast<size_t>(10000),
"Length of the converged chain.");
85 declareProperty(
"StepsBetweenValues", 10,
86 "Steps done between chain points to avoid correlation"
88 declareProperty(
"ConvergenceCriteria", 0.01,
"Variance in Cost Function for considering convergence reached.");
89 declareProperty(
"InnactiveConvergenceCriterion",
static_cast<size_t>(5),
90 "Number of Innactive Regenerations to consider"
91 " a certain parameter to be converged");
92 declareProperty(
"JumpAcceptanceRate", 0.6666666,
"Desired jumping acceptance rate");
94 declareProperty(
"SimAnnealingApplied",
false,
95 "If minimization should be run with Simulated"
97 declareProperty(
"MaximumTemperature", 10.0,
"Simulated Annealing maximum temperature");
98 declareProperty(
"NumRefrigerationSteps",
static_cast<size_t>(5),
"Simulated Annealing number of temperature changes");
99 declareProperty(
"SimAnnealingIterations",
static_cast<size_t>(10000),
100 "Number of iterations for the Simulated Annealig");
101 declareProperty(
"Overexploration",
false,
102 "If Temperatures < 1 are desired for overexploration,"
103 " no error will jump for that (The temperature is"
104 " constant during the convergence period)."
105 " Useful to find the exact minimum.");
107 declareProperty(
"PDF", DEFAULT_PDF_GROUP_NAME,
108 "Name for the output PDF workspace group. Default is " + DEFAULT_PDF_GROUP_NAME);
109 declareProperty(
"NumberBinsPDF", 20,
"Number of bins used for the output PDFs");
111 "The name to give the output workspace for the"
112 " complete chains.");
115 "The name to give the output workspace for just the"
119 "The name to give the output workspace");
122 "The name to give the output workspace (Parameter values and errors)");
139 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(function);
141 throw std::invalid_argument(
"FABADA works only with least squares."
142 " Different function was given.");
167 if (totalRequiredIterations >= maxIterations) {
168 throw std::length_error(
"Too few iterations to perform the"
169 " Simulated Annealing and/or the posterior chain plus"
170 " 350 iterations for the burn-in period. Increase"
171 " MaxIterations property");
182 throw std::runtime_error(
"Cost function isn't set up.");
197 for (
size_t i = 0; i <
m; i++) {
219 if (std::isnan(newValue))
220 throw std::runtime_error(
"Parameter value is NaN.");
221 newParameters.
set(i, newValue);
247 if (
m_counter % JUMP_CHECKING_RATE == 150)
264 double chi2Quotient =
fabs(
m_chi2 - oldChi2) / oldChi2;
302 g_log.
warning() <<
"StepsBetweenValues has a non valid value"
303 " (<= 0). Default one used"
304 " (StepsBetweenValues = 10).\n";
307 auto convLength = size_t(
double(chainLength) /
double(nSteps));
310 std::vector<std::vector<double>> reducedConvergedChain;
312 std::vector<double> bestParameters(
m_nParams);
313 std::vector<double> errorLeft(
m_nParams);
314 std::vector<double> errorRight(
m_nParams);
329 std::shared_ptr<MaleableCostFunction> leastSquaresMaleable =
331 leastSquaresMaleable->setDirtyInherited();
333 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(leastSquaresMaleable);
340 double mostPchi2 =
outputPDF(convLength, reducedConvergedChain);
383 double upper = bcon->upper();
387 while (newValue <
lower) {
388 if (std::abs(step) >
delta) {
397 while (newValue >
upper) {
398 if (std::abs(step) >
delta) {
418 if (j != parameterIndex) {
421 newValue = tie->
eval();
422 if (boost::math::isnan(newValue)) {
423 throw std::runtime_error(
"Parameter value is NaN.");
425 newParameters.
set(j, newValue);
433 newValue = tie->
eval();
434 if (boost::math::isnan(newValue)) {
435 throw std::runtime_error(
"Parameter value is NaN.");
437 newParameters.
set(parameterIndex, newValue);
443 std::shared_ptr<MaleableCostFunction> leastSquaresMaleable =
446 leastSquaresMaleable->setDirtyInherited();
449 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(leastSquaresMaleable);
464 m_chain[j].emplace_back(newParameters.
get(j));
478 double p = std::uniform_real_distribution<double>(0.0, 1.0)(rng);
481 m_chain[j].emplace_back(newParameters.
get(j));
498 std::shared_ptr<MaleableCostFunction> leastSquaresMaleable =
501 leastSquaresMaleable->setDirtyInherited();
504 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(leastSquaresMaleable);
514 const double jumpAR =
getProperty(
"JumpAcceptanceRate");
523 newJump =
m_jump[parameterIndex] / JUMP_CHECKING_RATE;
535 newJump =
m_jump[parameterIndex] * f / jumpAR;
543 m_jump[parameterIndex] = newJump;
547 if (std::abs(
m_jump[parameterIndex]) < LOW_JUMP_LIMIT) {
548 g_log.
warning() <<
"Wrong convergence might be reached for parameter " +
550 ". Try to set a proper initial value for this parameter\n";
559 size_t innactConvCriterion =
getProperty(
"InnactiveConvergenceCriterion");
563 bool ImmobilityConv =
false;
569 ImmobilityConv =
true;
581 g_log.
warning() <<
"Convergence detected through immobility."
582 " It might be a bad convergence.\n";
649 std::string failed =
"";
655 failed.replace(failed.end() - 2, failed.end(),
".");
657 " iterations.\n Try to set better initial values for parameters: " + failed +
658 " Or increase the maximum number of iterations "
659 "(MaxIterations property).");
677 size_t chainLength =
m_chain[0].size();
682 for (
size_t j = 0; j <
m_nParams + 1; ++j) {
683 auto &
X = wsC->mutableX(j);
684 auto &
Y = wsC->mutableY(j);
685 for (
size_t k = 0; k < chainLength; ++k) {
705 if (convLength > 0) {
708 g_log.
warning() <<
"Empty converged chain, empty Workspace returned.";
713 for (
size_t j = 0; j <
m_nParams + 1; ++j) {
715 std::vector<double>::const_iterator last =
m_chain[j].end();
716 std::vector<double> convChain(first, last);
717 auto &
X = wsConv->mutableX(j);
718 auto &
Y = wsConv->mutableY(j);
719 for (
size_t k = 0; k < convLength; ++k) {
721 Y[k] = convChain[nSteps * k];
738 wsChi2->addColumn(
"double",
"Chi2 Minimum");
739 wsChi2->addColumn(
"double",
"Most Probable Chi2");
740 wsChi2->addColumn(
"double",
"reduced Chi2 Minimum");
741 wsChi2->addColumn(
"double",
"Most Probable reduced Chi2");
745 size_t dataSize = domain->size();
749 double mostProbableChi2Red;
751 mostProbableChi2Red = mostProbableChi2 / (double(dataSize -
m_nParams));
753 g_log.
warning() <<
"Most probable chi square not calculated. -1 is returned.\n"
754 <<
"Most probable reduced chi square not calculated. -1 is "
756 mostProbableChi2Red = -1;
761 row <<
m_chi2 << mostProbableChi2 << minimumChi2Red << mostProbableChi2Red;
778 if (pdfLength <= 0) {
779 g_log.
warning() <<
"Non valid Number of bins for the PDF (<= 0)."
780 " Default value (20 bins) taken\n";
785 if (convLength > 0) {
787 std::vector<double> xValues((
m_nParams + 1) * (pdfLength + 1));
788 std::vector<double> yValues((
m_nParams + 1) * pdfLength);
789 std::vector<double> PDFYAxis(pdfLength, 0);
790 double const start = reducedChain[
m_nParams][0];
791 double const bin = (reducedChain[
m_nParams][convLength - 1] - start) /
double(pdfLength);
795 outputPDF(xValues, yValues, reducedChain, convLength, pdfLength);
799 g_log.
warning() <<
"No points to create PDF. Empty Workspace returned.\n";
807 std::vector<std::vector<double>>
const &reducedChain, std::size_t
const &convLength,
808 int const &pdfLength) {
811 parameterNames.emplace_back(
"Chi Squared");
815 if (AnalysisDataService::Instance().doesExist(pdfName)) {
816 auto groupPDF = AnalysisDataService::Instance().retrieveWS<
WorkspaceGroup>(pdfName);
818 AnalysisDataService::Instance().addOrReplace(pdfName, groupPDF);
820 auto groupPDF = std::make_shared<WorkspaceGroup>();
822 AnalysisDataService::Instance().addOrReplace(pdfName, groupPDF);
827 std::vector<std::vector<double>>
const &reducedChain,
828 int const &pdfLength, std::vector<double> &xValues,
829 std::vector<double> &yValues, std::vector<double> &PDFYAxis,
830 double const &start,
double const &bin) {
831 std::size_t step = 0;
832 std::size_t
const chiXStartPos =
m_nParams * (pdfLength + 1);
833 std::size_t
const chiYStartPos =
m_nParams * pdfLength;
835 xValues[chiXStartPos] = start;
836 for (std::size_t i = 1; i < static_cast<std::size_t>(pdfLength) + 1; i++) {
837 double binEnd = start + double(i) * bin;
838 xValues[chiXStartPos + i] = binEnd;
839 while (step < convLength && reducedChain[
m_nParams][step] <= binEnd) {
840 PDFYAxis[i - 1] += 1;
844 yValues[chiYStartPos + i - 1] = PDFYAxis[i - 1] / (double(convLength) * bin);
847 auto indexMostProbableChi2 = std::max_element(PDFYAxis.begin(), PDFYAxis.end());
849 return xValues[indexMostProbableChi2 - PDFYAxis.begin()] + (bin / 2.0);
853 std::vector<std::vector<double>>
const &reducedChain,
854 std::size_t
const &convLength,
int const &pdfLength) {
855 for (std::size_t j = 0; j <
m_nParams; ++j) {
858 std::vector<double> PDFYAxis(pdfLength, 0);
859 double start = reducedChain[j][0];
860 double bin = (reducedChain[j][convLength - 1] - start) /
double(pdfLength);
861 std::size_t step = 0;
862 std::size_t
const startXPos = j * (pdfLength + 1);
863 std::size_t
const startYPos = j * pdfLength;
865 xValues[startXPos] = start;
866 for (std::size_t i = 1; i < static_cast<std::size_t>(pdfLength) + 1; i++) {
867 double binEnd = start + double(i) * bin;
868 xValues[startXPos + i] = binEnd;
869 while (step < convLength && reducedChain[j][step] <= binEnd) {
870 PDFYAxis[i - 1] += 1;
873 yValues[startYPos + i - 1] = PDFYAxis[i - 1] / (double(convLength) * bin);
887 const std::vector<double> &errorLeft,
888 const std::vector<double> &errorRight) {
892 wsPdfE->addColumn(
"str",
"Name");
893 wsPdfE->addColumn(
"double",
"Value");
894 wsPdfE->addColumn(
"double",
"Left's error");
895 wsPdfE->addColumn(
"double",
"Right's error");
899 row <<
m_fitFunction->parameterName(j) << bestParameters[j] << errorLeft[j] << errorRight[j];
919 std::vector<std::vector<double>> &reducedChain,
920 std::vector<double> &bestParameters,
921 std::vector<double> &errorLeft,
922 std::vector<double> &errorRight) {
925 if (convLength > 0) {
927 for (
size_t e = 0; e <=
m_nParams; ++e) {
928 std::vector<double> v;
930 reducedChain.emplace_back(std::move(v));
934 for (
size_t k = 1; k < convLength; ++k) {
939 auto positionMinChi2 = std::min_element(reducedChain[
m_nParams].begin(), reducedChain[
m_nParams].end());
940 m_chi2 = *positionMinChi2;
945 for (
size_t k = 1; k < convLength; ++k) {
949 bestParameters[j] = reducedChain[j][positionMinChi2 - reducedChain[
m_nParams].begin()];
950 std::sort(reducedChain[j].begin(), reducedChain[j].end());
951 auto posBestPar = std::find(reducedChain[j].begin(), reducedChain[j].end(), bestParameters[j]);
952 double varLeft = 0, varRight = 0;
953 for (
auto k = reducedChain[j].begin(); k < reducedChain[j].end(); k += 2) {
955 varLeft += (*k - bestParameters[j]) * (*k - bestParameters[j]);
956 else if (k > posBestPar)
957 varRight += (*k - bestParameters[j]) * (*k - bestParameters[j]);
959 if (posBestPar != reducedChain[j].begin())
960 varLeft /=
double(posBestPar - reducedChain[j].begin());
961 if (posBestPar != reducedChain[j].end() - 1)
962 varRight /=
double(reducedChain[j].end() - posBestPar - 1);
964 errorLeft[j] = -sqrt(varLeft);
965 errorRight[j] = sqrt(varRight);
972 " Thus the parameters' errors are not"
975 bestParameters[k] = *(
m_chain[k].end() - 1);
987 throw std::invalid_argument(
"Function has 0 fitting parameters.");
1007 if (bcon->hasLower()) {
1008 if (param < bcon->
lower())
1011 if (bcon->hasUpper()) {
1012 if (param > bcon->upper())
1019 m_chain.emplace_back(std::vector<double>(1, param));
1021 m_jump.emplace_back(param != 0.0 ? std::abs(param / 10) : 0.01);
1045 g_log.
warning() <<
"MaximumTemperature not a valid temperature"
1046 " (T = 0). Default (T = 10.0) taken.\n";
1050 g_log.
warning() <<
"MaximumTemperature not a temperature"
1051 " (< 0), absolute value taken\n";
1058 " exploration (0 < T < 1), product inverse taken ("
1063 g_log.
warning() <<
"Overexploration wrong temperature. Not"
1064 " overexploring. Applying usual Simulated Annealing.\n";
1071 g_log.
warning() <<
"Wrong value for the number of refrigeration"
1072 " points (== 0). Therefore, default value (5 points) taken.\n";
1085 g_log.
warning() <<
"SimAnnealingIterations/NumRefrigerationSteps too small"
1086 " (< 50 it). Simulated Annealing not applied\n";
#define DECLARE_FUNCMINIMIZER(classname, username)
Macro for declaring a new type of minimizers to be used with the FuncMinimizerFactory.
IPeaksWorkspace_sptr workspace
double lower
lower and upper bounds on the multiplier, if known
An interface to a constraint.
double eval(bool setParameterValue=true)
Evaluate the expression.
TableRow represents a row in a TableWorkspace.
Class to hold a set of workspaces.
void addWorkspace(const Workspace_sptr &workspace)
Adds a workspace to the group.
A property class for workspaces.
A boundary constraint is designed to be used to set either upper or lower (or both) boundaries on a s...
const double & lower() const
Return the lower bound value.
A wrapper around Eigen::Vector.
void set(const size_t i, const double value)
Set an element.
double get(const size_t i) const
Get an element.
void resize(const size_t n)
Resize the vector.
size_t size() const
Size of the vector.
FABADA : Implements the FABADA Algorithm, based on a Adaptive Metropolis Algorithm extended with Gibb...
bool m_overexploration
Overexploration applied.
bool iterate(size_t iter) override
Do one iteration.
size_t m_nParams
Number of parameters of the FittingFunction (not necessarily the CostFunction)
size_t m_counter
The number of iterations done (restarted at each phase).
double gaussianStep(const double &jump)
Returns the step from a Gaussian given sigma = Jump.
std::shared_ptr< CostFunctions::CostFuncLeastSquares > m_leastSquares
Pointer to the cost function. Must be the least squares.
std::vector< int > m_changes
The number of changes done on each parameter.
double m_tempStep
Temperature step between different Simulated Annealing phases.
std::vector< double > m_jump
The jump for each parameter.
void tieApplication(const size_t ¶meterIndex, EigenVector &newParameters, double &newValue)
Applied to the other parameters first and sequentially, finally to the current one.
double outputPDF(std::size_t const &convLength, std::vector< std::vector< double > > &reducedChain)
Output PDF.
void jumpUpdate(const size_t ¶meterIndex)
Updates the ParameterIndex-th parameter jump if appropriate.
void boundApplication(const size_t ¶meterIndex, double &newValue, double &step)
Public methods only for testing purposes.
void outputChains()
Output Markov chains.
size_t m_maxIter
Maximum number of iterations.
void initSimulatedAnnealing()
Initialize member variables related to simulated annealing.
double m_temperature
Simulated Annealing temperature.
double m_chi2
The chi square result of previous iteration;.
void finalize() override
Finalize minimization, eg store additional outputs.
void simAnnealingRefrigeration()
Refrigerates the system if appropriate.
size_t m_counterGlobal
The global number of iterations done.
std::vector< double > m_criteria
Convergence criteria for each parameter.
std::vector< size_t > m_numInactiveRegenerations
Number of consecutive regenerations without changes.
void outputParameterTable(const std::vector< double > &bestParameters, const std::vector< double > &errorsLeft, const std::vector< double > &errorsRight)
Output parameter table.
size_t m_simAnnealingItStep
Number of iterations between Simulated Annealing refrigeration points.
void algorithmDisplacement(const size_t ¶meterIndex, const double &chi2New, const EigenVector &newParameters)
Given the new chi2, next position is calculated and updated.
std::vector< std::vector< double > > m_chain
Markov chain.
void outputCostFunctionTable(size_t convLength, double mostProbableChi2)
Output cost function.
void initialize(API::ICostFunction_sptr function, size_t maxIterations) override
Initialize minimizer, i.e. pass a function to minimize.
size_t m_convPoint
The point when convergence has been reached.
std::vector< bool > m_parChanged
Bool that idicates if a varible has changed at some self iteration.
double getMostProbableChiSquared(std::size_t const &convLength, std::vector< std::vector< double > > const &reducedChain, int const &pdfLength, std::vector< double > &xValues, std::vector< double > &yValues, std::vector< double > &PDFYAxis, double const &start, double const &bin)
Finds the most probable Chi Squared value.
void setParameterXAndYValuesForPDF(std::vector< double > &xValues, std::vector< double > &yValues, std::vector< std::vector< double > > const &reducedChain, std::size_t const &convLength, int const &pdfLength)
Computes the X and Y for the Parameter PDF's.
bool iterationContinuation()
Decides wheather iteration must continue or not.
std::vector< bool > m_parConverged
Convergence of each parameter.
double costFunctionVal() override
Return current value of the cost function.
std::vector< int > m_changesOld
To track convergence through immobility.
size_t m_leftRefrPoints
The number of refrigeration points left.
size_t m_chainIterations
The number of chain iterations.
API::IFunction_sptr m_fitFunction
Pointer to the Fitting Function (IFunction) inside the cost function.
bool m_converged
Boolean that indicates global convergence.
EigenVector m_parameters
Parameters' values.
void calculateConvChainAndBestParameters(size_t convLength, int nSteps, std::vector< std::vector< double > > &reducedChain, std::vector< double > &bestParameters, std::vector< double > &errorLeft, std::vector< double > &errorRight)
Calculated converged chain and parameters.
void initChainsAndParameters()
Initialize member variables related to fitting parameters.
void convergenceCheck()
Check for convergence (including Overexploration convergence), updates m_converged.
void outputConvergedChains(size_t convLength, int nSteps)
Output converged chains.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The Logger class is in charge of the publishing messages from the framework through various channels.
void warning(const std::string &msg)
Logs at warning level.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< T > createWorkspace(InitArgs... args)
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< ICostFunction > ICostFunction_sptr
define a shared pointer to a cost function
std::shared_ptr< FunctionDomain > FunctionDomain_sptr
typedef for a shared pointer
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Output
An output workspace.