13#include "MantidHistogramData/HistogramDx.h"
14#include "MantidHistogramData/HistogramE.h"
15#include "MantidHistogramData/HistogramX.h"
16#include "MantidHistogramData/HistogramY.h"
25#include <boost/format.hpp>
26#include <boost/math/special_functions.hpp>
27#include <boost/tuple/tuple.hpp>
33using Mantid::HistogramData::HistogramE;
34using Mantid::HistogramData::HistogramY;
39using MinMaxTuple = boost::tuple<double, double>;
41 return MinMaxTuple(rhsWS->x(0).front(), lhsWS->x(0).back());
63 const auto histogramCount =
static_cast<int>(source->getNumberHistograms());
65 for (
int i = 0; i < histogramCount; ++i) {
68 product->setSharedX(i, source->sharedX(i));
70 const auto &sourceY = source->y(i);
71 const auto &sourceE = source->e(i);
74 product->mutableY(i) = HistogramY(sourceY.size(), 0);
75 product->mutableE(i) = HistogramE(sourceE.size(), 0);
77 auto &newY = product->mutableY(i);
78 auto &newE = product->mutableE(i);
81 std::copy(sourceY.begin() + a1 + 1, sourceY.begin() + a2, newY.begin() + a1 + 1);
82 std::copy(sourceE.begin() + a1 + 1, sourceE.begin() + a2, newE.begin() + a1 + 1);
97 const auto histogramCount =
static_cast<int>(source->getNumberHistograms());
99 for (
int i = 0; i < histogramCount; ++i) {
102 auto &sourceY = source->mutableY(i);
103 auto &sourceE = source->mutableE(i);
104 for (
int binIndex = a1; binIndex < a2; ++binIndex) {
105 sourceY[binIndex] = 0;
106 sourceE[binIndex] = 0;
120 "LHS input workspace.");
122 "RHS input workspace, must be same type as LHSWorkspace "
123 "(histogram or point data).");
125 "Output stitched workspace.");
127 "Start overlap x-value in units of x-axis.");
129 "End overlap x-value in units of x-axis.");
131 "Rebinning Parameters. See Rebin for format. If only a "
132 "single value is provided, start and end are taken from "
133 "input workspaces.");
135 "Scaling either with respect to LHS workspace or RHS workspace");
137 "True to use a provided value for the scale factor.");
139 "OutputScalingWorkspace",
"",
140 "Output WorkspaceSingleValue containing the scale factor and its error. No workspace creation if left empty.");
141 auto manualScaleFactorValidator = std::make_shared<BoundedValidator<double>>();
142 manualScaleFactorValidator->setLower(0);
143 manualScaleFactorValidator->setExclusive(
true);
146 "Provided value for the scale factor.");
148 "The actual used value for the scaling factor.");
155 std::map<std::string, std::string> issues;
159 issues[
"LHSWorkspace"] =
"The LHSWorkspace must be a MatrixWorkspace.";
162 issues[
"RHSWorkspace"] =
"The RHSWorkspace must be a MatrixWorkspace.";
164 if (!issues.empty()) {
170 if (!compatible.empty()) {
172 if (!(compatible ==
"spectra must have either Dx values or not; ") ||
173 (
rhs->isHistogramData()))
174 issues[
"RHSWorkspace"] =
"Workspace " +
rhs->getName() +
" is not compatible: " + compatible +
"\n";
188 double startOverlapVal = this->
getProperty(
"StartOverlap");
190 const bool startOverlapBeyondRange = (startOverlapVal < intesectionMin) || (startOverlapVal > intesectionMax);
191 if (startOverlapProp->
isDefault() || startOverlapBeyondRange) {
192 if (!startOverlapProp->
isDefault() && startOverlapBeyondRange) {
194 std::sprintf(message,
195 "StartOverlap is outside range at %0.4f, Min is "
196 "%0.4f, Max is %0.4f . Forced to be: %0.4f",
197 startOverlapVal, intesectionMin, intesectionMax, intesectionMin);
200 startOverlapVal = intesectionMin;
201 std::stringstream buffer;
202 buffer <<
"StartOverlap calculated to be: " << startOverlapVal;
205 return startOverlapVal;
217 double endOverlapVal = this->
getProperty(
"EndOverlap");
219 const bool endOverlapBeyondRange = (endOverlapVal < intesectionMin) || (endOverlapVal > intesectionMax);
220 if (endOverlapProp->
isDefault() || endOverlapBeyondRange) {
221 if (!endOverlapProp->
isDefault() && endOverlapBeyondRange) {
223 std::sprintf(message,
224 "EndOverlap is outside range at %0.4f, Min is "
225 "%0.4f, Max is %0.4f . Forced to be: %0.4f",
226 endOverlapVal, intesectionMin, intesectionMax, intesectionMax);
229 endOverlapVal = intesectionMax;
230 std::stringstream buffer;
231 buffer <<
"EndOverlap calculated to be: " << endOverlapVal;
234 return endOverlapVal;
244 const bool scaleRHS)
const {
245 std::vector<double> inputParams = this->
getProperty(
"Params");
247 const bool areParamsDefault = prop->
isDefault();
249 const auto &lhsX = lhsWS->x(0);
250 auto it = std::min_element(lhsX.begin(), lhsX.end());
251 const double minLHSX = *it;
253 const auto &rhsX = rhsWS->x(0);
254 it = std::max_element(rhsX.begin(), rhsX.end());
255 const double maxRHSX = *it;
257 std::vector<double> result;
258 if (areParamsDefault) {
259 std::vector<double> calculatedParams;
263 double calculatedStep = 0;
267 calculatedStep = lhsX[1] - lhsX[0];
271 calculatedStep = rhsX[1] - rhsX[0];
274 calculatedParams.emplace_back(minLHSX);
275 calculatedParams.emplace_back(calculatedStep);
276 calculatedParams.emplace_back(maxRHSX);
277 result = calculatedParams;
279 if (inputParams.size() == 1) {
280 std::vector<double> calculatedParams;
281 calculatedParams.emplace_back(minLHSX);
282 calculatedParams.emplace_back(inputParams.front());
283 calculatedParams.emplace_back(maxRHSX);
284 result = calculatedParams;
286 result = inputParams;
299 rebin->setProperty(
"InputWorkspace", input);
300 rebin->setProperty(
"Params", params);
301 std::stringstream ssParams;
302 ssParams << params[0] <<
"," << params[1] <<
"," << params[2];
307 const auto histogramCount =
static_cast<int>(outWS->getNumberHistograms());
312 for (
int i = 0; i < histogramCount; ++i) {
319 auto &sourceY = outWS->mutableY(i);
320 auto &sourceE = outWS->mutableE(i);
322 for (
size_t j = 0; j < sourceY.size(); ++j) {
323 const double value = sourceY[j];
324 if (std::isnan(
value)) {
325 nanYIndexes.emplace_back(j);
327 }
else if (std::isinf(
value)) {
328 infYIndexes.emplace_back(j);
332 const double eValue = sourceE[j];
333 if (std::isnan(eValue)) {
334 nanEIndexes.emplace_back(j);
336 }
else if (std::isinf(eValue)) {
337 infEIndexes.emplace_back(j);
361 g_log.
information(
"Integration RangeLower: " + boost::lexical_cast<std::string>(start));
362 g_log.
information(
"Integration RangeUpper: " + boost::lexical_cast<std::string>(stop));
364 return integration->getProperty(
"OutputWorkspace");
387 const std::string in1 =
"__Stitch1D_intermediate_workspace_1__";
388 const std::string in2 =
"__Stitch1D_intermediate_workspace_2__";
389 Mantid::API::AnalysisDataService::Instance().addOrReplace(in1, inOne);
390 Mantid::API::AnalysisDataService::Instance().addOrReplace(in2, inTwo);
392 conjoinX->initialize();
393 conjoinX->setProperty(
"InputWorkspaces", std::vector<std::string>{in1, in2});
395 Mantid::API::AnalysisDataService::Instance().remove(in1);
396 Mantid::API::AnalysisDataService::Instance().remove(in2);
398 return std::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
408 auto a1 =
static_cast<int>(
workspace->yIndexOfX(startOverlap));
409 auto a2 =
static_cast<int>(
workspace->yIndexOfX(endOverlap));
411 throw std::runtime_error(
"The Params you have provided for binning yield a "
412 "workspace in which start and end overlap appear "
413 "in the same bin. Make binning finer via input "
416 return boost::tuple<int, int>(a1, a2);
424 for (
auto i = 0u; i < ws->getNumberHistograms(); ++i) {
425 const auto &e = ws->e(i);
427 if (std::accumulate(e.begin(), e.end(), 0.0) != 0.0) {
444 if (ws->size() == dxWS->size()) {
445 for (
size_t i = 0; i < ws->getNumberHistograms(); ++i) {
446 if (dxWS->hasDx(i) && !ws->hasDx(i) && !ws->isHistogramData()) {
447 ws->setSharedDx(i, dxWS->sharedDx(i));
453 if (m_scaleFactor < 1e-2 || m_scaleFactor > 1e2 || std::isnan(
m_scaleFactor)) {
454 std::stringstream messageBuffer;
455 messageBuffer <<
"Stitch1D calculated scale factor is: " <<
m_scaleFactor
456 <<
". Check the overlap region is non-zero.";
467 const MinMaxTuple intesectionXRegion = calculateXIntersection(lhsWS, rhsWS);
469 const size_t histogramCount = rhsWS->getNumberHistograms();
475 const double intersectionMin = intesectionXRegion.get<0>();
476 const double intersectionMax = intesectionXRegion.get<1>();
477 double startOverlap =
getStartOverlap(intersectionMin, intersectionMax);
478 double endOverlap =
getEndOverlap(intersectionMin, intersectionMax);
479 if (startOverlap > endOverlap) {
480 std::string message = boost::str(boost::format(
"Stitch1D cannot have a StartOverlap > EndOverlap. "
481 "StartOverlap: %0.9f, EndOverlap: %0.9f") %
482 startOverlap % endOverlap);
483 throw std::runtime_error(message);
486 const bool scaleRHS = this->
getProperty(
"ScaleRHSWorkspace");
490 if (lhsWS->isHistogramData()) {
492 const double xMin = params.front();
493 const double xMax = params.back();
501 if (startOverlap < xMin) {
502 std::string message = boost::str(boost::format(
"Stitch1D StartOverlap is outside the available X range. "
503 "StartOverlap: %10.9f, X min: %10.9f") %
504 startOverlap % xMin);
505 throw std::runtime_error(message);
507 if (endOverlap > xMax) {
508 std::string message = boost::str(boost::format(
"Stitch1D EndOverlap is outside the available X range. "
509 "EndOverlap: %10.9f, X max: %10.9f") %
511 throw std::runtime_error(message);
513 lhs =
rebin(lhs, params);
519 const bool useManualScaleFactor = this->
getProperty(
"UseManualScaleFactor");
520 if (useManualScaleFactor) {
526 auto rhsOverlapIntegrated =
integration(
rhs, startOverlap, endOverlap);
527 auto lhsOverlapIntegrated =
integration(lhs, startOverlap, endOverlap);
529 auto scalingFactors = lhsOverlapIntegrated / rhsOverlapIntegrated;
532 auto scalingFactors = rhsOverlapIntegrated / lhsOverlapIntegrated;
537 std::stringstream messageBuffer;
542 if (lhsWS->isHistogramData()) {
544 int a1 = boost::tuples::get<0>(startEnd);
545 int a2 = boost::tuples::get<1>(startEnd);
551 maskInPlace(a1 + 1,
static_cast<int>(lhs->blocksize()), lhs);
560 overlapave = sum * 0.5;
562 result = lhs + overlapave +
rhs;
567 g_log.
error(
"Could not retrieve joined workspace.");
571 childAlg->setProperty(
"InputWorkspace", result);
573 result = childAlg->getProperty(
"OutputWorkspace");
579 const std::string scalingWsName = this->
getPropertyValue(
"OutputScalingWorkspace");
580 if (!scalingWsName.empty()) {
584 createSingleAlg->executeAsChildAlg();
586 AnalysisDataService::Instance().addOrReplace(scalingWsName, singleWS);
593 auto histogramCount =
static_cast<int>(ws->getNumberHistograms());
595 for (
int i = 0; i < histogramCount; ++i) {
598 auto &sourceY = ws->mutableY(i);
601 sourceY[j] = std::numeric_limits<double>::quiet_NaN();
605 sourceY[j] = std::numeric_limits<double>::infinity();
609 sourceY[j] = std::numeric_limits<double>::quiet_NaN();
613 sourceY[j] = std::numeric_limits<double>::infinity();
#define DECLARE_ALGORITHM(classname)
const std::vector< double > & rhs
double value
The value of the point.
IPeaksWorkspace_sptr workspace
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
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 std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
A property class for workspaces.
void setReferenceProperties(const API::MatrixWorkspace_sptr &)
Sets the properties of the reference (usually first) workspace, to later check the compatibility of t...
std::string checkCompatibility(const API::MatrixWorkspace_sptr &, bool checkNumberHistograms=false)
Compares the properties of the input workspace with the reference.
Stitch1D : Stitches two Matrix Workspaces together into a single output.
SpecialTypeIndexes m_infEIndexes
Index per workspace spectra of Infs.
Mantid::API::MatrixWorkspace_sptr maskAllBut(int a1, int a2, Mantid::API::MatrixWorkspace_sptr &source)
Mask out everything but the data in the ranges.
SpecialTypeIndexes m_nanYIndexes
bool hasNonzeroErrors(Mantid::API::MatrixWorkspace_sptr &ws)
Does the x-axis have non-zero errors.
boost::tuple< int, int > findStartEndIndexes(double startOverlap, double endOverlap, Mantid::API::MatrixWorkspace_sptr &workspace)
Find the start and end indexes.
Mantid::API::MatrixWorkspace_sptr rebin(Mantid::API::MatrixWorkspace_sptr &input, const std::vector< double > ¶ms)
Perform rebin.
double m_errorScaleFactor
std::vector< double > getRebinParams(Mantid::API::MatrixWorkspace_const_sptr &lhsWS, Mantid::API::MatrixWorkspace_const_sptr &rhsWS, const bool scaleRHS) const
Get the rebin parameters.
void maskInPlace(int a1, int a2, Mantid::API::MatrixWorkspace_sptr &source)
Mask out everything but the data in the ranges, but do it inplace.
Mantid::API::MatrixWorkspace_sptr integration(Mantid::API::MatrixWorkspace_sptr const &input, const double start, const double stop)
Perform integration.
void scaleWorkspace(API::MatrixWorkspace_sptr &ws, API::MatrixWorkspace_sptr &scaleFactorWS, API::MatrixWorkspace_const_sptr &dxWS)
Scale workspace (left hand side or right hand side)
double getStartOverlap(const double intesectionMin, const double intesectionMax) const
Get the start overlap.
SpecialTypeIndexes m_nanEIndexes
Index per workspace spectra of Nans.
void exec() override
Overwrites Algorithm method.
SpecialTypeIndexes m_infYIndexes
double m_scaleFactor
Scaling factors.
void init() override
Overwrites Algorithm method.
double getEndOverlap(const double intesectionMin, const double intesectionMax) const
Get the end overlap.
static const double range_tolerance
Range tolerance.
Mantid::API::MatrixWorkspace_sptr weightedMean(Mantid::API::MatrixWorkspace_sptr const &inOne, Mantid::API::MatrixWorkspace_sptr const &inTwo)
Calculate the weighted mean.
void reinsertSpecialValues(const Mantid::API::MatrixWorkspace_sptr &ws)
Add back in any special values.
Mantid::API::MatrixWorkspace_sptr conjoinXAxis(Mantid::API::MatrixWorkspace_sptr const &inOne, Mantid::API::MatrixWorkspace_sptr const &inTwo)
Conjoin x axis.
std::map< std::string, std::string > validateInputs() override
Cross-check properties with each other.
Concrete workspace implementation.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void notice(const std::string &msg)
Logs at notice level.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
The concrete, templated class for properties.
Base class for properties.
virtual bool isDefault() const =0
Overriden function that returns if property has the same value that it was initialised with,...
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
std::shared_ptr< Algorithm > Algorithm_sptr
Typedef for a shared pointer to an Algorithm.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
MANTID_KERNEL_DLL bool withinAbsoluteDifference(T const x, T const y, S const tolerance)
Test whether x, y are within absolute tolerance tol.
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
@ Input
An input workspace.
@ Output
An output workspace.