Minus.cpp 8.06 KB
Newer Older
1
2
3
4
5
6
// 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 +
Nick Draper's avatar
re #68    
Nick Draper committed
7
#include "MantidAlgorithms/Minus.h"
8
#include "MantidKernel/VectorHelper.h"
Nick Draper's avatar
re #68    
Nick Draper committed
9
10
11

using namespace Mantid::API;
using namespace Mantid::Kernel;
12

13
14
15
16
17
18
19
namespace Mantid {
namespace Algorithms {
// Register the class into the algorithm factory
DECLARE_ALGORITHM(Minus)

const std::string Minus::alias() const { return "Subtract"; }

20
21
void Minus::performBinaryOperation(const HistogramData::Histogram &lhs,
                                   const HistogramData::Histogram &rhs,
Verena Reimund's avatar
Verena Reimund committed
22
23
                                   HistogramData::HistogramY &YOut,
                                   HistogramData::HistogramE &EOut) {
24
  std::transform(lhs.y().begin(), lhs.y().end(), rhs.y().begin(), YOut.begin(),
25
                 std::minus<double>());
26
  std::transform(lhs.e().begin(), lhs.e().end(), rhs.e().begin(), EOut.begin(),
27
28
                 VectorHelper::SumGaussError<double>());
}
29

30
void Minus::performBinaryOperation(const HistogramData::Histogram &lhs,
Verena Reimund's avatar
Verena Reimund committed
31
32
33
                                   const double rhsY, const double rhsE,
                                   HistogramData::HistogramY &YOut,
                                   HistogramData::HistogramE &EOut) {
34
  using std::placeholders::_1;
35
  std::transform(lhs.y().begin(), lhs.y().end(), YOut.begin(),
36
                 std::bind(std::minus<double>(), _1, rhsY));
37
38
  // Only do E if non-zero, otherwise just copy
  if (rhsE != 0)
39
    std::transform(lhs.e().begin(), lhs.e().end(), EOut.begin(),
40
                   std::bind(VectorHelper::SumGaussError<double>(), _1, rhsE));
41
  else
42
    EOut = lhs.e();
43
}
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// ===================================== 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, with the rhs being negatively weighted.
 *
 *  @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 Minus::performEventBinaryOperation(DataObjects::EventList &lhs,
                                        const DataObjects::EventList &rhs) {
  // Easy, no? :) - This appends the event lists, with the rhs being negatively
  // weighted.
  lhs -= rhs;
}
60

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/** 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 Minus::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 subtract a histogram from an "
      "event list in an EventWorkspace. Try switching to a Workspace2D before "
      "using Minus.");
}
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/** 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 Minus::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 subtract a number from an "
      "event list in an EventWorkspace. Try switching to a Workspace2D before "
      "using Minus.");
}
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
//---------------------------------------------------------------------------------------------
/** 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 Minus::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;
    // Can't flip - this is non-commutative
    m_flipSides = 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();
  }
}
129

130
131
132
133
134
135
136
137
//---------------------------------------------------------------------------------------------
/**
 *  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
 */
138
139
140
bool Minus::checkUnitCompatibility(
    const API::MatrixWorkspace_const_sptr lhs,
    const API::MatrixWorkspace_const_sptr rhs) const {
141
142
143
144
145
  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;
146
    }
147
148
149
150
    if (lhs->isDistribution() != rhs->isDistribution()) {
      g_log.error("The two workspaces are not compatible because one is "
                  "flagged as a distribution.");
      return false;
151
    }
152
153
154
  }
  return true;
}
155

156
157
158
159
160
161
162
163
//---------------------------------------------------------------------------------------------
/**
 *  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
 */
164
165
166
bool Minus::checkCompatibility(
    const API::MatrixWorkspace_const_sptr lhs,
    const API::MatrixWorkspace_const_sptr rhs) const {
167
168
169
170
171
  // Are we allowing the subtraction of different # of spectra, using detector
  // IDs to match up?
  if (m_AllowDifferentNumberSpectra) {
    return true;
  }
172

173
174
  if (!checkUnitCompatibility(lhs, rhs))
    return false;
175

176
177
178
  // Keep checking more generally.
  return BinaryOperation::checkCompatibility(lhs, rhs);
}
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//--------------------------------------------------------------------------------------------
/** 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
Minus::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.";
200
    }
201
202
203
  } else
    return BinaryOperation::checkSizeCompatibility(lhs, rhs);
}
LamarMoore's avatar
LamarMoore committed
204
205
} // namespace Algorithms
} // namespace Mantid