-
Notifications
You must be signed in to change notification settings - Fork 122
/
RebinToWorkspace.cpp
202 lines (178 loc) · 7.73 KB
/
RebinToWorkspace.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAlgorithms/RebinToWorkspace.h"
#include "MantidAPI/HistogramValidator.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidDataObjects/WorkspaceCreation.h"
#include "MantidHistogramData/Rebin.h"
namespace Mantid {
namespace Algorithms {
using namespace API;
using DataObjects::EventWorkspace;
using DataObjects::EventWorkspace_const_sptr;
using HistogramData::Counts;
using HistogramData::CountStandardDeviations;
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(RebinToWorkspace)
//---------------------------
// Private Methods
//---------------------------
/**
* Initialise the algorithm
*/
void RebinToWorkspace::init() {
// using namespace Mantid::DataObjects;
declareProperty(std::make_unique<WorkspaceProperty<>>(
"WorkspaceToRebin", "", Kernel::Direction::Input,
std::make_unique<API::HistogramValidator>()),
"The workspace on which to perform the algorithm "
"This must be a Histogram workspace, not Point data. "
"If this is a problem try ConvertToHistogram.");
declareProperty(std::make_unique<WorkspaceProperty<>>(
"WorkspaceToMatch", "", Kernel::Direction::Input,
std::make_unique<API::HistogramValidator>()),
"The workspace to match the bin boundaries against. "
"This must be a Histogram workspace, not Point data. "
"If this is a problem try ConvertToHistogram.");
declareProperty(
std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
Kernel::Direction::Output),
"The name of the workspace to be created as the output of the algorithm");
declareProperty("PreserveEvents", true,
"Keep the output workspace as an EventWorkspace, if the "
"input has events (default). "
"If the input and output EventWorkspace names are the same, "
"only the X bins are set, which is very quick. "
"If false, then the workspace gets converted to a "
"Workspace2D histogram.");
}
bool RebinToWorkspace::needToRebin(const MatrixWorkspace_sptr &left,
const MatrixWorkspace_sptr &rght) {
// converting from EventWorkspace to Workspace2D is a rebin
if (m_isEvents && (!m_preserveEvents))
return true;
// if pointers match they are the same object
if (left == rght)
return false;
// see if there is the same number of histograms
const size_t numHist = left->getNumberHistograms();
if (numHist != rght->getNumberHistograms())
return true;
// look for first non-equal x-axis between the workspaces
for (size_t i = 0; i < numHist; ++i) {
if (left->getSpectrum(i).x() != rght->getSpectrum(i).x()) {
return true;
}
}
// everything must be the same
return false;
}
/**
* Execute the algorithm
*/
void RebinToWorkspace::exec() {
// The input workspaces ...
MatrixWorkspace_sptr toRebin = getProperty("WorkspaceToRebin");
MatrixWorkspace_sptr toMatch = getProperty("WorkspaceToMatch");
m_preserveEvents = getProperty("PreserveEvents");
m_isEvents = bool(std::dynamic_pointer_cast<const EventWorkspace>(toRebin));
if (needToRebin(toRebin, toMatch)) {
g_log.information("Rebinning");
if (m_isEvents && (!m_preserveEvents)) {
this->histogram(toRebin, toMatch);
} else {
this->rebin(toRebin, toMatch);
}
} else { // don't need to rebin
g_log.information(
"WorkspaceToRebin and WorkspaceToMatch already have matched binning");
MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
const bool inPlace = (toRebin == outputWS);
if (!inPlace) {
outputWS = toRebin->clone();
}
this->setProperty("OutputWorkspace", outputWS);
}
}
// this follows closely what Rebin does except each x-axis is different
void RebinToWorkspace::rebin(MatrixWorkspace_sptr &toRebin,
MatrixWorkspace_sptr &toMatch) {
// create the output workspace
MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
const bool inPlace = (toRebin == outputWS);
if (!inPlace) {
outputWS = toRebin->clone();
}
auto outputWSEvents = std::dynamic_pointer_cast<EventWorkspace>(outputWS);
const auto numHist = static_cast<int>(toRebin->getNumberHistograms());
Progress prog(this, 0.5, 1.0, numHist);
// everything gets the same bin boundaries as the first spectrum
const bool matchingX =
(toRebin->getNumberHistograms() != toMatch->getNumberHistograms());
// rebin
PARALLEL_FOR_IF(Kernel::threadSafe(*toMatch, *outputWS))
for (int i = 0; i < numHist; ++i) {
PARALLEL_START_INTERUPT_REGION
const auto &edges = matchingX ? toMatch->histogram(0).binEdges()
: toMatch->histogram(i).binEdges();
if (m_isEvents) {
outputWSEvents->getSpectrum(i).setHistogram(edges);
} else {
outputWS->setHistogram(
i, HistogramData::rebin(toRebin->histogram(i), edges));
}
prog.report();
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
setProperty("OutputWorkspace", outputWS);
}
// handles the special case when binning from EventWorkspace to Workspace2D most
// efficiently by histogramming the events to the correct binning directly
void RebinToWorkspace::histogram(API::MatrixWorkspace_sptr &toRebin,
API::MatrixWorkspace_sptr &toMatch) {
const auto &inputWS =
std::dynamic_pointer_cast<const EventWorkspace>(toRebin);
const auto numHist = static_cast<int>(toRebin->getNumberHistograms());
// everything gets the same bin boundaries as the first spectrum
const bool matchingX =
(toRebin->getNumberHistograms() != toMatch->getNumberHistograms());
auto outputWS = DataObjects::create<API::HistoWorkspace>(*toRebin);
Progress prog(this, 0.25, 1.0, numHist);
// histogram
PARALLEL_FOR_IF(Kernel::threadSafe(*toMatch, *outputWS))
for (int i = 0; i < numHist; ++i) {
PARALLEL_START_INTERUPT_REGION
const auto &edges = matchingX ? toMatch->histogram(0).binEdges()
: toMatch->histogram(i).binEdges();
// TODO this should be in HistogramData/Rebin
const auto &eventlist = inputWS->getSpectrum(i);
MantidVec y_data(edges.size() - 1), e_data(edges.size() - 1);
eventlist.generateHistogram(edges.rawData(), y_data, e_data);
outputWS->setHistogram(i, edges, Counts(std::move(y_data)),
CountStandardDeviations(std::move(e_data)));
prog.report();
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
setProperty("OutputWorkspace", std::move(outputWS));
}
Parallel::ExecutionMode RebinToWorkspace::getParallelExecutionMode(
const std::map<std::string, Parallel::StorageMode> &storageModes) const {
// Probably we can relax these restrictions based on particular combination
// with storage mode of WorkspaceToRebin, but this is simple and sufficient
// for now.
if (storageModes.at("WorkspaceToMatch") != Parallel::StorageMode::Cloned)
throw std::runtime_error("WorkspaceToMatch must have " +
Parallel::toString(Parallel::StorageMode::Cloned));
return Parallel::getCorrespondingExecutionMode(
storageModes.at("WorkspaceToRebin"));
}
} // namespace Algorithms
} // namespace Mantid