Mantid
Loading...
Searching...
No Matches
Divide.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 +
8
9using namespace Mantid::API;
10using namespace Mantid::Kernel;
11using namespace Mantid::DataObjects;
12
13namespace Mantid::Algorithms {
14// Register the class into the algorithm factory
16
17void Divide::init() {
19 declareProperty("WarnOnZeroDivide", true,
20 "Algorithm usually warns if "
21 "division by 0 occurs. Set this "
22 "value to false if one does not "
23 "want this message appearing ");
24 declareProperty(std::make_unique<PropertyWithValue<OptionalBool>>("IsDistribution", OptionalBool::Unset),
25 "Set the IsDistribution property of the output workspace,"
26 "or leave empty for the default algorithm behavior.");
27}
28
30 m_warnOnZeroDivide = getProperty("WarnOnZeroDivide");
32}
33
34void Divide::performBinaryOperation(const HistogramData::Histogram &lhs, const HistogramData::Histogram &rhs,
35 HistogramData::HistogramY &YOut, HistogramData::HistogramE &EOut) {
36 const auto bins = static_cast<int>(lhs.e().size());
37
38 for (int j = 0; j < bins; ++j) {
39 // Get references to the input Y's
40 const double leftY = lhs.y()[j];
41 const double rightY = rhs.y()[j];
42
43 // error dividing two uncorrelated numbers, re-arrange so that you don't
44 // get infinity if leftY==0 (when rightY=0 the Y value and the result will
45 // both be infinity)
46 // (Sa/a)2 + (Sb/b)2 = (Sc/c)2
47 // (Sa c/a)2 + (Sb c/b)2 = (Sc)2
48 // = (Sa 1/b)2 + (Sb (a/b2))2
49 // (Sc)2 = (1/b)2( (Sa)2 + (Sb a/b)2 )
50 EOut[j] = sqrt(pow(lhs.e()[j], 2) + pow(leftY * rhs.e()[j] / rightY, 2)) / fabs(rightY);
51
52 // Copy the result last in case one of the input workspaces is also any
53 // output
54 YOut[j] = leftY / rightY;
55 }
56}
57
58void Divide::performBinaryOperation(const HistogramData::Histogram &lhs, const double rhsY, const double rhsE,
59 HistogramData::HistogramY &YOut, HistogramData::HistogramE &EOut) {
60 if (rhsY == 0 && m_warnOnZeroDivide)
61 g_log.warning() << "Division by zero: the RHS is a single-valued vector "
62 "with value zero."
63 << "\n";
64
65 // Do the right-hand part of the error calculation just once
66 const double rhsFactor = pow(rhsE / rhsY, 2);
67 const auto bins = static_cast<int>(lhs.e().size());
68 for (int j = 0; j < bins; ++j) {
69 // Get reference to input Y
70 const double leftY = lhs.y()[j];
71
72 // see comment in the function above for the error formula
73 EOut[j] = sqrt(pow(lhs.e()[j], 2) + pow(leftY, 2) * rhsFactor) / fabs(rhsY);
74 // Copy the result last in case one of the input workspaces is also any
75 // output
76 YOut[j] = leftY / rhsY;
77 }
78}
79
82
83 if (lhs->isRaggedWorkspace() && rhs->isRaggedWorkspace()) {
84 // if both workspaces are ragged, output workspace `isDistribution` flag will be true
85 out->setDistribution(true);
86 }
87 if (rhs->YUnit().empty() || !WorkspaceHelpers::matchingBins(lhs, rhs, true)) {
88 // Do nothing
89 }
90
91 // If the Y units match, then the output will be a distribution and will be
92 // dimensionless
93 else if (lhs->YUnit() == rhs->YUnit() && m_rhsBlocksize != 1) {
94 out->setYUnit("");
95 out->setDistribution(true);
96 }
97 // Else we need to set the unit that results from the division
98 else {
99 if (!lhs->YUnit().empty())
100 out->setYUnit(lhs->YUnit() + "/" + rhs->YUnit());
101 else
102 out->setYUnit("1/" + rhs->YUnit());
103 }
104
105 // override `isDistribution` if user provided
106 OptionalBool isDistribution = this->getProperty("IsDistribution");
107 if (isDistribution == OptionalBool::Value::True)
108 out->setDistribution(true);
109 else if (isDistribution == OptionalBool::Value::False)
110 out->setDistribution(false);
111}
112
113// ===================================== EVENT LIST BINARY OPERATIONS
114// ==========================================
122 // We must histogram the rhs event list to divide.
123 MantidVec rhsY, rhsE;
124 rhs.generateHistogram(rhs.readX(), rhsY, rhsE);
125 lhs.divide(rhs.readX(), rhsY, rhsE);
126}
127
137 const MantidVec &rhsE) {
138 // Divide is implemented at the EventList level.
139 lhs.divide(rhsX, rhsY, rhsE);
140}
141
150void Divide::performEventBinaryOperation(DataObjects::EventList &lhs, const double &rhsY, const double &rhsE) {
151 // Multiply is implemented at the EventList level.
152 lhs.divide(rhsY, rhsE);
153}
154
155//---------------------------------------------------------------------------------------------
163 if (m_elhs) {
164 // The lhs workspace is an EventWorkspace. It can be divided while keeping
165 // event-ishness
166 // Output will be EW
168 // Histogram sizes need not match
169 m_matchXSize = false;
170 } else {
171 m_keepEventWorkspace = false;
172 m_matchXSize = true;
173 }
174
175 // Division is not commutative = you can't flip sides.
176 m_flipSides = false;
177 // The RHS operand will be histogrammed first.
179}
180
181//--------------------------------------------------------------------------------------------
195 // --- Check for event workspaces - different than workspaces 2D! ---
196
197 // A SingleValueWorkspace on the right matches anything
198 if (rhs->size() == 1)
199 return "";
200
201 // A SingleValueWorkspace on the left only matches if rhs was single value
202 // too. Why are you using mantid to do simple math?!?
203 if (lhs->size() == 1)
204 return "The left side cannot contain a single value if the right side "
205 "isn't also a single value.";
206
207 // If RHS only has one value (1D vertical), the number of histograms needs to
208 // match.
209 // Each lhs spectrum will be divided by that scalar
210 // Are we allowing the division by different # of spectra, using detector IDs
211 // to match up?
213 (m_rhsBlocksize == 1 && lhs->getNumberHistograms() == rhs->getNumberHistograms())) {
214 return "";
215 }
216
217 if (m_matchXSize) {
218 // Past this point, for a 2D WS operation, we require the X arrays to match.
219 // Note this only checks the first spectrum except for ragged workspaces
221 return "X arrays must match when dividing 2D workspaces.";
222 }
223 }
224
225 // We don't need to check for matching bins for events. Yay events!
226 const size_t rhsSpec = rhs->getNumberHistograms();
227
228 // If the rhs has a single spectrum, then we can divide. The block size does
229 // NOT need to match,
230 if (rhsSpec == 1)
231 return "";
232
233 // Otherwise, the number of histograms needs to match, but the block size of
234 // each does NOT need to match.
235
236 if (lhs->getNumberHistograms() == rhs->getNumberHistograms()) {
237 return "";
238 } else {
239 return "Number of histograms not identical.";
240 }
241}
242
243} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
const std::vector< double > & rhs
#define fabs(x)
Definition Matrix.cpp:22
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
bool m_lhsRagged
Cache for if LHS workspace's is ragged.
size_t m_rhsBlocksize
Cache for RHS workspace's blocksize.
bool m_keepEventWorkspace
Variable set to true if the operation allows the output to stay as an EventWorkspace.
void init() override
Initialisation method.
bool m_rhsRagged
Cache for if RHS workspace's is ragged.
bool m_AllowDifferentNumberSpectra
The property value.
bool m_useHistogramForRhsEventWorkspace
Are we going to use the histogram representation of the RHS event list when performing the operation?...
bool m_matchXSize
matchXSize set to true if the X sizes of histograms must match.
bool m_flipSides
flipSides set to true if the rhs and lhs operands should be flipped - for commutative binary operatio...
void exec() override
Executes the algorithm.
DataObjects::EventWorkspace_const_sptr m_elhs
Left-hand side EventWorkspace.
Divide performs the division of two input workspaces.
Definition Divide.h:30
std::string checkSizeCompatibility(const API::MatrixWorkspace_const_sptr lhs, const API::MatrixWorkspace_const_sptr rhs) const override
Performs a simple check to see if the sizes of two workspaces are compatible for a binary operation I...
Definition Divide.cpp:193
void exec() override
Executes the algorithm.
Definition Divide.cpp:29
void performEventBinaryOperation(DataObjects::EventList &lhs, const DataObjects::EventList &rhs) override
Carries out the binary operation IN-PLACE on a single EventList, with another EventList as the right-...
Definition Divide.cpp:121
void setOutputUnits(const API::MatrixWorkspace_const_sptr lhs, const API::MatrixWorkspace_const_sptr rhs, API::MatrixWorkspace_sptr out) override
Should be overridden by operations that need to manipulate the units of the output workspace.
Definition Divide.cpp:80
void performBinaryOperation(const HistogramData::Histogram &lhs, const HistogramData::Histogram &rhs, HistogramData::HistogramY &YOut, HistogramData::HistogramE &EOut) override
Carries out the binary operation on a single spectrum, with another spectrum as the right-hand operan...
Definition Divide.cpp:34
void checkRequirements() override
Check what operation will be needed in order to apply the operation to these two types of workspaces.
Definition Divide.cpp:162
A class for holding :
Definition EventList.h:57
void divide(const double value, const double error=0.0) override
Divide the weights in this event list by a scalar with an (optional) error.
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
Kernel::Logger g_log("DetermineSpinStateOrder")
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition cow_ptr.h:172
static bool matchingBins(const std::shared_ptr< const MatrixWorkspace > &ws1, const std::shared_ptr< const MatrixWorkspace > &ws2, const bool firstOnly=false)
Checks whether the bins (X values) of two workspace are the same.