Mantid
Loading...
Searching...
No Matches
ConjoinWorkspaces.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
15namespace Mantid::Algorithms {
16
17using std::size_t;
18using namespace Kernel;
19using namespace API;
20using namespace DataObjects;
21
22// Register the algorithm into the AlgorithmFactory
23DECLARE_ALGORITHM(ConjoinWorkspaces)
24
25//----------------------------------------------------------------------------------------------
27void ConjoinWorkspaces::init() {
28 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace1", "", Direction::InOut),
29 "The name of the first input workspace");
30 declareProperty(std::make_unique<WorkspaceProperty<>>("InputWorkspace2", "", Direction::Input),
31 "The name of the second input workspace");
32 declareProperty(std::make_unique<PropertyWithValue<bool>>("CheckOverlapping", true, Direction::Input),
33 "Verify that the supplied data do not overlap");
34 declareProperty(std::make_unique<PropertyWithValue<std::string>>("YAxisLabel", "", Direction::Input),
35 "The label to set the Y axis to");
36 declareProperty(std::make_unique<PropertyWithValue<std::string>>("YAxisUnit", "", Direction::Input),
37 "The unit to set the Y axis to");
38 declareProperty(std::make_unique<PropertyWithValue<bool>>("CheckMatchingBins", true, Direction::Input),
39 "If true, the algorithm will check that the two input workspaces have matching bins.");
40}
41
42//----------------------------------------------------------------------------------------------
48 // Retrieve the input workspaces
49 MatrixWorkspace_const_sptr ws1 = getProperty("InputWorkspace1");
50 MatrixWorkspace_const_sptr ws2 = getProperty("InputWorkspace2");
51 DataObjects::EventWorkspace_const_sptr eventWs1 = std::dynamic_pointer_cast<const EventWorkspace>(ws1);
52 DataObjects::EventWorkspace_const_sptr eventWs2 = std::dynamic_pointer_cast<const EventWorkspace>(ws2);
53
54 // Make sure that we are not mis-matching EventWorkspaces and other types of
55 // workspaces
56 if (((eventWs1) && (!eventWs2)) || ((!eventWs1) && (eventWs2))) {
57 const std::string message("Only one of the input workspaces are of type "
58 "EventWorkspace; please use matching workspace "
59 "types (both EventWorkspace or both "
60 "Workspace2D).");
61 g_log.error(message);
62 throw std::invalid_argument(message);
63 }
64
65 // Check whether bins match
66 bool checkBins = getProperty("CheckMatchingBins");
67 if (checkBins && !checkBinning(ws1, ws2)) {
68 const std::string message("The bins do not match in the input workspaces. "
69 "Consider using RebinToWorkspace to preprocess "
70 "the workspaces before conjoining them.");
71 g_log.error(message);
72 throw std::invalid_argument(message);
73 }
74
75 if (eventWs1 && eventWs2) {
76 this->checkCompatibility(*eventWs1, *eventWs2);
77 auto output = conjoinEvents(*eventWs1, *eventWs2);
78 setYUnitAndLabel(*output);
79 // Set the result workspace to the first input
80 setProperty("InputWorkspace1", output);
81 } else {
82 auto output = conjoinHistograms(*ws1, *ws2);
83 setYUnitAndLabel(*output);
84 // Set the result workspace to the first input
85 setProperty("InputWorkspace1", output);
86 }
87
88 // Delete the second input workspace from the ADS
89 AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace2"));
90}
91
92//----------------------------------------------------------------------------------------------
99 const API::MatrixWorkspace_const_sptr &ws2) const {
100 if (ws1->isRaggedWorkspace() || ws2->isRaggedWorkspace()) {
101 return false;
102 }
103
104 // If neither workspace is ragged, we only need to check the first specrum.
105 // Otherwise the matchingBins() function requires the two workspaces to have
106 // the same number of spectra.
107 return WorkspaceHelpers::matchingBins(ws1, ws2, true);
108}
109
110//----------------------------------------------------------------------------------------------
120 bool checkSpectra) const {
121 // Loop through the first workspace adding all the spectrum numbers & UDETS to
122 // a set
123 std::set<specnum_t> spectra;
124 std::set<detid_t> detectors;
125 const size_t &nhist1 = ws1.getNumberHistograms();
126 for (size_t i = 0; i < nhist1; ++i) {
127 const auto &spec = ws1.getSpectrum(i);
128 const specnum_t spectrum = spec.getSpectrumNo();
129 spectra.insert(spectrum);
130 const auto &dets = spec.getDetectorIDs();
131 for (auto const &det : dets) {
132 detectors.insert(det);
133 }
134 }
135
136 // Now go throught the spectrum numbers & UDETS in the 2nd workspace, making
137 // sure that there's no overlap
138 const size_t &nhist2 = ws2.getNumberHistograms();
139 for (size_t j = 0; j < nhist2; ++j) {
140 const auto &spec = ws2.getSpectrum(j);
141 const specnum_t spectrum = spec.getSpectrumNo();
142 if (checkSpectra) {
143 if (spectrum > 0 && spectra.find(spectrum) != spectra.end()) {
144 g_log.error() << "The input workspaces have overlapping spectrum numbers " << spectrum << "\n";
145 throw std::invalid_argument("The input workspaces have overlapping spectrum numbers");
146 }
147 }
148 const auto &dets = spec.getDetectorIDs();
149 const auto it = std::find_if(dets.cbegin(), dets.cend(),
150 [&detectors](const auto &det) { return detectors.find(det) != detectors.cend(); });
151 if (it != dets.cend()) {
152 g_log.error() << "The input workspaces have common detectors: " << (*it) << std::endl;
153 throw std::invalid_argument("The input workspaces have common detectors");
154 }
155 }
156}
157
166 const DataObjects::EventWorkspace &ws2) {
167 this->checkCompatibility(ws1, ws2);
168
169 // Check there is no overlap
170 if (this->getProperty("CheckOverlapping")) {
171 this->checkForOverlap(ws1, ws2, false);
172 m_overlapChecked = true;
173 }
174
175 // Both are event workspaces. Use the special method
176 auto output = this->execEvent(ws1, ws2);
177
178 // Copy the history from the original workspace
179 output->history().addHistory(ws1.getHistory());
180 return output;
181}
182
191 const API::MatrixWorkspace &ws2) {
192 // Check that the input workspaces meet the requirements for this algorithm
193 this->checkCompatibility(ws1, ws2);
194
195 if (this->getProperty("CheckOverlapping")) {
196 this->checkForOverlap(ws1, ws2, true);
197 m_overlapChecked = true;
198 }
199
200 auto output = execWS2D(ws1, ws2);
201
202 // Copy the history from the original workspace
203 output->history().addHistory(ws1.getHistory());
204 return output;
205}
206
207/***
208 * This will ensure the spectrum numbers do not overlap by starting the second
209 *on at the first + 1
210 *
211 * @param ws1 The first workspace supplied to the algorithm.
212 * @param ws2 The second workspace supplied to the algorithm.
213 * @param output The workspace that is going to be returned by the algorithm.
214 */
216 MatrixWorkspace &output) {
217
218 if (this->getProperty("CheckOverlapping")) {
219 // If CheckOverlapping is required, then either skip fixing spectrum number
220 // or get stopped by an exception
221 if (!m_overlapChecked)
222 // This throws if the spectrum numbers overlap
223 checkForOverlap(ws1, ws2, true);
224 // At this point, we don't have to do anything
225 return;
226 }
227
228 // Because we were told not to check overlapping, fix up any errors we might
229 // run into
230 specnum_t min = -1;
231 specnum_t max = -1;
232 getMinMax(output, min, max);
233 if (max - min >= static_cast<specnum_t>(output.getNumberHistograms())) // nothing to do then
234 return;
235
236 // information for remapping the spectra numbers
237 specnum_t ws1min = -1;
238 specnum_t ws1max = -1;
239 getMinMax(ws1, ws1min, ws1max);
240
241 // change the axis by adding the maximum existing spectrum number to the
242 // current value
243 for (size_t i = ws1.getNumberHistograms(); i < output.getNumberHistograms(); i++) {
244 specnum_t origid = output.getSpectrum(i).getSpectrumNo();
245 output.getSpectrum(i).setSpectrumNo(origid + ws1max);
246 }
247}
248
252 // Call the base class method for most of the functionality
253 const bool retval = Algorithm::processGroups();
254
255 // If that was successful, remove the now empty group in the second input
256 // workspace property
257 if (retval)
258 AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace2"));
259
260 return retval;
261}
262
264 const std::string yLabel = getPropertyValue("YAXisLabel");
265 const std::string yUnit = getPropertyValue("YAxisUnit");
266
267 // Unit must be moved before label, as changing the unit resets the label
268 if (!yUnit.empty())
269 ws.setYUnit(yUnit);
270
271 if (!yLabel.empty())
272 ws.setYUnitLabel(yLabel);
273}
274
275} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual bool processGroups()
Process WorkspaceGroup inputs.
specnum_t getSpectrumNo() const
void setSpectrumNo(specnum_t num)
Sets the spectrum number of this spectrum.
Base MatrixWorkspace Abstract Class.
virtual ISpectrum & getSpectrum(const size_t index)=0
Return the underlying ISpectrum ptr at the given workspace index.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
void setYUnitLabel(const std::string &newLabel)
Sets a new caption for the data (Y axis) in the workspace.
void setYUnit(const std::string &newUnit)
Sets a new unit for the data (Y axis) in the workspace.
A property class for workspaces.
const WorkspaceHistory & getHistory() const
Returns a reference to the WorkspaceHistory const.
Definition Workspace.h:85
Joins two partial, non-overlapping workspaces into one.
void checkForOverlap(const API::MatrixWorkspace &ws1, const API::MatrixWorkspace &ws2, bool checkSpectra) const
Checks that the two input workspaces have non-overlapping spectra numbers and contributing detectors.
bool processGroups() override
Appends the removal of the empty group after execution to the Algorithm::processGroups() method.
void exec() override
Executes the algorithm.
void fixSpectrumNumbers(const API::MatrixWorkspace &ws1, const API::MatrixWorkspace &ws2, API::MatrixWorkspace &output) override
Abstract method to be implemented in concrete algorithm classes.
bool m_overlapChecked
True if spectra overlap.
API::MatrixWorkspace_sptr conjoinHistograms(const API::MatrixWorkspace &ws1, const API::MatrixWorkspace &ws2)
Conjoin two histogram workspaces together, including the history.
void setYUnitAndLabel(API::MatrixWorkspace &ws) const
API::MatrixWorkspace_sptr conjoinEvents(const DataObjects::EventWorkspace &ws1, const DataObjects::EventWorkspace &ws2)
Conjoin two event workspaces together, including the history.
bool checkBinning(const API::MatrixWorkspace_const_sptr &ws1, const API::MatrixWorkspace_const_sptr &ws2) const
Checks whether the binning is consistent between two workspaces.
void checkCompatibility(const API::MatrixWorkspace &ws1, const API::MatrixWorkspace &ws2)
Checks that the two input workspace have the same instrument, unit and distribution flag.
DataObjects::EventWorkspace_sptr execEvent(const DataObjects::EventWorkspace &eventWs1, const DataObjects::EventWorkspace &eventWs2)
Executes the algorithm for event workspace inputs.
void getMinMax(const API::MatrixWorkspace &ws, specnum_t &min, specnum_t &max)
Determine the minimum and maximum spectra ids.
API::MatrixWorkspace_sptr execWS2D(const API::MatrixWorkspace &ws1, const API::MatrixWorkspace &ws2)
Executes the algorithm for histogram workspace inputs.
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
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::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
int32_t specnum_t
Typedef for a spectrum Number.
Definition IDTypes.h:14
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.
@ InOut
Both an input & output workspace.
Definition Property.h:55
@ Input
An input workspace.
Definition Property.h:53