Mantid
Loading...
Searching...
No Matches
StripVanadiumPeaks.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"
14#include "MantidKernel/Unit.h"
16
17namespace Mantid::Algorithms {
18
19// Register the algorithm into the AlgorithmFactory
20DECLARE_ALGORITHM(StripVanadiumPeaks)
21
22using namespace Kernel;
23using namespace DataObjects;
24using namespace API;
25using namespace Kernel::VectorHelper;
26
28
30 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input),
31 "Name of the input workspace. If you use the default vanadium peak "
32 "positions are used, the workspace must be in units of d-spacing.");
33 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
34 "The name of the workspace to be created as the output of the "
35 "algorithm.\n"
36 "If the input workspace is an EventWorkspace, then the output must be "
37 "different (and will be made into a Workspace2D).");
38
39 auto min = std::make_shared<BoundedValidator<double>>();
40 min->setLower(1e-3);
41 // The estimated width of a peak in terms of number of channels
42 declareProperty("PeakWidthPercent", 1.0, min,
43 "The estimated peak width as a "
44 "percentage of the d-spacing "
45 "of the center of the peak.");
46
47 declareProperty("AlternativePeakPositions", "",
48 "Optional: enter a comma-separated list of the expected X-position of "
49 "the centre of the peaks. \n"
50 "Only peaks near these positions will be fitted.\n"
51 "If not entered, the default vanadium peak positions will be used.");
52
53 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
54 mustBePositive->setLower(0);
55 declareProperty("WorkspaceIndex", EMPTY_INT(), mustBePositive,
56 "If set, peaks will only be removed from this spectrum "
57 "(otherwise from all)");
58}
59
61 // Retrieve the input workspace
62 MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
63
64 // Check for trying to rewrite an EventWorkspace
65 EventWorkspace_sptr inputEvent = std::dynamic_pointer_cast<EventWorkspace>(inputWS);
66 MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
67 if (inputEvent && (inputWS == outputWS)) {
68 throw std::invalid_argument("Cannot strip vanadium peaks in-place for an EventWorkspace. Please "
69 "specify a different output workspace name, which will be a "
70 "Workspace2D copy of the input EventWorkspace.");
71 }
72
73 // If WorkspaceIndex has been set it must be valid
74 int singleIndex = getProperty("WorkspaceIndex");
75 bool singleSpectrum = !isEmpty(singleIndex);
76 if (singleSpectrum && singleIndex >= static_cast<int>(inputWS->getNumberHistograms())) {
77 g_log.error() << "The value of WorkspaceIndex provided (" << singleIndex
78 << ") is larger than the size of this workspace (" << inputWS->getNumberHistograms() << ")\n";
79 throw Kernel::Exception::IndexError(singleIndex, inputWS->getNumberHistograms() - 1,
80 "StripVanadiumPeaks WorkspaceIndex property");
81 }
82
83 // Create an output workspace - same size as input one
84 outputWS = WorkspaceFactory::Instance().create(inputWS);
85 // Copy the data over from the input to the output workspace
86 const auto nhists = static_cast<int>(inputWS->getNumberHistograms());
87 Progress progress(this, 0.0, 1.0, nhists * 2);
88
89 for (int k = 0; k < nhists; ++k) {
90 outputWS->setHistogram(k, inputWS->histogram(k));
91 progress.report();
92 }
93
94 // Get the peak center positions
95 std::string peakPositions = getPropertyValue("AlternativePeakPositions");
96 if (peakPositions.length() == 0) {
97 // Use the default Vanadium peak positions instead
98 peakPositions = "0.5044,0.5191,0.5350,0.5526,0.5936,0.6178,0.6453,0.6768,0."
99 "7134,0.7566,0.8089,0.8737,0.9571,1.0701,1.2356,1.5133,2."
100 "1401";
101 // Check for units
102 if (inputWS->getAxis(0)->unit()->unitID() != "dSpacing")
103 throw std::invalid_argument("Cannot strip using default Vanadium peak positions for an input "
104 "workspace whose units are not d-spacing. Convert to d-spacing or "
105 "specify your own alternative peak positions.");
106 }
107 std::vector<double> centers = Kernel::VectorHelper::splitStringIntoVector<double>(peakPositions);
108
109 // Get the width percentage
110 double widthPercent = getProperty("PeakWidthPercent");
111
112 for (int k = 0; k < nhists; ++k) {
113 if ((!singleSpectrum) || (singleIndex == k)) {
114 // Get the X and Y vectors
115 const auto &X = outputWS->x(k);
116
117 // Middle of each X bin
118 auto midX = outputWS->points(k);
119
120 // This'll be the output
121 auto &outY = outputWS->mutableY(k);
122
123 // Strip each peak listed
124 std::vector<double>::iterator it;
125 for (it = centers.begin(); it != centers.end(); ++it) {
126 // Peak center and width
127 double center = *it;
128 double width = center * widthPercent / 100.0;
129
130 // Find the bin indices on both sides.
131 // We use averaging regions of 1/2 width, centered at +- width/2 from
132 // the center
133 int L1 = getBinIndex(X.rawData(), center - width * 0.75);
134 int L2 = getBinIndex(X.rawData(), center - width * 0.25);
135 double leftX = (midX[L1] + midX[L2]) / 2;
136 double totY = 0;
137
138 for (int i = L1; i <= L2; i++) {
139 totY += outY[i];
140 }
141
142 double leftY = totY / (L2 - L1 + 1);
143
144 int R1 = getBinIndex(X.rawData(), center + width * 0.25);
145 int R2 = getBinIndex(X.rawData(), center + width * 0.75);
146 double rightX = (midX[R1] + midX[R2]) / 2;
147 totY = 0;
148
149 for (int i = R1; i <= R2; i++) {
150 totY += outY[i];
151 }
152
153 double rightY = totY / (R2 - R1 + 1);
154
155 // Make a simple fit with these two points
156 double slope = 1.0;
157 if (fabs(rightX - leftX) > 0.0) // avoid divide by 0
158 slope = (rightY - leftY) / (rightX - leftX);
159 double abscissa = leftY - slope * leftX;
160
161 // Now fill in the vector between the averaged areas
162 for (int i = L2; i <= R1; i++) {
163 outY[i] = midX[i] * slope + abscissa;
164 }
165 }
166
167 } // if the spectrum is to be changed.
168 progress.report();
169 } // each spectrum
170
171 // Save the output workspace
172 setProperty("OutputWorkspace", outputWS);
173}
174
175} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
#define fabs(x)
Definition: Matrix.cpp:22
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:85
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
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
void exec() override
Execution code.
void init() override
Initialisation code.
Exception for index errors.
Definition: Exception.h:284
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
template DLLExport std::vector< double > splitStringIntoVector< double >(std::string listString)
MANTID_KERNEL_DLL int getBinIndex(const std::vector< double > &bins, const double value)
Return the index into a vector of bin boundaries for a particular X value.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54