27static const std::string INPUT_WORKSPACE_PROPERTY =
"InputWorkspaces";
28static const std::string REFERENCE_WORKSPACE_PROPERTY =
"ReferenceWorkspace";
29static const std::string COMBINATION_BEHAVIOUR_PROPERTY =
"CombinationBehaviour";
30static const std::string SCALE_FACTOR_CALCULATION_PROPERTY =
"ScaleFactorCalculation";
31static const std::string MANUAL_SCALE_FACTORS_PROPERTY =
"ManualScaleFactors";
32static const std::string TIE_SCALE_FACTORS_PROPERTY =
"TieScaleFactors";
33static const std::string OUTPUT_WORKSPACE_PROPERTY =
"OutputWorkspace";
34static const std::string OUTPUT_SCALE_FACTORS_PROPERTY =
"OutputScaleFactorsWorkspace";
44 return std::make_pair(ws.
readX(0).front(), ws.
readX(0).back());
54 const auto minmax1 = getInterval(*ws1);
55 const auto minmax2 = getInterval(*ws2);
56 if (minmax1.first < minmax2.first) {
58 }
else if (minmax1.first > minmax2.first) {
61 return minmax1.second < minmax2.second;
73 const auto minmax1 = getInterval(*ws1);
74 const auto minmax2 = getInterval(*ws2);
75 if (minmax1.second < minmax2.first || minmax2.second < minmax1.first) {
77 ss <<
"No overlap is found between the intervals: [" << minmax1.first <<
"," << minmax1.second <<
"] and ["
78 << minmax2.first <<
", " << minmax2.second <<
"]";
79 throw std::runtime_error(ss.str());
81 return std::make_pair(std::max(minmax1.first, minmax2.first), std::min(minmax1.second, minmax2.second));
89double median(
const std::vector<double> &vec) {
92 const size_t s = vec.size();
93 std::vector<double> sorted = vec;
94 std::sort(sorted.begin(), sorted.end());
96 return 0.5 * (sorted[s / 2] + sorted[s / 2 - 1]);
108 const size_t nSpectra = ws->getNumberHistograms();
111 for (
int i = 0; i < static_cast<int>(
nSpectra); ++i) {
112 const size_t wsIndex =
static_cast<size_t>(i);
113 auto &
y = out->mutableY(wsIndex);
114 y = std::vector<double>(1, median(ws->readY(wsIndex)));
126 std::vector<double> allY;
127 allY.reserve(ws->getNumberHistograms() * ws->blocksize());
128 for (
size_t i = 0; i < ws->getNumberHistograms(); ++i) {
129 const auto spectrum = ws->mutableY(i).rawData();
130 std::copy(spectrum.cbegin(), spectrum.cend(), std::back_inserter(allY));
132 auto &
y = out->mutableY(0);
133 y = std::vector<double>(1, median(allY));
146 for (
int i = 0; i < static_cast<int>(
nSpectra); ++i) {
147 ws->mutableY(
static_cast<size_t>(i)) = std::vector<double>(nPoints, 1.);
162const
std::
string Stitch::name()
const {
return "Stitch"; }
171const std::string
Stitch::summary()
const {
return "Stitches overlapping spectra from multiple 2D workspaces."; }
175 std::map<std::string, std::string> issues;
176 const std::vector<std::string> inputs_given =
getProperty(INPUT_WORKSPACE_PROPERTY);
177 std::vector<std::string> workspaces;
181 }
catch (
const std::exception &e) {
182 issues[INPUT_WORKSPACE_PROPERTY] = std::string(e.what());
185 if (workspaces.size() < 2) {
186 issues[INPUT_WORKSPACE_PROPERTY] =
"Please provide at least 2 workspaces to stitch.";
190 const std::vector<double> factors =
getProperty(MANUAL_SCALE_FACTORS_PROPERTY);
191 if (factors.size() != workspaces.size()) {
192 issues[MANUAL_SCALE_FACTORS_PROPERTY] =
"If manual scale factors are requested, the number of scale factors must "
193 "match the number of input workspaces.";
199 }
catch (
const std::exception &e) {
200 issues[INPUT_WORKSPACE_PROPERTY] =
201 std::string(
"Please provide MatrixWorkspaces as or groups of those as input: ") + e.what();
204 if (!
isDefault(REFERENCE_WORKSPACE_PROPERTY)) {
206 if (std::find_if(workspaces.cbegin(), workspaces.cend(),
207 [&referenceName](
const auto wsName) { return wsName == referenceName; }) == workspaces.cend()) {
208 issues[REFERENCE_WORKSPACE_PROPERTY] =
"Reference workspace must be one of the input workspaces";
212 for (
const auto &wsName : workspaces) {
216 if (!compatible.empty()) {
217 issues[INPUT_WORKSPACE_PROPERTY] +=
"Workspace " + ws->getName() +
" is not compatible: " + compatible +
"\n";
220 if (!ws->isCommonBins()) {
221 issues[INPUT_WORKSPACE_PROPERTY] +=
"Workspace " + ws->getName() +
" is ragged which is not supported.\n";
223 if (ws->isHistogramData()) {
224 issues[INPUT_WORKSPACE_PROPERTY] +=
225 "Workspace " + ws->getName() +
" contains histogram data, only point data are supported.\n";
237 "The names of the input workspaces or groups of those as a list. "
238 "At least two compatible MatrixWorkspaces are required, having one spectrum each. ");
240 "The name of the workspace that will serve as the reference; "
241 "that is, the one that will not be scaled. If left blank, "
242 "stitching will be performed left to right in the order of x-axes ascending, "
243 "no matter the order of workspaces names in the input.");
249 "Manually specified scale factors, must follow the same order of the workspaces in the list.");
251 std::make_unique<EnabledWhenProperty>(SCALE_FACTOR_CALCULATION_PROPERTY,
IS_EQUAL_TO,
"Manual"));
253 "Whether or not to calculate a single scale factor per workspace for all the spectra.");
256 "The output workspace.");
259 "The output workspace containing the applied scale factors.");
267 const auto combinationBehaviour =
getPropertyValue(COMBINATION_BEHAVIOUR_PROPERTY);
268 const auto scaleFactorCalculation =
getPropertyValue(SCALE_FACTOR_CALCULATION_PROPERTY);
272 std::vector<std::string> clones;
273 std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(clones),
274 [](
const auto ws) { return
"__cloned_" + ws; });
275 if (scaleFactorCalculation ==
"Manual") {
276 scaleFactorsWorkspace = initScaleFactorsWorkspace(1, clones.size());
282 for (
const auto &ws : clones) {
285 if (!
isDefault(OUTPUT_SCALE_FACTORS_PROPERTY)) {
286 setProperty(OUTPUT_SCALE_FACTORS_PROPERTY, scaleFactorsWorkspace);
298 std::vector<MatrixWorkspace_sptr> workspaces;
299 std::transform(clones.cbegin(), clones.cend(), std::back_inserter(workspaces),
300 [](
const auto ws) { return AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(ws); });
301 const size_t nSpectrumInScaleFactors =
302 isDefault(TIE_SCALE_FACTORS_PROPERTY) ? workspaces[0]->getNumberHistograms() : 1;
303 scaleFactorsWorkspace = initScaleFactorsWorkspace(nSpectrumInScaleFactors, workspaces.size());
305 std::sort(workspaces.begin(), workspaces.end(), compareInterval);
306 auto progress = std::make_unique<Progress>(
this, 0.0, 1.0, workspaces.size());
308 size_t leftIterator = referenceIndex, rightIterator = referenceIndex;
312 while (leftIterator > 0) {
313 scale(workspaces[leftIterator], workspaces[leftIterator - 1], scaleFactorsWorkspace, clones);
317 while (rightIterator < workspaces.size() - 1) {
318 scale(workspaces[rightIterator], workspaces[rightIterator + 1], scaleFactorsWorkspace, clones);
331 const std::string &referenceName) {
332 size_t referenceIndex = 0;
333 if (!
isDefault(REFERENCE_WORKSPACE_PROPERTY)) {
334 const auto ref = std::find_if(workspaces.cbegin(), workspaces.cend(), [&referenceName](
const auto ws) {
335 return ws->getName() ==
"__cloned_" + referenceName;
337 referenceIndex = std::distance(workspaces.cbegin(), ref);
339 return referenceIndex;
349 cloner->setAlwaysStoreInADS(
true);
350 for (
const auto &ws : inputs) {
351 cloner->setProperty(
"InputWorkspace", ws);
352 cloner->setProperty(
"OutputWorkspace",
"__cloned_" + ws);
366 joiner->setProperty(
"InputWorkspaces", inputs);
372 sorter->setProperty(
"InputWorkspace", joined);
389 const auto overlap = getOverlap(wsToMatch, wsToScale);
391 cropper->setProperty(
"XMin", std::vector<double>({overlap.first}));
392 cropper->setProperty(
"XMax", std::vector<double>({overlap.second}));
394 cropper->setProperty(
"InputWorkspace", wsToMatch);
397 cropper->setProperty(
"InputWorkspace", wsToScale);
402 if (croppedToMatch->blocksize() > 1) {
404 interpolator->setProperty(
"WorkspaceToMatch", croppedToMatch);
405 interpolator->setProperty(
"WorkspaceToInterpolate", croppedToScale);
406 interpolator->setProperty(
"Linear2Points",
true);
407 interpolator->execute();
408 rebinnedToScale = interpolator->getProperty(
"OutputWorkspace");
410 if (croppedToMatch->readX(0) != croppedToScale->readX(0)) {
411 throw std::runtime_error(
412 "Unable to make the ratio; only one overlapping point is found and it is at different x");
414 rebinnedToScale = croppedToScale;
419 divider->setProperty(
"LHSWorkspace", rebinnedToScale);
420 divider->setProperty(
"RHSWorkspace", croppedToMatch);
424 getProperty(
"TieScaleFactors") ? medianWorkspaceGlobal(ratio) : medianWorkspaceLocal(ratio);
427 scaler->setAlwaysStoreInADS(
true);
428 scaler->setProperty(
"LHSWorkspace", wsToScale);
429 scaler->setProperty(
"RHSWorkspace", median);
430 scaler->setPropertyValue(
"OutputWorkspace", wsToScale->getName());
447 const std::vector<std::string> &inputs) {
448 const auto it = std::find(inputs.cbegin(), inputs.cend(), scaledWorkspace->getName());
449 const size_t index = std::distance(inputs.cbegin(), it);
451 for (
int i = 0; i < static_cast<int>(scaleFactorWorkspace->getNumberHistograms()); ++i) {
452 scaleFactorWorkspace->mutableY(i)[
index] = 1. / medianWorkspace->readY(i)[0];
466 auto &outputFactors = scaleFactorsWorkspace->mutableY(0);
467 auto progress = std::make_unique<Progress>(
this, 0.0, 1.0, inputs.size());
469 for (
int i = 0; i < static_cast<int>(inputs.size()); ++i) {
470 outputFactors[i] = scaleFactors[i];
472 scaler->setAlwaysStoreInADS(
true);
473 scaler->setPropertyValue(
"InputWorkspace", inputs[i]);
474 scaler->setProperty(
"Factor", scaleFactors[i]);
475 scaler->setPropertyValue(
"OutputWorkspace", inputs[i]);
#define DECLARE_ALGORITHM(classname)
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
Base MatrixWorkspace Abstract Class.
const MantidVec & readX(std::size_t const index) const
Deprecated, use x() instead.
A property class for workspaces.
static std::vector< std::string > unWrapGroups(const std::vector< std::string > &)
Flattens the list of group workspaces (if any) into list of 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.
Stitches overlapping spectra from multiple 2D workspaces.
void cloneWorkspaces(const std::vector< std::string > &inputs)
Clones all the input workspaces so that they can be scaled in-place without altering the inputs Clone...
void scaleWithMedianRatios(const std::vector< std::string > &clones, const std::string &referenceName, API::MatrixWorkspace_sptr &scaleFactorsWorkspace)
Scales workspaces by medians of point-wise ratios in the overlap regions.
void init() override
Initialize the algorithm's properties.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
API::MatrixWorkspace_sptr merge(const std::vector< std::string > &workspaces)
Combines the scaled workspaces together by interleaving their data This is equivalent to concatenatio...
void scale(const API::MatrixWorkspace_sptr &wsToMatch, const API::MatrixWorkspace_sptr &wsToScale, API::MatrixWorkspace_sptr scaleFactorsWorkspace, const std::vector< std::string > &inputs)
Scales one workspace to match the scale of the other The scale factors are calculated as medians of p...
int version() const override
Algorithm's version for identification.
std::map< std::string, std::string > validateInputs() override
Validate the input workspaces for compatibility.
void exec() override
Execute the algorithm.
void recordScaleFactor(const API::MatrixWorkspace_sptr &scaleFactorWorkspace, const API::MatrixWorkspace_sptr &medianWorkspace, const API::MatrixWorkspace_sptr &scaledWorkspace, const std::vector< std::string > &inputs)
Stores the multiplicative scale factors into a workspace Note that the scale factors are stored in th...
size_t getReferenceIndex(const std::vector< API::MatrixWorkspace_sptr > &workspaces, const std::string &referenceName)
Returns the index of the reference workspace in the sorted workspace list.
void scaleManual(const std::vector< std::string > &inputs, const std::vector< double > &scaleFactors, const API::MatrixWorkspace_sptr &scaleFactorsWorkspace)
Performs scaling with manual scale factors, which are treated as global, i.e.
const std::string category() const override
Algorithm's category for identification.
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 setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
ListValidator is a validator that requires the value of a property to be one of a defined list of pos...
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
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.
@ Output
An output workspace.