Mantid
Loading...
Searching...
No Matches
SmoothNeighbours.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 +
22
23using namespace Mantid::Kernel;
24using namespace Mantid::Geometry;
25using namespace Mantid::API;
26using namespace Mantid::DataObjects;
27
28using VecProperties = std::vector<Mantid::Kernel::Property *>;
30
31namespace Mantid::Algorithms {
32
33// Register the class into the algorithm factory
34DECLARE_ALGORITHM(SmoothNeighbours)
35
36namespace {
37// Used in custom GUI. Make sure you change them in SmoothNeighboursDialog.cpp
38// as well.
39const std::string NON_UNIFORM_GROUP = "NonUniform Detectors";
40const std::string RECTANGULAR_GROUP = "Rectangular Detectors";
41const std::string INPUT_WORKSPACE = "InputWorkspace";
42
45struct CallOnExit {
46 using Callable = std::function<void()>;
47 CallOnExit(Callable &&callable) noexcept : m_callable(std::move(callable)) {}
48 ~CallOnExit() {
49 try {
50 m_callable();
51 } catch (...) {
52 };
53 }
54
55private:
56 Callable m_callable;
57};
58} // namespace
59
60SmoothNeighbours::SmoothNeighbours() : API::Algorithm(), m_weightedSum(std::make_unique<NullWeighting>()) {}
61
63 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>(INPUT_WORKSPACE, "", Direction::Input,
64 std::make_shared<InstrumentValidator>()),
65 "The workspace containing the spectra to be averaged.");
66 declareProperty(std::make_unique<WorkspaceProperty<MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
67 "The name of the workspace to be created as the output of "
68 "the algorithm.");
69
70 // Unsigned double
71 auto mustBePositiveDouble = std::make_shared<BoundedValidator<double>>();
72 mustBePositiveDouble->setLower(0.0);
73
74 // Unsigned int.
75 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
76 mustBePositive->setLower(0);
77
78 std::vector<std::string> propOptions{"Flat", "Linear", "Parabolic", "Gaussian"};
79 declareProperty("WeightedSum", "Flat", std::make_shared<StringListValidator>(propOptions),
80 "What sort of Weighting scheme to use?\n"
81 " Flat: Effectively no-weighting, all weights are 1.\n"
82 " Linear: Linear weighting 1 - r/R from origin.\n"
83 " Parabolic : Weighting as cutoff - x + cutoff - y + 1."
84 " Gaussian : Uses the absolute distance x^2 + y^2 ... "
85 "normalised by the cutoff^2");
86
87 declareProperty("Sigma", 0.5, mustBePositiveDouble, "Sigma value for gaussian weighting schemes. Defaults to 0.5. ");
88 setPropertySettings("Sigma", std::make_unique<EnabledWhenProperty>("WeightedSum", IS_EQUAL_TO, "Gaussian"));
89
90 declareProperty("IgnoreMaskedDetectors", true, "If true, do not consider masked detectors in the NN search.");
91
92 declareProperty("PreserveEvents", true,
93 "If the InputWorkspace is an "
94 "EventWorkspace, this will preserve "
95 "the full event list (warning: this "
96 "will use much more memory!).");
97
98 // -- Rectangular properties --
99
100 declareProperty("AdjX", 1, mustBePositive,
101 "The number of X (horizontal) adjacent pixels to average together. "
102 "Only for instruments with RectangularDetectors. ");
103
104 declareProperty("AdjY", 1, mustBePositive,
105 "The number of Y (vertical) adjacent pixels to average together. "
106 "Only for instruments with RectangularDetectors. ");
107
108 declareProperty("SumPixelsX", 1, mustBePositive,
109 "The total number of X (horizontal) adjacent pixels to sum together. "
110 "Only for instruments with RectangularDetectors. AdjX will be ignored "
111 "if SumPixelsX > 1.");
112
113 declareProperty("SumPixelsY", 1, mustBePositive,
114 "The total number of Y (vertical) adjacent pixels to sum together. "
115 "Only for instruments with RectangularDetectors. AdjY will be ignored if "
116 "SumPixelsY > 1");
117
118 declareProperty("ZeroEdgePixels", 0, mustBePositive,
119 "The number of pixels to zero at edges. "
120 "Only for instruments with RectangularDetectors. ");
121
122 setPropertyGroup("AdjX", RECTANGULAR_GROUP);
123 setPropertyGroup("AdjY", RECTANGULAR_GROUP);
124 setPropertyGroup("SumPixelsX", RECTANGULAR_GROUP);
125 setPropertyGroup("SumPixelsY", RECTANGULAR_GROUP);
126 setPropertyGroup("ZeroEdgePixels", RECTANGULAR_GROUP);
127
128 // -- Non-uniform properties --
129
130 std::vector<std::string> radiusPropOptions{"Meters", "NumberOfPixels"};
131 declareProperty("RadiusUnits", "Meters", std::make_shared<StringListValidator>(radiusPropOptions),
132 "Units used to specify the radius.\n"
133 " Meters : Radius is in meters.\n"
134 " NumberOfPixels : Radius is in terms of the number of pixels.");
135
136 declareProperty("Radius", 0.0, mustBePositiveDouble,
137 "The radius cut-off around a pixel to look for nearest neighbours to "
138 "average. \n"
139 "This radius cut-off is applied to a set of nearest neighbours whose "
140 "number is "
141 "defined in the NumberOfNeighbours property. See below for more details. "
142 "\n"
143 "If 0, will use the AdjX and AdjY parameters for rectangular detectors "
144 "instead.");
145
146 declareProperty("NumberOfNeighbours", 8, mustBePositive,
147 "Number of nearest neighbouring pixels.\n"
148 "The default is 8.");
149
150 declareProperty("SumNumberOfNeighbours", 1,
151 "Sum nearest neighbouring pixels with same parent.\n"
152 "Number of pixels will be reduced. The default is false.");
153
154 declareProperty("ExpandSumAllPixels", false,
155 "OuputWorkspace will have same number of pixels as "
156 "InputWorkspace using SumPixelsX and SumPixelsY. Individual "
157 "pixels will have averages.");
158
159 setPropertyGroup("RadiusUnits", NON_UNIFORM_GROUP);
160 setPropertyGroup("Radius", NON_UNIFORM_GROUP);
161 setPropertyGroup("NumberOfNeighbours", NON_UNIFORM_GROUP);
162 setPropertyGroup("SumNumberOfNeighbours", NON_UNIFORM_GROUP);
163}
164
165//--------------------------------------------------------------------------------------------
170 g_log.debug("SmoothNeighbours processing assuming rectangular detectors.");
171
172 m_progress->resetNumSteps(m_inWS->getNumberHistograms(), 0.2, 0.5);
173
174 const auto &componentInfo = m_inWS->componentInfo();
175 const auto &detectorInfo = m_inWS->detectorInfo();
176
177 // To get the workspace index from the detector ID
178 const detid2index_map pixel_to_wi = m_inWS->getDetectorIDToWorkspaceIndexMap(true, true);
179
180 // Build a list of Rectangular/Grid Detectors (as component indices)
181 std::vector<size_t> detList;
182 for (size_t i = 0; i < componentInfo.size(); ++i) {
183 if (componentInfo.isGridDetector(i)) {
184 detList.emplace_back(i);
185 }
186 }
187
188 if (detList.empty()) {
189 // Not rectangular so use Nearest Neighbours
190 m_radius = translateToMeters("NumberOfPixels", std::max(m_adjX, m_adjY));
194 return;
195 }
196
197 Progress prog(this, 0.0, 1.0, detList.size());
198
199 // Resize the vector we are setting
200 m_neighbours.resize(m_inWS->getNumberHistograms());
201 int startX = -m_adjX;
202 int startY = -m_adjY;
203 int endX = m_adjX;
204 int endY = m_adjY;
205 const int sumX = getProperty("SumPixelsX");
206 const int sumY = getProperty("SumPixelsY");
207 bool sum = sumX * sumY > 1;
208 if (sum) {
209 startX = 0;
210 startY = 0;
211 endX = sumX - 1;
212 endY = sumY - 1;
213 }
214
215 m_outWI = 0;
216 // Build a map to sort by the detectorID
217 std::vector<std::pair<int, int>> idToIndexMap;
218 idToIndexMap.reserve(detList.size());
219 for (int i = 0; i < static_cast<int>(detList.size()); i++)
220 idToIndexMap.emplace_back(detectorInfo.detid(componentInfo.detectorIndexAtXYZ(detList[i], 0, 0, 0)), i);
221
222 // To sort in descending order
223 if (sum)
224 stable_sort(idToIndexMap.begin(), idToIndexMap.end());
225
226 // Loop through the RectangularDetector's we listed before.
227 for (const auto &idIndex : idToIndexMap) {
228 const size_t bankIndex = detList[idIndex.second];
229 const auto grid = componentInfo.pixelGridComponent(bankIndex);
230 const std::string det_name = componentInfo.name(bankIndex);
231 for (int j = 0; j < grid.nX; j += sumX) {
232 for (int k = 0; k < grid.nY; k += sumY) {
233 double totalWeight = 0;
234 // Neighbours and weights
235 std::vector<weightedNeighbour> neighbours;
236
237 for (int ix = startX; ix <= endX; ix++)
238 for (int iy = startY; iy <= endY; iy++) {
239 // Weights for corners=1; higher for center and adjacent pixels
240 double smweight = m_weightedSum->weightAt(m_adjX, ix, m_adjY, iy);
241
242 // Find the pixel ID at that XY position on the rectangular
243 // detector
244 if (j + ix >= grid.nX - m_edge || j + ix < m_edge)
245 continue;
246 if (k + iy >= grid.nY - m_edge || k + iy < m_edge)
247 continue;
248 int pixelID = detectorInfo.detid(componentInfo.detectorIndexAtXYZ(bankIndex, j + ix, k + iy, 0));
249
250 // Find the corresponding workspace index, if any
251 auto mapEntry = pixel_to_wi.find(pixelID);
252 if (mapEntry != pixel_to_wi.end()) {
253 size_t wi = mapEntry->second;
254 neighbours.emplace_back(wi, smweight);
255 // Count the total weight
256 totalWeight += smweight;
257 }
258 }
259
260 // Adjust the weights of each neighbour to normalize to unity
261 if (!sum || m_expandSumAllPixels)
262 for (auto &neighbour : neighbours)
263 neighbour.second /= totalWeight;
264
265 // Save the list of neighbours for this output workspace index.
266 m_neighbours[m_outWI] = neighbours;
267 m_outWI++;
268
269 m_progress->report("Finding Neighbours");
270 }
271 }
272 prog.report(det_name);
273 }
274}
275
276//--------------------------------------------------------------------------------------------
280 g_log.debug("SmoothNeighbours processing NOT assuming rectangular detectors.");
281
282 m_progress->resetNumSteps(m_inWS->getNumberHistograms(), 0.2, 0.5);
283 this->progress(0.2, "Building Neighbour Map");
284
285 const spec2index_map spec2index = m_inWS->getSpectrumToWorkspaceIndexMap();
286
287 // Resize the vector we are setting
288 m_neighbours.resize(m_inWS->getNumberHistograms());
289
290 bool ignoreMaskedDetectors = getProperty("IgnoreMaskedDetectors");
291 WorkspaceNearestNeighbourInfo neighbourInfo(*m_inWS, ignoreMaskedDetectors, m_nNeighbours);
292
293 // Cull by radius
294 RadiusFilter radiusFilter(m_radius);
295
296 // Go through every input workspace pixel
297 m_outWI = 0;
298 int sum = getProperty("SumNumberOfNeighbours");
299 size_t parent{ComponentInfo::invalidIndex}, grandparent{ComponentInfo::invalidIndex};
300 std::vector<bool> used(m_inWS->getNumberHistograms(), false);
301 const auto &componentInfo = m_inWS->componentInfo();
302 const auto &detectorInfo = m_inWS->detectorInfo();
303 for (size_t wi = 0; wi < m_inWS->getNumberHistograms(); wi++) {
304 if (sum > 1)
305 if (used[wi])
306 continue;
307 // We want to skip monitors
308 try {
309 // Get the list of detectors in this pixel
310 const auto &dets = m_inWS->getSpectrum(wi).getDetectorIDs();
311 const auto index = detectorInfo.indexOf(*dets.begin());
312 if (detectorInfo.isMonitor(index))
313 continue; // skip monitor
314 if (detectorInfo.isMasked(index)) {
315 // Calibration masks many detectors, but there should be 0s after
316 // smoothing
317 if (sum == 1)
318 m_outWI++;
319 continue; // skip masked detectors
320 }
321 if (sum > 1) {
322 if (componentInfo.hasParent(index)) {
323 parent = componentInfo.parent(index);
324 if (componentInfo.hasParent(parent))
325 grandparent = componentInfo.parent(parent);
326 }
327 }
329 continue; // skip missing detector
330 }
331
332 specnum_t inSpec = m_inWS->getSpectrum(wi).getSpectrumNo();
333
334 // Step one - Get the number of specified neighbours
335 SpectraDistanceMap insideGrid = neighbourInfo.getNeighboursExact(inSpec);
336
337 // Step two - Filter the results by the radius cut off.
338 SpectraDistanceMap neighbSpectra = radiusFilter.apply(insideGrid);
339
340 // Force the central pixel to always be there
341 // There seems to be a bug in nearestNeighbours, returns distance != 0.0 for
342 // the central pixel. So we force distance = 0
343 neighbSpectra[inSpec] = V3D(0.0, 0.0, 0.0);
344
345 // Neighbours and weights list
346 double totalWeight = 0;
347 int noNeigh = 0;
348 std::vector<weightedNeighbour> neighbours;
349
350 // Convert from spectrum numbers to workspace indices
351 for (const auto &specDistance : neighbSpectra) {
352 specnum_t spec = specDistance.first;
353
354 // Use the weighting strategy to calculate the weight.
355 double weight = m_weightedSum->weightAt(specDistance.second);
356
357 if (weight > 0) {
358 // Find the corresponding workspace index
359 auto mapIt = spec2index.find(spec);
360 if (mapIt != spec2index.end()) {
361 size_t neighWI = mapIt->second;
362 if (sum > 1) {
363 // Get the list of detectors in this pixel
364 const std::set<detid_t> &dets = m_inWS->getSpectrum(neighWI).getDetectorIDs();
365 const auto neighbParent = componentInfo.parent(detectorInfo.indexOf(*dets.begin()));
366 const auto neighbGParent = componentInfo.parent(neighbParent);
367 if (noNeigh >= sum || componentInfo.name(neighbParent) != componentInfo.name(parent) ||
368 componentInfo.name(neighbGParent) != componentInfo.name(grandparent) || used[neighWI])
369 continue;
370 noNeigh++;
371 used[neighWI] = true;
372 }
373 neighbours.emplace_back(neighWI, weight);
374 totalWeight += weight;
375 }
376 }
377 }
378
379 // Adjust the weights of each neighbour to normalize to unity
380 if (sum == 1)
381 for (auto &neighbour : neighbours)
382 neighbour.second /= totalWeight;
383
384 // Save the list of neighbours for this output workspace index.
385 m_neighbours[m_outWI] = neighbours;
386 m_outWI++;
387
388 m_progress->report("Finding Neighbours");
389 } // each workspace index
390}
391
399void SmoothNeighbours::setWeightingStrategy(const std::string &strategyName, double &cutOff) {
400 if (strategyName == "Flat") {
401 m_weightedSum = std::make_unique<FlatWeighting>();
402 } else if (strategyName == "Linear") {
403 m_weightedSum = std::make_unique<LinearWeighting>(cutOff);
404 } else if (strategyName == "Parabolic") {
405 m_weightedSum = std::make_unique<ParabolicWeighting>(cutOff);
406 } else if (strategyName == "Gaussian") {
407 m_weightedSum = std::make_unique<GaussianWeightingnD>(cutOff, getProperty("Sigma"));
408 }
409 g_log.information() << "Smoothing with " << strategyName << " Weighting\n";
410}
411
418double SmoothNeighbours::translateToMeters(const std::string &radiusUnits, const double &enteredRadius) const {
419 double translatedRadius = 0;
420 if (radiusUnits == "Meters") {
421 // Nothing more to do.
422 translatedRadius = enteredRadius;
423 } else if (radiusUnits == "NumberOfPixels") {
424 // Get the first idetector from the workspace index 0.
425 const auto &firstDet = m_inWS->spectrumInfo().detector(0);
426 // Find the bounding box of that detector
427 BoundingBox bbox;
428 firstDet.getBoundingBox(bbox);
429 // Multiply (meters/pixels) by number of pixels, note that enteredRadius
430 // takes on meaning of the number of pixels.
431 translatedRadius = bbox.width().norm() * enteredRadius;
432 } else {
433 const std::string message = "SmoothNeighbours::translateToMeters, Unknown Unit: " + radiusUnits;
434 throw std::invalid_argument(message);
435 }
436 return translatedRadius;
437}
438
443 m_inWS = getProperty("InputWorkspace");
444
445 m_preserveEvents = getProperty("PreserveEvents");
446 m_expandSumAllPixels = getProperty("ExpandSumAllPixels");
447
448 // Use the unit type to translate the entered radius into meters.
449 m_radius = translateToMeters(getProperty("RadiusUnits"), getProperty("Radius"));
450
452
453 m_adjX = getProperty("AdjX");
454 m_adjY = getProperty("AdjY");
455 m_edge = getProperty("ZeroEdgePixels");
456
457 m_nNeighbours = getProperty("NumberOfNeighbours");
458
459 // Progress reporting, first for the sorting
460 m_progress = std::make_unique<Progress>(this, 0.0, 0.2, m_inWS->getNumberHistograms());
461
462 // Clean up when we are done
463 CallOnExit resetInWSOnExit([this]() { m_inWS.reset(); });
464 CallOnExit resetNeighboursOnExit([this]() {
465 m_neighbours.clear();
466 m_neighbours.shrink_to_fit();
467 });
468
469 // Run the appropriate method depending on the type of the instrument
470 if (m_inWS->getInstrument()->containsRectDetectors() == Instrument::ContainsState::Full)
472 else
474
475 auto wsEvent = std::dynamic_pointer_cast<EventWorkspace>(m_inWS);
476 if (wsEvent)
477 wsEvent->sortAll(TOF_SORT, m_progress.get());
478 if (wsEvent && m_preserveEvents)
479 this->execEvent(wsEvent);
480 else
481 this->execWorkspace2D();
482}
483
484//--------------------------------------------------------------------------------------------
487 m_progress->resetNumSteps(m_inWS->getNumberHistograms(), 0.5, 1.0);
488
489 // Get some stuff from the input workspace
490 const size_t numberOfSpectra = m_outWI;
491
492 const size_t YLength = m_inWS->blocksize();
493
495 // Make a brand new Workspace2D
496 if (std::dynamic_pointer_cast<OffsetsWorkspace>(m_inWS)) {
497 g_log.information() << "Creating new OffsetsWorkspace\n";
498 outWS = MatrixWorkspace_sptr(new OffsetsWorkspace(m_inWS->getInstrument()));
499 } else {
500 outWS = std::dynamic_pointer_cast<MatrixWorkspace>(
501 API::WorkspaceFactory::Instance().create("Workspace2D", numberOfSpectra, YLength + 1, YLength));
502 }
503 this->setProperty("OutputWorkspace", outWS);
504
505 setupNewInstrument(*outWS);
506
507 // Go through all the output workspace
509 for (int outWIi = 0; outWIi < int(numberOfSpectra); outWIi++) {
511
512 auto &outSpec = outWS->getSpectrum(outWIi);
513 // Reset the Y and E vectors
514 outSpec.clearData();
515 auto &outY = outSpec.mutableY();
516 // We will temporarily carry the squared error
517 auto &outE = outSpec.mutableE();
518 // tmp to carry the X Data.
519 auto &outX = outSpec.mutableX();
520
521 // Which are the neighbours?
522 std::vector<weightedNeighbour> &neighbours = m_neighbours[outWIi];
523 std::vector<weightedNeighbour>::iterator it;
524 for (it = neighbours.begin(); it != neighbours.end(); ++it) {
525 size_t inWI = it->first;
526 double weight = it->second;
527 double weightSquared = weight * weight;
528
529 const auto &inSpec = m_inWS->getSpectrum(inWI);
530 const auto &inY = inSpec.y();
531 const auto &inE = inSpec.e();
532 const auto &inX = inSpec.x();
533
534 for (size_t i = 0; i < YLength; i++) {
535 // Add the weighted signal
536 outY[i] += inY[i] * weight;
537 // Square the error, scale by weight (which you have to square too),
538 // then add in quadrature
539 double errorSquared = inE[i];
540 errorSquared *= errorSquared;
541 errorSquared *= weightSquared;
542 outE[i] += errorSquared;
543 // Copy the X values as well
544 outX[i] = inX[i];
545 }
546 if (m_inWS->isHistogramData()) {
547 outX[YLength] = inX[YLength];
548 }
549 } //(each neighbour)
550
551 // Now un-square the error, since we summed it in quadrature
552 for (size_t i = 0; i < YLength; i++)
553 outE[i] = sqrt(outE[i]);
554
555 m_progress->report("Summing");
557 }
560 spreadPixels(outWS);
561}
562
563//--------------------------------------------------------------------------------------------
567 // Copy geometry over.
568 API::WorkspaceFactory::Instance().initializeFromParent(*m_inWS, outWS, false);
569
570 // Go through all the output workspace
571 size_t numberOfSpectra = outWS.getNumberHistograms();
572
573 for (int outWIi = 0; outWIi < int(numberOfSpectra); outWIi++) {
574 auto &outSpec = outWS.getSpectrum(outWIi);
575
576 // Reset detectors
577 outSpec.clearDetectorIDs();
578
579 // Which are the neighbours?
580 for (const auto &neighbor : m_neighbours[outWIi]) {
581 const auto &inSpec = m_inWS->getSpectrum(neighbor.first);
582 outSpec.addDetectorIDs(inSpec.getDetectorIDs());
583 }
584 }
585}
586//--------------------------------------------------------------------------------------------
590 // Get some stuff from the input workspace
591 const size_t numberOfSpectra = m_inWS->getNumberHistograms();
592
593 const size_t YLength = m_inWS->blocksize();
594
596 // Make a brand new Workspace2D
597 if (std::dynamic_pointer_cast<OffsetsWorkspace>(m_inWS)) {
598 g_log.information() << "Creating new OffsetsWorkspace\n";
599 outws2 = std::make_shared<OffsetsWorkspace>(m_inWS->getInstrument());
600 } else {
601 outws2 = std::dynamic_pointer_cast<MatrixWorkspace>(
602 API::WorkspaceFactory::Instance().create("Workspace2D", numberOfSpectra, YLength + 1, YLength));
603 }
604
605 // Copy geometry over.
606 API::WorkspaceFactory::Instance().initializeFromParent(*m_inWS, *outws2, false);
607 // Go through all the input workspace
608 for (int outWIi = 0; outWIi < int(numberOfSpectra); outWIi++) {
609 const auto &inSpec = m_inWS->getSpectrum(outWIi);
610 auto &outSpec2 = outws2->getSpectrum(outWIi);
611 outSpec2.mutableX() = inSpec.x();
612 outSpec2.addDetectorIDs(inSpec.getDetectorIDs());
613 // Zero the Y and E vectors
614 outSpec2.clearData();
615 }
616
617 // Go through all the output workspace
618 const size_t numberOfSpectra2 = outWS->getNumberHistograms();
619 for (int outWIi = 0; outWIi < int(numberOfSpectra2); outWIi++) {
620
621 // Which are the neighbours?
622 for (const auto &neighbor : m_neighbours[outWIi]) {
623 outws2->setHistogram(neighbor.first, outWS->histogram(outWIi));
624 }
625 }
626 this->setProperty("OutputWorkspace", outws2);
627}
628//--------------------------------------------------------------------------------------------
633 m_progress->resetNumSteps(m_inWS->getNumberHistograms(), 0.5, 1.0);
634
635 // Get some stuff from the input workspace
636 const size_t numberOfSpectra = m_outWI;
637 const auto YLength = static_cast<int>(m_inWS->blocksize());
638
640 // Make a brand new EventWorkspace
641 outWS = std::dynamic_pointer_cast<EventWorkspace>(
642 API::WorkspaceFactory::Instance().create("EventWorkspace", numberOfSpectra, YLength + 1, YLength));
643 // Copy geometry over.
644 API::WorkspaceFactory::Instance().initializeFromParent(*ws, *outWS, false);
645 // Ensure thread-safety
646 outWS->sortAll(TOF_SORT, nullptr);
647
648 this->setProperty("OutputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(outWS));
649
650 // Calculate total number of events for each EventList
651 std::vector<size_t> outputEvents(numberOfSpectra, 0);
652 for (int i = 0; i < int(numberOfSpectra); i++) {
653 const std::vector<weightedNeighbour> &neighbours = m_neighbours[i];
654 for (const auto &neighbour : neighbours) {
655 size_t inWI = neighbour.first;
656 outputEvents[i] += ws->getSpectrum(inWI).getNumberEvents();
657 }
658 }
659
660 // Go through all the output workspace
662 for (int outWIi = 0; outWIi < int(numberOfSpectra); outWIi++) {
664
665 // Create the output event list (empty)
666 EventList &outEL = outWS->getSpectrum(outWIi);
667 outEL.reserve(outputEvents[outWIi]);
668
669 // Which are the neighbours?
670 std::vector<weightedNeighbour> &neighbours = m_neighbours[outWIi];
671 std::vector<weightedNeighbour>::iterator it;
672 for (it = neighbours.begin(); it != neighbours.end(); ++it) {
673 size_t inWI = it->first;
674 // if(sum)outEL.copyInfoFrom(*ws->getSpectrum(inWI));
675 double weight = it->second;
676 // Copy the event list
677 EventList tmpEL = ws->getSpectrum(inWI);
678 // Scale it
679 tmpEL *= weight;
680 // Add it
681 outEL += tmpEL;
682 }
683
684 m_progress->report("Summing");
686 }
688
689 // Give the 0-th X bins to all the output spectra.
690 outWS->setAllX(m_inWS->binEdges(0));
692 spreadPixels(outWS);
693}
694
695} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
std::map< DeltaEMode::Type, std::string > index
#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.
const VecProperties ConstVecProperties
std::vector< Mantid::Kernel::Property * > VecProperties
Callable m_callable
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:76
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.
Kernel::Logger & g_log
Definition Algorithm.h:426
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
void clearDetectorIDs()
Clear the detector IDs set.
Base MatrixWorkspace Abstract Class.
virtual ISpectrum & getSpectrum(const size_t index)=0
Return the underlying ISpectrum ptr at the given workspace index.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
Helper class for reporting progress from algorithms.
Definition Progress.h:25
WorkspaceNearestNeighbourInfo provides easy access to nearest-neighbour information for a workspace.
std::map< specnum_t, Kernel::V3D > getNeighboursExact(specnum_t spec) const
Queries the WorkspaceNearestNeighbours object for the selected spectrum number.
A property class for workspaces.
SpectraDistanceMap apply(SpectraDistanceMap &unfiltered) const
Apply the filtering based on radius.
void execWorkspace2D()
Execute the algorithm for a Workspace2D/don't preserve events input.
std::vector< std::vector< weightedNeighbour > > m_neighbours
Vector of list of neighbours (with weight) for each workspace index.
void setWeightingStrategy(const std::string &strategyName, double &cutOff)
Sets the weighting stragegy.
void init() override
Virtual method - must be overridden by concrete algorithm.
std::unique_ptr< WeightingStrategy > m_weightedSum
Weight the neighbours during summing.
void findNeighboursUbiquitous()
Use NearestNeighbours to find the neighbours for any instrument.
size_t m_outWI
number of output workspace pixels
bool m_expandSumAllPixels
expand by pixel IDs
double m_radius
Radius to search nearest neighbours.
void spreadPixels(const API::MatrixWorkspace_sptr &outWS)
Build the instrument/detector setup in workspace.
void setupNewInstrument(API::MatrixWorkspace &outWS) const
Build the instrument/detector setup in workspace.
double translateToMeters(const std::string &radiusUnits, const double &enteredRadius) const
Translate the entered radius into meters.
Mantid::API::MatrixWorkspace_sptr m_inWS
Input workspace.
void exec() override
Executes the algorithm.
std::unique_ptr< Mantid::API::Progress > m_progress
Progress reporter.
void findNeighboursRectangular()
Fill the neighbours list given the AdjX AdjY parameters and an instrument with rectangular detectors.
void execEvent(Mantid::DataObjects::EventWorkspace_sptr &ws)
Execute the algorithm for a EventWorkspace input.
int m_nNeighbours
Number of neighbours.
A class for holding :
Definition EventList.h:57
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
An OffsetsWorkspace is a specialized Workspace2D where the Y value at each pixel is the offset to be ...
A simple structure that defines an axis-aligned cuboid shaped bounding box for a geometrical object.
Definition BoundingBox.h:33
Kernel::V3D width() const
Returns the width of the box.
Definition BoundingBox.h:97
static constexpr size_t invalidIndex
Returned by indexOfOrInvalid() for a component ID that is not part of this instrument.
Exception for when an item is not found in a collection.
Definition Exception.h:145
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings const > settings)
Add a PropertySettings instance to the chain of settings for a given property.
void setPropertyGroup(const std::string &name, const std::string &group)
Set the group for a given property.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
Class for 3D vectors.
Definition V3D.h:35
double norm() const noexcept
Definition V3D.h:270
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::map< specnum_t, Mantid::Kernel::V3D > SpectraDistanceMap
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
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.
std::unordered_map< specnum_t, size_t > spec2index_map
Map with key = spectrum number, value = workspace index.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
STL namespace.
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55