Mantid
Loading...
Searching...
No Matches
FitPeaks.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
11#include "MantidAPI/Axis.h"
19#include "MantidAPI/TableRow.h"
27#include "MantidHistogramData/EstimatePolynomial.h"
28#include "MantidHistogramData/Histogram.h"
29#include "MantidHistogramData/HistogramBuilder.h"
30#include "MantidHistogramData/HistogramIterator.h"
36
37#include "boost/algorithm/string.hpp"
38#include "boost/algorithm/string/trim.hpp"
39#include <limits>
40#include <utility>
41
42using namespace Mantid;
43using namespace Algorithms::PeakParameterHelper;
44using namespace Mantid::API;
45using namespace Mantid::DataObjects;
46using namespace Mantid::HistogramData;
47using namespace Mantid::Kernel;
48using namespace Mantid::Geometry;
49using Mantid::HistogramData::Histogram;
50using namespace std;
51
52namespace Mantid::Algorithms {
53
54namespace {
55namespace PropertyNames {
56const std::string INPUT_WKSP("InputWorkspace");
57const std::string OUTPUT_WKSP("OutputWorkspace");
58const std::string START_WKSP_INDEX("StartWorkspaceIndex");
59const std::string STOP_WKSP_INDEX("StopWorkspaceIndex");
60const std::string PEAK_CENTERS("PeakCenters");
61const std::string PEAK_CENTERS_WKSP("PeakCentersWorkspace");
62const std::string PEAK_FUNC("PeakFunction");
63const std::string BACK_FUNC("BackgroundType");
64const std::string FIT_WINDOW_LIST("FitWindowBoundaryList");
65const std::string FIT_WINDOW_WKSP("FitPeakWindowWorkspace");
66const std::string PEAK_WIDTH_PERCENT("PeakWidthPercent");
67const std::string PEAK_PARAM_NAMES("PeakParameterNames");
68const std::string PEAK_PARAM_VALUES("PeakParameterValues");
69const std::string PEAK_PARAM_TABLE("PeakParameterValueTable");
70const std::string FIT_FROM_RIGHT("FitFromRight");
71const std::string MINIMIZER("Minimizer");
72const std::string COST_FUNC("CostFunction");
73const std::string MAX_FIT_ITER("MaxFitIterations");
74const std::string BACKGROUND_Z_SCORE("FindBackgroundSigma");
75const std::string HIGH_BACKGROUND("HighBackground");
76const std::string POSITION_TOL("PositionTolerance");
77const std::string PEAK_MIN_HEIGHT("MinimumPeakHeight");
78const std::string CONSTRAIN_PEAK_POS("ConstrainPeakPositions");
79const std::string OUTPUT_WKSP_MODEL("FittedPeaksWorkspace");
80const std::string OUTPUT_WKSP_PARAMS("OutputPeakParametersWorkspace");
81const std::string OUTPUT_WKSP_PARAM_ERRS("OutputParameterFitErrorsWorkspace");
82const std::string RAW_PARAMS("RawPeakParameters");
83
84} // namespace PropertyNames
85} // namespace
86
87namespace FitPeaksAlgorithm {
88
89//----------------------------------------------------------------------------------------------
91PeakFitResult::PeakFitResult(size_t num_peaks, size_t num_params) : m_function_parameters_number(num_params) {
92 // check input
93 if (num_peaks == 0 || num_params == 0)
94 throw std::runtime_error("No peak or no parameter error.");
95
96 //
97 m_fitted_peak_positions.resize(num_peaks, std::numeric_limits<double>::quiet_NaN());
98 m_costs.resize(num_peaks, DBL_MAX);
99 m_function_parameters_vector.resize(num_peaks);
100 m_function_errors_vector.resize(num_peaks);
101 for (size_t ipeak = 0; ipeak < num_peaks; ++ipeak) {
102 m_function_parameters_vector[ipeak].resize(num_params, std::numeric_limits<double>::quiet_NaN());
103 m_function_errors_vector[ipeak].resize(num_params, std::numeric_limits<double>::quiet_NaN());
104 }
105
106 return;
107}
108
109//----------------------------------------------------------------------------------------------
111
113
114//----------------------------------------------------------------------------------------------
121double PeakFitResult::getParameterError(size_t ipeak, size_t iparam) const {
122 return m_function_errors_vector[ipeak][iparam];
123}
124
125//----------------------------------------------------------------------------------------------
132double PeakFitResult::getParameterValue(size_t ipeak, size_t iparam) const {
133 return m_function_parameters_vector[ipeak][iparam];
134}
135
136//----------------------------------------------------------------------------------------------
137double PeakFitResult::getPeakPosition(size_t ipeak) const { return m_fitted_peak_positions[ipeak]; }
138
139//----------------------------------------------------------------------------------------------
140double PeakFitResult::getCost(size_t ipeak) const { return m_costs[ipeak]; }
141
142//----------------------------------------------------------------------------------------------
144void PeakFitResult::setRecord(size_t ipeak, const double cost, const double peak_position,
145 const FitFunction &fit_functions) {
146 // check input
147 if (ipeak >= m_costs.size())
148 throw std::runtime_error("Peak index is out of range.");
149
150 // set the values
151 m_costs[ipeak] = cost;
152
153 // set peak position
154 m_fitted_peak_positions[ipeak] = peak_position;
155
156 // transfer from peak function to vector
157 size_t peak_num_params = fit_functions.peakfunction->nParams();
158 for (size_t ipar = 0; ipar < peak_num_params; ++ipar) {
159 // peak function
160 m_function_parameters_vector[ipeak][ipar] = fit_functions.peakfunction->getParameter(ipar);
161 m_function_errors_vector[ipeak][ipar] = fit_functions.peakfunction->getError(ipar);
162 }
163 for (size_t ipar = 0; ipar < fit_functions.bkgdfunction->nParams(); ++ipar) {
164 // background function
165 m_function_parameters_vector[ipeak][ipar + peak_num_params] = fit_functions.bkgdfunction->getParameter(ipar);
166 m_function_errors_vector[ipeak][ipar + peak_num_params] = fit_functions.bkgdfunction->getError(ipar);
167 }
168}
169
170//----------------------------------------------------------------------------------------------
175void PeakFitResult::setBadRecord(size_t ipeak, const double peak_position) {
176 // check input
177 if (ipeak >= m_costs.size())
178 throw std::runtime_error("Peak index is out of range");
179 if (peak_position >= 0.)
180 throw std::runtime_error("Can only set negative postion for bad record");
181
182 // set the values
183 m_costs[ipeak] = DBL_MAX;
184
185 // set peak position
186 m_fitted_peak_positions[ipeak] = peak_position;
187
188 // transfer from peak function to vector
189 for (size_t ipar = 0; ipar < m_function_parameters_number; ++ipar) {
190 m_function_parameters_vector[ipeak][ipar] = 0.;
191 m_function_errors_vector[ipeak][ipar] = std::numeric_limits<double>::quiet_NaN();
192 }
193}
194} // namespace FitPeaksAlgorithm
195
196//----------------------------------------------------------------------------------------------
198 : m_fitPeaksFromRight(true), m_fitIterations(50), m_numPeaksToFit(0), m_minPeakHeight(20.), m_bkgdSimga(1.),
199 m_peakPosTolCase234(false) {}
200
201//----------------------------------------------------------------------------------------------
205 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropertyNames::INPUT_WKSP, "", Direction::Input),
206 "Name of the input workspace for peak fitting.");
208 std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropertyNames::OUTPUT_WKSP, "", Direction::Output),
209 "Name of the output workspace containing peak centers for "
210 "fitting offset."
211 "The output workspace is point data."
212 "Each workspace index corresponds to a spectrum. "
213 "Each X value ranges from 0 to N-1, where N is the number of "
214 "peaks to fit. "
215 "Each Y value is the peak position obtained by peak fitting. "
216 "Negative value is used for error signals. "
217 "-1 for data is zero; -2 for maximum value is smaller than "
218 "specified minimum value."
219 "and -3 for non-converged fitting.");
220
221 // properties about fitting range and criteria
222 declareProperty(PropertyNames::START_WKSP_INDEX, EMPTY_INT(), "Starting workspace index for fit");
223 declareProperty(PropertyNames::STOP_WKSP_INDEX, EMPTY_INT(),
224 "Last workspace index to fit (which is included). "
225 "If a value larger than the workspace index of last spectrum, "
226 "then the workspace index of last spectrum is used.");
227
228 // properties about peak positions to fit
229 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::PEAK_CENTERS),
230 "List of peak centers to fit against.");
231 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropertyNames::PEAK_CENTERS_WKSP, "",
233 "MatrixWorkspace containing peak centers");
234
235 const std::string peakcentergrp("Peak Positions");
236 setPropertyGroup(PropertyNames::PEAK_CENTERS, peakcentergrp);
237 setPropertyGroup(PropertyNames::PEAK_CENTERS_WKSP, peakcentergrp);
238
239 // properties about peak profile
240 const std::vector<std::string> peakNames = FunctionFactory::Instance().getFunctionNames<API::IPeakFunction>();
241 declareProperty(PropertyNames::PEAK_FUNC, "Gaussian", std::make_shared<StringListValidator>(peakNames),
242 "Use of a BackToBackExponential profile is only reccomended if the "
243 "coeficients to calculate A and B are defined in the instrument "
244 "Parameters.xml file.");
245 const vector<string> bkgdtypes{"Flat", "Linear", "Quadratic"};
246 declareProperty(PropertyNames::BACK_FUNC, "Linear", std::make_shared<StringListValidator>(bkgdtypes),
247 "Type of Background.");
248
249 const std::string funcgroup("Function Types");
250 setPropertyGroup(PropertyNames::PEAK_FUNC, funcgroup);
251 setPropertyGroup(PropertyNames::BACK_FUNC, funcgroup);
252
253 // properties about peak range including fitting window and peak width
254 // (percentage)
255 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::FIT_WINDOW_LIST),
256 "List of left boundaries of the peak fitting window corresponding to "
257 "PeakCenters.");
258
259 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropertyNames::FIT_WINDOW_WKSP, "",
261 "MatrixWorkspace for of peak windows");
262
263 auto min = std::make_shared<BoundedValidator<double>>();
264 min->setLower(1e-3);
265 // min->setUpper(1.); TODO make this a limit
266 declareProperty(PropertyNames::PEAK_WIDTH_PERCENT, EMPTY_DBL(), min,
267 "The estimated peak width as a "
268 "percentage of the d-spacing "
269 "of the center of the peak. Value must be less than 1.");
270
271 const std::string fitrangeegrp("Peak Range Setup");
272 setPropertyGroup(PropertyNames::PEAK_WIDTH_PERCENT, fitrangeegrp);
273 setPropertyGroup(PropertyNames::FIT_WINDOW_LIST, fitrangeegrp);
274 setPropertyGroup(PropertyNames::FIT_WINDOW_WKSP, fitrangeegrp);
275
276 // properties about peak parameters' names and value
277 declareProperty(std::make_unique<ArrayProperty<std::string>>(PropertyNames::PEAK_PARAM_NAMES),
278 "List of peak parameters' names");
279 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::PEAK_PARAM_VALUES),
280 "List of peak parameters' value");
281 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>(PropertyNames::PEAK_PARAM_TABLE, "",
283 "Name of the an optional workspace, whose each column "
284 "corresponds to given peak parameter names"
285 ", and each row corresponds to a subset of spectra.");
286
287 const std::string startvaluegrp("Starting Parameters Setup");
288 setPropertyGroup(PropertyNames::PEAK_PARAM_NAMES, startvaluegrp);
289 setPropertyGroup(PropertyNames::PEAK_PARAM_VALUES, startvaluegrp);
290 setPropertyGroup(PropertyNames::PEAK_PARAM_TABLE, startvaluegrp);
291
292 // optimization setup
293 declareProperty(PropertyNames::FIT_FROM_RIGHT, true,
294 "Flag for the order to fit peaks. If true, peaks are fitted "
295 "from rightmost;"
296 "Otherwise peaks are fitted from leftmost.");
297
298 const std::vector<std::string> minimizerOptions = API::FuncMinimizerFactory::Instance().getKeys();
299 declareProperty(PropertyNames::MINIMIZER, "Levenberg-Marquardt",
301 "Minimizer to use for fitting.");
302
303 const std::array<string, 2> costFuncOptions = {{"Least squares", "Rwp"}};
304 declareProperty(PropertyNames::COST_FUNC, "Least squares",
305 Kernel::IValidator_sptr(new Kernel::ListValidator<std::string>(costFuncOptions)), "Cost functions");
306
307 auto min_max_iter = std::make_shared<BoundedValidator<int>>();
308 min_max_iter->setLower(49);
309 declareProperty(PropertyNames::MAX_FIT_ITER, 50, min_max_iter, "Maximum number of function fitting iterations.");
310
311 const std::string optimizergrp("Optimization Setup");
312 setPropertyGroup(PropertyNames::MINIMIZER, optimizergrp);
313 setPropertyGroup(PropertyNames::COST_FUNC, optimizergrp);
314
315 // other helping information
316 declareProperty(PropertyNames::BACKGROUND_Z_SCORE, 1.0,
317 "Multiplier of standard deviations of the variance for convergence of "
318 "peak elimination. Default is 1.0. ");
319
320 declareProperty(PropertyNames::HIGH_BACKGROUND, true,
321 "Flag whether the data has high background comparing to "
322 "peaks' intensities. "
323 "For example, vanadium peaks usually have high background.");
324
325 declareProperty(std::make_unique<ArrayProperty<double>>(PropertyNames::POSITION_TOL),
326 "List of tolerance on fitted peak positions against given peak positions."
327 "If there is only one value given, then ");
328
329 declareProperty(PropertyNames::PEAK_MIN_HEIGHT, 0.,
330 "Minimum peak height such that all the fitted peaks with "
331 "height under this value will be excluded.");
332
333 declareProperty(PropertyNames::CONSTRAIN_PEAK_POS, true,
334 "If true peak position will be constrained by estimated positions "
335 "(highest Y value position) and "
336 "the peak width either estimted by observation or calculate.");
337
338 // additional output for reviewing
339 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>(PropertyNames::OUTPUT_WKSP_MODEL, "",
341 "Name of the output matrix workspace with fitted peak. "
342 "This output workspace have the same dimesion as the input workspace."
343 "The Y values belonged to peaks to fit are replaced by fitted value. "
344 "Values of estimated background are used if peak fails to be fit.");
345
346 declareProperty(std::make_unique<WorkspaceProperty<API::ITableWorkspace>>(PropertyNames::OUTPUT_WKSP_PARAMS, "",
348 "Name of table workspace containing all fitted peak parameters.");
349
350 // Optional output table workspace for each individual parameter's fitting
351 // error
352 declareProperty(std::make_unique<WorkspaceProperty<API::ITableWorkspace>>(PropertyNames::OUTPUT_WKSP_PARAM_ERRS, "",
354 "Name of workspace containing all fitted peak parameters' fitting error."
355 "It must be used along with FittedPeaksWorkspace and RawPeakParameters "
356 "(True)");
357
358 declareProperty(PropertyNames::RAW_PARAMS, true,
359 "false generates table with effective centre/width/height "
360 "parameters. true generates a table with peak function "
361 "parameters");
362
363 const std::string addoutgrp("Analysis");
364 setPropertyGroup(PropertyNames::OUTPUT_WKSP_PARAMS, addoutgrp);
365 setPropertyGroup(PropertyNames::OUTPUT_WKSP_MODEL, addoutgrp);
366 setPropertyGroup(PropertyNames::OUTPUT_WKSP_PARAM_ERRS, addoutgrp);
367 setPropertyGroup(PropertyNames::RAW_PARAMS, addoutgrp);
368}
369
370//----------------------------------------------------------------------------------------------
373std::map<std::string, std::string> FitPeaks::validateInputs() {
374 map<std::string, std::string> issues;
375
376 // check that the peak parameters are in parallel properties
377 bool haveCommonPeakParameters(false);
378 std::vector<string> suppliedParameterNames = getProperty(PropertyNames::PEAK_PARAM_NAMES);
379 std::vector<double> peakParamValues = getProperty(PropertyNames::PEAK_PARAM_VALUES);
380 if ((!suppliedParameterNames.empty()) || (!peakParamValues.empty())) {
381 haveCommonPeakParameters = true;
382 if (suppliedParameterNames.size() != peakParamValues.size()) {
383 issues[PropertyNames::PEAK_PARAM_NAMES] = "must have same number of values as PeakParameterValues";
384 issues[PropertyNames::PEAK_PARAM_VALUES] = "must have same number of values as PeakParameterNames";
385 }
386 }
387
388 // get the information out of the table
389 std::string partablename = getPropertyValue(PropertyNames::PEAK_PARAM_TABLE);
390 if (!partablename.empty()) {
391 if (haveCommonPeakParameters) {
392 const std::string msg = "Parameter value table and initial parameter "
393 "name/value vectors cannot be given "
394 "simultanenously.";
395 issues[PropertyNames::PEAK_PARAM_TABLE] = msg;
396 issues[PropertyNames::PEAK_PARAM_NAMES] = msg;
397 issues[PropertyNames::PEAK_PARAM_VALUES] = msg;
398 } else {
399 m_profileStartingValueTable = getProperty(PropertyNames::PEAK_PARAM_TABLE);
400 suppliedParameterNames = m_profileStartingValueTable->getColumnNames();
401 }
402 }
403
404 // check that the suggested peak parameter names exist in the peak function
405 if (!suppliedParameterNames.empty()) {
406 std::string peakfunctiontype = getPropertyValue(PropertyNames::PEAK_FUNC);
408 std::dynamic_pointer_cast<IPeakFunction>(API::FunctionFactory::Instance().createFunction(peakfunctiontype));
409
410 // put the names in a vector
411 std::vector<string> functionParameterNames;
412 for (size_t i = 0; i < m_peakFunction->nParams(); ++i)
413 functionParameterNames.emplace_back(m_peakFunction->parameterName(i));
414 // check that the supplied names are in the function
415 // it is acceptable to be missing parameters
416 bool failed = false;
417 for (const auto &name : suppliedParameterNames) {
418 if (std::find(functionParameterNames.begin(), functionParameterNames.end(), name) ==
419 functionParameterNames.end()) {
420 failed = true;
421 break;
422 }
423 }
424 if (failed) {
425 std::string msg = "Specified invalid parameter for peak function";
426 if (haveCommonPeakParameters)
427 issues[PropertyNames::PEAK_PARAM_NAMES] = msg;
428 else
429 issues[PropertyNames::PEAK_PARAM_TABLE] = msg;
430 }
431 }
432
433 // check inputs for uncertainty (fitting error)
434 const std::string error_table_name = getPropertyValue(PropertyNames::OUTPUT_WKSP_PARAM_ERRS);
435 if (!error_table_name.empty()) {
436 const bool use_raw_params = getProperty(PropertyNames::RAW_PARAMS);
437 if (!use_raw_params) {
438 issues[PropertyNames::OUTPUT_WKSP_PARAM_ERRS] = "Cannot be used with " + PropertyNames::RAW_PARAMS + "=False";
439 issues[PropertyNames::RAW_PARAMS] =
440 "Cannot be False with " + PropertyNames::OUTPUT_WKSP_PARAM_ERRS + " specified";
441 }
442 }
443
444 return issues;
445}
446
447//----------------------------------------------------------------------------------------------
449 // process inputs
451
452 // create output workspace: fitted peak positions
454
455 // create output workspace: fitted peaks' parameters values
457
458 // create output workspace: calculated from fitted peak and background
460
461 // fit peaks
462 auto fit_results = fitPeaks();
463
464 // set the output workspaces to properites
465 processOutputs(fit_results);
466}
467
468//----------------------------------------------------------------------------------------------
470 // input workspaces
471 m_inputMatrixWS = getProperty(PropertyNames::INPUT_WKSP);
472
473 if (m_inputMatrixWS->getAxis(0)->unit()->unitID() == "dSpacing")
474 m_inputIsDSpace = true;
475 else
476 m_inputIsDSpace = false;
477
478 // spectra to fit
479 int start_wi = getProperty(PropertyNames::START_WKSP_INDEX);
480 if (isEmpty(start_wi))
482 else
483 m_startWorkspaceIndex = static_cast<size_t>(start_wi);
484
485 // last spectrum's workspace index, which is included
486 int stop_wi = getProperty(PropertyNames::STOP_WKSP_INDEX);
487 if (isEmpty(stop_wi))
488 m_stopWorkspaceIndex = m_inputMatrixWS->getNumberHistograms() - 1;
489 else {
490 m_stopWorkspaceIndex = static_cast<size_t>(stop_wi);
491 if (m_stopWorkspaceIndex > m_inputMatrixWS->getNumberHistograms() - 1)
492 m_stopWorkspaceIndex = m_inputMatrixWS->getNumberHistograms() - 1;
493 }
494
495 // optimizer, cost function and fitting scheme
496 m_minimizer = getPropertyValue(PropertyNames::MINIMIZER);
497 m_costFunction = getPropertyValue(PropertyNames::COST_FUNC);
498 m_fitPeaksFromRight = getProperty(PropertyNames::FIT_FROM_RIGHT);
499 m_constrainPeaksPosition = getProperty(PropertyNames::CONSTRAIN_PEAK_POS);
500 m_fitIterations = getProperty(PropertyNames::MAX_FIT_ITER);
501
502 // Peak centers, tolerance and fitting range
504 // check
505 if (m_numPeaksToFit == 0)
506 throw std::runtime_error("number of peaks to fit is zero.");
507 // about how to estimate the peak width
508 m_peakWidthPercentage = getProperty(PropertyNames::PEAK_WIDTH_PERCENT);
511 if (m_peakWidthPercentage >= 1.) // TODO
512 throw std::runtime_error("PeakWidthPercent must be less than 1");
513 g_log.debug() << "peak width/value = " << m_peakWidthPercentage << "\n";
514
515 // set up background
516 m_highBackground = getProperty(PropertyNames::HIGH_BACKGROUND);
517 m_bkgdSimga = getProperty(PropertyNames::BACKGROUND_Z_SCORE);
518
519 // Set up peak and background functions
521
522 // about peak width and other peak parameter estimating method
523 if (m_peakWidthPercentage > 0.)
524 m_peakWidthEstimateApproach = EstimatePeakWidth::InstrumentResolution;
525 else if (isObservablePeakProfile((m_peakFunction->name())))
526 m_peakWidthEstimateApproach = EstimatePeakWidth::Observation;
527 else
528 m_peakWidthEstimateApproach = EstimatePeakWidth::NoEstimation;
529 // m_peakWidthEstimateApproach = EstimatePeakWidth::NoEstimation;
530 g_log.debug() << "Process inputs [3] peak type: " << m_peakFunction->name()
531 << ", background type: " << m_bkgdFunction->name() << "\n";
532
535
536 return;
537}
538
539//----------------------------------------------------------------------------------------------
543 // peak functions
544 std::string peakfunctiontype = getPropertyValue(PropertyNames::PEAK_FUNC);
546 std::dynamic_pointer_cast<IPeakFunction>(API::FunctionFactory::Instance().createFunction(peakfunctiontype));
547
548 // background functions
549 std::string bkgdfunctiontype = getPropertyValue(PropertyNames::BACK_FUNC);
550 std::string bkgdname;
551 if (bkgdfunctiontype == "Linear")
552 bkgdname = "LinearBackground";
553 else if (bkgdfunctiontype == "Flat") {
554 g_log.warning("There may be problems with Flat background");
555 bkgdname = "FlatBackground";
556 } else
557 bkgdname = bkgdfunctiontype;
559 std::dynamic_pointer_cast<IBackgroundFunction>(API::FunctionFactory::Instance().createFunction(bkgdname));
561 m_linearBackgroundFunction = std::dynamic_pointer_cast<IBackgroundFunction>(
562 API::FunctionFactory::Instance().createFunction("LinearBackground"));
563 else
565
566 // TODO check that both parameter names and values exist
567 // input peak parameters
568 std::string partablename = getPropertyValue(PropertyNames::PEAK_PARAM_TABLE);
569 m_peakParamNames = getProperty(PropertyNames::PEAK_PARAM_NAMES);
570
572 if (partablename.empty() && (!m_peakParamNames.empty())) {
573 // use uniform starting value of peak parameters
574 m_initParamValues = getProperty(PropertyNames::PEAK_PARAM_VALUES);
575 // convert the parameter name in string to parameter name in integer index
577 // m_uniformProfileStartingValue = true;
578 } else if ((!partablename.empty()) && m_peakParamNames.empty()) {
579 // use non-uniform starting value of peak parameters
581 } else if (peakfunctiontype != "Gaussian") {
582 // user specifies nothing
583 g_log.warning("Neither parameter value table nor initial "
584 "parameter name/value vectors is specified. Fitting might "
585 "not be reliable for peak profile other than Gaussian");
586 }
587
588 return;
589}
590
591//----------------------------------------------------------------------------------------------
596 // get peak fit window
597 std::vector<double> peakwindow = getProperty(PropertyNames::FIT_WINDOW_LIST);
598 std::string peakwindowname = getPropertyValue(PropertyNames::FIT_WINDOW_WKSP);
599 API::MatrixWorkspace_const_sptr peakwindowws = getProperty(PropertyNames::FIT_WINDOW_WKSP);
600
601 // in most case, calculate window by instrument resolution is False
603
604 if ((!peakwindow.empty()) && peakwindowname.empty()) {
605 // Peak windows are uniform among spectra: use vector for peak windows
607
608 // check peak positions
610 throw std::invalid_argument("Uniform peak range/window requires uniform peak positions.");
611 // check size
612 if (peakwindow.size() != m_numPeaksToFit * 2)
613 throw std::invalid_argument("Peak window vector must be twice as large as number of peaks.");
614
615 // set up window to m_peakWindowVector
617 for (size_t i = 0; i < m_numPeaksToFit; ++i) {
618 std::vector<double> peakranges(2);
619 peakranges[0] = peakwindow[i * 2];
620 peakranges[1] = peakwindow[i * 2 + 1];
621 // check peak window (range) against peak centers
622 if ((peakranges[0] < m_peakCenters[i]) && (m_peakCenters[i] < peakranges[1])) {
623 // pass check: set
624 m_peakWindowVector[i] = peakranges;
625 } else {
626 // failed
627 std::stringstream errss;
628 errss << "Peak " << i << ": user specifies an invalid range and peak center against " << peakranges[0] << " < "
629 << m_peakCenters[i] << " < " << peakranges[1];
630 throw std::invalid_argument(errss.str());
631 }
632 } // END-FOR
633 // END for uniform peak window
634 } else if (peakwindow.empty() && peakwindowws != nullptr) {
635 // use matrix workspace for non-uniform peak windows
636 m_peakWindowWorkspace = getProperty(PropertyNames::FIT_WINDOW_WKSP);
637 m_uniformPeakWindows = false;
638
639 // check size
640 if (m_peakWindowWorkspace->getNumberHistograms() == m_inputMatrixWS->getNumberHistograms())
642 else if (m_peakWindowWorkspace->getNumberHistograms() == (m_stopWorkspaceIndex - m_startWorkspaceIndex + 1))
644 else
645 throw std::invalid_argument("Peak window workspace has unmatched number of spectra");
646
647 // check range for peak windows and peak positions
648 size_t window_index_start(0);
650 window_index_start = m_startWorkspaceIndex;
651 size_t center_index_start(0);
653 center_index_start = m_startWorkspaceIndex;
654
655 // check each spectrum whether the window is defined with the correct size
656 for (size_t wi = 0; wi < m_peakWindowWorkspace->getNumberHistograms(); ++wi) {
657 // check size
658 if (m_peakWindowWorkspace->y(wi).size() != m_numPeaksToFit * 2) {
659 std::stringstream errss;
660 errss << "Peak window workspace index " << wi << " has incompatible number of fit windows (x2) "
661 << m_peakWindowWorkspace->y(wi).size() << " with the number of peaks " << m_numPeaksToFit << " to fit.";
662 throw std::invalid_argument(errss.str());
663 }
664 const auto &peakWindowX = m_peakWindowWorkspace->x(wi);
665
666 // check window range against peak center
667 size_t window_index = window_index_start + wi;
668 size_t center_index = window_index - center_index_start;
669 const auto &peakCenterX = m_peakCenterWorkspace->x(center_index);
670
671 for (size_t ipeak = 0; ipeak < m_numPeaksToFit; ++ipeak) {
672 double left_w_bound = peakWindowX[ipeak * 2]; // TODO getting on y
673 double right_w_bound = peakWindowX[ipeak * 2 + 1];
674 double center = peakCenterX[ipeak];
675 if (!(left_w_bound < center && center < right_w_bound)) {
676 std::stringstream errss;
677 errss << "Workspace index " << wi << " has incompatible peak window (" // <<<<<<< HERE!!!!!!!!!
678 << left_w_bound << ", " << right_w_bound << ") with " << ipeak << "-th expected peak's center "
679 << center;
680 throw std::runtime_error(errss.str());
681 }
682 }
683 }
684 } else if (peakwindow.empty()) {
685 // no peak window is defined, then the peak window will be estimated by
686 // delta(D)/D
689 else
690 throw std::invalid_argument("Without definition of peak window, the "
691 "input workspace must be in unit of dSpacing "
692 "and Delta(D)/D must be given!");
693
694 } else {
695 // non-supported situation
696 throw std::invalid_argument("One and only one of peak window array and "
697 "peak window workspace can be specified.");
698 }
699
700 return;
701}
702
703//----------------------------------------------------------------------------------------------
713 // peak centers
714 m_peakCenters = getProperty(PropertyNames::PEAK_CENTERS);
715 API::MatrixWorkspace_const_sptr peakcenterws = getProperty(PropertyNames::PEAK_CENTERS_WKSP);
716 if (!peakcenterws)
717 g_log.notice("Peak centers are not specified by peak center workspace");
718
719 std::string peakpswsname = getPropertyValue(PropertyNames::PEAK_CENTERS_WKSP);
720 if ((!m_peakCenters.empty()) && peakcenterws == nullptr) {
721 // peak positions are uniform among all spectra
723 // number of peaks to fit!
725 } else if (m_peakCenters.empty() && peakcenterws != nullptr) {
726 // peak positions can be different among spectra
728 m_peakCenterWorkspace = getProperty(PropertyNames::PEAK_CENTERS_WKSP);
729 // number of peaks to fit!
731 g_log.debug() << "Input peak center workspace: " << m_peakCenterWorkspace->x(0).size() << ", "
732 << m_peakCenterWorkspace->y(0).size() << "\n";
733
734 // check matrix worksapce for peak positions
735 const size_t peak_center_ws_spectra_number = m_peakCenterWorkspace->getNumberHistograms();
736 if (peak_center_ws_spectra_number == m_inputMatrixWS->getNumberHistograms()) {
737 // full spectra
738 m_partialSpectra = false;
739 } else if (peak_center_ws_spectra_number == m_stopWorkspaceIndex - m_startWorkspaceIndex + 1) {
740 // partial spectra
741 m_partialSpectra = true;
742 } else {
743 // a case indicating programming error
744 g_log.error() << "Peak center workspace has " << peak_center_ws_spectra_number << " spectra;"
745 << "Input workspace has " << m_inputMatrixWS->getNumberHistograms() << " spectra;"
746 << "User specifies to fit peaks from " << m_startWorkspaceIndex << " to " << m_stopWorkspaceIndex
747 << ". They are mismatched to each other.\n";
748 throw std::invalid_argument("Input peak center workspace has mismatched "
749 "number of spectra to selected spectra to "
750 "fit.");
751 }
752
753 } else {
754 std::stringstream errss;
755 errss << "One and only one in 'PeakCenters' (vector) and "
756 "'PeakCentersWorkspace' shall be given. "
757 << "'PeakCenters' has size " << m_peakCenters.size() << ", and name of peak center workspace "
758 << "is " << peakpswsname;
759 throw std::invalid_argument(errss.str());
760 }
761
762 return;
763}
764
765//----------------------------------------------------------------------------------------------
772 // check code integrity
773 if (m_numPeaksToFit == 0)
774 throw std::runtime_error("ProcessInputPeakTolerance() must be called after "
775 "ProcessInputPeakCenters()");
776
777 // peak tolerance
778 m_peakPosTolerances = getProperty(PropertyNames::POSITION_TOL);
779
780 if (m_peakPosTolerances.empty()) {
781 // case 2, 3, 4
782 m_peakPosTolerances.clear();
783 m_peakPosTolCase234 = true;
784 } else if (m_peakPosTolerances.size() == 1) {
785 // only 1 uniform peak position tolerance is defined: expand to all peaks
786 double peak_tol = m_peakPosTolerances[0];
787 m_peakPosTolerances.resize(m_numPeaksToFit, peak_tol);
788 } else if (m_peakPosTolerances.size() != m_numPeaksToFit) {
789 // not uniform but number of peaks does not match
790 g_log.error() << "number of peak position tolerance " << m_peakPosTolerances.size()
791 << " is not same as number of peaks " << m_numPeaksToFit << "\n";
792 throw std::runtime_error("Number of peak position tolerances and number of "
793 "peaks to fit are inconsistent.");
794 }
795
796 // minimum peak height: set default to zero
797 m_minPeakHeight = getProperty(PropertyNames::PEAK_MIN_HEIGHT);
799 m_minPeakHeight = 0.;
800
801 return;
802}
803
804//----------------------------------------------------------------------------------------------
811 // get a map for peak profile parameter name and parameter index
812 std::map<std::string, size_t> parname_index_map;
813 for (size_t iparam = 0; iparam < m_peakFunction->nParams(); ++iparam)
814 parname_index_map.insert(std::make_pair(m_peakFunction->parameterName(iparam), iparam));
815
816 // define peak parameter names (class variable) if using table
819
820 // map the input parameter names to parameter indexes
821 for (const auto &paramName : m_peakParamNames) {
822 auto locator = parname_index_map.find(paramName);
823 if (locator != parname_index_map.end()) {
824 m_initParamIndexes.emplace_back(locator->second);
825 } else {
826 // a parameter name that is not defined in the peak profile function. An
827 // out-of-range index is thus set to this
828 g_log.warning() << "Given peak parameter " << paramName
829 << " is not an allowed parameter of peak "
830 "function "
831 << m_peakFunction->name() << "\n";
832 m_initParamIndexes.emplace_back(m_peakFunction->nParams() * 10);
833 }
834 }
835
836 return;
837}
838
839//----------------------------------------------------------------------------------------------
842std::vector<std::shared_ptr<FitPeaksAlgorithm::PeakFitResult>> FitPeaks::fitPeaks() {
844
847 size_t num_fit_result = m_stopWorkspaceIndex - m_startWorkspaceIndex + 1;
848 std::vector<std::shared_ptr<FitPeaksAlgorithm::PeakFitResult>> fit_result_vector(num_fit_result);
849
850 const int nThreads = FrameworkManager::Instance().getNumOMPThreads();
851 size_t chunkSize = num_fit_result / nThreads;
852
853 PRAGMA_OMP(parallel for schedule(dynamic, 1) )
854 for (int ithread = 0; ithread < nThreads; ithread++) {
856 auto iws_begin = m_startWorkspaceIndex + chunkSize * static_cast<size_t>(ithread);
857 auto iws_end = (ithread == nThreads - 1) ? m_stopWorkspaceIndex + 1 : iws_begin + chunkSize;
858
859 // vector to store fit params for last good fit to each peak
860 std::vector<std::vector<double>> lastGoodPeakParameters(m_numPeaksToFit,
861 std::vector<double>(m_peakFunction->nParams(), 0.0));
862
863 for (auto wi = iws_begin; wi < iws_end; ++wi) {
864 // peaks to fit
865 std::vector<double> expected_peak_centers = getExpectedPeakPositions(static_cast<size_t>(wi));
866
867 // initialize output for this
868 size_t numfuncparams = m_peakFunction->nParams() + m_bkgdFunction->nParams();
869 std::shared_ptr<FitPeaksAlgorithm::PeakFitResult> fit_result =
870 std::make_shared<FitPeaksAlgorithm::PeakFitResult>(m_numPeaksToFit, numfuncparams);
871
872 fitSpectrumPeaks(static_cast<size_t>(wi), expected_peak_centers, fit_result, lastGoodPeakParameters);
873
874 PARALLEL_CRITICAL(FindPeaks_WriteOutput) {
875 writeFitResult(static_cast<size_t>(wi), expected_peak_centers, fit_result);
876 fit_result_vector[wi - m_startWorkspaceIndex] = fit_result;
877 }
878 prog.report();
879 }
881 }
883
884 return fit_result_vector;
885}
886
887namespace {
889std::vector<std::string> supported_peak_profiles{"Gaussian", "Lorentzian", "PseudoVoigt", "Voigt",
890 "BackToBackExponential"};
891
892double numberCounts(const Histogram &histogram) {
893 double total = 0.;
894 for (const auto &value : histogram.y())
895 total += std::fabs(value);
896 return total;
897}
898
899//----------------------------------------------------------------------------------------------
906double numberCounts(const Histogram &histogram, const double xmin, const double xmax) {
907 const auto &vector_x = histogram.points();
908
909 // determine left boundary
910 auto start_iter = vector_x.begin();
911 if (xmin > vector_x.front())
912 start_iter = std::lower_bound(vector_x.begin(), vector_x.end(), xmin);
913 if (start_iter == vector_x.end())
914 return 0.; // past the end of the data means nothing to integrate
915 // determine right boundary
916 auto stop_iter = vector_x.end();
917 if (xmax < vector_x.back()) // will set at end of vector if too large
918 stop_iter = std::lower_bound(start_iter, stop_iter, xmax);
919
920 // convert to indexes to sum over y
921 size_t start_index = static_cast<size_t>(start_iter - vector_x.begin());
922 size_t stop_index = static_cast<size_t>(stop_iter - vector_x.begin());
923
924 // integrate
925 double total = 0.;
926 for (size_t i = start_index; i < stop_index; ++i)
927 total += std::fabs(histogram.y()[i]);
928 return total;
929}
930} // namespace
931
932//----------------------------------------------------------------------------------------------
935void FitPeaks::fitSpectrumPeaks(size_t wi, const std::vector<double> &expected_peak_centers,
936 const std::shared_ptr<FitPeaksAlgorithm::PeakFitResult> &fit_result,
937 std::vector<std::vector<double>> &lastGoodPeakParameters) {
938 // Spectrum contains very weak signal: do not proceed and return
939 if (numberCounts(m_inputMatrixWS->histogram(wi)) <= m_minPeakHeight) {
940 for (size_t i = 0; i < fit_result->getNumberPeaks(); ++i)
941 fit_result->setBadRecord(i, -1.);
942 return; // don't do anything
943 }
944
945 // Set up sub algorithm Fit for peak and background
946 IAlgorithm_sptr peak_fitter; // both peak and background (combo)
947 try {
948 peak_fitter = createChildAlgorithm("Fit", -1, -1, false);
949 } catch (Exception::NotFoundError &) {
950 std::stringstream errss;
951 errss << "The FitPeak algorithm requires the CurveFitting library";
952 g_log.error(errss.str());
953 throw std::runtime_error(errss.str());
954 }
955
956 // Clone background function
957 IBackgroundFunction_sptr bkgdfunction = std::dynamic_pointer_cast<API::IBackgroundFunction>(m_bkgdFunction->clone());
958
959 // set up properties of algorithm (reference) 'Fit'
960 peak_fitter->setProperty("Minimizer", m_minimizer);
961 peak_fitter->setProperty("CostFunction", m_costFunction);
962 peak_fitter->setProperty("CalcErrors", true);
963
964 const double x0 = m_inputMatrixWS->histogram(wi).x().front();
965 const double xf = m_inputMatrixWS->histogram(wi).x().back();
966
967 // index of previous peak in same spectrum (initially invalid)
968 size_t prev_peak_index = m_numPeaksToFit;
969 bool neighborPeakSameSpectrum = false;
970
971 for (size_t fit_index = 0; fit_index < m_numPeaksToFit; ++fit_index) {
972 // convert fit index to peak index (in ascending order)
973 size_t peak_index(fit_index);
975 peak_index = m_numPeaksToFit - fit_index - 1;
976
977 // reset the background function
978 for (size_t i = 0; i < bkgdfunction->nParams(); ++i)
979 bkgdfunction->setParameter(i, 0.);
980
981 double expected_peak_pos = expected_peak_centers[peak_index];
982
983 // clone peak function for each peak (need to do this so can
984 // set center and calc any parameters from xml)
985 auto peakfunction = std::dynamic_pointer_cast<API::IPeakFunction>(m_peakFunction->clone());
986 peakfunction->setCentre(expected_peak_pos);
987 peakfunction->setMatrixWorkspace(m_inputMatrixWS, wi, 0.0, 0.0);
988
989 std::map<size_t, double> keep_values;
990 for (size_t ipar = 0; ipar < peakfunction->nParams(); ++ipar) {
991 if (peakfunction->isFixed(ipar)) {
992 // save value of these parameters which have just been calculated
993 // if they were set to be fixed (e.g. for the B2Bexp this would
994 // typically be A and B but not Sigma)
995 keep_values[ipar] = peakfunction->getParameter(ipar);
996 // let them be free to fit as these are typically refined from a
997 // focussed bank
998 peakfunction->unfix(ipar);
999 }
1000 }
1001
1002 // Determine whether to set starting parameter from fitted value
1003 // of same peak but different spectrum
1004 bool samePeakCrossSpectrum = (lastGoodPeakParameters[peak_index].size() >
1005 static_cast<size_t>(std::count_if(lastGoodPeakParameters[peak_index].begin(),
1006 lastGoodPeakParameters[peak_index].end(),
1007 [&](auto const &val) { return val <= 1e-10; })));
1008
1009 // Check whether current spectrum's pixel (detector ID) is close to its
1010 // previous spectrum's pixel (detector ID).
1011 try {
1012 if (wi > 0 && samePeakCrossSpectrum) {
1013 // First spectrum or discontinuous detector ID: do not start from same
1014 // peak of last spectrum
1015 std::shared_ptr<const Geometry::Detector> pdetector =
1016 std::dynamic_pointer_cast<const Geometry::Detector>(m_inputMatrixWS->getDetector(wi - 1));
1017 std::shared_ptr<const Geometry::Detector> cdetector =
1018 std::dynamic_pointer_cast<const Geometry::Detector>(m_inputMatrixWS->getDetector(wi));
1019
1020 // If they do have detector ID
1021 if (pdetector && cdetector) {
1022 auto prev_id = pdetector->getID();
1023 auto curr_id = cdetector->getID();
1024 if (prev_id + 1 != curr_id)
1025 samePeakCrossSpectrum = false;
1026 } else {
1027 samePeakCrossSpectrum = false;
1028 }
1029
1030 } else {
1031 // first spectrum in the workspace: no peak's fitting result to copy
1032 // from
1033 samePeakCrossSpectrum = false;
1034 }
1035 } catch (const std::runtime_error &) {
1036 // workspace does not have detector ID set: there is no guarantee that the
1037 // adjacent spectra can have similar peak profiles
1038 samePeakCrossSpectrum = false;
1039 }
1040
1041 // Set starting values of the peak function
1042 if (samePeakCrossSpectrum) { // somePeakFit
1043 // Get from local best result
1044 for (size_t i = 0; i < peakfunction->nParams(); ++i) {
1045 peakfunction->setParameter(i, lastGoodPeakParameters[peak_index][i]);
1046 }
1047 } else if (neighborPeakSameSpectrum) {
1048 // set the peak parameters from last good fit to that peak
1049 for (size_t i = 0; i < peakfunction->nParams(); ++i) {
1050 peakfunction->setParameter(i, lastGoodPeakParameters[prev_peak_index][i]);
1051 }
1052 }
1053
1054 // reset center though - don't know before hand which element this is
1055 peakfunction->setCentre(expected_peak_pos);
1056 // reset value of parameters that were fixed (but are now free to vary)
1057 for (const auto &[ipar, value] : keep_values) {
1058 peakfunction->setParameter(ipar, value);
1059 }
1060
1061 double cost(DBL_MAX);
1062 if (expected_peak_pos <= x0 || expected_peak_pos >= xf) {
1063 // out of range and there won't be any fit
1064 peakfunction->setIntensity(0);
1065 } else {
1066 // find out the peak position to fit
1067 std::pair<double, double> peak_window_i = getPeakFitWindow(wi, peak_index);
1068
1069 // Decide whether to estimate peak width by observation
1070 // If no peaks fitted in the same or cross spectrum then the user supplied
1071 // parameters will be used if present and the width will not be estimated
1072 // (note this will overwrite parameter values caluclated from
1073 // Parameters.xml)
1074 auto useUserSpecifedIfGiven = !(samePeakCrossSpectrum || neighborPeakSameSpectrum);
1075 bool observe_peak_width = decideToEstimatePeakParams(useUserSpecifedIfGiven, peakfunction);
1076
1077 if (observe_peak_width && m_peakWidthEstimateApproach == EstimatePeakWidth::NoEstimation) {
1078 g_log.warning("Peak width can be estimated as ZERO. The result can be wrong");
1079 }
1080
1081 // do fitting with peak and background function (no analysis at this
1082 // point)
1083 cost = fitIndividualPeak(wi, peak_fitter, expected_peak_pos, peak_window_i, observe_peak_width, peakfunction,
1084 bkgdfunction);
1085 }
1086
1087 // process fitting result
1088 FitPeaksAlgorithm::FitFunction fit_function;
1089 fit_function.peakfunction = peakfunction;
1090 fit_function.bkgdfunction = bkgdfunction;
1091
1092 auto good_fit = processSinglePeakFitResult(wi, peak_index, cost, expected_peak_centers, fit_function,
1093 fit_result); // sets the record
1094
1095 if (good_fit) {
1096 // reset the flag such that there is at a peak fit in this spectrum
1097 neighborPeakSameSpectrum = true;
1098 prev_peak_index = peak_index;
1099 // copy values
1100 for (size_t i = 0; i < lastGoodPeakParameters[peak_index].size(); ++i) {
1101 lastGoodPeakParameters[peak_index][i] = peakfunction->getParameter(i);
1102 }
1103 }
1104 }
1105
1106 return;
1107}
1108
1109//----------------------------------------------------------------------------------------------
1118bool FitPeaks::decideToEstimatePeakParams(const bool firstPeakInSpectrum,
1119 const API::IPeakFunction_sptr &peak_function) {
1120 // should observe the peak width if the user didn't supply all of the peak
1121 // function parameters
1122 bool observe_peak_shape(m_initParamIndexes.size() != peak_function->nParams());
1123
1124 if (!m_initParamIndexes.empty()) {
1125 // user specifies starting value of peak parameters
1126 if (firstPeakInSpectrum) {
1127 // set the parameter values in a vector and loop over it
1128 // first peak. using the user-specified value
1129 for (size_t i = 0; i < m_initParamIndexes.size(); ++i) {
1130 const size_t param_index = m_initParamIndexes[i];
1131 const double param_value = m_initParamValues[i];
1132 peak_function->setParameter(param_index, param_value);
1133 }
1134 } else {
1135 // using the fitted paramters from the previous fitting result
1136 // do noting
1137 }
1138 } else {
1139 // no previously defined peak parameters: observation is thus required
1140 observe_peak_shape = true;
1141 }
1142
1143 return observe_peak_shape;
1144}
1145
1146//----------------------------------------------------------------------------------------------
1158bool FitPeaks::processSinglePeakFitResult(size_t wsindex, size_t peakindex, const double cost,
1159 const std::vector<double> &expected_peak_positions,
1160 const FitPeaksAlgorithm::FitFunction &fitfunction,
1161 const std::shared_ptr<FitPeaksAlgorithm::PeakFitResult> &fit_result) {
1162 // determine peak position tolerance
1163 double postol(DBL_MAX);
1164 bool case23(false);
1165 if (m_peakPosTolCase234) {
1166 // peak tolerance is not defined
1167 if (m_numPeaksToFit == 1) {
1168 // case (d) one peak only
1169 postol = m_inputMatrixWS->histogram(wsindex).x().back() - m_inputMatrixWS->histogram(wsindex).x().front();
1170 } else {
1171 // case b and c: more than 1 peaks without defined peak tolerance
1172 case23 = true;
1173 }
1174 } else {
1175 // user explicitly specified
1176 if (peakindex >= m_peakPosTolerances.size())
1177 throw std::runtime_error("Peak tolerance out of index");
1178 postol = m_peakPosTolerances[peakindex];
1179 }
1180
1181 // get peak position and analyze the fitting is good or not by various
1182 // criteria
1183 auto peak_pos = fitfunction.peakfunction->centre();
1184 auto peak_fwhm = fitfunction.peakfunction->fwhm();
1185 bool good_fit(false);
1186 if ((cost < 0) || (cost >= DBL_MAX - 1.) || std::isnan(cost)) {
1187 // unphysical cost function value
1188 peak_pos = -4;
1189 } else if (fitfunction.peakfunction->height() < m_minPeakHeight) {
1190 // peak height is under minimum request
1191 peak_pos = -3;
1192 } else if (case23) {
1193 // case b and c to check peak position without defined peak tolerance
1194 std::pair<double, double> fitwindow = getPeakFitWindow(wsindex, peakindex);
1195 if (fitwindow.first < fitwindow.second) {
1196 // peak fit window is specified or calculated: use peak window as position
1197 // tolerance
1198 if (peak_pos < fitwindow.first || peak_pos > fitwindow.second) {
1199 // peak is out of fit window
1200 peak_pos = -2;
1201 g_log.debug() << "Peak position " << peak_pos << " is out of fit "
1202 << "window boundary " << fitwindow.first << ", " << fitwindow.second << "\n";
1203 } else if (peak_fwhm > (fitwindow.second - fitwindow.first)) {
1204 // peak is too wide or window is too small
1205 peak_pos = -2.25;
1206 g_log.debug() << "Peak position " << peak_pos << " has fwhm "
1207 << "wider than the fit window " << fitwindow.second - fitwindow.first << "\n";
1208 } else {
1209 good_fit = true;
1210 }
1211 } else {
1212 // use the 1/2 distance to neiboring peak without defined peak window
1213 double left_bound(-1);
1214 if (peakindex > 0)
1215 left_bound = 0.5 * (expected_peak_positions[peakindex] - expected_peak_positions[peakindex - 1]);
1216 double right_bound(-1);
1217 if (peakindex < m_numPeaksToFit - 1)
1218 right_bound = 0.5 * (expected_peak_positions[peakindex + 1] - expected_peak_positions[peakindex]);
1219 if (left_bound < 0)
1220 left_bound = right_bound;
1221 if (right_bound < left_bound)
1222 right_bound = left_bound;
1223 if (left_bound < 0 || right_bound < 0)
1224 throw std::runtime_error("Code logic error such that left or right "
1225 "boundary of peak position is negative.");
1226 if (peak_pos < left_bound || peak_pos > right_bound) {
1227 peak_pos = -2.5;
1228 } else if (peak_fwhm > (right_bound - left_bound)) {
1229 // peak is too wide or window is too small
1230 peak_pos = -2.75;
1231 g_log.debug() << "Peak position " << peak_pos << " has fwhm "
1232 << "wider than the fit window " << right_bound - left_bound << "\n";
1233 } else {
1234 good_fit = true;
1235 }
1236 }
1237 } else if (fabs(fitfunction.peakfunction->centre() - expected_peak_positions[peakindex]) > postol) {
1238 // peak center is not within tolerance
1239 peak_pos = -5;
1240 g_log.debug() << "Peak position difference "
1241 << fabs(fitfunction.peakfunction->centre() - expected_peak_positions[peakindex])
1242 << " is out of range of tolerance: " << postol << "\n";
1243 } else {
1244 // all criteria are passed
1245 good_fit = true;
1246 }
1247
1248 // set cost function to DBL_MAX if fitting is bad
1249 double adjust_cost(cost);
1250 if (!good_fit) {
1251 // set the cost function value to DBL_MAX
1252 adjust_cost = DBL_MAX;
1253 }
1254
1255 // reset cost
1256 if (adjust_cost > DBL_MAX - 1) {
1257 fitfunction.peakfunction->setIntensity(0);
1258 }
1259
1260 // chi2
1261 fit_result->setRecord(peakindex, adjust_cost, peak_pos, fitfunction);
1262
1263 return good_fit;
1264}
1265
1266//----------------------------------------------------------------------------------------------
1272void FitPeaks::calculateFittedPeaks(std::vector<std::shared_ptr<FitPeaksAlgorithm::PeakFitResult>> fit_results) {
1273 // check
1274 if (!m_fittedParamTable)
1275 throw std::runtime_error("No parameters");
1276
1277 const size_t num_peakfunc_params = m_peakFunction->nParams();
1278 const size_t num_bkgdfunc_params = m_bkgdFunction->nParams();
1279
1281 for (auto iws = static_cast<int64_t>(m_startWorkspaceIndex); iws <= static_cast<int64_t>(m_stopWorkspaceIndex);
1282 ++iws) {
1284 // get a copy of peak function and background function
1285 IPeakFunction_sptr peak_function = std::dynamic_pointer_cast<IPeakFunction>(m_peakFunction->clone());
1286 IBackgroundFunction_sptr bkgd_function = std::dynamic_pointer_cast<IBackgroundFunction>(m_bkgdFunction->clone());
1287 std::shared_ptr<FitPeaksAlgorithm::PeakFitResult> fit_result_i = fit_results[iws - m_startWorkspaceIndex];
1288 // FIXME - This is a just a pure check
1289 if (!fit_result_i)
1290 throw std::runtime_error("There is something wroing with PeakFitResult vector!");
1291
1292 for (size_t ipeak = 0; ipeak < m_numPeaksToFit; ++ipeak) {
1293 // get and set the peak function parameters
1294 const double chi2 = fit_result_i->getCost(ipeak);
1295 if (chi2 > 10.e10)
1296 continue;
1297
1298 for (size_t iparam = 0; iparam < num_peakfunc_params; ++iparam)
1299 peak_function->setParameter(iparam, fit_result_i->getParameterValue(ipeak, iparam));
1300 for (size_t iparam = 0; iparam < num_bkgdfunc_params; ++iparam)
1301 bkgd_function->setParameter(iparam, fit_result_i->getParameterValue(ipeak, num_peakfunc_params + iparam));
1302 // use domain and function to calcualte
1303 // get the range of start and stop to construct a function domain
1304 const auto &vec_x = m_fittedPeakWS->points(static_cast<size_t>(iws));
1305 std::pair<double, double> peakwindow = getPeakFitWindow(static_cast<size_t>(iws), ipeak);
1306 auto start_x_iter = std::lower_bound(vec_x.begin(), vec_x.end(), peakwindow.first);
1307 auto stop_x_iter = std::lower_bound(vec_x.begin(), vec_x.end(), peakwindow.second);
1308
1309 if (start_x_iter == stop_x_iter)
1310 throw std::runtime_error("Range size is zero in calculateFittedPeaks");
1311
1312 FunctionDomain1DVector domain(start_x_iter, stop_x_iter);
1313 FunctionValues values(domain);
1314 CompositeFunction_sptr comp_func = std::make_shared<API::CompositeFunction>();
1315 comp_func->addFunction(peak_function);
1316 comp_func->addFunction(bkgd_function);
1317 comp_func->function(domain, values);
1318
1319 // copy over the values
1320 size_t istart = static_cast<size_t>(start_x_iter - vec_x.begin());
1321 size_t istop = static_cast<size_t>(stop_x_iter - vec_x.begin());
1322 for (size_t yindex = istart; yindex < istop; ++yindex) {
1323 m_fittedPeakWS->dataY(static_cast<size_t>(iws))[yindex] = values.getCalculated(yindex - istart);
1324 }
1325 } // END-FOR (ipeak)
1327 } // END-FOR (iws)
1329
1330 return;
1331}
1332namespace {
1333double estimateBackgroundParameters(const Histogram &histogram, const std::pair<size_t, size_t> &peak_window,
1334 const API::IBackgroundFunction_sptr &bkgd_function) {
1335 // for estimating background parameters
1336 // 0 = constant, 1 = linear
1337 const auto POLYNOMIAL_ORDER = std::min<size_t>(1, bkgd_function->nParams());
1338
1339 if (peak_window.first >= peak_window.second)
1340 throw std::runtime_error("Invalid peak window");
1341
1342 // reset the background function
1343 const auto nParams = bkgd_function->nParams();
1344 for (size_t i = 0; i < nParams; ++i)
1345 bkgd_function->setParameter(i, 0.);
1346
1347 // 10 is a magic number that worked in a variety of situations
1348 const size_t iback_start = peak_window.first + 10;
1349 const size_t iback_stop = peak_window.second - 10;
1350
1351 double chisq{DBL_MAX}; // how well the fit worked
1352
1353 // use the simple way to find linear background
1354 // there aren't enough bins in the window to try to estimate so just leave the
1355 // estimate at zero
1356 if (iback_start < iback_stop) {
1357 double bkgd_a0{0.}; // will be fit
1358 double bkgd_a1{0.}; // may be fit
1359 double bkgd_a2{0.}; // will be ignored
1360 HistogramData::estimateBackground(POLYNOMIAL_ORDER, histogram, peak_window.first, peak_window.second, iback_start,
1361 iback_stop, bkgd_a0, bkgd_a1, bkgd_a2, chisq);
1362 // update the background function with the result
1363 bkgd_function->setParameter(0, bkgd_a0);
1364 if (nParams > 1)
1365 bkgd_function->setParameter(1, bkgd_a1);
1366 // quadratic term is always estimated to be zero
1367 }
1368
1369 return chisq;
1370}
1371} // anonymous namespace
1372
1373//----------------------------------------------------------------------------------------------
1379bool FitPeaks::isObservablePeakProfile(const std::string &peakprofile) {
1380 return (std::find(supported_peak_profiles.begin(), supported_peak_profiles.end(), peakprofile) !=
1381 supported_peak_profiles.end());
1382}
1383
1384//----------------------------------------------------------------------------------------------
1387bool FitPeaks::fitBackground(const size_t &ws_index, const std::pair<double, double> &fit_window,
1388 const double &expected_peak_pos, const API::IBackgroundFunction_sptr &bkgd_func) {
1389 constexpr size_t MIN_POINTS{10}; // TODO explain why 10
1390
1391 // find out how to fit background
1392 const auto &points = m_inputMatrixWS->histogram(ws_index).points();
1393 size_t start_index = findXIndex(points.rawData(), fit_window.first);
1394 size_t expected_peak_index = findXIndex(points.rawData(), expected_peak_pos, start_index);
1395 size_t stop_index = findXIndex(points.rawData(), fit_window.second, expected_peak_index);
1396
1397 // treat 5 as a magic number - TODO explain why
1398 bool good_fit(false);
1399 if (expected_peak_index - start_index > MIN_POINTS && stop_index - expected_peak_index > MIN_POINTS) {
1400 // enough data points left for multi-domain fitting
1401 // set a smaller fit window
1402 const std::pair<double, double> vec_min{fit_window.first, points[expected_peak_index + 5]};
1403 const std::pair<double, double> vec_max{points[expected_peak_index - 5], fit_window.second};
1404
1405 // reset background function value
1406 for (size_t n = 0; n < bkgd_func->nParams(); ++n)
1407 bkgd_func->setParameter(n, 0);
1408
1409 double chi2 = fitFunctionMD(bkgd_func, m_inputMatrixWS, ws_index, vec_min, vec_max);
1410
1411 // process
1412 if (chi2 < DBL_MAX - 1) {
1413 good_fit = true;
1414 }
1415
1416 } else {
1417 // fit as a single domain function. check whether the result is good or bad
1418
1419 // TODO FROM HERE!
1420 g_log.debug() << "Don't know what to do with background fitting with single "
1421 << "domain function! " << (expected_peak_index - start_index) << " points to the left "
1422 << (stop_index - expected_peak_index) << " points to the right\n";
1423 }
1424
1425 return good_fit;
1426}
1427
1428//----------------------------------------------------------------------------------------------
1431double FitPeaks::fitIndividualPeak(size_t wi, const API::IAlgorithm_sptr &fitter, const double expected_peak_center,
1432 const std::pair<double, double> &fitwindow, const bool estimate_peak_width,
1433 const API::IPeakFunction_sptr &peakfunction,
1434 const API::IBackgroundFunction_sptr &bkgdfunc) {
1435 double cost(DBL_MAX);
1436
1437 // confirm that there is something to fit
1438 if (numberCounts(m_inputMatrixWS->histogram(wi), fitwindow.first, fitwindow.second) <= m_minPeakHeight)
1439 return cost;
1440
1441 if (m_highBackground) {
1442 // fit peak with high background!
1443 cost = fitFunctionHighBackground(fitter, fitwindow, wi, expected_peak_center, estimate_peak_width, peakfunction,
1444 bkgdfunc);
1445 } else {
1446 // fit peak and background
1447 cost = fitFunctionSD(fitter, peakfunction, bkgdfunc, m_inputMatrixWS, wi, fitwindow, expected_peak_center,
1448 estimate_peak_width, true);
1449 }
1450
1451 return cost;
1452}
1453
1454//----------------------------------------------------------------------------------------------
1461 const API::IBackgroundFunction_sptr &bkgd_function,
1462 const API::MatrixWorkspace_sptr &dataws, size_t wsindex,
1463 const std::pair<double, double> &peak_range, const double &expected_peak_center,
1464 bool estimate_peak_width, bool estimate_background) {
1465 std::stringstream errorid;
1466 errorid << "(WorkspaceIndex=" << wsindex << " PeakCentre=" << expected_peak_center << ")";
1467
1468 // generate peak window
1469 if (peak_range.first >= peak_range.second) {
1470 std::stringstream msg;
1471 msg << "Invalid peak window: xmin>xmax (" << peak_range.first << ", " << peak_range.second << ")" << errorid.str();
1472 throw std::runtime_error(msg.str());
1473 }
1474
1475 // determine the peak window in array index
1476 const auto &histogram = dataws->histogram(wsindex);
1477 const auto &vector_x = histogram.points();
1478 const auto start_index = findXIndex(vector_x, peak_range.first);
1479 const auto stop_index = findXIndex(vector_x, peak_range.second, start_index);
1480 if (start_index == stop_index)
1481 throw std::runtime_error("Range size is zero in estimatePeakParameters");
1482 std::pair<size_t, size_t> peak_window = std::make_pair(start_index, stop_index);
1483
1484 // Estimate background
1485 if (estimate_background) {
1486 estimateBackgroundParameters(histogram, peak_window, bkgd_function);
1487 }
1488
1489 // Estimate peak profile parameter
1490 peak_function->setCentre(expected_peak_center); // set expected position first
1491 int result = estimatePeakParameters(histogram, peak_window, peak_function, bkgd_function, estimate_peak_width,
1493 if (result != GOOD) {
1494 peak_function->setCentre(expected_peak_center);
1495 if (result == NOSIGNAL || result == LOWPEAK) {
1496 return DBL_MAX; // exit early - don't fit
1497 }
1498 }
1499
1500 // Create the composition function
1501 CompositeFunction_sptr comp_func = std::make_shared<API::CompositeFunction>();
1502 comp_func->addFunction(peak_function);
1503 comp_func->addFunction(bkgd_function);
1504 IFunction_sptr fitfunc = std::dynamic_pointer_cast<IFunction>(comp_func);
1505
1506 // Set the properties
1507 fit->setProperty("Function", fitfunc);
1508 fit->setProperty("InputWorkspace", dataws);
1509 fit->setProperty("WorkspaceIndex", static_cast<int>(wsindex));
1510 fit->setProperty("MaxIterations", m_fitIterations); // magic number
1511 fit->setProperty("StartX", peak_range.first);
1512 fit->setProperty("EndX", peak_range.second);
1513 fit->setProperty("IgnoreInvalidData", true);
1514
1516 // set up a constraint on peak position
1517 double peak_center = peak_function->centre();
1518 double peak_width = peak_function->fwhm();
1519 std::stringstream peak_center_constraint;
1520 peak_center_constraint << (peak_center - 0.5 * peak_width) << " < f0." << peak_function->getCentreParameterName()
1521 << " < " << (peak_center + 0.5 * peak_width);
1522
1523 // set up a constraint on peak height
1524 fit->setProperty("Constraints", peak_center_constraint.str());
1525 }
1526
1527 // Execute fit and get result of fitting background
1528 g_log.debug() << "[E1201] FitSingleDomain Before fitting, Fit function: " << fit->asString() << "\n";
1529 errorid << " starting function [" << comp_func->asString() << "]";
1530 try {
1531 fit->execute();
1532 g_log.debug() << "[E1202] FitSingleDomain After fitting, Fit function: " << fit->asString() << "\n";
1533
1534 if (!fit->isExecuted()) {
1535 g_log.warning() << "Fitting peak SD (single domain) failed to execute. " + errorid.str();
1536 return DBL_MAX;
1537 }
1538 } catch (std::invalid_argument &e) {
1539 errorid << ": " << e.what();
1540 g_log.warning() << "While fitting " + errorid.str();
1541 return DBL_MAX; // probably the wrong thing to do
1542 }
1543
1544 // Retrieve result
1545 std::string fitStatus = fit->getProperty("OutputStatus");
1546 double chi2{std::numeric_limits<double>::max()};
1547 if (fitStatus == "success") {
1548 chi2 = fit->getProperty("OutputChi2overDoF");
1549 }
1550
1551 return chi2;
1552}
1553
1554//----------------------------------------------------------------------------------------------
1556 const size_t wsindex, const std::pair<double, double> &vec_xmin,
1557 const std::pair<double, double> &vec_xmax) {
1558 // Note: after testing it is found that multi-domain Fit cannot be reused
1560 try {
1561 fit = createChildAlgorithm("Fit", -1, -1, false);
1562 } catch (Exception::NotFoundError &) {
1563 std::stringstream errss;
1564 errss << "The FitPeak algorithm requires the CurveFitting library";
1565 throw std::runtime_error(errss.str());
1566 }
1567 // set up background fit instance
1568 fit->setProperty("Minimizer", m_minimizer);
1569 fit->setProperty("CostFunction", m_costFunction);
1570 fit->setProperty("CalcErrors", true);
1571
1572 // This use multi-domain; but does not know how to set up IFunction_sptr
1573 // fitfunc,
1574 std::shared_ptr<MultiDomainFunction> md_function = std::make_shared<MultiDomainFunction>();
1575
1576 // Set function first
1577 md_function->addFunction(std::move(fit_function));
1578
1579 // set domain for function with index 0 covering both sides
1580 md_function->clearDomainIndices();
1581 md_function->setDomainIndices(0, {0, 1});
1582
1583 // Set the properties
1584 fit->setProperty("Function", std::dynamic_pointer_cast<IFunction>(md_function));
1585 fit->setProperty("InputWorkspace", dataws);
1586 fit->setProperty("WorkspaceIndex", static_cast<int>(wsindex));
1587 fit->setProperty("StartX", vec_xmin.first);
1588 fit->setProperty("EndX", vec_xmax.first);
1589 fit->setProperty("InputWorkspace_1", dataws);
1590 fit->setProperty("WorkspaceIndex_1", static_cast<int>(wsindex));
1591 fit->setProperty("StartX_1", vec_xmin.second);
1592 fit->setProperty("EndX_1", vec_xmax.second);
1593 fit->setProperty("MaxIterations", m_fitIterations);
1594 fit->setProperty("IgnoreInvalidData", true);
1595
1596 // Execute
1597 fit->execute();
1598 if (!fit->isExecuted()) {
1599 throw runtime_error("Fit is not executed on multi-domain function/data. ");
1600 }
1601
1602 // Retrieve result
1603 std::string fitStatus = fit->getProperty("OutputStatus");
1604
1605 double chi2 = DBL_MAX;
1606 if (fitStatus == "success") {
1607 chi2 = fit->getProperty("OutputChi2overDoF");
1608 }
1609
1610 return chi2;
1611}
1612
1613//----------------------------------------------------------------------------------------------
1615double FitPeaks::fitFunctionHighBackground(const IAlgorithm_sptr &fit, const std::pair<double, double> &fit_window,
1616 const size_t &ws_index, const double &expected_peak_center,
1617 bool observe_peak_shape, const API::IPeakFunction_sptr &peakfunction,
1618 const API::IBackgroundFunction_sptr &bkgdfunc) {
1620
1621 // high background to reduce
1622 API::IBackgroundFunction_sptr high_bkgd_function =
1623 std::dynamic_pointer_cast<API::IBackgroundFunction>(m_linearBackgroundFunction->clone());
1624
1625 // Fit the background first if there is enough data points
1626 fitBackground(ws_index, fit_window, expected_peak_center, high_bkgd_function);
1627
1628 // Get partial of the data
1629 std::vector<double> vec_x, vec_y, vec_e;
1630 getRangeData(ws_index, fit_window, vec_x, vec_y, vec_e);
1631
1632 // Reduce the background
1633 reduceByBackground(high_bkgd_function, vec_x, vec_y);
1634 for (size_t n = 0; n < bkgdfunc->nParams(); ++n)
1635 bkgdfunc->setParameter(n, 0);
1636
1637 // Create a new workspace
1638 API::MatrixWorkspace_sptr reduced_bkgd_ws = createMatrixWorkspace(vec_x, vec_y, vec_e);
1639
1640 // Fit peak with background
1641 fitFunctionSD(fit, peakfunction, bkgdfunc, reduced_bkgd_ws, 0, {vec_x.front(), vec_x.back()}, expected_peak_center,
1642 observe_peak_shape, false);
1643
1644 // add the reduced background back
1645 bkgdfunc->setParameter(0, bkgdfunc->getParameter(0) + high_bkgd_function->getParameter(0));
1646 bkgdfunc->setParameter(1, bkgdfunc->getParameter(1) + // TODO doesn't work for flat background
1647 high_bkgd_function->getParameter(1));
1648
1649 double cost = fitFunctionSD(fit, peakfunction, bkgdfunc, m_inputMatrixWS, ws_index, {vec_x.front(), vec_x.back()},
1650 expected_peak_center, false, false);
1651
1652 return cost;
1653}
1654
1655//----------------------------------------------------------------------------------------------
1658 const std::vector<double> &vec_y,
1659 const std::vector<double> &vec_e) {
1660 size_t size = vec_x.size();
1661 size_t ysize = vec_y.size();
1662
1663 HistogramBuilder builder;
1664 builder.setX(size);
1665 builder.setY(ysize);
1666 MatrixWorkspace_sptr matrix_ws = create<Workspace2D>(1, builder.build());
1667
1668 auto &dataX = matrix_ws->mutableX(0);
1669 auto &dataY = matrix_ws->mutableY(0);
1670 auto &dataE = matrix_ws->mutableE(0);
1671
1672 dataX.assign(vec_x.cbegin(), vec_x.cend());
1673 dataY.assign(vec_y.cbegin(), vec_y.cend());
1674 dataE.assign(vec_e.cbegin(), vec_e.cend());
1675
1676 return matrix_ws;
1677}
1678
1679//----------------------------------------------------------------------------------------------
1683 // create output workspace for peak positions: can be partial spectra to input
1684 // workspace
1685 size_t num_hist = m_stopWorkspaceIndex - m_startWorkspaceIndex + 1;
1686 m_outputPeakPositionWorkspace = create<Workspace2D>(num_hist, Points(m_numPeaksToFit));
1687 // set default
1688 for (size_t wi = 0; wi < num_hist; ++wi) {
1689 // convert to workspace index of input data workspace
1690 size_t inp_wi = wi + m_startWorkspaceIndex;
1691 std::vector<double> expected_position = getExpectedPeakPositions(inp_wi);
1692 for (size_t ipeak = 0; ipeak < m_numPeaksToFit; ++ipeak) {
1693 m_outputPeakPositionWorkspace->dataX(wi)[ipeak] = expected_position[ipeak];
1694 }
1695 }
1696
1697 return;
1698}
1699
1700//----------------------------------------------------------------------------------------------
1708 const std::vector<std::string> &param_names, bool with_chi2) {
1709
1710 // add columns
1711 table_ws->addColumn("int", "wsindex");
1712 table_ws->addColumn("int", "peakindex");
1713 for (const auto &param_name : param_names)
1714 table_ws->addColumn("double", param_name);
1715 if (with_chi2)
1716 table_ws->addColumn("double", "chi2");
1717
1718 // add rows
1719 const size_t numParam = m_fittedParamTable->columnCount() - 3;
1720 for (size_t iws = m_startWorkspaceIndex; iws <= m_stopWorkspaceIndex; ++iws) {
1721 for (size_t ipeak = 0; ipeak < m_numPeaksToFit; ++ipeak) {
1722 API::TableRow newRow = table_ws->appendRow();
1723 newRow << static_cast<int>(iws); // workspace index
1724 newRow << static_cast<int>(ipeak); // peak number
1725 for (size_t iparam = 0; iparam < numParam; ++iparam)
1726 newRow << 0.; // parameters for each peak
1727 if (with_chi2)
1728 newRow << DBL_MAX; // chisq
1729 }
1730 }
1731
1732 return;
1733}
1734
1735//----------------------------------------------------------------------------------------------
1741 // peak parameter workspace
1742 m_rawPeaksTable = getProperty(PropertyNames::RAW_PARAMS);
1743
1744 // create parameters
1745 // peak
1746 std::vector<std::string> param_vec;
1747 if (m_rawPeaksTable) {
1748 param_vec = m_peakFunction->getParameterNames();
1749 } else {
1750 param_vec.emplace_back("centre");
1751 param_vec.emplace_back("width");
1752 param_vec.emplace_back("height");
1753 param_vec.emplace_back("intensity");
1754 }
1755 // background
1756 for (size_t iparam = 0; iparam < m_bkgdFunction->nParams(); ++iparam)
1757 param_vec.emplace_back(m_bkgdFunction->parameterName(iparam));
1758
1759 // parameter value table
1760 m_fittedParamTable = std::make_shared<TableWorkspace>();
1762
1763 // for error workspace
1764 std::string fiterror_table_name = getPropertyValue(PropertyNames::OUTPUT_WKSP_PARAM_ERRS);
1765 // do nothing if user does not specifiy
1766 if (fiterror_table_name.empty()) {
1767 // not specified
1768 m_fitErrorTable = nullptr;
1769 } else {
1770 // create table and set up parameter table
1771 m_fitErrorTable = std::make_shared<TableWorkspace>();
1773 }
1774
1775 return;
1776}
1777
1778//----------------------------------------------------------------------------------------------
1783 // matrix workspace contained calculated peaks from fitting
1784 std::string fit_ws_name = getPropertyValue(PropertyNames::OUTPUT_WKSP_MODEL);
1785 if (fit_ws_name.size() == 0) {
1786 // skip if user does not specify
1787 m_fittedPeakWS = nullptr;
1788 return;
1789 }
1790
1791 // create a wokspace with same size as in the input matrix workspace
1792 m_fittedPeakWS = create<Workspace2D>(*m_inputMatrixWS);
1793}
1794
1795//----------------------------------------------------------------------------------------------
1797void FitPeaks::processOutputs(std::vector<std::shared_ptr<FitPeaksAlgorithm::PeakFitResult>> fit_result_vec) {
1798 setProperty(PropertyNames::OUTPUT_WKSP, m_outputPeakPositionWorkspace);
1799 setProperty(PropertyNames::OUTPUT_WKSP_PARAMS, m_fittedParamTable);
1800
1801 if (m_fitErrorTable) {
1802 g_log.warning("Output error table workspace");
1803 setProperty(PropertyNames::OUTPUT_WKSP_PARAM_ERRS, m_fitErrorTable);
1804 } else {
1805 g_log.warning("No error table output");
1806 }
1807
1808 // optional
1810 g_log.debug("about to calcualte fitted peaks");
1811 calculateFittedPeaks(std::move(fit_result_vec));
1812 setProperty(PropertyNames::OUTPUT_WKSP_MODEL, m_fittedPeakWS);
1813 }
1814}
1815
1816//----------------------------------------------------------------------------------------------
1818std::vector<double> FitPeaks::getExpectedPeakPositions(size_t wi) {
1819 // check
1820 if (wi < m_startWorkspaceIndex || wi > m_stopWorkspaceIndex) {
1821 std::stringstream errss;
1822 errss << "Workspace index " << wi << " is out of range [" << m_startWorkspaceIndex << ", " << m_stopWorkspaceIndex
1823 << "]";
1824 throw std::runtime_error(errss.str());
1825 }
1826
1827 // initialize output array
1828 std::vector<double> exp_centers(m_numPeaksToFit);
1829
1831 // uniform peak centers among spectra: simple copy
1832 exp_centers = m_peakCenters;
1833 } else {
1834 // no uniform peak center. locate the input workspace index
1835 // in the peak center workspace peak in the workspae
1836
1837 // get the relative workspace index in input peak position workspace
1838 size_t peak_wi = wi - m_startWorkspaceIndex;
1839 // get values
1840 exp_centers = m_peakCenterWorkspace->x(peak_wi).rawData();
1841 }
1842
1843 return exp_centers;
1844}
1845
1846//----------------------------------------------------------------------------------------------
1848std::pair<double, double> FitPeaks::getPeakFitWindow(size_t wi, size_t ipeak) {
1849 // check workspace index
1850 if (wi < m_startWorkspaceIndex || wi > m_stopWorkspaceIndex) {
1851 std::stringstream errss;
1852 errss << "Workspace index " << wi << " is out of range [" << m_startWorkspaceIndex << ", " << m_stopWorkspaceIndex
1853 << "]";
1854 throw std::runtime_error(errss.str());
1855 }
1856
1857 // check peak index
1858 if (ipeak >= m_numPeaksToFit) {
1859 std::stringstream errss;
1860 errss << "Peak index " << ipeak << " is out of range (" << m_numPeaksToFit << ")";
1861 throw std::runtime_error(errss.str());
1862 }
1863
1864 double left(0), right(0);
1866 // calcualte peak window by delta(d)/d
1867 double peak_pos = getExpectedPeakPositions(wi)[ipeak];
1868 // calcalate expected peak width
1869 double estimate_peak_width = peak_pos * m_peakWidthPercentage;
1870 // using a MAGIC number to estimate the peak window
1871 double MAGIC = 3.0;
1872 left = peak_pos - estimate_peak_width * MAGIC;
1873 right = peak_pos + estimate_peak_width * MAGIC;
1874 } else if (m_uniformPeakWindows) {
1875 // uniform peak fit window
1876 assert(m_peakWindowVector.size() > 0); // peak fit window must be given!
1877
1878 left = m_peakWindowVector[ipeak][0];
1879 right = m_peakWindowVector[ipeak][1];
1880 } else if (m_peakWindowWorkspace) {
1881 // no uniform peak fit window. locate peak in the workspace
1882 // get workspace index in m_peakWindowWorkspace
1883 size_t window_wi = wi - m_startWorkspaceIndex;
1884
1885 left = m_peakWindowWorkspace->x(window_wi)[ipeak * 2];
1886 right = m_peakWindowWorkspace->x(window_wi)[ipeak * 2 + 1];
1887 } else {
1888 throw std::runtime_error("Unhandled case for get peak fit window!");
1889 }
1890 if (left >= right) {
1891 std::stringstream errss;
1892 errss << "Peak window is inappropriate for workspace index " << wi << " peak " << ipeak << ": " << left
1893 << " >= " << right;
1894 throw std::runtime_error(errss.str());
1895 }
1896
1897 return std::make_pair(left, right);
1898}
1899
1900//----------------------------------------------------------------------------------------------
1903void FitPeaks::getRangeData(size_t iws, const std::pair<double, double> &fit_window, std::vector<double> &vec_x,
1904 std::vector<double> &vec_y, std::vector<double> &vec_e) {
1905
1906 // get the original vector of X and determine the start and end index
1907 const auto &orig_x = m_inputMatrixWS->histogram(iws).x();
1908 size_t left_index = findXIndex(orig_x, fit_window.first);
1909 size_t right_index = findXIndex(orig_x, fit_window.second, left_index);
1910
1911 if (left_index >= right_index) {
1912 std::stringstream err_ss;
1913 err_ss << "Unable to get subset of histogram from given fit window. "
1914 << "Fit window: " << fit_window.first << ", " << fit_window.second << ". Vector X's range is "
1915 << orig_x.front() << ", " << orig_x.back();
1916 throw std::runtime_error(err_ss.str());
1917 }
1918
1919 // copy X, Y and E
1920 size_t num_elements = right_index - left_index;
1921 vec_x.resize(num_elements);
1922 std::copy(orig_x.begin() + left_index, orig_x.begin() + right_index, vec_x.begin());
1923
1924 // modify right_index if it is at the end
1925 if (m_inputMatrixWS->isHistogramData() && right_index == orig_x.size() - 1) {
1926 right_index -= 1;
1927 if (right_index == left_index)
1928 throw std::runtime_error("Histogram workspace have same left and right "
1929 "boundary index for Y and E.");
1930 num_elements -= 1;
1931 }
1932
1933 // get original vector of Y and E
1934 const std::vector<double> orig_y = m_inputMatrixWS->histogram(iws).y().rawData();
1935 const std::vector<double> orig_e = m_inputMatrixWS->histogram(iws).e().rawData();
1936 vec_y.resize(num_elements);
1937 vec_e.resize(num_elements);
1938 std::copy(orig_y.begin() + left_index, orig_y.begin() + right_index, vec_y.begin());
1939 std::copy(orig_e.begin() + left_index, orig_e.begin() + right_index, vec_e.begin());
1940
1941 return;
1942}
1943
1944//----------------------------------------------------------------------------------------------
1950void FitPeaks::reduceByBackground(const API::IBackgroundFunction_sptr &bkgd_func, const std::vector<double> &vec_x,
1951 std::vector<double> &vec_y) {
1952 // calculate the background
1953 FunctionDomain1DVector vectorx(vec_x.begin(), vec_x.end());
1954 FunctionValues vector_bkgd(vectorx);
1955 bkgd_func->function(vectorx, vector_bkgd);
1956
1957 // subtract the background from the supplied data
1958 for (size_t i = 0; i < vec_y.size(); ++i) {
1959 (vec_y)[i] -= vector_bkgd[i];
1960 // it is better not to mess up with E here
1961 }
1962
1963 return;
1964}
1965
1966//----------------------------------------------------------------------------------------------
1975void FitPeaks::writeFitResult(size_t wi, const std::vector<double> &expected_positions,
1976 const std::shared_ptr<FitPeaksAlgorithm::PeakFitResult> &fit_result) {
1977 // convert to
1978 size_t out_wi = wi - m_startWorkspaceIndex;
1979 if (out_wi >= m_outputPeakPositionWorkspace->getNumberHistograms()) {
1980 g_log.error() << "workspace index " << wi << " is out of output peak position workspace "
1981 << "range of spectra, which contains " << m_outputPeakPositionWorkspace->getNumberHistograms()
1982 << " spectra"
1983 << "\n";
1984 throw std::runtime_error("Out of boundary to set output peak position workspace");
1985 }
1986
1987 // Fill the output peak position workspace
1988 for (size_t ipeak = 0; ipeak < m_numPeaksToFit; ++ipeak) {
1989 double exp_peak_pos(expected_positions[ipeak]);
1990 double fitted_peak_pos = fit_result->getPeakPosition(ipeak);
1991 double peak_chi2 = fit_result->getCost(ipeak);
1992
1993 m_outputPeakPositionWorkspace->mutableX(out_wi)[ipeak] = exp_peak_pos;
1994 m_outputPeakPositionWorkspace->mutableY(out_wi)[ipeak] = fitted_peak_pos;
1995 m_outputPeakPositionWorkspace->mutableE(out_wi)[ipeak] = peak_chi2;
1996 }
1997
1998 // Output the peak parameters to the table workspace
1999 // check vector size
2000
2001 // last column of the table is for chi2
2002 size_t chi2_index = m_fittedParamTable->columnCount() - 1;
2003
2004 // check TableWorkspace and given FitResult
2005 if (m_rawPeaksTable) {
2006 // duplicate from FitPeakResult to table workspace
2007 // check again with the column size versus peak parameter values
2008 if (fit_result->getNumberParameters() != m_fittedParamTable->columnCount() - 3) {
2009 g_log.error() << "Peak of type (" << m_peakFunction->name() << ") has " << fit_result->getNumberParameters()
2010 << " parameters. Parameter table shall have 3 more "
2011 "columns. But not it has "
2012 << m_fittedParamTable->columnCount() << " columns\n";
2013 throw std::runtime_error("Peak parameter vector for one peak has different sizes to output "
2014 "table workspace");
2015 }
2016 } else {
2017 // effective peak profile parameters: need to re-construct the peak function
2018 if (4 + m_bkgdFunction->nParams() != m_fittedParamTable->columnCount() - 3) {
2019
2020 std::stringstream err_ss;
2021 err_ss << "Peak has 4 effective peak parameters and " << m_bkgdFunction->nParams() << " background parameters "
2022 << ". Parameter table shall have 3 more columns. But not it has " << m_fittedParamTable->columnCount()
2023 << " columns";
2024 throw std::runtime_error(err_ss.str());
2025 }
2026 }
2027
2028 // go through each peak
2029 // get a copy of peak function and background function
2030 IPeakFunction_sptr peak_function = std::dynamic_pointer_cast<IPeakFunction>(m_peakFunction->clone());
2031 size_t num_peakfunc_params = peak_function->nParams();
2032 size_t num_bkgd_params = m_bkgdFunction->nParams();
2033
2034 for (size_t ipeak = 0; ipeak < m_numPeaksToFit; ++ipeak) {
2035 // get row number
2036 size_t row_index = out_wi * m_numPeaksToFit + ipeak;
2037
2038 // treat as different cases for writing out raw or effective parametr
2039 if (m_rawPeaksTable) {
2040 // duplicate from FitPeakResult to table workspace
2041 for (size_t iparam = 0; iparam < num_peakfunc_params + num_bkgd_params; ++iparam) {
2042 size_t col_index = iparam + 2;
2043 // fitted parameter's value
2044 m_fittedParamTable->cell<double>(row_index, col_index) = fit_result->getParameterValue(ipeak, iparam);
2045 // fitted parameter's fitting error
2046 if (m_fitErrorTable) {
2047 m_fitErrorTable->cell<double>(row_index, col_index) = fit_result->getParameterError(ipeak, iparam);
2048 }
2049
2050 } // end for (iparam)
2051 } else {
2052 // effective peak profile parameter
2053 // construct the peak function
2054 for (size_t iparam = 0; iparam < num_peakfunc_params; ++iparam)
2055 peak_function->setParameter(iparam, fit_result->getParameterValue(ipeak, iparam));
2056
2057 // set the effective peak parameters
2058 m_fittedParamTable->cell<double>(row_index, 2) = peak_function->centre();
2059 m_fittedParamTable->cell<double>(row_index, 3) = peak_function->fwhm();
2060 m_fittedParamTable->cell<double>(row_index, 4) = peak_function->height();
2061 m_fittedParamTable->cell<double>(row_index, 5) = peak_function->intensity();
2062
2063 // background
2064 for (size_t iparam = 0; iparam < num_bkgd_params; ++iparam)
2065 m_fittedParamTable->cell<double>(row_index, 6 + iparam) =
2066 fit_result->getParameterValue(ipeak, num_peakfunc_params + iparam);
2067 }
2068
2069 // set chi2
2070 m_fittedParamTable->cell<double>(row_index, chi2_index) = fit_result->getCost(ipeak);
2071 }
2072
2073 return;
2074}
2075
2076//----------------------------------------------------------------------------------------------
2078 std::string height_name("");
2079
2080 std::vector<std::string> peak_parameters = peak_function->getParameterNames();
2081 for (const auto &name : peak_parameters) {
2082 if (name == "Height") {
2083 height_name = "Height";
2084 break;
2085 } else if (name == "I") {
2086 height_name = "I";
2087 break;
2088 } else if (name == "Intensity") {
2089 height_name = "Intensity";
2090 break;
2091 }
2092 }
2093
2094 if (height_name.empty())
2095 throw std::runtime_error("Peak height parameter name cannot be found.");
2096
2097 return height_name;
2098}
2099
2101
2102} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double value
The value of the point.
Definition: FitMW.cpp:51
double left
Definition: LineProfile.cpp:80
double right
Definition: LineProfile.cpp:81
#define fabs(x)
Definition: Matrix.cpp:22
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
Definition: MultiThreaded.h:94
#define PARALLEL_CRITICAL(name)
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PRAGMA_OMP(expression)
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
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
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.
double getCalculated(size_t i) const
Get i-th calculated value.
An interface to a peak function, which extend the interface of IFunctionWithLocation by adding method...
Definition: IPeakFunction.h:51
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
A property class for workspaces.
size_t m_function_parameters_number
number of function parameters
Definition: FitPeaks.h:53
std::vector< std::vector< double > > m_function_parameters_vector
Definition: FitPeaks.h:59
PeakFitResult(size_t num_peaks, size_t num_params)
Holds all of the fitting information for a single spectrum.
Definition: FitPeaks.cpp:91
double getParameterValue(size_t ipeak, size_t iparam) const
get the fitted value of a particular parameter
Definition: FitPeaks.cpp:132
std::vector< std::vector< double > > m_function_errors_vector
fitted peak and background parameters' fitting error
Definition: FitPeaks.h:61
void setRecord(size_t ipeak, const double cost, const double peak_position, const FitFunction &fit_functions)
set the peak fitting record/parameter for one peak
Definition: FitPeaks.cpp:144
double getParameterError(size_t ipeak, size_t iparam) const
get the fitting error of a particular parameter
Definition: FitPeaks.cpp:121
void setBadRecord(size_t ipeak, const double peak_position)
The peak postition should be negative and indicates what went wrong.
Definition: FitPeaks.cpp:175
Algorithms::PeakParameterHelper::EstimatePeakWidth m_peakWidthEstimateApproach
Flag for observing peak width: there are 3 states (1) no estimation (2) from 'observation' (3) calcul...
Definition: FitPeaks.h:248
API::MatrixWorkspace_const_sptr m_peakCenterWorkspace
Definition: FitPeaks.h:230
void generateFittedParametersValueWorkspaces()
Generate output workspaces.
Definition: FitPeaks.cpp:1740
void setupParameterTableWorkspace(const API::ITableWorkspace_sptr &table_ws, const std::vector< std::string > &param_names, bool with_chi2)
Set up parameter table (parameter value or error)
Definition: FitPeaks.cpp:1707
std::vector< double > m_peakPosTolerances
Definition: FitPeaks.h:244
API::IPeakFunction_sptr m_peakFunction
Peak profile name.
Definition: FitPeaks.h:209
bool fitBackground(const size_t &ws_index, const std::pair< double, double > &fit_window, const double &expected_peak_pos, const API::IBackgroundFunction_sptr &bkgd_func)
fit background
Definition: FitPeaks.cpp:1387
void fitSpectrumPeaks(size_t wi, const std::vector< double > &expected_peak_centers, const std::shared_ptr< FitPeaksAlgorithm::PeakFitResult > &fit_result, std::vector< std::vector< double > > &lastGoodPeakParameters)
fit peaks in a same spectrum
Definition: FitPeaks.cpp:935
double fitFunctionSD(const API::IAlgorithm_sptr &fit, const API::IPeakFunction_sptr &peak_function, const API::IBackgroundFunction_sptr &bkgd_function, const API::MatrixWorkspace_sptr &dataws, size_t wsindex, const std::pair< double, double > &peak_range, const double &expected_peak_center, bool estimate_peak_width, bool estimate_background)
Methods to fit functions (general)
Definition: FitPeaks.cpp:1460
double fitIndividualPeak(size_t wi, const API::IAlgorithm_sptr &fitter, const double expected_peak_center, const std::pair< double, double > &fitwindow, const bool estimate_peak_width, const API::IPeakFunction_sptr &peakfunction, const API::IBackgroundFunction_sptr &bkgdfunc)
Fit an individual peak.
Definition: FitPeaks.cpp:1431
API::MatrixWorkspace_sptr m_outputPeakPositionWorkspace
output workspace for peak positions
Definition: FitPeaks.h:193
API::MatrixWorkspace_sptr m_fittedPeakWS
matrix workspace contained calcalated peaks+background from fitted result it has same number of spect...
Definition: FitPeaks.h:205
API::ITableWorkspace_const_sptr m_profileStartingValueTable
table workspace for profile parameters' starting value
Definition: FitPeaks.h:265
std::string m_minimizer
Minimzer.
Definition: FitPeaks.h:216
API::IBackgroundFunction_sptr m_linearBackgroundFunction
Linear background function for high background fitting.
Definition: FitPeaks.h:213
bool m_peakPosTolCase234
peak positon tolerance case b, c and d
Definition: FitPeaks.h:280
std::map< std::string, std::string > validateInputs() override
Validate inputs.
Definition: FitPeaks.cpp:373
std::vector< double > getExpectedPeakPositions(size_t wi)
methods to retrieve fit range and peak centers
Definition: FitPeaks.cpp:1818
double m_peakWidthPercentage
flag to estimate peak width from
Definition: FitPeaks.h:235
API::IBackgroundFunction_sptr m_bkgdFunction
Background function.
Definition: FitPeaks.h:211
size_t m_startWorkspaceIndex
start index
Definition: FitPeaks.h:239
double fitFunctionHighBackground(const API::IAlgorithm_sptr &fit, const std::pair< double, double > &fit_window, const size_t &ws_index, const double &expected_peak_center, bool observe_peak_shape, const API::IPeakFunction_sptr &peakfunction, const API::IBackgroundFunction_sptr &bkgdfunc)
fit a single peak with high background
Definition: FitPeaks.cpp:1615
bool m_calculateWindowInstrument
flag to calcualte peak fit window from instrument resolution
Definition: FitPeaks.h:257
void processInputPeakCenters()
peak centers
Definition: FitPeaks.cpp:712
std::vector< std::shared_ptr< FitPeaksAlgorithm::PeakFitResult > > fitPeaks()
suites of method to fit peaks
Definition: FitPeaks.cpp:842
double m_minPeakHeight
minimum peak height without background and it also serves as the criteria for observed peak parameter
Definition: FitPeaks.h:272
std::string m_costFunction
Cost function.
Definition: FitPeaks.h:218
void processInputFunctions()
process inputs for peak and background functions
Definition: FitPeaks.cpp:542
void processInputPeakTolerance()
process inputs about fitted peak positions' tolerance
Definition: FitPeaks.cpp:771
void writeFitResult(size_t wi, const std::vector< double > &expected_positions, const std::shared_ptr< FitPeaksAlgorithm::PeakFitResult > &fit_result)
Write result of peak fit per spectrum to output analysis workspaces.
Definition: FitPeaks.cpp:1975
size_t m_stopWorkspaceIndex
stop index (workspace index of the last spectrum included)
Definition: FitPeaks.h:241
void exec() override
Main exec method.
Definition: FitPeaks.cpp:448
void init() override
Init.
Definition: FitPeaks.cpp:204
std::vector< std::string > m_peakParamNames
input peak parameters' names
Definition: FitPeaks.h:260
bool isObservablePeakProfile(const std::string &peakprofile)
check whether FitPeaks supports observation on a certain peak profile's parameters (width!...
Definition: FitPeaks.cpp:1379
void processInputFitRanges()
process inputs for peak fitting range
Definition: FitPeaks.cpp:595
API::MatrixWorkspace_sptr createMatrixWorkspace(const std::vector< double > &vec_x, const std::vector< double > &vec_y, const std::vector< double > &vec_e)
Create a single spectrum workspace for fitting.
Definition: FitPeaks.cpp:1657
void generateOutputPeakPositionWS()
main method to create output workspaces
Definition: FitPeaks.cpp:1682
void generateCalculatedPeaksWS()
Generate workspace for calculated values.
Definition: FitPeaks.cpp:1782
double fitFunctionMD(API::IFunction_sptr fit_function, const API::MatrixWorkspace_sptr &dataws, const size_t wsindex, const std::pair< double, double > &vec_xmin, const std::pair< double, double > &vec_xmax)
Definition: FitPeaks.cpp:1555
std::string getPeakHeightParameterName(const API::IPeakFunction_const_sptr &peak_function)
Get the parameter name for peak height (I or height or etc)
Definition: FitPeaks.cpp:2077
const std::string name() const override
Algorithm's name.
Definition: FitPeaks.h:70
void calculateFittedPeaks(std::vector< std::shared_ptr< FitPeaksAlgorithm::PeakFitResult > > fit_results)
calculate peak+background for fitted
Definition: FitPeaks.cpp:1272
API::ITableWorkspace_sptr m_fittedParamTable
output analysis workspaces table workspace for fitted parameters
Definition: FitPeaks.h:196
bool decideToEstimatePeakParams(const bool firstPeakInSpectrum, const API::IPeakFunction_sptr &peak_function)
Decide whether to estimate peak parameters.
Definition: FitPeaks.cpp:1118
void convertParametersNameToIndex()
Convert peak function's parameter names to parameter index for fast access.
Definition: FitPeaks.cpp:810
void processOutputs(std::vector< std::shared_ptr< FitPeaksAlgorithm::PeakFitResult > > fit_result_vec)
Set the workspaces and etc to output properties.
Definition: FitPeaks.cpp:1797
bool m_highBackground
flag for high background
Definition: FitPeaks.h:275
std::vector< double > m_initParamValues
input peak parameters' starting values corresponding to above peak parameter names
Definition: FitPeaks.h:263
std::vector< double > m_peakCenters
Designed peak positions and tolerance.
Definition: FitPeaks.h:229
void reduceByBackground(const API::IBackgroundFunction_sptr &bkgd_func, const std::vector< double > &vec_x, std::vector< double > &vec_y)
Reduce background.
Definition: FitPeaks.cpp:1950
std::vector< std::vector< double > > m_peakWindowVector
peak windows
Definition: FitPeaks.h:252
void getRangeData(size_t iws, const std::pair< double, double > &fit_window, std::vector< double > &vec_x, std::vector< double > &vec_y, std::vector< double > &vec_e)
get vector X, Y and E in a given range
Definition: FitPeaks.cpp:1903
API::MatrixWorkspace_sptr m_inputMatrixWS
mandatory input and output workspaces
Definition: FitPeaks.h:188
std::pair< double, double > getPeakFitWindow(size_t wi, size_t ipeak)
get the peak fit window
Definition: FitPeaks.cpp:1848
std::vector< size_t > m_initParamIndexes
input starting parameters' indexes in peak function
Definition: FitPeaks.h:226
bool m_fitPeaksFromRight
Fit from right or left.
Definition: FitPeaks.h:220
bool m_rawPeaksTable
flag to show that the pamarameters in table are raw parameters or effective parameters
Definition: FitPeaks.h:201
void processInputs()
process inputs (main and child algorithms)
Definition: FitPeaks.cpp:469
int m_fitIterations
Fit iterations.
Definition: FitPeaks.h:222
API::MatrixWorkspace_const_sptr m_peakWindowWorkspace
Definition: FitPeaks.h:253
bool m_uniformProfileStartingValue
flag for profile startng value being uniform or not
Definition: FitPeaks.h:267
API::ITableWorkspace_sptr m_fitErrorTable
table workspace for fitted parameters' fitting error. This is optional
Definition: FitPeaks.h:198
bool m_partialSpectra
flag whether the peak center workspace has only a subset of spectra to fit
Definition: FitPeaks.h:243
bool processSinglePeakFitResult(size_t wsindex, size_t peakindex, const double cost, const std::vector< double > &expected_peak_positions, const FitPeaksAlgorithm::FitFunction &fitfunction, const std::shared_ptr< FitPeaksAlgorithm::PeakFitResult > &fit_result)
Process the result from fitting a single peak.
Definition: FitPeaks.cpp:1158
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
Exception for when an item is not found in a collection.
Definition: Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
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 report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
Definition: ProgressBase.h:51
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
StartsWithValidator is a validator that requires the value of a property to start with one of the str...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< IBackgroundFunction > IBackgroundFunction_sptr
std::shared_ptr< IPeakFunction > IPeakFunction_sptr
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< const IPeakFunction > IPeakFunction_const_sptr
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
MANTID_ALGORITHMS_DLL size_t findXIndex(const vector_like &vecx, const double x, const size_t startindex=0)
Get an index of a value in a sorted vector.
MANTID_ALGORITHMS_DLL int estimatePeakParameters(const HistogramData::Histogram &histogram, const std::pair< size_t, size_t > &peak_window, const API::IPeakFunction_sptr &peakfunction, const API::IBackgroundFunction_sptr &bkgdfunction, bool observe_peak_width, const EstimatePeakWidth peakWidthEstimateApproach, const double peakWidthPercentage, const double minPeakHeight)
Estimate peak parameters by 'observation'.
std::shared_ptr< IValidator > IValidator_sptr
A shared_ptr to an IValidator.
Definition: IValidator.h:26
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
Definition: MultiThreaded.h:22
Helper class which provides the Collimation Length for SANS instruments.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
STL namespace.
API::IBackgroundFunction_sptr bkgdfunction
Definition: FitPeaks.h:35
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54