Mantid
Loading...
Searching...
No Matches
IntegrateByComponent.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 +
14#include "MantidTypes/SpectrumDefinition.h"
15
16#include <gsl/gsl_statistics.h>
17#include <unordered_map>
18
19namespace Mantid::Algorithms {
20
21// Register the algorithm into the AlgorithmFactory
22DECLARE_ALGORITHM(IntegrateByComponent)
23
24using namespace Mantid::API;
25using namespace Mantid::Kernel;
26
27//----------------------------------------------------------------------------------------------
29const std::string IntegrateByComponent::name() const { return "IntegrateByComponent"; }
30
32int IntegrateByComponent::version() const { return 1; }
33
35const std::string IntegrateByComponent::category() const { return "Utility\\Workspaces"; }
36
37//----------------------------------------------------------------------------------------------
38
39//----------------------------------------------------------------------------------------------
43 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace", "", Direction::Input,
44 std::make_shared<HistogramValidator>()),
45 "The input workspace.");
46 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
47 "The output workspace.");
48 auto mustBePosInt = std::make_shared<BoundedValidator<int>>();
49 mustBePosInt->setLower(0);
50 declareProperty("LevelsUp", 0, mustBePosInt,
51 "Levels above pixel that will be used to compute the average.\n"
52 "If no level is specified, the median is over the whole instrument.\n If "
53 "0, it will just return the integrated values in each pixel");
54}
55
56//----------------------------------------------------------------------------------------------
60 MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
61 int parents = getProperty("LevelsUp");
62 // Make sure it's integrated
63 auto childAlg = createChildAlgorithm("Integration", 0, 0.2);
64 childAlg->setProperty("InputWorkspace", inputWS);
65 childAlg->setProperty("StartWorkspaceIndex", 0);
66 childAlg->setProperty("EndWorkspaceIndex", EMPTY_INT());
67 childAlg->setProperty("RangeLower", inputWS->getXMin());
68 childAlg->setProperty("RangeUpper", inputWS->getXMax());
69 childAlg->setPropertyValue("IncludePartialBins", "1");
70 childAlg->executeAsChildAlg();
71 MatrixWorkspace_sptr integratedWS = childAlg->getProperty("OutputWorkspace");
72
73 if (parents > 0) {
74 std::vector<std::vector<size_t>> specmap = makeMap(integratedWS, parents);
75 API::Progress prog(this, 0.3, 1.0, specmap.size());
76 // calculate averages
77 const auto &spectrumInfo = integratedWS->spectrumInfo();
78 for (auto hists : specmap) {
79 prog.report();
80 std::vector<double> averageYInput, averageEInput;
81
83 for (int i = 0; i < static_cast<int>(hists.size()); ++i) { // NOLINT
85
86 if (spectrumInfo.isMonitor(hists[i]))
87 continue;
88 if (spectrumInfo.isMasked(hists[i]))
89 continue;
90
91 const double yValue = integratedWS->y(hists[i])[0];
92 const double eValue = integratedWS->e(hists[i])[0];
93
94 if (!std::isfinite(yValue) || !std::isfinite(eValue)) // NaNs/Infs
95 continue;
96
97 // Now we have a good value
98 PARALLEL_CRITICAL(IntegrateByComponent_good) {
99 averageYInput.emplace_back(yValue);
100 averageEInput.emplace_back(eValue * eValue);
101 }
102
104 }
106
107 double averageY, averageE;
108 if (averageYInput.empty()) {
109 g_log.information("some group has no valid histograms. Will use 0 for average.");
110 averageY = 0.;
111 averageE = 0.;
112 } else {
113 averageY = gsl_stats_mean(&averageYInput[0], 1, averageEInput.size());
114 averageE = std::sqrt(gsl_stats_mean(&averageEInput[0], 1, averageYInput.size()));
115 }
116
117 PARALLEL_FOR_IF(Kernel::threadSafe(*integratedWS))
118 for (int i = 0; i < static_cast<int>(hists.size()); ++i) { // NOLINT
120 if (spectrumInfo.isMonitor(hists[i]))
121 continue;
122 if (spectrumInfo.isMasked(hists[i]))
123 continue;
124
125 const double yValue = integratedWS->y(hists[i])[0];
126 const double eValue = integratedWS->e(hists[i])[0];
127 if (!std::isfinite(yValue) || !std::isfinite(eValue)) // NaNs/Infs
128 continue;
129
130 // Now we have a good value
131 PARALLEL_CRITICAL(IntegrateByComponent_setaverage) {
132 integratedWS->mutableY(hists[i])[0] = averageY;
133 integratedWS->mutableE(hists[i])[0] = averageE;
134 }
135
137 }
139 }
140 }
141 // Assign it to the output workspace property
142 setProperty("OutputWorkspace", integratedWS);
143}
144
152std::vector<std::vector<size_t>> IntegrateByComponent::makeInstrumentMap(const API::MatrixWorkspace_sptr &countsWS) {
153 std::vector<std::vector<size_t>> mymap;
154 std::vector<size_t> single;
155
156 for (size_t i = 0; i < countsWS->getNumberHistograms(); i++) {
157 single.emplace_back(i);
158 }
159 mymap.emplace_back(single);
160 return mymap;
161}
162
170std::vector<std::vector<size_t>> IntegrateByComponent::makeMap(const API::MatrixWorkspace_sptr &countsWS, int parents) {
171 // keyed by the component index of the ancestor
172 std::unordered_multimap<size_t, size_t> mymap;
173
174 if (parents == 0) // this should not happen in this file, but if one reuses
175 // the function and parents==0, the program has a sudden end
176 // without this check.
177 {
178 return makeInstrumentMap(countsWS);
179 }
180
181 const auto spectrumInfo = countsWS->spectrumInfo();
182 const auto &componentInfo = countsWS->componentInfo();
183 for (size_t i = 0; i < countsWS->getNumberHistograms(); i++) {
184 if (!spectrumInfo.hasDetectors(i)) {
185 g_log.debug("Spectrum has no detector, skipping");
186 continue;
187 }
188
189 // walk up the component tree to the requested ancestor
190 size_t ancestor = spectrumInfo.firstDetectorIndex(i);
191 for (int level = 0; level < parents; ++level) {
192 if (!componentInfo.hasParent(ancestor)) {
193 g_log.warning("Too many levels up. Will ignore LevelsUp");
194 return makeInstrumentMap(countsWS);
195 }
196 ancestor = componentInfo.parent(ancestor);
197 }
198 mymap.emplace(ancestor, i);
199 }
200
201 std::vector<std::vector<size_t>> speclist;
202 std::vector<size_t> speclistsingle;
203
204 auto s_it = mymap.begin();
205 for (auto m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it) {
206 const size_t theKey = (*m_it).first;
207 auto keyRange = mymap.equal_range(theKey);
208
209 // Iterate over all map elements with key == theKey
210 speclistsingle.clear();
211 for (s_it = keyRange.first; s_it != keyRange.second; ++s_it) {
212 speclistsingle.emplace_back((*s_it).second);
213 }
214 speclist.emplace_back(speclistsingle);
215 }
216
217 return speclist;
218}
219
220} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
#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:426
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
void init() override
Initialize the algorithm's properties.
std::vector< std::vector< size_t > > makeMap(const API::MatrixWorkspace_sptr &countsWS, int parents)
method to check which spectra should be averaged
std::vector< std::vector< size_t > > makeInstrumentMap(const API::MatrixWorkspace_sptr &countsWS)
method to create the map with all spectra
int version() const override
Algorithm's version for identification.
const std::string name() const override
Algorithm's name for identification.
const std::string category() const override
Algorithm's category for identification.
void exec() override
Execute the algorithm.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
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
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.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
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
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55