Mantid
Loading...
Searching...
No Matches
CentroidPeaks.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 +
13#include "MantidKernel/Unit.h"
15#include <boost/algorithm/clamp.hpp>
16
18
19namespace Mantid::Crystal {
20
21// Register the algorithm into the AlgorithmFactory
22DECLARE_ALGORITHM(CentroidPeaks)
23
24using namespace Mantid::API;
25using namespace Mantid::DataObjects;
26using namespace Mantid::Geometry;
27using namespace Mantid::Kernel;
28using namespace Mantid::Crystal;
29
30//----------------------------------------------------------------------------------------------
34 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("InPeaksWorkspace", "", Direction::Input),
35 "A PeaksWorkspace containing the peaks to centroid.");
36
37 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input),
38 "An input 2D Workspace.");
39
40 declareProperty(std::make_unique<PropertyWithValue<int>>("PeakRadius", 10, Direction::Input),
41 "Fixed radius around each peak position in which to calculate the "
42 "centroid.");
43
44 declareProperty(std::make_unique<PropertyWithValue<int>>("EdgePixels", 0, Direction::Input),
45 "The number of pixels where peaks are removed at edges. Only "
46 "for instruments with RectangularDetectors. ");
47
48 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("OutPeaksWorkspace", "", Direction::Output),
49 "The output PeaksWorkspace will be a copy of the input PeaksWorkspace "
50 "with the peaks' positions modified by the new found centroids.");
51}
52
53//----------------------------------------------------------------------------------------------
58
60 Mantid::DataObjects::PeaksWorkspace_sptr inPeakWS = getProperty("InPeaksWorkspace");
61
63 Mantid::DataObjects::PeaksWorkspace_sptr peakWS = getProperty("OutPeaksWorkspace");
64 if (peakWS != inPeakWS)
65 peakWS = inPeakWS->clone();
66
68 int PeakRadius = getProperty("PeakRadius");
69
70 ComponentInfo const &compInfo = m_inWS->componentInfo();
71
72 int MinPeaks = -1;
73 int MaxPeaks = -1;
74 size_t Numberwi = m_inWS->getNumberHistograms();
75 int NumberPeaks = peakWS->getNumberPeaks();
76 for (int i = 0; i < NumberPeaks; ++i) {
77 Peak const &peak = peakWS->getPeaks()[i];
78 int pixelID = peak.getDetectorID();
79
80 // Find the workspace index for this detector ID
81 if (m_wi_to_detid_map.find(pixelID) != m_wi_to_detid_map.end()) {
82 size_t wi = m_wi_to_detid_map[pixelID];
83 if (MinPeaks == -1 && peak.getRunNumber() == m_inWS->getRunNumber() && wi < Numberwi)
84 MinPeaks = i;
85 if (peak.getRunNumber() == m_inWS->getRunNumber() && wi < Numberwi)
86 MaxPeaks = i;
87 }
88 }
89
90 const auto inBlocksize = static_cast<int64_t>(m_inWS->blocksize());
91 int Edge = getProperty("EdgePixels");
92 Progress prog(this, MinPeaks, 1.0, MaxPeaks);
94 for (int i = MinPeaks; i <= MaxPeaks; ++i) {
96 // Get a direct ref to that peak.
97 auto &peak = peakWS->getPeak(i);
98 int col = peak.getCol();
99 int row = peak.getRow();
100 int pixelID = peak.getDetectorID();
101 auto detidIterator = m_wi_to_detid_map.find(pixelID);
102 if (detidIterator == m_wi_to_detid_map.end()) {
103 continue;
104 }
105 size_t workspaceIndex = detidIterator->second;
106 double TOFPeakd = peak.getTOF();
107 const auto &X = m_inWS->x(workspaceIndex);
108 int chan = Kernel::VectorHelper::getBinIndex(X.rawData(), TOFPeakd);
109 std::string bankName = peak.getBankName();
110 int nCols = 0, nRows = 0;
111 sizeBanks(bankName, nCols, nRows);
112
113 double intensity = 0.0;
114 double chancentroid = 0.0;
115
116 int chanstart = std::max(0, chan - PeakRadius);
117 int chanend = std::min(static_cast<int>(X.size()), chan + PeakRadius);
118 double rowcentroid = 0.0;
119 int rowstart = std::max(0, row - PeakRadius);
120 int rowend = std::min(nRows - 1, row + PeakRadius);
121 double colcentroid = 0.0;
122 int colstart = std::max(0, col - PeakRadius);
123 int colend = std::min(nCols - 1, col + PeakRadius);
124 for (int ichan = chanstart; ichan <= chanend; ++ichan) {
125 for (int irow = rowstart; irow <= rowend; ++irow) {
126 for (int icol = colstart; icol <= colend; ++icol) {
127 if (edgePixel(compInfo, bankName, icol, irow, Edge)) {
128 continue;
129 }
130 const auto it = m_wi_to_detid_map.find(findPixelID(bankName, icol, irow));
131 if (it == m_wi_to_detid_map.end())
132 continue;
133
134 const auto &histogram = m_inWS->y(it->second);
135
136 intensity += histogram[ichan];
137 rowcentroid += irow * histogram[ichan];
138 colcentroid += icol * histogram[ichan];
139 chancentroid += ichan * histogram[ichan];
140 }
141 }
142 }
143 // Set pixelID to change row and col
144 row = (int)std::lround(rowcentroid / intensity);
145 boost::algorithm::clamp(row, 0, nRows - 1);
146 col = (int)std::lround(colcentroid / intensity);
147 boost::algorithm::clamp(col, 0, nCols - 1);
148 chan = (int)std::lround(chancentroid / intensity);
149 boost::algorithm::clamp(chan, 0, static_cast<int>(inBlocksize));
150
151 // Set wavelength to change tof for peak object
152 if (!edgePixel(compInfo, bankName, col, row, Edge)) {
153 peak.setDetectorID(findPixelID(bankName, col, row));
154 detidIterator = m_wi_to_detid_map.find(findPixelID(bankName, col, row));
155 workspaceIndex = (detidIterator->second);
157 std::vector<double> timeflight;
158 timeflight.emplace_back(m_inWS->x(workspaceIndex)[chan]);
159 double scattering = peak.getScattering();
160 double L1 = peak.getL1();
161 double L2 = peak.getL2();
162 wl.fromTOF(timeflight, timeflight, L1, 0, {{UnitParams::l2, L2}, {UnitParams::twoTheta, scattering}});
163 const double lambda = timeflight[0];
164 timeflight.clear();
165
166 peak.setWavelength(lambda);
167 peak.setBinCount(m_inWS->y(workspaceIndex)[chan]);
168 }
170 }
172 removeEdgePeaks(*peakWS);
173
174 // Save the output
175 setProperty("OutPeaksWorkspace", peakWS);
176}
177
178//----------------------------------------------------------------------------------------------
183
185 Mantid::DataObjects::PeaksWorkspace_sptr inPeakWS = getProperty("InPeaksWorkspace");
186
188 Mantid::DataObjects::PeaksWorkspace_sptr peakWS = getProperty("OutPeaksWorkspace");
189 if (peakWS != inPeakWS)
190 peakWS = inPeakWS->clone();
191
192 ComponentInfo const &compInfo = m_inWS->componentInfo();
193
195 int PeakRadius = getProperty("PeakRadius");
196
197 int MinPeaks = -1;
198 int MaxPeaks = -1;
199 size_t Numberwi = m_inWS->getNumberHistograms();
200 int NumberPeaks = peakWS->getNumberPeaks();
201
202 for (int i = 0; i < NumberPeaks; ++i) {
203 auto &peak = peakWS->getPeak(i);
204 int pixelID = peak.getDetectorID();
205
206 // Find the workspace index for this detector ID
207 if (m_wi_to_detid_map.find(pixelID) != m_wi_to_detid_map.end()) {
208 size_t wi = m_wi_to_detid_map[pixelID];
209 if (MinPeaks == -1 && peak.getRunNumber() == m_inWS->getRunNumber() && wi < Numberwi)
210 MinPeaks = i;
211 if (peak.getRunNumber() == m_inWS->getRunNumber() && wi < Numberwi)
212 MaxPeaks = i;
213 }
214 }
215
216 int Edge = getProperty("EdgePixels");
217 Progress prog(this, MinPeaks, 1.0, MaxPeaks);
219 for (int i = MinPeaks; i <= MaxPeaks; ++i) {
221 // Get a direct ref to that peak.
222 auto &peak = peakWS->getPeak(i);
223 int col = peak.getCol();
224 int row = peak.getRow();
225 double TOFPeakd = peak.getTOF();
226 std::string bankName = peak.getBankName();
227 int nCols = 0, nRows = 0;
228 sizeBanks(bankName, nCols, nRows);
229
230 double intensity = 0.0;
231 double tofcentroid = 0.0;
232 if (edgePixel(compInfo, bankName, col, row, Edge)) {
233 continue;
234 }
235
236 double tofstart = TOFPeakd * std::pow(1.004, -PeakRadius);
237 double tofend = TOFPeakd * std::pow(1.004, PeakRadius);
238 double rowcentroid = 0.0;
239 int rowstart = std::max(0, row - PeakRadius);
240 int rowend = std::min(nRows - 1, row + PeakRadius);
241 double colcentroid = 0.0;
242 int colstart = std::max(0, col - PeakRadius);
243 int colend = std::min(nCols - 1, col + PeakRadius);
244 for (int irow = rowstart; irow <= rowend; ++irow) {
245 for (int icol = colstart; icol <= colend; ++icol) {
246 if (edgePixel(compInfo, bankName, icol, irow, Edge)) {
247 continue;
248 }
249 auto it1 = m_wi_to_detid_map.find(findPixelID(bankName, icol, irow));
250 size_t workspaceIndex = (it1->second);
251 EventList el = m_eventW->getSpectrum(workspaceIndex);
253 std::vector<WeightedEventNoTime> events = el.getWeightedEventsNoTime();
254
255 // Check for events in tof range
256 for (const auto &event : events) {
257 double tof = event.tof();
258 if (tof > tofstart && tof < tofend) {
259 double weight = event.weight();
260 intensity += weight;
261 rowcentroid += irow * weight;
262 colcentroid += icol * weight;
263 tofcentroid += tof * weight;
264 }
265 }
266 }
267 }
268 // Set pixelID to change row and col
269 row = int(rowcentroid / intensity);
270 boost::algorithm::clamp(row, 0, nRows - 1);
271 col = int(colcentroid / intensity);
272 boost::algorithm::clamp(col, 0, nCols - 1);
273 if (!edgePixel(compInfo, bankName, col, row, Edge)) {
274 peak.setDetectorID(findPixelID(bankName, col, row));
275
276 // Set wavelength to change tof for peak object
277 double tof = tofcentroid / intensity;
279 std::vector<double> timeflight;
280 timeflight.emplace_back(tof);
281 double scattering = peak.getScattering();
282 double L1 = peak.getL1();
283 double L2 = peak.getL2();
284 wl.fromTOF(timeflight, timeflight, L1, 0, {{UnitParams::l2, L2}, {UnitParams::twoTheta, scattering}});
285 const double lambda = timeflight[0];
286 timeflight.clear();
287
288 peak.setWavelength(lambda);
289 peak.setBinCount(intensity);
290 }
292 }
294 removeEdgePeaks(*peakWS);
295
296 // Save the output
297 setProperty("OutPeaksWorkspace", peakWS);
298}
299
300//----------------------------------------------------------------------------------------------
304 m_inWS = getProperty("InputWorkspace");
305 m_inst = m_inWS->getInstrument();
306 // For quickly looking up workspace index from det id
307 m_wi_to_detid_map = m_inWS->getDetectorIDToWorkspaceIndexMap();
308
309 m_eventW = std::dynamic_pointer_cast<const EventWorkspace>(m_inWS);
310 if (m_eventW) {
311 m_eventW->sortAll(TOF_SORT, nullptr);
312 this->integrateEvent();
313 } else {
314 this->integrate();
315 }
316}
317
318int CentroidPeaks::findPixelID(const std::string &bankName, int col, int row) {
319 std::shared_ptr<const IComponent> parent = m_inst->getComponentByName(bankName);
320 if (parent->type() == "RectangularDetector") {
321 std::shared_ptr<const RectangularDetector> RDet = std::dynamic_pointer_cast<const RectangularDetector>(parent);
322
323 std::shared_ptr<Detector> pixel = RDet->getAtXY(col, row);
324 return pixel->getID();
325 } else {
326 std::string bankName0 = bankName;
327 // Only works for WISH
328 bankName0.erase(0, 4);
329 std::ostringstream pixelString;
330 pixelString << m_inst->getName() << "/" << bankName0 << "/" << bankName << "/tube" << std::setw(3)
331 << std::setfill('0') << col << "/pixel" << std::setw(4) << std::setfill('0') << row;
332 std::shared_ptr<const Geometry::IComponent> component = m_inst->getComponentByName(pixelString.str());
333 std::shared_ptr<const Detector> pixel = std::dynamic_pointer_cast<const Detector>(component);
334 return pixel->getID();
335 }
336}
337
339 int Edge = getProperty("EdgePixels");
340 std::vector<int> badPeaks;
341 size_t numPeaks = peakWS.getNumberPeaks();
342 ComponentInfo const &compInfo = m_inWS->componentInfo();
343 for (int i = 0; i < static_cast<int>(numPeaks); i++) {
344 // Get a direct ref to that peak.
345 const auto &peak = peakWS.getPeak(i);
346 int col = peak.getCol();
347 int row = peak.getRow();
348 const std::string &bankName = peak.getBankName();
349
350 if (edgePixel(compInfo, bankName, col, row, Edge)) {
351 badPeaks.emplace_back(i);
352 }
353 }
354 peakWS.removePeaks(std::move(badPeaks));
355}
356
357void CentroidPeaks::sizeBanks(const std::string &bankName, int &nCols, int &nRows) {
358 if (bankName == "None")
359 return;
360 ExperimentInfo expInfo;
361 expInfo.setInstrument(m_inst);
362 const auto &compInfo = expInfo.componentInfo();
363
364 // Get a single bank
365 auto bank = m_inst->getComponentByName(bankName);
366 auto bankID = bank->getComponentID();
367 auto allBankDetectorIndexes = compInfo.detectorsInSubtree(compInfo.indexOf(bankID));
368
369 nRows = static_cast<int>(compInfo.componentsInSubtree(compInfo.indexOf(bankID)).size() -
370 allBankDetectorIndexes.size() - 1);
371 nCols = static_cast<int>(allBankDetectorIndexes.size()) / nRows;
372
373 if (nCols * nRows != static_cast<int>(allBankDetectorIndexes.size())) {
374 // Need grandchild instead of child
375 nRows = static_cast<int>(compInfo.componentsInSubtree(compInfo.indexOf(bankID)).size() -
376 allBankDetectorIndexes.size() - 2);
377 nCols = static_cast<int>(allBankDetectorIndexes.size()) / nRows;
378 }
379}
380
381} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
const std::vector< double > * lambda
#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_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.
This class is shared by a few Workspace types and holds information related to a particular experimen...
const Geometry::ComponentInfo & componentInfo() const
void setInstrument(const Geometry::Instrument_const_sptr &instr)
Instrument accessors.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
void init() override
Initialise the properties.
int findPixelID(const std::string &bankName, int col, int row)
void integrateEvent()
Integrate the peaks of the workspace using parameters saved in the algorithm class.
void removeEdgePeaks(Mantid::DataObjects::PeaksWorkspace &peakWS)
void integrate()
Integrate the peaks of the workspace using parameters saved in the algorithm class.
Geometry::Instrument_const_sptr m_inst
void exec() override
Run the algorithm.
Mantid::detid2index_map m_wi_to_detid_map
DataObjects::EventWorkspace_const_sptr m_eventW
API::MatrixWorkspace_sptr m_inWS
Input 2D Workspace.
void sizeBanks(const std::string &bankName, int &nCols, int &nRows)
int getRunNumber() const override
Return the run number this peak was measured at.
Definition BasePeak.cpp:77
A class for holding :
Definition EventList.h:57
std::vector< WeightedEventNoTime > & getWeightedEventsNoTime()
Return the list of WeightedEvent contained.
void switchTo(Mantid::API::EventType newType) override
Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
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
int getDetectorID() const override
Get the ID of the detector at the center of the peak
Definition Peak.cpp:265
The class PeaksWorkspace stores information about a set of SCD peaks.
void removePeaks(std::vector< int > badPeaks) override
Removes multiple peaks.
Peak & getPeak(size_t const peakNum) override
Return a reference to the Peak.
ComponentInfo : Provides a component centric view on to the instrument.
std::vector< size_t > detectorsInSubtree(size_t componentIndex) const
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The concrete, templated class for properties.
void fromTOF(std::vector< double > &xdata, std::vector< double > const &ydata, const double &_l1, const int &_emode, std::initializer_list< std::pair< const UnitParams, double > > params)
Convert from time-of-flight to the concrete unit.
Definition Unit.cpp:178
Wavelength in Angstrom.
Definition Unit.h:267
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
MANTID_GEOMETRY_DLL bool edgePixel(ComponentInfo const &info, const std::string &bankName, int col, int row, int Edge)
Function to find peaks near detector edge.
Definition EdgePixel.cpp:24
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.
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.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54