Newer
Older
Russell Taylor
committed
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/ConjoinWorkspaces.h"
#include "MantidAPI/WorkspaceValidators.h"
#include "MantidAPI/SpectraDetectorMap.h"
namespace Mantid
{
namespace Algorithms
{
using namespace Kernel;
using namespace API;
using namespace DataObjects;
Russell Taylor
committed
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(ConjoinWorkspaces)
//----------------------------------------------------------------------------------------------
Russell Taylor
committed
/// Default constructor
Gigg, Martyn Anthony
committed
ConjoinWorkspaces::ConjoinWorkspaces() : Algorithm(), m_progress(NULL) {}
Russell Taylor
committed
//----------------------------------------------------------------------------------------------
Russell Taylor
committed
/// Destructor
Gigg, Martyn Anthony
committed
ConjoinWorkspaces::~ConjoinWorkspaces()
{
if( m_progress )
{
delete m_progress;
}
}
Russell Taylor
committed
//----------------------------------------------------------------------------------------------
/** Initialize the properties */
Russell Taylor
committed
void ConjoinWorkspaces::init()
{
Russell Taylor
committed
declareProperty(new WorkspaceProperty<>("InputWorkspace1",
"", Direction::Input, new CommonBinsValidator<>),
Steve Williams
committed
"The name of the first input workspace");
Russell Taylor
committed
declareProperty(new WorkspaceProperty<>("InputWorkspace2",
"", Direction::Input, new CommonBinsValidator<>),
Steve Williams
committed
"The name of the second input workspace");
Russell Taylor
committed
}
//----------------------------------------------------------------------------------------------
Russell Taylor
committed
/** Executes the algorithm
* @throw std::invalid_argument If the input workspaces do not meet the requirements of this algorithm
*/
void ConjoinWorkspaces::exec()
{
// Retrieve the input workspaces
Russell Taylor
committed
MatrixWorkspace_const_sptr ws1 = getProperty("InputWorkspace1");
MatrixWorkspace_const_sptr ws2 = getProperty("InputWorkspace2");
event_ws1 = boost::dynamic_pointer_cast<const EventWorkspace>(ws1);
event_ws2 = boost::dynamic_pointer_cast<const EventWorkspace>(ws2);
//Make sure that we are not mis-matching EventWorkspaces and other types of workspaces
if (((event_ws1) && (!event_ws2)) || ((!event_ws1) && (event_ws2)))
{
const std::string message("Only one of the input workspaces are of type EventWorkspace; please use matching workspace types (both EventWorkspace's or both Workspace2D's).");
g_log.error(message);
throw std::invalid_argument(message);
}
if (event_ws1 && event_ws2)
{
//Both are event workspaces. Use the special method
this->execEvent();
return;
}
Russell Taylor
committed
// Check that the input workspaces meet the requirements for this algorithm
this->validateInputs(ws1,ws2);
// Create the output workspace
const int totalHists = ws1->getNumberHistograms() + ws2->getNumberHistograms();
Russell Taylor
committed
MatrixWorkspace_sptr output = WorkspaceFactory::Instance().create("Workspace2D",totalHists,ws1->readX(0).size(),
Russell Taylor
committed
ws1->readY(0).size());
Russell Taylor
committed
// Copy over stuff from first input workspace
WorkspaceFactory::Instance().initializeFromParent(ws1,output,true);
Russell Taylor
committed
// Create the X values inside a cow pointer - they will be shared in the output workspace
Russell Taylor
committed
cow_ptr<MantidVec> XValues;
Russell Taylor
committed
XValues.access() = ws1->readX(0);
Gigg, Martyn Anthony
committed
// Initialize the progress reporting object
m_progress = new API::Progress(this, 0.0, 1.0, totalHists);
Russell Taylor
committed
// Loop over the input workspaces in turn copying the data into the output one
Russell Taylor
committed
Axis* outAxis = output->getAxis(1);
Russell Taylor
committed
const int& nhist1 = ws1->getNumberHistograms();
const Axis* axis1 = ws1->getAxis(1);
Russell Taylor
committed
PARALLEL_FOR2(ws1, output)
Gigg, Martyn Anthony
committed
for (int i = 0; i < nhist1; ++i)
Russell Taylor
committed
{
Russell Taylor
committed
PARALLEL_START_INTERUPT_REGION
output->setX(i,XValues);
output->dataY(i) = ws1->readY(i);
output->dataE(i) = ws1->readE(i);
// Copy the spectrum number
Gigg, Martyn Anthony
committed
outAxis->spectraNo(i) = axis1->spectraNo(i);
// Propagate masking, if needed
if ( ws1->hasMaskedBins(i) )
{
const MatrixWorkspace::MaskList& inputMasks = ws1->maskedBins(i);
MatrixWorkspace::MaskList::const_iterator it;
for (it = inputMasks.begin(); it != inputMasks.end(); ++it)
{
Gigg, Martyn Anthony
committed
output->maskBin(i,(*it).first,(*it).second);
}
}
Gigg, Martyn Anthony
committed
m_progress->report();
Russell Taylor
committed
PARALLEL_END_INTERUPT_REGION
Russell Taylor
committed
}
Russell Taylor
committed
PARALLEL_CHECK_INTERUPT_REGION
Gigg, Martyn Anthony
committed
//For second loop we use the offset from the first
Russell Taylor
committed
const int& nhist2 = ws2->getNumberHistograms();
const Axis* axis2 = ws2->getAxis(1);
Gigg, Martyn Anthony
committed
Russell Taylor
committed
PARALLEL_FOR2(ws2, output)
Gigg, Martyn Anthony
committed
for (int j = 0; j < nhist2; ++j)
Russell Taylor
committed
{
Russell Taylor
committed
PARALLEL_START_INTERUPT_REGION
output->setX(nhist1 + j,XValues);
output->dataY(nhist1 + j) = ws2->readY(j);
output->dataE(nhist1 + j) = ws2->readE(j);
// Copy the spectrum number
Gigg, Martyn Anthony
committed
outAxis->spectraNo(nhist1 + j) = axis2->spectraNo(j);
// Propagate masking, if needed
if ( ws2->hasMaskedBins(j) )
{
const MatrixWorkspace::MaskList& inputMasks = ws2->maskedBins(j);
MatrixWorkspace::MaskList::const_iterator it;
for (it = inputMasks.begin(); it != inputMasks.end(); ++it)
{
Gigg, Martyn Anthony
committed
output->maskBin(nhist1 + j,(*it).first,(*it).second);
}
Gigg, Martyn Anthony
committed
}
m_progress->report();
Russell Taylor
committed
PARALLEL_END_INTERUPT_REGION
Russell Taylor
committed
}
Russell Taylor
committed
PARALLEL_CHECK_INTERUPT_REGION
Russell Taylor
committed
// Delete the input workspaces from the ADS
AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace1"));
AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace2"));
// Create & assign an output workspace property with the workspace name the same as the first input
Russell Taylor
committed
declareProperty(new WorkspaceProperty<>("Output",getPropertyValue("InputWorkspace1"),Direction::Output));
setProperty("Output",output);
Russell Taylor
committed
}
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
//----------------------------------------------------------------------------------------------
/** Executes the algorithm
* @throw std::invalid_argument If the input workspaces do not meet the requirements of this algorithm
*/
void ConjoinWorkspaces::execEvent()
{
//We do not need to check that binning is compatible, just that there is no overlap
this->checkForOverlap(event_ws1, event_ws2);
// Create the output workspace
const int totalHists = event_ws1->getNumberHistograms() + event_ws2->getNumberHistograms();
EventWorkspace_sptr output = boost::dynamic_pointer_cast<EventWorkspace>(
WorkspaceFactory::Instance().create("EventWorkspace",
totalHists, event_ws1->readX(0).size(), event_ws1->readY(0).size())
);
// Copy over stuff from first input workspace
WorkspaceFactory::Instance().initializeFromParent(event_ws1,output,true);
// Create the X values inside a cow pointer - they will be shared in the output workspace
cow_ptr<MantidVec> XValues;
XValues.access() = event_ws1->readX(0);
// Initialize the progress reporting object
m_progress = new API::Progress(this, 0.0, 1.0, totalHists);
const int& nhist1 = event_ws1->getNumberHistograms();
const Axis* axis1 = event_ws1->getAxis(1);
// PARALLEL_FOR2(event_ws1, output)
for (int i = 0; i < nhist1; ++i)
{
// PARALLEL_START_INTERUPT_REGION
//This is the spectrum # at the input
int specNo = axis1->spectraNo(i);
//Copy the events over
output->getEventList(specNo).clear();
output->getEventList(specNo) += event_ws1->getEventListAtWorkspaceIndex(i).getEvents();
m_progress->report();
// PARALLEL_END_INTERUPT_REGION
}
// PARALLEL_CHECK_INTERUPT_REGION
//For second loop we use the offset from the first
const int& nhist2 = event_ws2->getNumberHistograms();
const Axis* axis2 = event_ws2->getAxis(1);
// PARALLEL_FOR2(event_ws2, output)
for (int j = 0; j < nhist2; ++j)
{
// PARALLEL_START_INTERUPT_REGION
//This is the spectrum # at the input
int specNo = axis2->spectraNo(j);
//Copy the events over
output->getEventList(specNo).clear();
output->getEventList(specNo) += event_ws2->getEventListAtWorkspaceIndex(j).getEvents();
m_progress->report();
// PARALLEL_END_INTERUPT_REGION
}
// PARALLEL_CHECK_INTERUPT_REGION
//This will make the spectramap axis.
output->doneLoadingData();
//Set the same bins for all output pixels
output->setAllX(XValues);
// Delete the input workspaces from the ADS
AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace1"));
AnalysisDataService::Instance().remove(getPropertyValue("InputWorkspace2"));
// Create & assign an output workspace property with the workspace name the same as the first input
declareProperty(new WorkspaceProperty<>("Output",getPropertyValue("InputWorkspace1"),Direction::Output));
setProperty("Output", boost::dynamic_pointer_cast<MatrixWorkspace>(output) );
}
//----------------------------------------------------------------------------------------------
Russell Taylor
committed
/** Checks that the two input workspace have common binning & size, the same instrument & unit.
* Also calls the checkForOverlap method.
* @param ws1 The first input workspace
* @param ws2 The second input workspace
* @throw std::invalid_argument If the workspaces are not compatible
*/
Roman Tolchenov
committed
void ConjoinWorkspaces::validateInputs(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2) const
Russell Taylor
committed
{
Russell Taylor
committed
// This is the full check for common binning
Russell Taylor
committed
if ( !WorkspaceHelpers::commonBoundaries(ws1) || !WorkspaceHelpers::commonBoundaries(ws2) )
{
g_log.error("Both input workspaces must have common binning for all their spectra");
throw std::invalid_argument("Both input workspaces must have common binning for all their spectra");
}
Russell Taylor
committed
if ( ws1->getInstrument()->getName() != ws2->getInstrument()->getName() )
Russell Taylor
committed
{
Russell Taylor
committed
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
const std::string message("The input workspaces are not compatible because they come from different instruments");
g_log.error(message);
throw std::invalid_argument(message);
}
Unit_const_sptr ws1_unit = ws1->getAxis(0)->unit();
Unit_const_sptr ws2_unit = ws2->getAxis(0)->unit();
const std::string ws1_unitID = ( ws1_unit ? ws1_unit->unitID() : "" );
const std::string ws2_unitID = ( ws2_unit ? ws2_unit->unitID() : "" );
if ( ws1_unitID != ws2_unitID )
{
const std::string message("The input workspaces are not compatible because they have different units on the X axis");
g_log.error(message);
throw std::invalid_argument(message);
}
if ( ws1->isDistribution() != ws2->isDistribution() )
{
const std::string message("The input workspaces have inconsistent distribution flags");
g_log.error(message);
throw std::invalid_argument(message);
}
if ( !WorkspaceHelpers::matchingBins(ws1,ws2,true) )
{
const std::string message("The input workspaces are not compatible because they have different binning");
g_log.error(message);
throw std::invalid_argument(message);
Russell Taylor
committed
}
this->checkForOverlap(ws1,ws2);
}
//----------------------------------------------------------------------------------------------
Russell Taylor
committed
/** Checks that the two input workspaces have non-overlapping spectra numbers and contributing detectors
* @param ws1 The first input workspace
* @param ws2 The second input workspace
* @throw std::invalid_argument If there is some overlap
*/
Roman Tolchenov
committed
void ConjoinWorkspaces::checkForOverlap(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2) const
Russell Taylor
committed
{
// Loop through the first workspace adding all the spectrum numbers & UDETS to a set
const Axis* axis1 = ws1->getAxis(1);
Russell Taylor
committed
const SpectraDetectorMap& specmap1 = ws1->spectraMap();
Russell Taylor
committed
std::set<int> spectra, detectors;
const int& nhist1 = ws1->getNumberHistograms();
for (int i = 0; i < nhist1; ++i)
{
const int spectrum = axis1->spectraNo(i);
spectra.insert(spectrum);
Russell Taylor
committed
const std::vector<int> dets = specmap1.getDetectors(spectrum);
Russell Taylor
committed
std::vector<int>::const_iterator it;
Russell Taylor
committed
for (it = dets.begin(); it != dets.end(); ++it)
{
Russell Taylor
committed
detectors.insert(*it);
Russell Taylor
committed
}
}
// Now go throught the spectrum numbers & UDETS in the 2nd workspace, making sure that there's no overlap
const Axis* axis2 = ws2->getAxis(1);
Russell Taylor
committed
const SpectraDetectorMap& specmap2 = ws2->spectraMap();
Russell Taylor
committed
const int& nhist2 = ws2->getNumberHistograms();
for (int j = 0; j < nhist2; ++j)
{
const int spectrum = axis2->spectraNo(j);
Russell Taylor
committed
if ( spectrum > 0 && spectra.find(spectrum) != spectra.end() )
Russell Taylor
committed
{
Russell Taylor
committed
g_log.error("The input workspaces have overlapping spectrum numbers");
throw std::invalid_argument("The input workspaces have overlapping spectrum numbers");
Russell Taylor
committed
}
Russell Taylor
committed
std::vector<int> dets = specmap2.getDetectors(spectrum);
Russell Taylor
committed
std::vector<int>::const_iterator it;
Russell Taylor
committed
for (it = dets.begin(); it != dets.end(); ++it)
{
Russell Taylor
committed
if ( detectors.find(*it) != detectors.end() )
Russell Taylor
committed
{
g_log.error("The input workspaces have common detectors");
throw std::invalid_argument("The input workspaces have common detectors");
}
}
}
}
} // namespace Algorithm
} // namespace Mantid