-
Notifications
You must be signed in to change notification settings - Fork 122
/
Plus.cpp
240 lines (226 loc) · 9.67 KB
/
Plus.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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// 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
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAlgorithms/Plus.h"
#include "MantidKernel/VectorHelper.h"
using namespace Mantid::API;
using namespace Mantid::Kernel;
using namespace Mantid::DataObjects;
namespace Mantid {
namespace Algorithms {
// Register the class into the algorithm factory
DECLARE_ALGORITHM(Plus)
// ===================================== HISTOGRAM BINARY OPERATIONS
// ==========================================
//---------------------------------------------------------------------------------------------
void Plus::performBinaryOperation(const HistogramData::Histogram &lhs,
const HistogramData::Histogram &rhs,
HistogramData::HistogramY &YOut,
HistogramData::HistogramE &EOut) {
std::transform(lhs.y().begin(), lhs.y().end(), rhs.y().begin(), YOut.begin(),
std::plus<double>());
std::transform(lhs.e().begin(), lhs.e().end(), rhs.e().begin(), EOut.begin(),
VectorHelper::SumGaussError<double>());
}
//---------------------------------------------------------------------------------------------
void Plus::performBinaryOperation(const HistogramData::Histogram &lhs,
const double rhsY, const double rhsE,
HistogramData::HistogramY &YOut,
HistogramData::HistogramE &EOut) {
std::transform(lhs.y().begin(), lhs.y().end(), YOut.begin(),
std::bind2nd(std::plus<double>(), rhsY));
// Only do E if non-zero, otherwise just copy
if (rhsE != 0)
std::transform(lhs.e().begin(), lhs.e().end(), EOut.begin(),
std::bind2nd(VectorHelper::SumGaussError<double>(), rhsE));
else
EOut = lhs.e();
}
// ===================================== EVENT LIST BINARY OPERATIONS
// ==========================================
/** Carries out the binary operation IN-PLACE on a single EventList,
* with another EventList as the right-hand operand.
* The event lists simply get appended.
*
* @param lhs :: Reference to the EventList that will be modified in place.
* @param rhs :: Const reference to the EventList on the right hand side.
*/
void Plus::performEventBinaryOperation(DataObjects::EventList &lhs,
const DataObjects::EventList &rhs) {
// Easy, no? :) - This appends the event lists.
lhs += rhs;
}
/** Carries out the binary operation IN-PLACE on a single EventList,
* with another (histogrammed) spectrum as the right-hand operand.
*
* @param lhs :: Reference to the EventList that will be modified in place.
* @param rhsX :: The vector of rhs X bin boundaries
* @param rhsY :: The vector of rhs data values
* @param rhsE :: The vector of rhs error values
*/
void Plus::performEventBinaryOperation(DataObjects::EventList &lhs,
const MantidVec &rhsX,
const MantidVec &rhsY,
const MantidVec &rhsE) {
(void)lhs; // Avoid compiler warnings
(void)rhsX;
(void)rhsY;
(void)rhsE;
throw Exception::NotImplementedError(
"Plus::performEventBinaryOperation() cannot add a histogram to an event "
"list in an EventWorkspace. Try switching to a Workspace2D before "
"adding.");
}
/** Carries out the binary operation IN-PLACE on a single EventList,
* with a single (double) value as the right-hand operand.
* THROWS since it is not possible to add a value to an event list.
*
* @param lhs :: Reference to the EventList that will be modified in place.
* @param rhsY :: The rhs data value
* @param rhsE :: The rhs error value
*/
void Plus::performEventBinaryOperation(DataObjects::EventList &lhs,
const double &rhsY, const double &rhsE) {
(void)lhs; // Avoid compiler warnings
(void)rhsY;
(void)rhsE;
throw Exception::NotImplementedError("Plus::performEventBinaryOperation() "
"cannot add a number to an event list "
"in an EventWorkspace. Try switching to "
"a Workspace2D before adding.");
}
//---------------------------------------------------------------------------------------------
/** Check what operation will be needed in order to apply the operation
* to these two types of workspaces. This function must be overridden
* and checked against all 9 possible combinations.
*
* Must set: m_matchXSize, m_flipSides, m_keepEventWorkspace
*/
void Plus::checkRequirements() {
if (m_erhs && m_elhs) {
// Two EventWorkspaces! They can be concatenated.
// Output will be EW
m_keepEventWorkspace = true;
// Histogram sizes need not match
m_matchXSize = false;
// If adding in place to the right-hand-side: flip it so you add in-place to
// the lhs.
m_flipSides = (m_eout == m_erhs);
m_useHistogramForRhsEventWorkspace = false;
// Special case for plus/minus: if there is only one bin on the RHS, use the
// 2D method (appending event lists)
// so that the single bin is not treated as a scalar
m_do2D_even_for_SingleColumn_on_rhs = true;
} else {
// either or both workspace are "other"
// Use the default behaviour
BinaryOperation::checkRequirements();
// Except that commutation is possible
// If LHS is smaller, e.g. single-value, flip sides to put it on the right
m_flipSides = (m_lhs->size() < m_rhs->size());
}
}
//---------------------------------------------------------------------------------------------
/**
* Return true if the units and distribution-type of the workspaces make them
* compatible
* @param lhs :: first workspace to check for compatibility
* @param rhs :: second workspace to check for compatibility
* @return workspace unit compatibility flag
*/
bool Plus::checkUnitCompatibility(
const API::MatrixWorkspace_const_sptr lhs,
const API::MatrixWorkspace_const_sptr rhs) const {
if (lhs->size() > 1 && rhs->size() > 1) {
if (lhs->YUnit() != rhs->YUnit()) {
g_log.error("The two workspaces are not compatible because they have "
"different units for the data (Y).");
return false;
}
if (lhs->isDistribution() != rhs->isDistribution()) {
g_log.error("The two workspaces are not compatible because one is "
"flagged as a distribution.");
return false;
}
}
return true;
}
//---------------------------------------------------------------------------------------------
/**
* Check the given workspaces for unit, distribution and binary operation
* compatibility. Return is true is the workspaces are compatible.
* @param lhs :: first workspace to check for compatibility
* @param rhs :: second workspace to check for compatibility
* @return workspace compatibility flag
*/
bool Plus::checkCompatibility(const API::MatrixWorkspace_const_sptr lhs,
const API::MatrixWorkspace_const_sptr rhs) const {
if (!checkUnitCompatibility(lhs, rhs))
return false;
// Keep checking more generally.
return CommutativeBinaryOperation::checkCompatibility(lhs, rhs);
}
//--------------------------------------------------------------------------------------------
/** Performs a simple check to see if the sizes of two workspaces are compatible
* for a binary operation
* In order to be size compatible then the larger workspace
* must divide be the size of the smaller workspace leaving no remainder
* @param lhs :: the first workspace to compare
* @param rhs :: the second workspace to compare
* @retval "" The two workspaces are size compatible
* @retval "<reason why not compatible>" The two workspaces are NOT size
* compatible
*/
std::string
Plus::checkSizeCompatibility(const API::MatrixWorkspace_const_sptr lhs,
const API::MatrixWorkspace_const_sptr rhs) const {
if (m_erhs && m_elhs) {
if (lhs->getNumberHistograms() == rhs->getNumberHistograms()) {
return "";
} else {
return "Number of histograms not identical.";
}
} else {
// get the largest workspace
API::MatrixWorkspace_const_sptr wsLarger;
API::MatrixWorkspace_const_sptr wsSmaller;
if (rhs->size() > lhs->size()) {
wsLarger = rhs;
wsSmaller = lhs;
} else {
wsLarger = lhs;
wsSmaller = rhs;
}
// call the base routine
return BinaryOperation::checkSizeCompatibility(wsLarger, wsSmaller);
}
}
//---------------------------------------------------------------------------------------------
/** Adds the integrated proton currents, proton charges, of the two input
* workspaces together
* @param lhs :: one of the workspace samples to be summed
* @param rhs :: the other workspace sample to be summed
* @param ans :: the sample in the output workspace
*/
void Plus::operateOnRun(const Run &lhs, const Run &rhs, Run &ans) const {
// The addition operator of Run will add the proton charges, append logs, etc.
// If ans=lhs or ans=rhs then we need to be careful in which order we do this
if (&rhs == &ans) {
// The output is the same as the RHS workspace so needs to be set to that
// run object
ans = rhs;
ans += lhs;
} else {
// The output is either the same as the LHS workspace so needs to be set to
// that run object
// or it is a completely separate workspace meaning that it actually doesn't
// matter
ans = lhs;
ans += rhs;
}
}
} // namespace Algorithms
} // namespace Mantid