Mantid
Loading...
Searching...
No Matches
MaskPeaksWorkspace.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 +
12#include "MantidAPI/TableRow.h"
20
21#include <boost/math/special_functions/round.hpp>
22
23namespace Mantid::Crystal {
24
25// Register the class into the algorithm factory
26DECLARE_ALGORITHM(MaskPeaksWorkspace)
27
28using namespace Kernel;
29using namespace API;
30using namespace DataObjects;
31using namespace Geometry;
32using std::string;
33
35MaskPeaksWorkspace::MaskPeaksWorkspace() : m_xMin{0}, m_xMax{0}, m_yMin{0}, m_yMax{0}, m_tofMin{0}, m_tofMax{0} {}
36
41
42 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input,
43 std::make_shared<InstrumentValidator>()),
44 "A workspace containing one or more rectangular area "
45 "detectors. Each spectrum needs to correspond to only one "
46 "pixelID (e.g. no grouping or previous calls to "
47 "SumNeighbours).");
48 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("InPeaksWorkspace", "", Direction::Input),
49 "The name of the workspace that will be created. Can replace "
50 "the input workspace.");
51 declareProperty("XMin", -2, "Minimum of X (col) Range to mask peak relative to peak's center");
52 declareProperty("XMax", 2, "Maximum of X (col) Range to mask peak relative to peak's center");
53 declareProperty("YMin", -2, "Minimum of Y (row) Range to mask peak relative to peak's center");
54 declareProperty("YMax", 2, "Maximum of Y (row) Range to mask peak relative to peak's center");
55 declareProperty("TOFMin", EMPTY_DBL(),
56 "Optional(all TOF if not specified): "
57 "Minimum TOF relative to peak's "
58 "center TOF.");
59 declareProperty("TOFMax", EMPTY_DBL(),
60 "Optional(all TOF if not specified): "
61 "Maximum TOF relative to peak's "
62 "center TOF.");
63}
64
72
73 PeaksWorkspace_const_sptr peaksW = getProperty("InPeaksWorkspace");
74
75 // To get the workspace index from the detector ID
76 const detid2index_map pixel_to_wi = m_inputW->getDetectorIDToWorkspaceIndexMap();
77 const auto &componentInfo = m_inputW->componentInfo();
78
79 // Init a table workspace
80 DataObjects::TableWorkspace_sptr tablews = std::make_shared<DataObjects::TableWorkspace>();
81 tablews->addColumn("double", "XMin");
82 tablews->addColumn("double", "XMax");
83 tablews->addColumn("str", "SpectraList");
84
85 // Loop over peaks
86 const std::vector<Peak> &peaks = peaksW->getPeaks();
87 PARALLEL_FOR_IF(Kernel::threadSafe(*m_inputW, *peaksW, *tablews))
88 for (int i = 0; i < static_cast<int>(peaks.size()); i++) { // NOLINT
90 const Peak &peak = peaks[i];
91 // get the peak location on the detector
92 double col = peak.getCol();
93 double row = peak.getRow();
94 int xPeak = boost::math::iround(col) - 1;
95 int yPeak = boost::math::iround(row) - 1;
96 g_log.debug() << "Generating information for peak at x=" << xPeak << " y=" << yPeak << "\n";
97
98 // the detector component for the peak will have all pixels that we mask
99 const string &bankName = peak.getBankName();
100 if (bankName == "None")
101 continue;
102 size_t bankIndex;
103 try {
104 bankIndex = componentInfo.indexOfAny(bankName);
105 } catch (std::invalid_argument &) {
106 g_log.debug() << "Component " + bankName + " does not exist in instrument\n";
107 continue;
108 }
109
110 // determine the range in time-of-flight
111 double x0;
112 double xf;
113 bool tofRangeSet(false);
114 size_t wi = this->getWkspIndex(pixel_to_wi, bankIndex, xPeak, yPeak);
115 if (wi != static_cast<size_t>(EMPTY_INT())) { // scope limit the workspace index
116 this->getTofRange(x0, xf, peak.getTOF(), m_inputW->x(wi));
117 tofRangeSet = true;
118 }
119
120 // determine the spectrum numbers to mask
121 std::set<size_t> spectra;
122 for (int ix = m_xMin; ix <= m_xMax; ix++) {
123 for (int iy = m_yMin; iy <= m_yMax; iy++) {
124 // Find the pixel ID at that XY position on the rectangular detector
125 size_t wj = this->getWkspIndex(pixel_to_wi, bankIndex, xPeak + ix, yPeak + iy);
126 if (wj == static_cast<size_t>(EMPTY_INT()))
127 continue;
128 spectra.insert(wj);
129 if (!tofRangeSet) { // scope limit the workspace index
130 this->getTofRange(x0, xf, peak.getTOF(), m_inputW->x(wj));
131 tofRangeSet = true;
132 }
133 }
134 }
135
136 // sanity check the results
137 if (!tofRangeSet) {
138 g_log.warning() << "Failed to set time-of-flight range for peak (x=" << xPeak << ", y=" << yPeak
139 << ", tof=" << peak.getTOF() << ")\n";
140 } else if (spectra.empty()) {
141 g_log.warning() << "Failed to find spectra for peak (x=" << xPeak << ", y=" << yPeak << ", tof=" << peak.getTOF()
142 << ")\n";
143 continue;
144 } else
145 PARALLEL_CRITICAL(tablews) {
146 // append to the table workspace
147 API::TableRow newrow = tablews->appendRow();
148 newrow << x0 << xf << Kernel::Strings::toString(spectra);
149 }
151 } // end loop over peaks
153
154 // Mask bins
155 auto maskbinstb = createChildAlgorithm("MaskBinsFromTable", 0.5, 1.0, true);
156 maskbinstb->setProperty("InputWorkspace", m_inputW);
157 maskbinstb->setPropertyValue("OutputWorkspace", m_inputW->getName());
158 maskbinstb->setProperty("MaskingInformation", tablews);
159 maskbinstb->execute();
160}
161
163 m_inputW = getProperty("InputWorkspace");
164
165 m_xMin = getProperty("XMin");
166 m_xMax = getProperty("XMax");
167 if (m_xMin >= m_xMax)
168 throw std::runtime_error("Must specify Xmin<Xmax");
169
170 m_yMin = getProperty("YMin");
171 m_yMax = getProperty("YMax");
172 if (m_yMin >= m_yMax)
173 throw std::runtime_error("Must specify Ymin<Ymax");
174
175 // Get the value of TOF range to mask
176 m_tofMin = getProperty("TOFMin");
177 m_tofMax = getProperty("TOFMax");
178 if ((!isEmpty(m_tofMin)) && (!isEmpty(m_tofMax))) {
179 if (m_tofMin >= m_tofMax)
180 throw std::runtime_error("Must specify TOFMin < TOFMax");
181 } else if ((!isEmpty(m_tofMin)) || (!isEmpty(m_tofMax))) // check if only one is empty
182 {
183 throw std::runtime_error("Must specify both TOFMin and TOFMax or neither");
184 }
185}
186
187size_t MaskPeaksWorkspace::getWkspIndex(const detid2index_map &pixel_to_wi, const size_t bankIndex, const int x,
188 const int y) {
189 const auto &componentInfo = m_inputW->componentInfo();
190
191 if (componentInfo.isGridDetector(bankIndex)) {
192 const auto &detectorInfo = m_inputW->detectorInfo();
193 const auto grid = componentInfo.pixelGridComponent(bankIndex);
194 if (x >= grid.nX || x < 0 || y >= grid.nY || y < 0) {
195 // throw std::runtime_error("Failed to find workspace index for x=" + std::to_string(x) + " y=" +
196 // std::to_string(y) + "(max x=" + std::to_string(grid.nX) +
197 // ", max y=" + std::to_string(grid.nY) + ")"); // Useful for debugging
198 return EMPTY_INT();
199 }
200
201 int pixelID = detectorInfo.detid(componentInfo.detectorIndexAtXYZ(bankIndex, x, y, 0));
202
203 // Find the corresponding workspace index, if any
204 auto wiEntry = pixel_to_wi.find(pixelID);
205 if (wiEntry == pixel_to_wi.end()) {
206 std::stringstream msg;
207 msg << "Failed to find workspace index for x=" << x << " y=" << y;
208 throw std::runtime_error(msg.str());
209 }
210 return wiEntry->second;
211 } else {
212 auto children = componentInfo.children(bankIndex);
213
214 auto grandchildren = componentInfo.children(children[0]);
215
216 auto NROWS = static_cast<int>(grandchildren.size());
217 auto NCOLS = static_cast<int>(children.size());
218
219 std::ostringstream msg;
220 if (m_inputW->getInstrumentName() == "CORELLI") {
221 msg << "Instrument is CORELLI\n";
222 // CORELLI has one extra layer than WISH
223 auto greatgrandchildren = componentInfo.children(grandchildren[0]);
224 // update for CORELLI
225 NCOLS = static_cast<int>(grandchildren.size());
226 NROWS = static_cast<int>(greatgrandchildren.size());
227 } else {
228 msg << "Instrument is WISH\n";
229 }
230
231 // Wish pixels and tubes start at 1 not 0
232 if (x - 1 >= NCOLS || x - 1 < 0 || y - 1 >= NROWS || y - 1 < 0) {
233 // useful for future dev in plan
234 // msg << "--(x,y) = (" << x << "," << y << ")\n"
235 // << "--NCOLS = " << NCOLS << "\n"
236 // << "--NROWS = " << NROWS << "\n";
237 // g_log.warning() << msg.str();
238 return EMPTY_INT();
239 }
240
241 std::string bankName = componentInfo.name(bankIndex);
242 auto it = pixel_to_wi.find(findPixelID(bankName, x, y));
243 if (it == pixel_to_wi.end())
244 return EMPTY_INT();
245 return (it->second);
246 }
247}
248
256void MaskPeaksWorkspace::getTofRange(double &tofMin, double &tofMax, const double tofPeak,
257 const HistogramData::HistogramX &tof) {
258 tofMin = tof.front();
259 tofMax = tof.back() - 1;
260 if (!isEmpty(m_tofMin)) {
261 tofMin = tofPeak + m_tofMin;
262 }
263 if (!isEmpty(m_tofMax)) {
264 tofMax = tofPeak + m_tofMax;
265 }
266}
267
276int MaskPeaksWorkspace::findPixelID(const std::string &bankName, int col, int row) {
277 auto const &componentInfo = m_inputW->componentInfo();
278 size_t const parentIndex = componentInfo.indexOfAny(bankName);
279 if (componentInfo.isGridDetector(parentIndex)) {
280 auto const &detectorInfo = m_inputW->detectorInfo();
281 return detectorInfo.detid(componentInfo.detectorIndexAtXYZ(parentIndex, col, row, 0));
282 } else if (m_inputW->getInstrumentName() == "CORELLI") {
283 // Checking for CORELLI
284 // pixel full name example
285 // /CORELLI/A row/bank10/sixteenpack/tube10/pixel23
286 // ^ the extra layer that makes CORELLI different from WISH
287 std::ostringstream pixelString;
288 pixelString << componentInfo.name(parentIndex) // /CORELLI/A row/bank10
289 << "/sixteenpack" // /sixteenpack
290 << "/tube" << col // /tube10
291 << "/pixel" << row; // /pixel23
292 Geometry::Instrument_const_sptr Iptr = m_inputW->getInstrument();
293 std::shared_ptr<const Geometry::IComponent> component = Iptr->getComponentByName(pixelString.str());
294 std::shared_ptr<const Detector> pixel = std::dynamic_pointer_cast<const Detector>(component);
295 //
296 return pixel->getID();
297 } else {
298 std::string bankName0 = bankName;
299 // Only works for WISH
300 bankName0.erase(0, 4);
301 std::ostringstream pixelString;
302 pixelString << m_inputW->getInstrumentName() << "/" << bankName0 << "/" << bankName << "/tube" << std::setw(3)
303 << std::setfill('0') << col << "/pixel" << std::setw(4) << std::setfill('0') << row;
304 Geometry::Instrument_const_sptr Iptr = m_inputW->getInstrument();
305 std::shared_ptr<const Geometry::IComponent> component = Iptr->getComponentByName(pixelString.str());
306 std::shared_ptr<const Detector> pixel = std::dynamic_pointer_cast<const Detector>(component);
307 return pixel->getID();
308 }
309}
310} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
#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...
#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 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.
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:423
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
TableRow represents a row in a TableWorkspace.
Definition TableRow.h:39
A property class for workspaces.
double m_tofMin
The start of the box around the peak in tof.
int findPixelID(const std::string &bankName, int col, int row)
void init() override
Initialisation method.
int m_xMin
The start of the X range for fitting.
int m_yMax
The end of the Y range for fitting.
std::size_t getWkspIndex(const detid2index_map &pixel_to_wi, const size_t bankIndex, const int x, const int y)
void exec() override
Executes the algorithm.
double m_tofMax
The end of the box around the peak in tof.
void getTofRange(double &tofMin, double &tofMax, const double tofPeak, const HistogramData::HistogramX &tof)
API::MatrixWorkspace_sptr m_inputW
A pointer to the input workspace.
void retrieveProperties()
Read in all the input parameters.
int m_xMax
The end of the X range for fitting.
int m_yMin
The start of the Y range for fitting.
Structure describing a single-crystal peak.
Definition Peak.h:34
int getCol() const override
For RectangularDetectors only, returns the column (x) of the pixel of the detector or -1 if not found...
Definition Peak.cpp:335
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
std::shared_ptr< const PeaksWorkspace > PeaksWorkspace_const_sptr
Typedef for a shared pointer to a const peaks workspace.
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
std::string toString(const T &value)
Convert a number to a string.
Definition Strings.cpp:734
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.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition EmptyValues.h:24
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53