Newer
Older
#include "MantidAPI/AnalysisDataService.h"
Federico Montesino Pouzols
committed
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidHistogramData/HistogramE.h"
#include "MantidHistogramData/HistogramDx.h"
#include "MantidHistogramData/HistogramX.h"
#include "MantidHistogramData/HistogramY.h"
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/MultiThreaded.h"
#include "MantidKernel/PropertyWithValue.h"
#include "MantidKernel/RebinParamsValidator.h"
#include <boost/tuple/tuple.hpp>
#include <boost/format.hpp>
#include <boost/math/special_functions.hpp>
using namespace Mantid::Kernel;
using Mantid::HistogramData::HistogramDx;
using Mantid::HistogramData::HistogramX;
using Mantid::HistogramData::HistogramY;
using Mantid::HistogramData::Points;
using MinMaxTuple = boost::tuple<double, double>;
MinMaxTuple calculateXIntersection(MatrixWorkspace_sptr lhsWS,
MatrixWorkspace_sptr rhsWS) {
return MinMaxTuple(rhsWS->x(0).front(), lhsWS->x(0).back());
bool isNonzero(double i) { return (0 != i); }
namespace Mantid {
namespace Algorithms {
* This is required for machine precision reasons. Used to adjust StartOverlap
*and EndOverlap so that they are
* inclusive of bin boundaries if they are sitting ontop of the bin boundaries.
*/
const double Stitch1D::range_tolerance = 1e-9;
// Register the algorithm into the AlgorithmFactory
/** Zero out all y and e data that is not in the region a1 to a2.
* @param a1 : Zero based bin index (first one)
* @param a2 : Zero based bin index (last one inclusive)
* @param source : Workspace providing the source data.
* @return Masked workspace.
*/
MatrixWorkspace_sptr Stitch1D::maskAllBut(int a1, int a2,
MatrixWorkspace_sptr &source) {
MatrixWorkspace_sptr product = WorkspaceFactory::Instance().create(source);
const int histogramCount = static_cast<int>(source->getNumberHistograms());
PARALLEL_FOR_IF(Kernel::threadSafe(*source, *product))
for (int i = 0; i < histogramCount; ++i) {
PARALLEL_START_INTERUPT_REGION
// Copy over the bin boundaries
const auto &sourceY = source->y(i);
const auto &sourceE = source->e(i);
// initially zero - out the data.
product->mutableY(i) = HistogramY(sourceY.size(), 0);
product->mutableE(i) = HistogramE(sourceE.size(), 0);
auto &newY = product->mutableY(i);
auto &newE = product->mutableE(i);
// Copy over the non-zero stuff
std::copy(sourceY.begin() + a1 + 1, sourceY.begin() + a2,
newY.begin() + a1 + 1);
std::copy(sourceE.begin() + a1 + 1, sourceE.begin() + a2,
newE.begin() + a1 + 1);
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
return product;
}
/** Mask out data in the region between a1 and a2 with zeros. Operation
* performed on the original workspace
* @param a1 : start position in X
* @param a2 : end position in X
* @param source : Workspace to mask.
*/
void Stitch1D::maskInPlace(int a1, int a2, MatrixWorkspace_sptr source) {
const int histogramCount = static_cast<int>(source->getNumberHistograms());
PARALLEL_FOR_IF(Kernel::threadSafe(*source))
for (int i = 0; i < histogramCount; ++i) {
PARALLEL_START_INTERUPT_REGION
// Copy over the data
auto &sourceY = source->mutableY(i);
auto &sourceE = source->mutableE(i);
for (int i = a1; i < a2; ++i) {
sourceY[i] = 0;
sourceE[i] = 0;
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
}
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void Stitch1D::init() {
declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
"LHSWorkspace", "", Direction::Input),
"LHS input workspace.");
declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
"RHSWorkspace", "", Direction::Input),
"RHS input workspace, must be same type as LHSWorkspace "
"(histogram or point data).");
declareProperty(make_unique<WorkspaceProperty<MatrixWorkspace>>(
"OutputWorkspace", "", Direction::Output),
declareProperty(make_unique<PropertyWithValue<double>>(
"StartOverlap", Mantid::EMPTY_DBL(), Direction::Input),
"Start overlap x-value in units of x-axis.");
declareProperty(make_unique<PropertyWithValue<double>>(
"EndOverlap", Mantid::EMPTY_DBL(), Direction::Input),
"End overlap x-value in units of x-axis.");
declareProperty(make_unique<ArrayProperty<double>>(
"Params", boost::make_shared<RebinParamsValidator>(true)),
"Rebinning Parameters. See Rebin for format. If only a "
"single value is provided, start and end are taken from "
"input workspaces.");
declareProperty(
make_unique<PropertyWithValue<bool>>("ScaleRHSWorkspace", true,
Direction::Input),
"Scaling either with respect to LHS workspace or RHS workspace");
declareProperty(make_unique<PropertyWithValue<bool>>("UseManualScaleFactor",
false, Direction::Input),
"True to use a provided value for the scale factor.");
auto manualScaleFactorValidator =
boost::make_shared<BoundedValidator<double>>();
manualScaleFactorValidator->setLower(0);
manualScaleFactorValidator->setExclusive(true);
declareProperty(make_unique<PropertyWithValue<double>>(
"ManualScaleFactor", 1.0, manualScaleFactorValidator,
Direction::Input),
"Provided value for the scale factor.");
declareProperty(make_unique<PropertyWithValue<double>>(
"OutScaleFactor", Mantid::EMPTY_DBL(), Direction::Output),
"The actual used value for the scaling factor.");
}
/** Validate the algorithm's properties.
* @return A map of porperty names and their issues.
*/
std::map<std::string, std::string> Stitch1D::validateInputs(void) {
std::map<std::string, std::string> issues;
MatrixWorkspace_sptr lhs = getProperty("LHSWorkspace");
MatrixWorkspace_sptr rhs = getProperty("RHSWorkspace");
if (lhs->isHistogramData() && !rhs->isHistogramData())
issues["RHSWorkspace"] = "Must be a histogram like LHSWorkspace.";
if (!lhs->isHistogramData() && rhs->isHistogramData())
issues["RHSWorkspace"] = "Must be point data like LHSWorkspace.";
return issues;
}
/** Gets the start of the overlapping region
@param intesectionMin :: The minimum possible value for the overlapping region
to inhabit
@param intesectionMax :: The maximum possible value for the overlapping region
to inhabit
@return a double contianing the start of the overlapping region
*/
double Stitch1D::getStartOverlap(const double &intesectionMin,
const double &intesectionMax) const {
Property *startOverlapProp = this->getProperty("StartOverlap");
double startOverlapVal = this->getProperty("StartOverlap");
startOverlapVal -= this->range_tolerance;
const bool startOverlapBeyondRange =
(startOverlapVal < intesectionMin) || (startOverlapVal > intesectionMax);
if (startOverlapProp->isDefault() || startOverlapBeyondRange) {
if (!startOverlapProp->isDefault() && startOverlapBeyondRange) {
char message[200];
std::sprintf(message, "StartOverlap is outside range at %0.4f, Min is "
"%0.4f, Max is %0.4f . Forced to be: %0.4f",
startOverlapVal, intesectionMin, intesectionMax,
intesectionMin);
g_log.warning(std::string(message));
startOverlapVal = intesectionMin;
std::stringstream buffer;
buffer << "StartOverlap calculated to be: " << startOverlapVal;
g_log.information(buffer.str());
}
return startOverlapVal;
}
/** Gets the end of the overlapping region
@param intesectionMin :: The minimum possible value for the overlapping region
to inhabit
@param intesectionMax :: The maximum possible value for the overlapping region
to inhabit
@return a double contianing the end of the overlapping region
*/
double Stitch1D::getEndOverlap(const double &intesectionMin,
const double &intesectionMax) const {
Property *endOverlapProp = this->getProperty("EndOverlap");
double endOverlapVal = this->getProperty("EndOverlap");
endOverlapVal += this->range_tolerance;
const bool endOverlapBeyondRange =
(endOverlapVal < intesectionMin) || (endOverlapVal > intesectionMax);
if (endOverlapProp->isDefault() || endOverlapBeyondRange) {
if (!endOverlapProp->isDefault() && endOverlapBeyondRange) {
char message[200];
std::sprintf(message, "EndOverlap is outside range at %0.4f, Min is "
"%0.4f, Max is %0.4f . Forced to be: %0.4f",
endOverlapVal, intesectionMin, intesectionMax,
intesectionMax);
g_log.warning(std::string(message));
endOverlapVal = intesectionMax;
std::stringstream buffer;
buffer << "EndOverlap calculated to be: " << endOverlapVal;
g_log.information(buffer.str());
}
return endOverlapVal;
}
/** Gets the rebinning parameters and calculates any missing values
@param lhsWS :: The left hand side input workspace
@param rhsWS :: The right hand side input workspace
@param scaleRHS :: Scale the right hand side workspace
@return a vector<double> contianing the rebinning parameters
*/
std::vector<double> Stitch1D::getRebinParams(MatrixWorkspace_sptr &lhsWS,
MatrixWorkspace_sptr &rhsWS,
const bool scaleRHS) const {
std::vector<double> inputParams = this->getProperty("Params");
Property *prop = this->getProperty("Params");
const bool areParamsDefault = prop->isDefault();
auto it = std::min_element(lhsX.begin(), lhsX.end());
const double minLHSX = *it;
it = std::max_element(rhsX.begin(), rhsX.end());
const double maxRHSX = *it;
// Calculate the step size based on the existing step size of the LHS
// workspace. That way scale factors should be reasonably maintained.
double calculatedStep = 0;
if (scaleRHS) {
// Calculate the step from the workspace that will not be scaled. The LHS
// workspace.
calculatedStep = lhsX[1] - lhsX[0];
} else {
// Calculate the step from the workspace that will not be scaled. The RHS
// workspace.
calculatedStep = rhsX[1] - rhsX[0];
calculatedParams.push_back(minLHSX);
calculatedParams.push_back(calculatedStep);
calculatedParams.push_back(maxRHSX);
result = calculatedParams;
} else {
if (inputParams.size() == 1) {
calculatedParams.push_back(minLHSX);
calculatedParams.push_back(inputParams.front()); // Use the step supplied.
calculatedParams.push_back(maxRHSX);
result = calculatedParams;
} else {
result = inputParams; // user has provided params. Use those.
}
}
return result;
}
/** Runs the Rebin Algorithm as a child and replaces special values
@param input :: The input workspace
@param params :: a vector<double> containing rebinning parameters
@return A shared pointer to the resulting MatrixWorkspace
*/
MatrixWorkspace_sptr Stitch1D::rebin(MatrixWorkspace_sptr &input,
auto rebin = this->createChildAlgorithm("Rebin");
rebin->setProperty("InputWorkspace", input);
rebin->setProperty("Params", params);
std::stringstream ssParams;
ssParams << params[0] << "," << params[1] << "," << params[2];
g_log.information("Rebinning Params: " + ssParams.str());
rebin->execute();
MatrixWorkspace_sptr outWS = rebin->getProperty("OutputWorkspace");
const int histogramCount = static_cast<int>(outWS->getNumberHistograms());
// Record special values and then mask them out as zeros. Special values are
// remembered and then replaced post processing.
PARALLEL_FOR_IF(Kernel::threadSafe(*outWS))
for (int i = 0; i < histogramCount; ++i) {
PARALLEL_START_INTERUPT_REGION
std::vector<size_t> &nanEIndexes = m_nanEIndexes[i];
std::vector<size_t> &nanYIndexes = m_nanYIndexes[i];
std::vector<size_t> &infEIndexes = m_infEIndexes[i];
std::vector<size_t> &infYIndexes = m_infYIndexes[i];
auto &sourceY = outWS->mutableY(i);
auto &sourceE = outWS->mutableE(i);
for (size_t j = 0; j < sourceY.size(); ++j) {
const double &value = sourceY[j];
nanYIndexes.push_back(j);
sourceY[j] = 0;
infYIndexes.push_back(j);
sourceY[j] = 0;
const double &eValue = sourceE[j];
nanEIndexes.push_back(j);
sourceE[j] = 0;
infEIndexes.push_back(j);
sourceE[j] = 0;
}
PARALLEL_END_INTERUPT_REGION
}
PARALLEL_CHECK_INTERUPT_REGION
/** Runs the Integration Algorithm as a child.
@param input :: The input workspace
@param start :: a double defining the start of the region to integrate
@param stop :: a double defining the end of the region to integrate
@return A shared pointer to the resulting MatrixWorkspace
*/
MatrixWorkspace_sptr Stitch1D::integration(MatrixWorkspace_sptr &input,
const double &start,
const double &stop) {
auto integration = this->createChildAlgorithm("Integration");
integration->initialize();
integration->setProperty("InputWorkspace", input);
integration->setProperty("RangeLower", start);
integration->setProperty("RangeUpper", stop);
g_log.information("Integration RangeLower: " +
boost::lexical_cast<std::string>(start));
g_log.information("Integration RangeUpper: " +
boost::lexical_cast<std::string>(stop));
integration->execute();
return integration->getProperty("OutputWorkspace");
/** Runs the WeightedMean Algorithm as a child
@param inOne :: The first input workspace
@param inTwo :: The second input workspace
@return A shared pointer to the resulting MatrixWorkspace
*/
MatrixWorkspace_sptr Stitch1D::weightedMean(MatrixWorkspace_sptr &inOne,
MatrixWorkspace_sptr &inTwo) {
auto weightedMean = this->createChildAlgorithm("WeightedMean");
weightedMean->initialize();
weightedMean->setProperty("InputWorkspace1", inOne);
weightedMean->setProperty("InputWorkspace2", inTwo);
weightedMean->execute();
return weightedMean->getProperty("OutputWorkspace");
/** Runs the ConjoinXRuns Algorithm as a child
@param inWS :: Input workspace
@return A shared pointer to the resulting MatrixWorkspace
*/
MatrixWorkspace_sptr Stitch1D::conjoinXAxis(MatrixWorkspace_sptr &inOne,
MatrixWorkspace_sptr &inTwo) {
std::string in1 = "__Stitch1D_intermediate_workspace_1__";
std::string in2 = "__Stitch1D_intermediate_workspace_2__";
Mantid::API::AnalysisDataService::Instance().addOrReplace(in1, inOne);
Mantid::API::AnalysisDataService::Instance().addOrReplace(in2, inTwo);
auto conjoinX = this->createChildAlgorithm("ConjoinXRuns");
conjoinX->initialize();
conjoinX->setProperty("InputWorkspaces", std::vector<std::string>{in1, in2});
Mantid::API::AnalysisDataService::Instance().remove(in1);
Mantid::API::AnalysisDataService::Instance().remove(in2);
API::Workspace_sptr ws = conjoinX->getProperty("OutputWorkspace");
return boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
@param inWS :: Input workspace
@return A shared pointer to the resulting MatrixWorkspace
*/
MatrixWorkspace_sptr Stitch1D::sortXAxis(MatrixWorkspace_sptr &inWS) {
// using a std::multimap (keys are sorted)
std::multimap<double, double> sorter;
for (size_t i = 0; i < inWS->getNumberHistograms(); ++i) {
for (size_t k = 0; k < inWS->size(); ++k) {
sorter.insert(std::pair<double, double>(inWS->x(i)[k], inWS->y(i)[k]));
sorter.insert(std::pair<double, double>(inWS->x(i)[k], inWS->e(i)[k]));
if (inWS->hasDx(i))
sorter.insert(std::pair<double, double>(inWS->x(i)[k], inWS->dx(i)[k]));
}
Mantid::MantidVec vecx(inWS->size());
Mantid::MantidVec vecy(inWS->size());
Mantid::MantidVec vece(inWS->size());
Mantid::MantidVec vecdx(inWS->size());
int l = 0;
for (auto it = sorter.cbegin(); it != sorter.cend(); ++it) {
vecx[l] = it->first;
vecy[l] = it->second;
vece[l] = (++it)->second;
if (inWS->hasDx(i))
vecdx[l] = (++it)->second;
++l;
}
auto x = make_cow<HistogramX>(std::move(vecx));
auto y = make_cow<HistogramY>(std::move(vecy));
auto e = make_cow<HistogramE>(std::move(vece));
inWS->setSharedX(i, x);
inWS->setSharedY(i, y);
inWS->setSharedE(i, e);
if (inWS->hasDx(i)) {
auto dx = make_cow<HistogramDx>(std::move(vecdx));
inWS->setSharedDx(i, dx);
/** Runs the CreateSingleValuedWorkspace Algorithm as a child
@param val :: The double to convert to a single value workspace
@return A shared pointer to the resulting MatrixWorkspace
*/
MatrixWorkspace_sptr Stitch1D::singleValueWS(double val) {
auto singleValueWS =
this->createChildAlgorithm("CreateSingleValuedWorkspace");
singleValueWS->initialize();
singleValueWS->setProperty("DataValue", val);
singleValueWS->execute();
return singleValueWS->getProperty("OutputWorkspace");
/** Finds the bins containing the ends of the overlapping region
@param startOverlap :: The start of the overlapping region
@param endOverlap :: The end of the overlapping region
@param workspace :: The workspace to determine the overlaps inside
@return a boost::tuple<int,int> containing the bin indexes of the overlaps
*/
boost::tuple<int, int>
Stitch1D::findStartEndIndexes(double startOverlap, double endOverlap,
MatrixWorkspace_sptr &workspace) {
int a1 = static_cast<int>(workspace->binIndexOf(startOverlap));
int a2 = static_cast<int>(workspace->binIndexOf(endOverlap));
if (a1 == a2) {
throw std::runtime_error("The Params you have provided for binning yield a "
"workspace in which start and end overlap appear "
"in the same bin. Make binning finer via input "
"Params.");
}
return boost::tuple<int, int>(a1, a2);
}
/** Determines if a workspace has non zero errors
@param ws :: The input workspace
@return True if there are any non-zero errors in the workspace
*/
bool Stitch1D::hasNonzeroErrors(MatrixWorkspace_sptr ws) {
int64_t ws_size = static_cast<int64_t>(ws->getNumberHistograms());
bool hasNonZeroErrors = false;
PARALLEL_FOR_IF(Kernel::threadSafe(*ws))
PARALLEL_START_INTERUPT_REGION
if (!hasNonZeroErrors) // Keep checking
auto it = std::find_if(e.begin(), e.end(), isNonzero);
if (it != e.end()) {
PARALLEL_CRITICAL(has_non_zero) {
hasNonZeroErrors =
true; // Set flag. Should not need to check any more spectra.
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
/**
* @brief scaleWorkspace will set m_scaleFactor and m_errorScaleFactor
* @param ws :: Input workspace
* @param divident
* @param divisor
* @param dxWS :: A MatrixWorkspace (size of ws) containing Dx values
*/
void Stitch1D::scaleWorkspace(MatrixWorkspace_sptr ws,
MatrixWorkspace_sptr divident,
MatrixWorkspace_sptr divisor,
MatrixWorkspace_sptr dxWS) {
const auto ratio = divident / divisor;
ws *= ratio;
// We lost Dx values (Multiply) and need to get them back for point data
if (ws->size() == dxWS->size()) {
for (size_t i = 0; i < ws->getNumberHistograms(); ++i) {
if (dxWS->hasDx(i) && !ws->hasDx(i)) {
ws->setSharedDx(i, dxWS->sharedDx(i));
}
}
}
m_scaleFactor = ratio->y(0).front();
m_errorScaleFactor = ratio->e(0).front();
if (m_scaleFactor < 1e-2 || m_scaleFactor > 1e2 ||
std::isnan(m_scaleFactor)) {
std::stringstream messageBuffer;
messageBuffer << "Stitch1D calculated scale factor is: " << m_scaleFactor
<< ". Check that in both input workspaces the integrated "
"overlap region is non-zero.";
g_log.warning(messageBuffer.str());
}
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void Stitch1D::exec() {
MatrixWorkspace_sptr lhsWS = this->getProperty("LHSWorkspace");
MatrixWorkspace_sptr rhsWS = this->getProperty("RHSWorkspace");
const MinMaxTuple intesectionXRegion = calculateXIntersection(lhsWS, rhsWS);
const size_t histogramCount = rhsWS->getNumberHistograms();
m_nanYIndexes.resize(histogramCount);
m_infYIndexes.resize(histogramCount);
m_nanEIndexes.resize(histogramCount);
m_infEIndexes.resize(histogramCount);
const double intersectionMin = intesectionXRegion.get<0>();
const double intersectionMax = intesectionXRegion.get<1>();
double startOverlap;
double endOverlap;
if (lhsWS->isHistogramData()) {
startOverlap = getStartOverlap(intersectionMin, intersectionMax);
endOverlap = getEndOverlap(intersectionMin, intersectionMax);
if (startOverlap > endOverlap) {
std::string message = boost::str(
boost::format("Stitch1D cannot have a StartOverlap > EndOverlap. "
"StartOverlap: %0.9f, EndOverlap: %0.9f") %
startOverlap % endOverlap);
throw std::runtime_error(message);
}
} else {
startOverlap = intersectionMin;
endOverlap = intersectionMax;
}
const bool scaleRHS = this->getProperty("ScaleRHSWorkspace");
MatrixWorkspace_sptr lhs;
MatrixWorkspace_sptr rhs;
if (lhsWS->isHistogramData()) {
MantidVec params = getRebinParams(lhsWS, rhsWS, scaleRHS);
const double &xMin = params.front();
const double &xMax = params.back();
if (std::abs(xMin - startOverlap) < 1E-6)
startOverlap = xMin;
if (std::abs(xMax - endOverlap) < 1E-6)
endOverlap = xMax;
if (startOverlap < xMin) {
std::string message = boost::str(
boost::format(
"Stitch1D StartOverlap is outside the available X range. "
"StartOverlap: %10.9f, X min: %10.9f") %
startOverlap % xMin);
throw std::runtime_error(message);
}
if (endOverlap > xMax) {
std::string message = boost::str(
boost::format("Stitch1D EndOverlap is outside the available X range. "
"EndOverlap: %10.9f, X max: %10.9f") %
endOverlap % xMax);
throw std::runtime_error(message);
}
lhs = rebin(lhsWS, params);
rhs = rebin(rhsWS, params);
} else {
lhs = lhsWS;
rhs = rhsWS;
m_scaleFactor = this->getProperty("ManualScaleFactor");
m_errorScaleFactor = m_scaleFactor;
const bool useManualScaleFactor = this->getProperty("UseManualScaleFactor");
if (useManualScaleFactor) {
MatrixWorkspace_sptr manualScaleFactorWS = singleValueWS(m_scaleFactor);
if (scaleRHS)
rhs *= manualScaleFactorWS;
else
lhs *= manualScaleFactorWS;
const auto rhsOverlapIntegrated =
integration(rhs, startOverlap, endOverlap);
const auto lhsOverlapIntegrated =
integration(lhs, startOverlap, endOverlap);
if (scaleRHS)
scaleWorkspace(rhs, lhsOverlapIntegrated, rhsOverlapIntegrated, rhsWS);
else
scaleWorkspace(lhs, rhsOverlapIntegrated, lhsOverlapIntegrated, lhsWS);
// Provide log information about the scale factors used in the calculations.
std::stringstream messageBuffer;
messageBuffer << "Scale Factor Y is: " << m_scaleFactor
<< " Scale Factor E is: " << m_errorScaleFactor;
g_log.notice(messageBuffer.str());
MatrixWorkspace_sptr result;
if (lhsWS->isHistogramData()) { // If the input workspaces are histograms ...
boost::tuple<int, int> startEnd =
findStartEndIndexes(startOverlap, endOverlap, lhs);
int a1 = boost::tuples::get<0>(startEnd);
int a2 = boost::tuples::get<1>(startEnd);
// Mask out everything BUT the overlap region as a new workspace.
MatrixWorkspace_sptr overlap1 = maskAllBut(a1, a2, lhs);
// Mask out everything BUT the overlap region as a new workspace.
MatrixWorkspace_sptr overlap2 = maskAllBut(a1, a2, rhs);
// Mask out everything AFTER the overlap region as a new workspace.
maskInPlace(a1 + 1, static_cast<int>(lhs->blocksize()), lhs);
// Mask out everything BEFORE the overlap region as a new workspace.
maskInPlace(0, a2, rhs);
MatrixWorkspace_sptr overlapave;
if (hasNonzeroErrors(overlap1) && hasNonzeroErrors(overlap2)) {
overlapave = weightedMean(overlap1, overlap2);
} else {
g_log.information("Using un-weighted mean for Stitch1D overlap mean");
MatrixWorkspace_sptr sum = overlap1 + overlap2;
MatrixWorkspace_sptr denominator = singleValueWS(2.0);
overlapave = sum / denominator;
}
result = lhs + overlapave + rhs;
reinsertSpecialValues(result);
} else { // The input workspaces are point data ... join & sort
MatrixWorkspace_sptr ws = conjoinXAxis(lhs, rhs);
if (!ws)
g_log.error("Could not retrieve joined workspace.");
result = sortXAxis(ws);
}
setProperty("OutputWorkspace", result);
setProperty("OutScaleFactor", m_scaleFactor);
/** Put special values back.
* @param ws : MatrixWorkspace to resinsert special values into.
*/
void Stitch1D::reinsertSpecialValues(MatrixWorkspace_sptr ws) {
int histogramCount = static_cast<int>(ws->getNumberHistograms());
PARALLEL_FOR_IF(Kernel::threadSafe(*ws))
for (int i = 0; i < histogramCount; ++i) {
PARALLEL_START_INTERUPT_REGION
// Copy over the data
sourceY[j] = std::numeric_limits<double>::quiet_NaN();
sourceY[j] = std::numeric_limits<double>::infinity();
sourceY[j] = std::numeric_limits<double>::quiet_NaN();
sourceY[j] = std::numeric_limits<double>::infinity();