Mantid
Loading...
Searching...
No Matches
ProcessBackground.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 +
8#include "MantidAPI/Axis.h"
10#include "MantidAPI/TableRow.h"
20
21#include <algorithm>
22#include <boost/algorithm/string.hpp>
23#include <boost/algorithm/string/predicate.hpp>
24#include <boost/algorithm/string/split.hpp>
25#include <utility>
26
27using namespace Mantid;
28
29using namespace Mantid::API;
30
31using namespace Mantid::Kernel;
32
33using namespace Mantid::DataObjects;
34
35using namespace Mantid::CurveFitting;
36
37using namespace HistogramData;
38
39using namespace std;
40
42
43using namespace CurveFitting;
44
46
47//----------------------------------------------------------------------------------------------
51 : m_dataWS(), m_outputWS(), m_wsIndex(-1), m_lowerBound(DBL_MAX), m_upperBound(DBL_MIN), m_bkgdType(),
52 m_numFWHM(-1.) {}
53
54//----------------------------------------------------------------------------------------------
58 // Input and output Workspace
59 declareProperty(std::make_unique<WorkspaceProperty<Workspace2D>>("InputWorkspace", "Anonymous", Direction::Input),
60 "Name of the output workspace containing the processed background.");
61
62 // Workspace index
63 declareProperty("WorkspaceIndex", 0, "Workspace index for the input workspaces.");
64
65 // Output workspace
66 declareProperty(std::make_unique<WorkspaceProperty<Workspace2D>>("OutputWorkspace", "", Direction::Output),
67 "Output workspace containing processed background");
68
69 // Function Options
70 std::vector<std::string> options{"SelectBackgroundPoints", "RemovePeaks", "DeleteRegion", "AddRegion"};
71
72 auto validator = std::make_shared<Kernel::StringListValidator>(options);
73 declareProperty("Options", "RemovePeaks", validator, "Name of the functionality realized by this algorithm.");
74
75 // Boundary
76 declareProperty("LowerBound", Mantid::EMPTY_DBL(), "Lower boundary of the data to have background processed.");
77 declareProperty("UpperBound", Mantid::EMPTY_DBL(), "Upper boundary of the data to have background processed.");
78
79 auto refwsprop = std::make_unique<WorkspaceProperty<Workspace2D>>("ReferenceWorkspace", "", Direction::Input,
81 declareProperty(std::move(refwsprop), "Name of the workspace containing the data "
82 "required by function AddRegion.");
83 setPropertySettings("ReferenceWorkspace", std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "AddRegion"));
84
85 // Optional Function Type
86 std::vector<std::string> bkgdtype{"Polynomial", "Chebyshev"};
87 auto bkgdvalidator = std::make_shared<Kernel::StringListValidator>(bkgdtype);
88 declareProperty("BackgroundType", "Polynomial", bkgdvalidator,
89 "Type of the background. Options include Polynomial and Chebyshev.");
90 setPropertySettings("BackgroundType",
91 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
92
93 vector<string> funcoptions{"N/A", "FitGivenDataPoints", "UserFunction"};
94 auto fovalidator = std::make_shared<StringListValidator>(funcoptions);
95 declareProperty("SelectionMode", "N/A", fovalidator,
96 "If choise is UserFunction, background will be selected by "
97 "an input background "
98 "function. Otherwise, background function will be fitted "
99 "from user's input data points.");
100 setPropertySettings("SelectionMode",
101 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
102
103 declareProperty("BackgroundOrder", 0, "Order of polynomial or chebyshev background. ");
104 setPropertySettings("BackgroundOrder",
105 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
106 setPropertySettings("BackgroundOrder",
107 std::make_unique<VisibleWhenProperty>("SelectionMode", IS_EQUAL_TO, "FitGivenDataPoints"));
108
109 // User input background points for "SelectBackground"
110 auto arrayproperty = std::make_unique<Kernel::ArrayProperty<double>>("BackgroundPoints");
111 declareProperty(std::move(arrayproperty), "Vector of doubles, each of which is the "
112 "X-axis value of the background point "
113 "selected by user.");
114 setPropertySettings("BackgroundPoints",
115 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
116 setPropertySettings("BackgroundPoints",
117 std::make_unique<VisibleWhenProperty>("SelectionMode", IS_EQUAL_TO, "FitGivenDataPoints"));
118
119 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("BackgroundTableWorkspace", "", Direction::Input,
121 "Name of the table workspace containing background "
122 "parameters for mode SelectBackgroundPoints.");
123 setPropertySettings("BackgroundTableWorkspace",
124 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
125 setPropertySettings("BackgroundTableWorkspace",
126 std::make_unique<VisibleWhenProperty>("SelectionMode", IS_EQUAL_TO, "UserFunction"));
127
128 // Mode to select background
129 vector<string> pointsselectmode{"All Background Points", "Input Background Points Only"};
130 auto modevalidator = std::make_shared<StringListValidator>(pointsselectmode);
131 declareProperty("BackgroundPointSelectMode", "All Background Points", modevalidator,
132 "Mode to select background points. ");
133 setPropertySettings("BackgroundPointSelectMode",
134 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
135 setPropertySettings("BackgroundPointSelectMode",
136 std::make_unique<VisibleWhenProperty>("SelectionMode", IS_EQUAL_TO, "FitGivenDataPoints"));
137
138 // Background tolerance
139 declareProperty("NoiseTolerance", 1.0, "Tolerance of noise range. ");
140 setPropertySettings("NoiseTolerance",
141 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
142
143 // Background tolerance
144 declareProperty("NegativeNoiseTolerance", EMPTY_DBL(), "Tolerance of noise range for negative number. ");
145 setPropertySettings("NegativeNoiseTolerance",
146 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
147
148 // Optional output workspace
150 std::make_unique<WorkspaceProperty<Workspace2D>>("UserBackgroundWorkspace", "_dummy01", Direction::Output),
151 "Output workspace containing fitted background from points "
152 "specified by users.");
153 setPropertySettings("UserBackgroundWorkspace",
154 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
155
156 // Optional output workspace
157 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("OutputBackgroundParameterWorkspace", "_dummy02",
159 "Output parameter table workspace containing the background fitting "
160 "result. ");
161 setPropertySettings("OutputBackgroundParameterWorkspace",
162 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
163
164 // Output background type.
165 std::vector<std::string> outbkgdtype{"Polynomial", "Chebyshev"};
166 auto outbkgdvalidator = std::make_shared<Kernel::StringListValidator>(outbkgdtype);
167 declareProperty("OutputBackgroundType", "Polynomial", outbkgdvalidator,
168 "Type of background to fit with selected background points.");
169 setPropertySettings("OutputBackgroundType",
170 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
171
172 // Output background type.
173 declareProperty("OutputBackgroundOrder", 6, "Order of background to fit with selected background points.");
174 setPropertySettings("OutputBackgroundOrder",
175 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "SelectBackgroundPoints"));
176
177 // Peak table workspac for "RemovePeaks"
178 declareProperty(std::make_unique<WorkspaceProperty<TableWorkspace>>("BraggPeakTableWorkspace", "", Direction::Input,
180 "Name of table workspace containing peaks' parameters. ");
181 setPropertySettings("BraggPeakTableWorkspace",
182 std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "RemovePeaks"));
183
184 // Number of FWHM to have peak removed
185 declareProperty("NumberOfFWHM", 1.0, "Number of FWHM to as the peak region to have peak removed. ");
186 setPropertySettings("NumberOfFWHM", std::make_unique<VisibleWhenProperty>("Options", IS_EQUAL_TO, "RemovePeaks"));
187}
188
189//----------------------------------------------------------------------------------------------
193 // Process general properties
194 m_dataWS = this->getProperty("InputWorkspace");
195 if (!m_dataWS) {
196 g_log.error() << "Input Workspace cannot be obtained.\n";
197 throw std::invalid_argument("Input Workspace cannot be obtained.");
198 }
199
200 m_bkgdType = getPropertyValue("BackgroundType");
201
202 int intemp = getProperty("WorkspaceIndex");
203 if (intemp < 0)
204 throw std::invalid_argument("WorkspaceIndex is not allowed to be less than 0. ");
205 m_wsIndex = intemp;
206 if (m_wsIndex >= static_cast<int>(m_dataWS->getNumberHistograms()))
207 throw runtime_error("Workspace index is out of boundary.");
208
209 m_lowerBound = getProperty("LowerBound");
210 m_upperBound = getProperty("UpperBound");
212 m_lowerBound = m_dataWS->x(m_wsIndex).front();
214 m_upperBound = m_dataWS->x(m_wsIndex).back();
215
216 // 2. Do different work
217 std::string option = getProperty("Options");
218 if (option == "RemovePeaks") {
219 removePeaks();
220 } else if (option == "DeleteRegion") {
221 deleteRegion();
222 } else if (option == "AddRegion") {
223 addRegion();
224 } else if (option == "SelectBackgroundPoints") {
225
227 } else {
228 g_log.error() << "Option " << option << " is not supported. \n";
229 throw std::invalid_argument("Unsupported option. ");
230 }
231
232 // 3. Set output
233 setProperty("OutputWorkspace", m_outputWS);
234}
235
236//----------------------------------------------------------------------------------------------
240 // Dummy outputs to make it work with python script
241 setPropertyValue("UserBackgroundWorkspace", "dummy0");
242 Workspace2D_sptr dummyws =
243 std::dynamic_pointer_cast<Workspace2D>(WorkspaceFactory::Instance().create("Workspace2D", 1, 1, 1));
244 setProperty("UserBackgroundWorkspace", dummyws);
245
246 setPropertyValue("OutputBackgroundParameterWorkspace", "dummy1");
247 TableWorkspace_sptr dummytbws = std::make_shared<TableWorkspace>();
248 setProperty("OutputBackgroundParameterWorkspace", dummytbws);
249}
250
251//----------------------------------------------------------------------------------------------
255 // Check boundary
257 throw std::invalid_argument("Using DeleteRegion. Both LowerBound and "
258 "UpperBound must be specified.");
259 }
260 if (m_lowerBound >= m_upperBound) {
261 throw std::invalid_argument("Lower boundary cannot be equal or larger than upper boundary.");
262 }
263
264 const auto &dataX = m_dataWS->x(0);
265 const auto &dataY = m_dataWS->y(0);
266 const auto &dataE = m_dataWS->e(0);
267
268 // Find the dimensions of the region excluded by m_lowerBound and m_upperBound
269 std::vector<size_t> incIndexes;
270 for (size_t i = 0; i < dataY.size(); i++) {
271 if (dataX[i] < m_lowerBound || dataX[i] > m_upperBound) {
272 incIndexes.emplace_back(i);
273 }
274 }
275 size_t sizex = incIndexes.size();
276 size_t sizey = sizex;
277 if (dataX.size() > dataY.size()) {
278 sizex++;
279 }
280
281 // Create a new workspace with these dimensions and copy data from the defined
282 // region
283 API::MatrixWorkspace_sptr mws = API::WorkspaceFactory::Instance().create("Workspace2D", 1, sizex, sizey);
284 m_outputWS = std::dynamic_pointer_cast<DataObjects::Workspace2D>(mws);
285 m_outputWS->getAxis(0)->setUnit(m_dataWS->getAxis(0)->unit()->unitID());
286
287 for (size_t i = 0; i < sizey; i++) {
288 size_t index = incIndexes[i];
289 m_outputWS->mutableX(0)[i] = dataX[index];
290 m_outputWS->mutableY(0)[i] = dataY[index];
291 m_outputWS->mutableE(0)[i] = dataE[index];
292 }
293 if (sizex > sizey) {
294 m_outputWS->mutableX(0)[sizex - 1] = dataX.back();
295 }
296
297 // Set up dummies
299}
300
301//----------------------------------------------------------------------------------------------
305 // Check boundary, which are required
307 throw std::invalid_argument("Using AddRegion. Both LowerBound and UpperBound must be specified.");
308 }
309 if (m_lowerBound >= m_upperBound) {
310 throw std::invalid_argument("Lower boundary cannot be equal or larger than upper boundary.");
311 }
312
313 // Copy data to a set of vectors
314 const auto &vecX = m_dataWS->x(0);
315 const auto &vecY = m_dataWS->y(0);
316 const auto &vecE = m_dataWS->e(0);
317
318 std::vector<double> vx, vy, ve;
319 for (size_t i = 0; i < vecY.size(); ++i) {
320 double xtmp = vecX[i];
321 if (xtmp < m_lowerBound || xtmp > m_upperBound) {
322 vx.emplace_back(vecX[i]);
323 vy.emplace_back(vecY[i]);
324 ve.emplace_back(vecE[i]);
325 }
326 }
327
328 // Histogram
329 if (vecX.size() > vecY.size())
330 vx.emplace_back(vecX.back());
331
332 // Get access to reference workspace
333 DataObjects::Workspace2D_const_sptr refWS = getProperty("ReferenceWorkspace");
334 if (!refWS)
335 throw std::invalid_argument("ReferenceWorkspace is not given. ");
336
337 const auto &refX = refWS->x(0);
338 const auto &refY = refWS->y(0);
339 const auto &refE = refWS->e(0);
340
341 // 4. Insert the value of the reference workspace from lowerBoundary to
342 // upperBoundary
343 std::vector<double>::const_iterator refiter;
344 refiter = std::lower_bound(refX.begin(), refX.end(), m_lowerBound);
345 size_t sindex = size_t(refiter - refX.begin());
346 refiter = std::lower_bound(refX.begin(), refX.end(), m_upperBound);
347 size_t eindex = size_t(refiter - refX.begin());
348
349 for (size_t i = sindex; i < eindex; ++i) {
350 const double tmpx = refX[i];
351 const double tmpy = refY[i];
352 const double tmpe = refE[i];
353
354 // Locate the position of tmpx in the array to be inserted
355 auto newit = std::lower_bound(vx.begin(), vx.end(), tmpx);
356 size_t newindex = size_t(newit - vx.begin());
357
358 // insert tmpx, tmpy, tmpe by iterator
359 vx.insert(newit, tmpx);
360
361 newit = vy.begin() + newindex;
362 vy.insert(newit, tmpy);
363
364 newit = ve.begin() + newindex;
365 ve.insert(newit, tmpe);
366 }
367
368 // Check
369 const auto it = std::adjacent_find(vx.cbegin(), vx.cend(), std::greater_equal<double>());
370 if (it != vx.cend()) {
371 g_log.error() << "The vector X with value inserted is not ordered incrementally" << std::endl;
372 throw std::runtime_error("Build new vector error!");
373 }
374
375 // Construct the new Workspace
376 m_outputWS = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
377 API::WorkspaceFactory::Instance().create("Workspace2D", 1, vx.size(), vy.size()));
378 m_outputWS->getAxis(0)->setUnit(m_dataWS->getAxis(0)->unit()->unitID());
379 m_outputWS->setHistogram(0, Histogram(Points(vx), Counts(vy), CountStandardDeviations(ve)));
380
381 // Write out dummy output workspaces
383}
384
385//----------------------------------------------------------------------------------------------
386// Methods for selecting background points
387//----------------------------------------------------------------------------------------------
388
389//----------------------------------------------------------------------------------------------
393 // Select background points
394 string smode = getProperty("SelectionMode");
395 if (smode == "FitGivenDataPoints") {
397 } else if (smode == "UserFunction") {
399 } else {
400 throw runtime_error("N/A is not supported.");
401 }
402
403 // Fit the background points if output backgrond parameter workspace is given
404 // explicitly
405 string outbkgdparwsname = getPropertyValue("OutputBackgroundParameterWorkspace");
406 if (!outbkgdparwsname.empty() && outbkgdparwsname != "_dummy02") {
407 // Will fit the selected background
408 string bkgdfunctype = getPropertyValue("OutputBackgroundType");
409 fitBackgroundFunction(bkgdfunctype);
410 } else {
412 }
413
414 m_outputWS->getAxis(0)->setUnit(m_dataWS->getAxis(0)->unit()->unitID());
415}
416
417//----------------------------------------------------------------------------------------------
421 // Get special input properties
422 std::vector<double> bkgdpoints = getProperty("BackgroundPoints");
423 string mode = getProperty("BackgroundPointSelectMode");
424
425 // Construct background workspace for fit
426 std::vector<size_t> realIndexes;
427 const auto &vecX = m_dataWS->x(m_wsIndex);
428 const auto &vecY = m_dataWS->y(m_wsIndex);
429 const auto &vecE = m_dataWS->e(m_wsIndex);
430 for (size_t i = 0; i < bkgdpoints.size(); ++i) {
431 // Data range validation
432 double bkgdpoint = bkgdpoints[i];
433 if (bkgdpoint < vecX.front()) {
434 g_log.warning() << "Input background point " << bkgdpoint << " is out of lower boundary. "
435 << "Use X[0] = " << vecX.front() << " instead."
436 << "\n";
437 bkgdpoint = vecX.front();
438 } else if (bkgdpoint > vecX.back()) {
439 g_log.warning() << "Input background point " << bkgdpoint
440 << " is out of upper boundary. Use X[-1] = " << vecX.back() << " instead."
441 << "\n";
442 bkgdpoint = vecX.back();
443 }
444
445 // Find the index in
446 std::vector<double>::const_iterator it;
447 it = std::lower_bound(vecX.begin(), vecX.end(), bkgdpoint);
448 size_t index = size_t(it - vecX.begin());
449
450 g_log.debug() << "DBx502 Background Points " << i << " Index = " << index << " For TOF = " << bkgdpoints[i]
451 << " in [" << vecX[0] << ", " << vecX.back() << "] "
452 << "\n";
453
454 // Add index to list
455 realIndexes.emplace_back(index);
456
457 } // ENDFOR (i)
458
459 size_t wsSize = realIndexes.size();
460 DataObjects::Workspace2D_sptr bkgdWS = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
461 API::WorkspaceFactory::Instance().create("Workspace2D", 1, wsSize, wsSize));
462 for (size_t i = 0; i < wsSize; ++i) {
463 size_t index = realIndexes[i];
464 bkgdWS->mutableX(0)[i] = vecX[index];
465 bkgdWS->mutableY(0)[i] = vecY[index];
466 bkgdWS->mutableE(0)[i] = vecE[index];
467 }
468
469 // Select background points according to mode
470 if (mode == "All Background Points") {
471 // Select (possibly) all background points
473 } else if (mode == "Input Background Points Only") {
474 // Use the input background points only
475 m_outputWS = bkgdWS;
476 } else {
477 stringstream errss;
478 errss << "Background select mode " << mode << " is not supported by ProcessBackground.";
479 g_log.error(errss.str());
480 throw runtime_error(errss.str());
481 }
482}
483
484//----------------------------------------------------------------------------------------------
488 // Process properties
490 TableWorkspace_sptr bkgdtablews = getProperty("BackgroundTableWorkspace");
491
492 // Set up background function from table
493 size_t numrows = bkgdtablews->rowCount();
494 map<string, double> parmap;
495 for (size_t i = 0; i < numrows; ++i) {
496 TableRow row = bkgdtablews->getRow(i);
497 string parname;
498 double parvalue;
499 row >> parname >> parvalue;
500 if (parname[0] == 'A')
501 parmap.emplace(parname, parvalue);
502 }
503
504 auto bkgdorder = static_cast<int>(parmap.size() - 1); // A0 - A(n) total n+1 parameters
505 bkgdfunc->setAttributeValue("n", bkgdorder);
506 for (const auto &mit : parmap) {
507 string parname = mit.first;
508 double parvalue = mit.second;
509 bkgdfunc->setParameter(parname, parvalue);
510 }
511
512 // Filter out
514}
515
516//----------------------------------------------------------------------------------------------
520 // Get background type and create bakground function
522
523 int bkgdorder = getProperty("BackgroundOrder");
524 if (bkgdorder == 0)
525 g_log.warning("(Input) background function order is 0. It might not be "
526 "able to give a good estimation.");
527
528 bkgdfunction->setAttributeValue("n", bkgdorder);
529 bkgdfunction->initialize();
530
531 g_log.information() << "Input background points has " << bkgdWS->x(0).size() << " data points for fit " << bkgdorder
532 << "-th order " << bkgdfunction->name() << " (background) function" << bkgdfunction->asString()
533 << "\n";
534
535 // Fit input (a few) background pionts to get initial guess
537 try {
538 fit = this->createChildAlgorithm("Fit", 0.0, 0.2, true);
539 } catch (Exception::NotFoundError &) {
540 g_log.error() << "Requires CurveFitting library.\n";
541 throw;
542 }
543
544 double startx = m_lowerBound;
545 double endx = m_upperBound;
546 fit->setProperty("Function", std::dynamic_pointer_cast<API::IFunction>(bkgdfunction));
547 fit->setProperty("InputWorkspace", bkgdWS);
548 fit->setProperty("WorkspaceIndex", 0);
549 fit->setProperty("MaxIterations", 500);
550 fit->setProperty("StartX", startx);
551 fit->setProperty("EndX", endx);
552 fit->setProperty("Minimizer", "Levenberg-Marquardt");
553 fit->setProperty("CostFunction", "Least squares");
554
555 fit->executeAsChildAlg();
556
557 // Get fit result
558 // a) Status
559 std::string fitStatus = fit->getProperty("OutputStatus");
560 bool allowedfailure = (fitStatus.find("Changes") < fitStatus.size()) && (fitStatus.find("small") < fitStatus.size());
561 if (fitStatus != "success" && !allowedfailure) {
562 g_log.error() << "ProcessBackground: Fit Status = " << fitStatus << ". Not to update fit result\n";
563 throw std::runtime_error("Bad Fit " + fitStatus);
564 }
565
566 // b) check that chi2 got better
567 const double chi2 = fit->getProperty("OutputChi2overDoF");
568 g_log.information() << "Fit background: Fit Status = " << fitStatus << ", chi2 = " << chi2 << "\n";
569
570 // Filter and construct for the output workspace
571 Workspace2D_sptr outws = filterForBackground(bkgdfunction);
572
573 return outws;
574} // END OF FUNCTION
575
576//----------------------------------------------------------------------------------------------
581
582 if (backgroundtype == "Polynomial") {
583 bkgdfunction = std::dynamic_pointer_cast<Functions::BackgroundFunction>(std::make_shared<Functions::Polynomial>());
584 bkgdfunction->initialize();
585 } else if (backgroundtype == "Chebyshev") {
586 Chebyshev_sptr cheby = std::make_shared<Functions::Chebyshev>();
587 bkgdfunction = std::dynamic_pointer_cast<Functions::BackgroundFunction>(cheby);
588 bkgdfunction->initialize();
589
590 g_log.debug() << "[D] Chebyshev is set to range " << m_lowerBound << ", " << m_upperBound << "\n";
591 bkgdfunction->setAttributeValue("StartX", m_lowerBound);
592 bkgdfunction->setAttributeValue("EndX", m_upperBound);
593 } else {
594 stringstream errss;
595 errss << "Background of type " << backgroundtype << " is not supported. ";
596 g_log.error(errss.str());
597 throw std::invalid_argument(errss.str());
598 }
599
600 return bkgdfunction;
601}
602
603//----------------------------------------------------------------------------------------------
607 double posnoisetolerance = getProperty("NoiseTolerance");
608 double negnoisetolerance = getProperty("NegativeNoiseTolerance");
609 if (isEmpty(negnoisetolerance))
610 negnoisetolerance = posnoisetolerance;
611
612 // Calcualte theoretical values
613 const auto &x = m_dataWS->x(m_wsIndex);
614 API::FunctionDomain1DVector domain(x.rawData());
615 API::FunctionValues values(domain);
616 bkgdfunction->function(domain, values);
617
618 g_log.information() << "Function used to select background points : " << bkgdfunction->asString() << "\n";
619
620 // Optional output
621 string userbkgdwsname = getPropertyValue("UserBackgroundWorkspace");
622 if (userbkgdwsname.empty())
623 throw runtime_error("In mode SelectBackgroundPoints, "
624 "UserBackgroundWorkspace must be given!");
625
626 size_t sizex = domain.size();
627 size_t sizey = values.size();
628 MatrixWorkspace_sptr visualws =
629 std::dynamic_pointer_cast<MatrixWorkspace>(WorkspaceFactory::Instance().create("Workspace2D", 4, sizex, sizey));
630 for (size_t i = 0; i < sizex; ++i) {
631 for (size_t j = 0; j < 4; ++j) {
632 visualws->mutableX(j)[i] = domain[i];
633 }
634 }
635 for (size_t i = 0; i < sizey; ++i) {
636 visualws->mutableY(0)[i] = values[i];
637 visualws->mutableY(1)[i] = m_dataWS->y(m_wsIndex)[i] - values[i];
638 visualws->mutableY(2)[i] = posnoisetolerance;
639 visualws->mutableY(3)[i] = -negnoisetolerance;
640 }
641 setProperty("UserBackgroundWorkspace", visualws);
642
643 // Filter for background
644 std::vector<size_t> selectedIndexes;
645 for (size_t i = 0; i < domain.size(); ++i) {
646 double purey = visualws->y(1)[i];
647 if (purey < posnoisetolerance && purey > -negnoisetolerance) {
648 selectedIndexes.emplace_back(i);
649 }
650 }
651 size_t wsSize = selectedIndexes.size();
652 g_log.information() << "Found " << wsSize << " background points out of " << m_dataWS->x(m_wsIndex).size()
653 << " total data points. "
654 << "\n";
655
656 // Build new workspace for OutputWorkspace
657 size_t nspec = 3;
658 Workspace2D_sptr outws = std::dynamic_pointer_cast<DataObjects::Workspace2D>(
659 API::WorkspaceFactory::Instance().create("Workspace2D", nspec, wsSize, wsSize));
660 for (size_t i = 0; i < wsSize; ++i) {
661 size_t index = selectedIndexes[i];
662 for (size_t j = 0; j < nspec; ++j)
663 outws->mutableX(j)[i] = domain[index];
664 outws->mutableY(0)[i] = m_dataWS->y(m_wsIndex)[index];
665 outws->mutableE(0)[i] = m_dataWS->e(m_wsIndex)[index];
666 }
667
668 return outws;
669}
670
671//----------------------------------------------------------------------------------------------
674void ProcessBackground::fitBackgroundFunction(const std::string &bkgdfunctiontype) {
675 // Get background type and create bakground function
676 BackgroundFunction_sptr bkgdfunction = createBackgroundFunction(bkgdfunctiontype);
677
678 int bkgdorder = getProperty("OutputBackgroundOrder");
679 bkgdfunction->setAttributeValue("n", bkgdorder);
680
681 if (bkgdfunctiontype == "Chebyshev") {
682 double xmin = m_outputWS->x(0).front();
683 double xmax = m_outputWS->x(0).back();
684 g_log.information() << "Chebyshev Fit range: " << xmin << ", " << xmax << "\n";
685 bkgdfunction->setAttributeValue("StartX", xmin);
686 bkgdfunction->setAttributeValue("EndX", xmax);
687 }
688
689 g_log.information() << "Fit selected background " << bkgdfunctiontype << " to data workspace with "
690 << m_outputWS->getNumberHistograms() << " spectra."
691 << "\n";
692
693 // Fit input (a few) background pionts to get initial guess
695 try {
696 fit = this->createChildAlgorithm("Fit", 0.9, 1.0, true);
697 } catch (Exception::NotFoundError &) {
698 g_log.error() << "Requires CurveFitting library.\n";
699 throw;
700 }
701
702 g_log.information() << "Fitting background function: " << bkgdfunction->asString() << "\n";
703
704 double startx = m_lowerBound;
705 double endx = m_upperBound;
706 fit->setProperty("Function", std::dynamic_pointer_cast<API::IFunction>(bkgdfunction));
707 fit->setProperty("InputWorkspace", m_outputWS);
708 fit->setProperty("WorkspaceIndex", 0);
709 fit->setProperty("MaxIterations", 500);
710 fit->setProperty("StartX", startx);
711 fit->setProperty("EndX", endx);
712 fit->setProperty("Minimizer", "Levenberg-MarquardtMD");
713 fit->setProperty("CostFunction", "Least squares");
714
715 fit->executeAsChildAlg();
716
717 // Get fit status and chi^2
718 std::string fitStatus = fit->getProperty("OutputStatus");
719 bool allowedfailure = (fitStatus.find("Changes") < fitStatus.size()) && (fitStatus.find("small") < fitStatus.size());
720 if (fitStatus != "success" && !allowedfailure) {
721 g_log.error() << "ProcessBackground: Fit Status = " << fitStatus << ". Not to update fit result\n";
722 throw std::runtime_error("Bad Fit " + fitStatus);
723 }
724
725 const double chi2 = fit->getProperty("OutputChi2overDoF");
726 g_log.information() << "Fit background: Fit Status = " << fitStatus << ", chi2 = " << chi2 << "\n";
727
728 // Get out the parameter names
729 API::IFunction_sptr funcout = fit->getProperty("Function");
730 TableWorkspace_sptr outbkgdparws = std::make_shared<TableWorkspace>();
731 outbkgdparws->addColumn("str", "Name");
732 outbkgdparws->addColumn("double", "Value");
733
734 TableRow typerow = outbkgdparws->appendRow();
735 typerow << bkgdfunctiontype << 0.;
736
737 vector<string> parnames = funcout->getParameterNames();
738 size_t nparam = funcout->nParams();
739 for (size_t i = 0; i < nparam; ++i) {
740 TableRow newrow = outbkgdparws->appendRow();
741 newrow << parnames[i] << funcout->getParameter(i);
742 }
743
744 TableRow chi2row = outbkgdparws->appendRow();
745 chi2row << "Chi-square" << chi2;
746
747 g_log.information() << "Set table workspace (#row = " << outbkgdparws->rowCount()
748 << ") to OutputBackgroundParameterTable. "
749 << "\n";
750 setProperty("OutputBackgroundParameterWorkspace", outbkgdparws);
751
752 // Set output workspace
753 const auto &vecX = m_outputWS->x(0);
754 const auto &vecY = m_outputWS->y(0);
755 FunctionDomain1DVector domain(vecX.rawData());
756 FunctionValues values(domain);
757
758 funcout->function(domain, values);
759
760 auto &dataModel = m_outputWS->mutableY(1);
761 auto &dataDiff = m_outputWS->mutableY(2);
762 for (size_t i = 0; i < dataModel.size(); ++i) {
763 dataModel[i] = values[i];
764 dataDiff[i] = vecY[i] - dataModel[i];
765 }
766}
767
768//----------------------------------------------------------------------------------------------
769// Remove peaks
770//----------------------------------------------------------------------------------------------
771
772//----------------------------------------------------------------------------------------------
776 // Get input
777 TableWorkspace_sptr peaktablews = getProperty("BraggPeakTableWorkspace");
778 if (!peaktablews)
779 throw runtime_error("Option RemovePeaks requires input to BgraggPeaTablekWorkspace.");
780
781 m_numFWHM = getProperty("NumberOfFWHM");
782 if (m_numFWHM <= 0.)
783 throw runtime_error("NumberOfFWHM must be larger than 0. ");
784
785 // Remove peaks
786 RemovePeaks remove;
787 remove.setup(peaktablews);
789
790 // Dummy outputs
792}
793
794//----------------------------------------------------------------------------------------------
797void RemovePeaks::setup(const TableWorkspace_sptr &peaktablews) {
798 // Parse table workspace
800
801 // Check
802 if (m_vecPeakCentre.size() != m_vecPeakFWHM.size())
803 throw runtime_error("Number of peak centres and FWHMs are different!");
804 else if (m_vecPeakCentre.empty())
805 throw runtime_error("There is not any peak entry in input table workspace.");
806}
807
808//----------------------------------------------------------------------------------------------
812 // Check
813 if (m_vecPeakCentre.empty())
814 throw runtime_error("RemovePeaks has not been setup yet. ");
815
816 // Initialize vectors
817 const auto &vecX = dataws->x(wsindex);
818 const auto &vecY = dataws->y(wsindex);
819 const auto &vecE = dataws->e(wsindex);
820
821 size_t sizex = vecX.size();
822 vector<bool> vec_useX(sizex, true);
823
824 // Exclude regions
825 size_t numbkgdpoints = excludePeaks(vecX.rawData(), vec_useX, m_vecPeakCentre, m_vecPeakFWHM, numfwhm);
826 size_t numbkgdpointsy = numbkgdpoints;
827 size_t sizey = vecY.size();
828 if (sizex > sizey)
829 --numbkgdpointsy;
830
831 // Construct output workspace
832 Workspace2D_sptr outws = std::dynamic_pointer_cast<Workspace2D>(
833 WorkspaceFactory::Instance().create("Workspace2D", 1, numbkgdpoints, numbkgdpointsy));
834 outws->getAxis(0)->setUnit(dataws->getAxis(0)->unit()->unitID());
835 auto &outX = outws->mutableX(0);
836 auto &outY = outws->mutableY(0);
837 auto &outE = outws->mutableE(0);
838 size_t index = 0;
839 for (size_t i = 0; i < sizex; ++i) {
840 if (vec_useX[i]) {
841 if (index >= numbkgdpoints)
842 throw runtime_error("Programming logic error (1)");
843 outX[index] = vecX[i];
844 ++index;
845 }
846 }
847 index = 0;
848 for (size_t i = 0; i < sizey; ++i) {
849 if (vec_useX[i]) {
850 if (index >= numbkgdpointsy)
851 throw runtime_error("Programming logic error (2)");
852 outY[index] = vecY[i];
853 outE[index] = vecE[i];
854 ++index;
855 }
856 }
857
858 return outws;
859}
860
861//----------------------------------------------------------------------------------------------
864void RemovePeaks::parsePeakTableWorkspace(const TableWorkspace_sptr &peaktablews, vector<double> &vec_peakcentre,
865 vector<double> &vec_peakfwhm) {
866 // Get peak table workspace information
867 vector<string> colnames = peaktablews->getColumnNames();
868 int index_centre = -1;
869 int index_fwhm = -1;
870 for (int i = 0; i < static_cast<int>(colnames.size()); ++i) {
871 string colname = colnames[i];
872 if (colname == "TOF_h")
873 index_centre = i;
874 else if (colname == "FWHM")
875 index_fwhm = i;
876 }
877
878 if (index_centre < 0 || index_fwhm < 0) {
879 throw runtime_error("Input Bragg peak table workspace does not have TOF_h and/or FWHM");
880 }
881
882 // Get values
883 size_t numrows = peaktablews->rowCount();
884 vec_peakcentre.resize(numrows, 0.);
885 vec_peakfwhm.resize(numrows, 0.);
886
887 for (size_t i = 0; i < numrows; ++i) {
888 double centre = peaktablews->cell<double>(i, index_centre);
889 double fwhm = peaktablews->cell<double>(i, index_fwhm);
890 vec_peakcentre[i] = centre;
891 vec_peakfwhm[i] = fwhm;
892 }
893}
894
895//----------------------------------------------------------------------------------------------
898size_t RemovePeaks::excludePeaks(vector<double> v_inX, vector<bool> &v_useX, const vector<double> &v_centre,
899 const vector<double> &v_fwhm, double num_fwhm) {
900 // Validate
901 if (v_centre.size() != v_fwhm.size())
902 throw runtime_error("Input different number of peak centres and fwhm.");
903 if (v_inX.size() != v_useX.size())
904 throw runtime_error("Input differetn number of vec X and flag X.");
905
906 // Flag peak regions
907 size_t numpeaks = v_centre.size();
908 for (size_t i = 0; i < numpeaks; ++i) {
909 // Define boundary
910 double centre = v_centre[i];
911 double fwhm = v_fwhm[i];
912 double xmin = centre - num_fwhm * fwhm;
913 double xmax = centre + num_fwhm * fwhm;
914
915 vector<double>::iterator viter;
916 int i_min, i_max;
917
918 // Locate index in v_inX
919 if (xmin <= v_inX.front())
920 i_min = 0;
921 else if (xmin >= v_inX.back())
922 i_min = static_cast<int>(v_inX.size()) - 1;
923 else {
924 viter = lower_bound(v_inX.begin(), v_inX.end(), xmin);
925 i_min = static_cast<int>(viter - v_inX.begin());
926 }
927
928 if (xmax <= v_inX.front())
929 i_max = 0;
930 else if (xmax >= v_inX.back())
931 i_max = static_cast<int>(v_inX.size()) - 1;
932 else {
933 viter = lower_bound(v_inX.begin(), v_inX.end(), xmax);
934 i_max = static_cast<int>(viter - v_inX.begin());
935 }
936
937 // Flag the excluded region
938 for (int excluded = i_min; excluded <= i_max; ++excluded)
939 v_useX[excluded] = false;
940 }
941
942 return std::count(v_useX.cbegin(), v_useX.cend(), true);
943}
944
945} // namespace Mantid::CurveFitting::Functions
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::map< DeltaEMode::Type, std::string > index
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
Kernel::Logger & g_log
Definition Algorithm.h:422
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
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.
size_t size() const override
Return the number of arguments in the domain.
A class to store values calculated by a function.
size_t size() const
Return the number of values.
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
ProcessBackground : Process background obtained from LeBailFit.
DataObjects::Workspace2D_sptr autoBackgroundSelection(const DataObjects::Workspace2D_sptr &bkgdWS)
Select background points automatically.
void fitBackgroundFunction(const std::string &bkgdfunctiontype)
Fit background function.
DataObjects::Workspace2D_const_sptr m_dataWS
void setupDummyOutputWSes()
Set up dummy output optional workspaces.
void removePeaks()
Remove peaks in a certain region.
void selectFromGivenFunction()
Select background points (main)
BackgroundFunction_sptr createBackgroundFunction(const std::string &backgroundtype)
Create a background function from input properties.
double m_numFWHM
Number of FWHM of range of peak to be removed.
DataObjects::Workspace2D_sptr filterForBackground(const BackgroundFunction_sptr &bkgdfunction)
Filter non-background data points out and create a background workspace.
void addRegion()
Add a certain region from a reference workspace.
void deleteRegion()
Remove a certain region from input workspace.
void selectFromGivenXValues()
Select background points (main)
void parsePeakTableWorkspace(const DataObjects::TableWorkspace_sptr &peaktablews, std::vector< double > &vec_peakcentre, std::vector< double > &vec_peakfwhm)
Parse peak centre and FWHM from a table workspace.
void setup(const DataObjects::TableWorkspace_sptr &peaktablews)
Set up: parse peak workspace to vectors.
size_t excludePeaks(std::vector< double > v_inX, std::vector< bool > &v_useX, const std::vector< double > &v_centre, const std::vector< double > &v_fwhm, double num_fwhm)
Exclude peak regions.
DataObjects::Workspace2D_sptr removePeaks(const API::MatrixWorkspace_const_sptr &dataws, int wsindex, double numfwhm)
Remove peaks from a input workspace.
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 setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
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:743
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< Chebyshev > Chebyshev_sptr
Definition Chebyshev.h:54
std::shared_ptr< BackgroundFunction > BackgroundFunction_sptr
std::shared_ptr< Workspace2D > Workspace2D_sptr
shared pointer to Mantid::DataObjects::Workspace2D
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< const Workspace2D > Workspace2D_const_sptr
shared pointer to Mantid::DataObjects::Workspace2D (const version)
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
Helper class which provides the Collimation Length for SANS instruments.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54