24#include "MantidHistogramData/LinearGenerator.h"
31#include <boost/math/special_functions/fpclassify.hpp>
44std::string
const 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) {
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",
true,
"If the PDF's should be calculated or not.");
108 declareProperty(
"NumberBinsPDF", 20,
"Number of bins used for the output PDFs");
110 "The name to give the output workspace for the"
111 " complete chains.");
114 "The name to give the output workspace for just the"
118 "The name to give the output workspace");
121 "The name to give the output workspace (Parameter values and errors)");
138 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(function);
140 throw std::invalid_argument(
"FABADA works only with least squares."
141 " Different function was given.");
166 if (totalRequiredIterations >= maxIterations) {
167 throw std::length_error(
"Too few iterations to perform the"
168 " Simulated Annealing and/or the posterior chain plus"
169 " 350 iterations for the burn-in period. Increase"
170 " MaxIterations property");
181 throw std::runtime_error(
"Cost function isn't set up.");
196 for (
size_t i = 0; i <
m; i++) {
218 if (std::isnan(newValue))
219 throw std::runtime_error(
"Parameter value is NaN.");
220 newParameters.
set(i, newValue);
246 if (
m_counter % JUMP_CHECKING_RATE == 150)
263 double chi2Quotient =
fabs(
m_chi2 - oldChi2) / oldChi2;
301 g_log.
warning() <<
"StepsBetweenValues has a non valid value"
302 " (<= 0). Default one used"
303 " (StepsBetweenValues = 10).\n";
306 auto convLength = size_t(
double(chainLength) /
double(nSteps));
309 std::vector<std::vector<double>> reducedConvergedChain;
311 std::vector<double> bestParameters(
m_nParams);
312 std::vector<double> errorLeft(
m_nParams);
313 std::vector<double> errorRight(
m_nParams);
328 std::shared_ptr<MaleableCostFunction> leastSquaresMaleable =
330 leastSquaresMaleable->setDirtyInherited();
332 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(leastSquaresMaleable);
339 double mostPchi2 =
outputPDF(convLength, reducedConvergedChain);
381 double lower = bcon->lower();
382 double upper = bcon->upper();
386 while (newValue <
lower) {
387 if (std::abs(step) >
delta) {
396 while (newValue >
upper) {
397 if (std::abs(step) >
delta) {
417 if (j != parameterIndex) {
420 newValue = tie->
eval();
421 if (boost::math::isnan(newValue)) {
422 throw std::runtime_error(
"Parameter value is NaN.");
424 newParameters.
set(j, newValue);
432 newValue = tie->
eval();
433 if (boost::math::isnan(newValue)) {
434 throw std::runtime_error(
"Parameter value is NaN.");
436 newParameters.
set(parameterIndex, newValue);
442 std::shared_ptr<MaleableCostFunction> leastSquaresMaleable =
445 leastSquaresMaleable->setDirtyInherited();
448 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(leastSquaresMaleable);
463 m_chain[j].emplace_back(newParameters.
get(j));
477 double p = std::uniform_real_distribution<double>(0.0, 1.0)(rng);
480 m_chain[j].emplace_back(newParameters.
get(j));
497 std::shared_ptr<MaleableCostFunction> leastSquaresMaleable =
500 leastSquaresMaleable->setDirtyInherited();
503 m_leastSquares = std::dynamic_pointer_cast<CostFunctions::CostFuncLeastSquares>(leastSquaresMaleable);
513 const double jumpAR =
getProperty(
"JumpAcceptanceRate");
522 newJump =
m_jump[parameterIndex] / JUMP_CHECKING_RATE;
534 newJump =
m_jump[parameterIndex] * f / jumpAR;
542 m_jump[parameterIndex] = newJump;
546 if (std::abs(
m_jump[parameterIndex]) < LOW_JUMP_LIMIT) {
547 g_log.
warning() <<
"Wrong convergence might be reached for parameter " +
549 ". Try to set a proper initial value for this parameter\n";
558 size_t innactConvCriterion =
getProperty(
"InnactiveConvergenceCriterion");
562 bool ImmobilityConv =
false;
568 ImmobilityConv =
true;
580 g_log.
warning() <<
"Convergence detected through immobility."
581 " It might be a bad convergence.\n";
648 std::string failed =
"";
654 failed.replace(failed.end() - 2, failed.end(),
".");
656 " iterations.\n Try to set better initial values for parameters: " + failed +
657 " Or increase the maximum number of iterations "
658 "(MaxIterations property).");
676 size_t chainLength =
m_chain[0].size();
681 for (
size_t j = 0; j <
m_nParams + 1; ++j) {
682 auto &
X = wsC->mutableX(j);
683 auto &
Y = wsC->mutableY(j);
684 for (
size_t k = 0; k < chainLength; ++k) {
704 if (convLength > 0) {
707 g_log.
warning() <<
"Empty converged chain, empty Workspace returned.";
712 for (
size_t j = 0; j <
m_nParams + 1; ++j) {
714 std::vector<double>::const_iterator last =
m_chain[j].end();
715 std::vector<double> convChain(first, last);
716 auto &
X = wsConv->mutableX(j);
717 auto &
Y = wsConv->mutableY(j);
718 for (
size_t k = 0; k < convLength; ++k) {
720 Y[k] = convChain[nSteps * k];
737 wsChi2->addColumn(
"double",
"Chi2 Minimum");
738 wsChi2->addColumn(
"double",
"Most Probable Chi2");
739 wsChi2->addColumn(
"double",
"reduced Chi2 Minimum");
740 wsChi2->addColumn(
"double",
"Most Probable reduced Chi2");
744 size_t dataSize = domain->size();
748 double mostProbableChi2Red;
750 mostProbableChi2Red = mostProbableChi2 / (double(dataSize -
m_nParams));
752 g_log.
warning() <<
"Most probable chi square not calculated. -1 is returned.\n"
753 <<
"Most probable reduced chi square not calculated. -1 is "
755 mostProbableChi2Red = -1;
760 row <<
m_chi2 << mostProbableChi2 << minimumChi2Red << mostProbableChi2Red;
777 if (pdfLength <= 0) {
778 g_log.
warning() <<
"Non valid Number of bins for the PDF (<= 0)."
779 " Default value (20 bins) taken\n";
784 if (convLength > 0) {
786 std::vector<double> xValues((
m_nParams + 1) * (pdfLength + 1));
787 std::vector<double> yValues((
m_nParams + 1) * pdfLength);
788 std::vector<double> PDFYAxis(pdfLength, 0);
789 double const start = reducedChain[
m_nParams][0];
790 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>> &reducedChain, std::size_t
const &convLength,
808 int const &pdfLength) {
811 parameterNames.emplace_back(
"Chi Squared");
819 auto groupPDF = std::make_shared<WorkspaceGroup>();
826 std::vector<std::vector<double>> &reducedChain,
int const &pdfLength,
827 std::vector<double> &xValues, std::vector<double> &yValues,
828 std::vector<double> &PDFYAxis,
double const &start,
830 std::size_t step = 0;
831 std::size_t
const chiXStartPos =
m_nParams * (pdfLength + 1);
832 std::size_t
const chiYStartPos =
m_nParams * pdfLength;
834 xValues[chiXStartPos] = start;
835 for (std::size_t i = 1; i < static_cast<std::size_t>(pdfLength) + 1; i++) {
836 double binEnd = start + double(i) * bin;
837 xValues[chiXStartPos + i] = binEnd;
838 while (step < convLength && reducedChain[
m_nParams][step] <= binEnd) {
839 PDFYAxis[i - 1] += 1;
843 yValues[chiYStartPos + i - 1] = PDFYAxis[i - 1] / (double(convLength) * bin);
846 auto indexMostProbableChi2 = std::max_element(PDFYAxis.begin(), PDFYAxis.end());
848 return xValues[indexMostProbableChi2 - PDFYAxis.begin()] + (bin / 2.0);
852 std::vector<std::vector<double>> &reducedChain,
853 std::size_t
const &convLength,
int const &pdfLength) {
854 for (std::size_t j = 0; j <
m_nParams; ++j) {
857 std::vector<double> PDFYAxis(pdfLength, 0);
858 double start = reducedChain[j][0];
859 double bin = (reducedChain[j][convLength - 1] - start) /
double(pdfLength);
860 std::size_t step = 0;
861 std::size_t
const startXPos = j * (pdfLength + 1);
862 std::size_t
const startYPos = j * pdfLength;
864 xValues[startXPos] = start;
865 for (std::size_t i = 1; i < static_cast<std::size_t>(pdfLength) + 1; i++) {
866 double binEnd = start + double(i) * bin;
867 xValues[startXPos + i] = binEnd;
868 while (step < convLength && reducedChain[j][step] <= binEnd) {
869 PDFYAxis[i - 1] += 1;
872 yValues[startYPos + i - 1] = PDFYAxis[i - 1] / (double(convLength) * bin);
886 const std::vector<double> &errorLeft,
887 const std::vector<double> &errorRight) {
891 wsPdfE->addColumn(
"str",
"Name");
892 wsPdfE->addColumn(
"double",
"Value");
893 wsPdfE->addColumn(
"double",
"Left's error");
894 wsPdfE->addColumn(
"double",
"Right's error");
898 row <<
m_fitFunction->parameterName(j) << bestParameters[j] << errorLeft[j] << errorRight[j];
918 std::vector<std::vector<double>> &reducedChain,
919 std::vector<double> &bestParameters,
920 std::vector<double> &errorLeft,
921 std::vector<double> &errorRight) {
924 if (convLength > 0) {
926 for (
size_t e = 0; e <=
m_nParams; ++e) {
927 std::vector<double> v;
929 reducedChain.emplace_back(std::move(v));
933 for (
size_t k = 1; k < convLength; ++k) {
938 auto positionMinChi2 = std::min_element(reducedChain[
m_nParams].begin(), reducedChain[
m_nParams].end());
939 m_chi2 = *positionMinChi2;
944 for (
size_t k = 1; k < convLength; ++k) {
948 bestParameters[j] = reducedChain[j][positionMinChi2 - reducedChain[
m_nParams].begin()];
949 std::sort(reducedChain[j].begin(), reducedChain[j].end());
950 auto posBestPar = std::find(reducedChain[j].begin(), reducedChain[j].end(), bestParameters[j]);
951 double varLeft = 0, varRight = 0;
952 for (
auto k = reducedChain[j].begin(); k < reducedChain[j].end(); k += 2) {
954 varLeft += (*k - bestParameters[j]) * (*k - bestParameters[j]);
955 else if (k > posBestPar)
956 varRight += (*k - bestParameters[j]) * (*k - bestParameters[j]);
958 if (posBestPar != reducedChain[j].begin())
959 varLeft /=
double(posBestPar - reducedChain[j].begin());
960 if (posBestPar != reducedChain[j].end() - 1)
961 varRight /=
double(reducedChain[j].end() - posBestPar - 1);
963 errorLeft[j] = -sqrt(varLeft);
964 errorRight[j] = sqrt(varRight);
971 " Thus the parameters' errors are not"
974 bestParameters[k] = *(
m_chain[k].end() - 1);
986 throw std::invalid_argument(
"Function has 0 fitting parameters.");
1006 if (bcon->hasLower()) {
1007 if (param < bcon->
lower())
1010 if (bcon->hasUpper()) {
1011 if (param > bcon->upper())
1018 m_chain.emplace_back(std::vector<double>(1, param));
1020 m_jump.emplace_back(param != 0.0 ? std::abs(param / 10) : 0.01);
1044 g_log.
warning() <<
"MaximumTemperature not a valid temperature"
1045 " (T = 0). Default (T = 10.0) taken.\n";
1049 g_log.
warning() <<
"MaximumTemperature not a temperature"
1050 " (< 0), absolute value taken\n";
1057 " exploration (0 < T < 1), product inverse taken ("
1062 g_log.
warning() <<
"Overexploration wrong temperature. Not"
1063 " overexploring. Applying usual Simulated Annealing.\n";
1070 g_log.
warning() <<
"Wrong value for the number of refrigeration"
1071 " points (== 0). Therefore, default value (5 points) taken.\n";
1084 g_log.
warning() <<
"SimAnnealingIterations/NumRefrigerationSteps too small"
1085 " (< 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.
virtual 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...
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 setParameterXAndYValuesForPDF(std::vector< double > &xValues, std::vector< double > &yValues, std::vector< std::vector< double > > &reducedChain, std::size_t const &convLength, int const &pdfLength)
Computes the X and Y for the Parameter PDF's.
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.
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.
double getMostProbableChiSquared(std::size_t const &convLength, std::vector< std::vector< double > > &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 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.
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.
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.