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;
// 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
/// Destructor
Gigg, Martyn Anthony
committed
ConjoinWorkspaces::~ConjoinWorkspaces()
{
if( m_progress )
{
delete m_progress;
}
}
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
}
/** 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");
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
}
/** 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
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
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);
}
/** 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