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"
19
20#include <boost/math/special_functions/round.hpp>
21
22namespace Mantid::Crystal {
23
24// Register the class into the algorithm factory
25DECLARE_ALGORITHM(MaskPeaksWorkspace)
26
27using namespace Kernel;
28using namespace API;
29using namespace DataObjects;
30using namespace Geometry;
31using std::string;
32
34MaskPeaksWorkspace::MaskPeaksWorkspace() : m_xMin{0}, m_xMax{0}, m_yMin{0}, m_yMax{0}, m_tofMin{0}, m_tofMax{0} {}
35
40
41 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input,
42 std::make_shared<InstrumentValidator>()),
43 "A workspace containing one or more rectangular area "
44 "detectors. Each spectrum needs to correspond to only one "
45 "pixelID (e.g. no grouping or previous calls to "
46 "SumNeighbours).");
47 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("InPeaksWorkspace", "", Direction::Input),
48 "The name of the workspace that will be created. Can replace "
49 "the input workspace.");
50 declareProperty("XMin", -2, "Minimum of X (col) Range to mask peak relative to peak's center");
51 declareProperty("XMax", 2, "Maximum of X (col) Range to mask peak relative to peak's center");
52 declareProperty("YMin", -2, "Minimum of Y (row) Range to mask peak relative to peak's center");
53 declareProperty("YMax", 2, "Maximum of Y (row) Range to mask peak relative to peak's center");
54 declareProperty("TOFMin", EMPTY_DBL(),
55 "Optional(all TOF if not specified): "
56 "Minimum TOF relative to peak's "
57 "center TOF.");
58 declareProperty("TOFMax", EMPTY_DBL(),
59 "Optional(all TOF if not specified): "
60 "Maximum TOF relative to peak's "
61 "center TOF.");
62}
63
71
72 PeaksWorkspace_const_sptr peaksW = getProperty("InPeaksWorkspace");
73
74 // To get the workspace index from the detector ID
75 const detid2index_map pixel_to_wi = m_inputW->getDetectorIDToWorkspaceIndexMap();
76 // Get some stuff from the input workspace
77 Geometry::Instrument_const_sptr inst = m_inputW->getInstrument();
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 Geometry::IComponent_const_sptr comp = inst->getComponentByName(bankName);
103 if (!comp) {
104 g_log.debug() << "Component " + bankName + " does not exist in instrument\n";
105 continue;
106 }
107
108 // determine the range in time-of-flight
109 double x0;
110 double xf;
111 bool tofRangeSet(false);
112 size_t wi = this->getWkspIndex(pixel_to_wi, comp, xPeak, yPeak);
113 if (wi != static_cast<size_t>(EMPTY_INT())) { // scope limit the workspace index
114 this->getTofRange(x0, xf, peak.getTOF(), m_inputW->x(wi));
115 tofRangeSet = true;
116 }
117
118 // determine the spectrum numbers to mask
119 std::set<size_t> spectra;
120 for (int ix = m_xMin; ix <= m_xMax; ix++) {
121 for (int iy = m_yMin; iy <= m_yMax; iy++) {
122 // Find the pixel ID at that XY position on the rectangular detector
123 size_t wj = this->getWkspIndex(pixel_to_wi, comp, xPeak + ix, yPeak + iy);
124 if (wj == static_cast<size_t>(EMPTY_INT()))
125 continue;
126 spectra.insert(wj);
127 if (!tofRangeSet) { // scope limit the workspace index
128 this->getTofRange(x0, xf, peak.getTOF(), m_inputW->x(wj));
129 tofRangeSet = true;
130 }
131 }
132 }
133
134 // sanity check the results
135 if (!tofRangeSet) {
136 g_log.warning() << "Failed to set time-of-flight range for peak (x=" << xPeak << ", y=" << yPeak
137 << ", tof=" << peak.getTOF() << ")\n";
138 } else if (spectra.empty()) {
139 g_log.warning() << "Failed to find spectra for peak (x=" << xPeak << ", y=" << yPeak << ", tof=" << peak.getTOF()
140 << ")\n";
141 continue;
142 } else
143 PARALLEL_CRITICAL(tablews) {
144 // append to the table workspace
145 API::TableRow newrow = tablews->appendRow();
146 newrow << x0 << xf << Kernel::Strings::toString(spectra);
147 }
149 } // end loop over peaks
151
152 // Mask bins
153 auto maskbinstb = createChildAlgorithm("MaskBinsFromTable", 0.5, 1.0, true);
154 maskbinstb->setProperty("InputWorkspace", m_inputW);
155 maskbinstb->setPropertyValue("OutputWorkspace", m_inputW->getName());
156 maskbinstb->setProperty("MaskingInformation", tablews);
157 maskbinstb->execute();
158}
159
161 m_inputW = getProperty("InputWorkspace");
162
163 m_xMin = getProperty("XMin");
164 m_xMax = getProperty("XMax");
165 if (m_xMin >= m_xMax)
166 throw std::runtime_error("Must specify Xmin<Xmax");
167
168 m_yMin = getProperty("YMin");
169 m_yMax = getProperty("YMax");
170 if (m_yMin >= m_yMax)
171 throw std::runtime_error("Must specify Ymin<Ymax");
172
173 // Get the value of TOF range to mask
174 m_tofMin = getProperty("TOFMin");
175 m_tofMax = getProperty("TOFMax");
176 if ((!isEmpty(m_tofMin)) && (!isEmpty(m_tofMax))) {
177 if (m_tofMin >= m_tofMax)
178 throw std::runtime_error("Must specify TOFMin < TOFMax");
179 } else if ((!isEmpty(m_tofMin)) || (!isEmpty(m_tofMax))) // check if only one is empty
180 {
181 throw std::runtime_error("Must specify both TOFMin and TOFMax or neither");
182 }
183}
184
186 const int x, const int y) {
187 Geometry::RectangularDetector_const_sptr det = std::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp);
188 Geometry::Instrument_const_sptr Iptr = m_inputW->getInstrument();
189
190 if (det) {
191 if (x >= det->xpixels() || x < 0 || y >= det->ypixels() || y < 0) {
192 // throw std::runtime_error("Failed to find workspace index for x=" + std::to_string(x) + " y=" +
193 // std::to_string(y) + "(max x=" + std::to_string(det->xpixels()) +
194 // ", max y=" + std::to_string(det->ypixels()) + ")"); // Useful for debugging
195 return EMPTY_INT();
196 }
197
198 int pixelID = det->getAtXY(x, y)->getID();
199
200 // Find the corresponding workspace index, if any
201 auto wiEntry = pixel_to_wi.find(pixelID);
202 if (wiEntry == pixel_to_wi.end()) {
203 std::stringstream msg;
204 msg << "Failed to find workspace index for x=" << x << " y=" << y;
205 throw std::runtime_error(msg.str());
206 }
207 return wiEntry->second;
208 } else {
209 const auto &componentInfo = m_inputW->componentInfo();
210 const size_t compIndex = componentInfo.indexOfAny(comp->getName());
211 auto children = componentInfo.children(compIndex);
212
213 auto grandchildren = componentInfo.children(children[0]);
214
215 auto NROWS = static_cast<int>(grandchildren.size());
216 auto NCOLS = static_cast<int>(children.size());
217
218 std::ostringstream msg;
219 if (Iptr->getName().compare("CORELLI") == 0) {
220 msg << "Instrument is CORELLI\n";
221 // CORELLI has one extra layer than WISH
222 auto greatgrandchildren = componentInfo.children(grandchildren[0]);
223 // update for CORELLI
224 NCOLS = static_cast<int>(grandchildren.size());
225 NROWS = static_cast<int>(greatgrandchildren.size());
226 } else {
227 msg << "Instrument is WISH\n";
228 }
229
230 // Wish pixels and tubes start at 1 not 0
231 if (x - 1 >= NCOLS || x - 1 < 0 || y - 1 >= NROWS || y - 1 < 0) {
232 // useful for future dev in plan
233 // msg << "--(x,y) = (" << x << "," << y << ")\n"
234 // << "--NCOLS = " << NCOLS << "\n"
235 // << "--NROWS = " << NROWS << "\n";
236 // g_log.warning() << msg.str();
237 return EMPTY_INT();
238 }
239
240 std::string bankName = comp->getName();
241 auto it = pixel_to_wi.find(findPixelID(bankName, x, y));
242 if (it == pixel_to_wi.end())
243 return EMPTY_INT();
244 return (it->second);
245 }
246}
247
255void MaskPeaksWorkspace::getTofRange(double &tofMin, double &tofMax, const double tofPeak,
256 const HistogramData::HistogramX &tof) {
257 tofMin = tof.front();
258 tofMax = tof.back() - 1;
259 if (!isEmpty(m_tofMin)) {
260 tofMin = tofPeak + m_tofMin;
261 }
262 if (!isEmpty(m_tofMax)) {
263 tofMax = tofPeak + m_tofMax;
264 }
265}
266
275int MaskPeaksWorkspace::findPixelID(const std::string &bankName, int col, int row) {
276 Geometry::Instrument_const_sptr Iptr = m_inputW->getInstrument();
277 std::shared_ptr<const IComponent> parent = Iptr->getComponentByName(bankName);
278
279 if (parent->type() == "RectangularDetector") {
280 std::shared_ptr<const RectangularDetector> RDet = std::dynamic_pointer_cast<const RectangularDetector>(parent);
281
282 std::shared_ptr<Detector> pixel = RDet->getAtXY(col, row);
283 return pixel->getID();
284 } else if (Iptr->getName().compare("CORELLI") == 0) {
285 // Checking for CORELLI
286 // pixel full name example
287 // /CORELLI/A row/bank10/sixteenpack/tube10/pixel23
288 // ^ the extra layer that makes CORELLI different from WISH
289 std::ostringstream pixelString;
290 pixelString << parent->getFullName() // /CORELLI/A row/bank10
291 << "/sixteenpack" // /sixteenpack
292 << "/tube" << col // /tube10
293 << "/pixel" << row; // /pixel23
294 std::shared_ptr<const Geometry::IComponent> component = Iptr->getComponentByName(pixelString.str());
295 std::shared_ptr<const Detector> pixel = std::dynamic_pointer_cast<const Detector>(component);
296 //
297 return pixel->getID();
298 } else {
299 std::string bankName0 = bankName;
300 // Only works for WISH
301 bankName0.erase(0, 4);
302 std::ostringstream pixelString;
303 pixelString << Iptr->getName() << "/" << bankName0 << "/" << bankName << "/tube" << std::setw(3)
304 << std::setfill('0') << col << "/pixel" << std::setw(4) << std::setfill('0') << row;
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:538
#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:422
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)
std::size_t getWkspIndex(const detid2index_map &pixel_to_wi, const Geometry::IComponent_const_sptr &comp, const int x, const int y)
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.
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 IComponent > IComponent_const_sptr
Typdef of a shared pointer to a const IComponent.
Definition IComponent.h:167
std::shared_ptr< const RectangularDetector > RectangularDetector_const_sptr
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