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 int MinPeaks = -1;
71 int MaxPeaks = -1;
72 size_t Numberwi = inWS->getNumberHistograms();
73 int NumberPeaks = peakWS->getNumberPeaks();
74 for (int i = 0; i < NumberPeaks; ++i) {
75 Peak &peak = peakWS->getPeaks()[i];
76 int pixelID = peak.getDetectorID();
77
78 // Find the workspace index for this detector ID
79 if (wi_to_detid_map.find(pixelID) != wi_to_detid_map.end()) {
80 size_t wi = wi_to_detid_map[pixelID];
81 if (MinPeaks == -1 && peak.getRunNumber() == inWS->getRunNumber() && wi < Numberwi)
82 MinPeaks = i;
83 if (peak.getRunNumber() == inWS->getRunNumber() && wi < Numberwi)
84 MaxPeaks = i;
85 }
86 }
87
88 const auto inBlocksize = static_cast<int>(inWS->blocksize());
89 int Edge = getProperty("EdgePixels");
90 Progress prog(this, MinPeaks, 1.0, MaxPeaks);
92 for (int i = MinPeaks; i <= MaxPeaks; ++i) {
94 // Get a direct ref to that peak.
95 auto &peak = peakWS->getPeak(i);
96 int col = peak.getCol();
97 int row = peak.getRow();
98 int pixelID = peak.getDetectorID();
99 auto detidIterator = wi_to_detid_map.find(pixelID);
100 if (detidIterator == wi_to_detid_map.end()) {
101 continue;
102 }
103 size_t workspaceIndex = detidIterator->second;
104 double TOFPeakd = peak.getTOF();
105 const auto &X = inWS->x(workspaceIndex);
106 int chan = Kernel::VectorHelper::getBinIndex(X.rawData(), TOFPeakd);
107 std::string bankName = peak.getBankName();
108 int nCols = 0, nRows = 0;
109 sizeBanks(bankName, nCols, nRows);
110
111 double intensity = 0.0;
112 double chancentroid = 0.0;
113
114 int chanstart = std::max(0, chan - PeakRadius);
115 int chanend = std::min(static_cast<int>(X.size()), chan + PeakRadius);
116 double rowcentroid = 0.0;
117 int rowstart = std::max(0, row - PeakRadius);
118 int rowend = std::min(nRows - 1, row + PeakRadius);
119 double colcentroid = 0.0;
120 int colstart = std::max(0, col - PeakRadius);
121 int colend = std::min(nCols - 1, col + PeakRadius);
122 for (int ichan = chanstart; ichan <= chanend; ++ichan) {
123 for (int irow = rowstart; irow <= rowend; ++irow) {
124 for (int icol = colstart; icol <= colend; ++icol) {
125 if (edgePixel(inst, bankName, icol, irow, Edge))
126 continue;
127 const auto it = wi_to_detid_map.find(findPixelID(bankName, icol, irow));
128 if (it == wi_to_detid_map.end())
129 continue;
130
131 const auto &histogram = inWS->y(it->second);
132
133 intensity += histogram[ichan];
134 rowcentroid += irow * histogram[ichan];
135 colcentroid += icol * histogram[ichan];
136 chancentroid += ichan * histogram[ichan];
137 }
138 }
139 }
140 // Set pixelID to change row and col
141 row = (int)std::lround(rowcentroid / intensity);
142 boost::algorithm::clamp(row, 0, nRows - 1);
143 col = (int)std::lround(colcentroid / intensity);
144 boost::algorithm::clamp(col, 0, nCols - 1);
145 chan = (int)std::lround(chancentroid / intensity);
146 boost::algorithm::clamp(chan, 0, inBlocksize);
147
148 // Set wavelength to change tof for peak object
149 if (!edgePixel(inst, bankName, col, row, Edge)) {
150 peak.setDetectorID(findPixelID(bankName, col, row));
151 detidIterator = wi_to_detid_map.find(findPixelID(bankName, col, row));
152 workspaceIndex = (detidIterator->second);
154 std::vector<double> timeflight;
155 timeflight.emplace_back(inWS->x(workspaceIndex)[chan]);
156 double scattering = peak.getScattering();
157 double L1 = peak.getL1();
158 double L2 = peak.getL2();
159 wl.fromTOF(timeflight, timeflight, L1, 0, {{UnitParams::l2, L2}, {UnitParams::twoTheta, scattering}});
160 const double lambda = timeflight[0];
161 timeflight.clear();
162
163 peak.setWavelength(lambda);
164 peak.setBinCount(inWS->y(workspaceIndex)[chan]);
165 }
167 }
169 removeEdgePeaks(*peakWS);
170
171 // Save the output
172 setProperty("OutPeaksWorkspace", peakWS);
173}
174
175//----------------------------------------------------------------------------------------------
180
182 Mantid::DataObjects::PeaksWorkspace_sptr inPeakWS = getProperty("InPeaksWorkspace");
183
185 Mantid::DataObjects::PeaksWorkspace_sptr peakWS = getProperty("OutPeaksWorkspace");
186 if (peakWS != inPeakWS)
187 peakWS = inPeakWS->clone();
188
190 int PeakRadius = getProperty("PeakRadius");
191
192 int MinPeaks = -1;
193 int MaxPeaks = -1;
194 size_t Numberwi = inWS->getNumberHistograms();
195 int NumberPeaks = peakWS->getNumberPeaks();
196
197 for (int i = 0; i < NumberPeaks; ++i) {
198 auto &peak = peakWS->getPeak(i);
199 int pixelID = peak.getDetectorID();
200
201 // Find the workspace index for this detector ID
202 if (wi_to_detid_map.find(pixelID) != wi_to_detid_map.end()) {
203 size_t wi = wi_to_detid_map[pixelID];
204 if (MinPeaks == -1 && peak.getRunNumber() == inWS->getRunNumber() && wi < Numberwi)
205 MinPeaks = i;
206 if (peak.getRunNumber() == inWS->getRunNumber() && wi < Numberwi)
207 MaxPeaks = i;
208 }
209 }
210
211 int Edge = getProperty("EdgePixels");
212 Progress prog(this, MinPeaks, 1.0, MaxPeaks);
214 for (int i = MinPeaks; i <= MaxPeaks; ++i) {
216 // Get a direct ref to that peak.
217 auto &peak = peakWS->getPeak(i);
218 int col = peak.getCol();
219 int row = peak.getRow();
220 double TOFPeakd = peak.getTOF();
221 std::string bankName = peak.getBankName();
222 int nCols = 0, nRows = 0;
223 sizeBanks(bankName, nCols, nRows);
224
225 double intensity = 0.0;
226 double tofcentroid = 0.0;
227 if (edgePixel(inst, bankName, col, row, Edge))
228 continue;
229
230 double tofstart = TOFPeakd * std::pow(1.004, -PeakRadius);
231 double tofend = TOFPeakd * std::pow(1.004, PeakRadius);
232 double rowcentroid = 0.0;
233 int rowstart = std::max(0, row - PeakRadius);
234 int rowend = std::min(nRows - 1, row + PeakRadius);
235 double colcentroid = 0.0;
236 int colstart = std::max(0, col - PeakRadius);
237 int colend = std::min(nCols - 1, col + PeakRadius);
238 for (int irow = rowstart; irow <= rowend; ++irow) {
239 for (int icol = colstart; icol <= colend; ++icol) {
240 if (edgePixel(inst, bankName, icol, irow, Edge))
241 continue;
242 auto it1 = wi_to_detid_map.find(findPixelID(bankName, icol, irow));
243 size_t workspaceIndex = (it1->second);
244 EventList el = eventW->getSpectrum(workspaceIndex);
246 std::vector<WeightedEventNoTime> events = el.getWeightedEventsNoTime();
247
248 // Check for events in tof range
249 for (const auto &event : events) {
250 double tof = event.tof();
251 if (tof > tofstart && tof < tofend) {
252 double weight = event.weight();
253 intensity += weight;
254 rowcentroid += irow * weight;
255 colcentroid += icol * weight;
256 tofcentroid += tof * weight;
257 }
258 }
259 }
260 }
261 // Set pixelID to change row and col
262 row = int(rowcentroid / intensity);
263 boost::algorithm::clamp(row, 0, nRows - 1);
264 col = int(colcentroid / intensity);
265 boost::algorithm::clamp(col, 0, nCols - 1);
266 if (!edgePixel(inst, bankName, col, row, Edge)) {
267 peak.setDetectorID(findPixelID(bankName, col, row));
268
269 // Set wavelength to change tof for peak object
270 double tof = tofcentroid / intensity;
272 std::vector<double> timeflight;
273 timeflight.emplace_back(tof);
274 double scattering = peak.getScattering();
275 double L1 = peak.getL1();
276 double L2 = peak.getL2();
277 wl.fromTOF(timeflight, timeflight, L1, 0, {{UnitParams::l2, L2}, {UnitParams::twoTheta, scattering}});
278 const double lambda = timeflight[0];
279 timeflight.clear();
280
281 peak.setWavelength(lambda);
282 peak.setBinCount(intensity);
283 }
285 }
287 removeEdgePeaks(*peakWS);
288
289 // Save the output
290 setProperty("OutPeaksWorkspace", peakWS);
291}
292
293//----------------------------------------------------------------------------------------------
297 inWS = getProperty("InputWorkspace");
298 inst = inWS->getInstrument();
299 // For quickly looking up workspace index from det id
300 wi_to_detid_map = inWS->getDetectorIDToWorkspaceIndexMap();
301
302 eventW = std::dynamic_pointer_cast<const EventWorkspace>(inWS);
303 if (eventW) {
304 eventW->sortAll(TOF_SORT, nullptr);
305 this->integrateEvent();
306 } else {
307 this->integrate();
308 }
309}
310
311int CentroidPeaks::findPixelID(const std::string &bankName, int col, int row) {
312 std::shared_ptr<const IComponent> parent = inst->getComponentByName(bankName);
313 if (parent->type() == "RectangularDetector") {
314 std::shared_ptr<const RectangularDetector> RDet = std::dynamic_pointer_cast<const RectangularDetector>(parent);
315
316 std::shared_ptr<Detector> pixel = RDet->getAtXY(col, row);
317 return pixel->getID();
318 } else {
319 std::string bankName0 = bankName;
320 // Only works for WISH
321 bankName0.erase(0, 4);
322 std::ostringstream pixelString;
323 pixelString << inst->getName() << "/" << bankName0 << "/" << bankName << "/tube" << std::setw(3)
324 << std::setfill('0') << col << "/pixel" << std::setw(4) << std::setfill('0') << row;
325 std::shared_ptr<const Geometry::IComponent> component = inst->getComponentByName(pixelString.str());
326 std::shared_ptr<const Detector> pixel = std::dynamic_pointer_cast<const Detector>(component);
327 return pixel->getID();
328 }
329}
330
332 int Edge = getProperty("EdgePixels");
333 std::vector<int> badPeaks;
334 size_t numPeaks = peakWS.getNumberPeaks();
335 for (int i = 0; i < static_cast<int>(numPeaks); i++) {
336 // Get a direct ref to that peak.
337 const auto &peak = peakWS.getPeak(i);
338 int col = peak.getCol();
339 int row = peak.getRow();
340 const std::string &bankName = peak.getBankName();
341
342 if (edgePixel(inst, bankName, col, row, Edge)) {
343 badPeaks.emplace_back(i);
344 }
345 }
346 peakWS.removePeaks(std::move(badPeaks));
347}
348
349void CentroidPeaks::sizeBanks(const std::string &bankName, int &nCols, int &nRows) {
350 if (bankName == "None")
351 return;
352 ExperimentInfo expInfo;
353 expInfo.setInstrument(inst);
354 const auto &compInfo = expInfo.componentInfo();
355
356 // Get a single bank
357 auto bank = inst->getComponentByName(bankName);
358 auto bankID = bank->getComponentID();
359 auto allBankDetectorIndexes = compInfo.detectorsInSubtree(compInfo.indexOf(bankID));
360
361 nRows = static_cast<int>(compInfo.componentsInSubtree(compInfo.indexOf(bankID)).size() -
362 allBankDetectorIndexes.size() - 1);
363 nCols = static_cast<int>(allBankDetectorIndexes.size()) / nRows;
364
365 if (nCols * nRows != static_cast<int>(allBankDetectorIndexes.size())) {
366 // Need grandchild instead of child
367 nRows = static_cast<int>(compInfo.componentsInSubtree(compInfo.indexOf(bankID)).size() -
368 allBankDetectorIndexes.size() - 2);
369 nCols = static_cast<int>(allBankDetectorIndexes.size()) / nRows;
370 }
371}
372
373} // namespace Mantid::Crystal
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
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...
Definition: MultiThreaded.h:94
#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.
Definition: Algorithm.cpp:1913
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
API::MatrixWorkspace_sptr inWS
Input 2D Workspace.
Definition: CentroidPeaks.h:52
Mantid::detid2index_map wi_to_detid_map
Definition: CentroidPeaks.h:54
void exec() override
Run the algorithm.
Geometry::Instrument_const_sptr inst
Definition: CentroidPeaks.h:49
void sizeBanks(const std::string &bankName, int &nCols, int &nRows)
DataObjects::EventWorkspace_const_sptr eventW
Definition: CentroidPeaks.h:53
int getRunNumber() const override
Return the run number this peak was measured at.
Definition: BasePeak.cpp:78
A class for holding :
Definition: EventList.h:56
std::vector< WeightedEventNoTime > & getWeightedEventsNoTime()
Return the list of WeightedEvent contained.
Definition: EventList.cpp:823
void switchTo(Mantid::API::EventType newType) override
Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
Definition: EventList.cpp:649
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:341
int getDetectorID() const
Get the ID of the detector at the center of the peak
Definition: Peak.cpp:271
The class PeaksWorkspace stores information about a set of SCD peaks.
Peak & getPeak(int peakNum) override
Return a reference to the Peak.
void removePeaks(std::vector< int > badPeaks) override
Removes multiple peaks.
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 > &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:177
Wavelength in Angstrom.
Definition: Unit.h:302
@ WEIGHTED_NOTIME
Definition: IEventList.h:18
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
MANTID_GEOMETRY_DLL bool edgePixel(const Geometry::Instrument_const_sptr &inst, const std::string &bankName, int col, int row, int Edge)
Function to find peaks near detector edge.
Definition: EdgePixel.cpp:22
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.
Definition: MultiThreaded.h:22
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54