21#include "MantidIndexing/IndexInfo.h"
28#include "MantidTypes/SpectrumDefinition.h"
30using Mantid::HistogramData::HistogramX;
37using namespace Kernel;
39using namespace Geometry;
40using namespace DataObjects;
41using namespace RunCombinationOptions;
48 "The names of the input workspaces as a list. You may "
49 "also group workspaces using the GUI or [[GroupWorkspaces]], and specify "
50 "the name of the group instead.");
52 "Name of the output workspace");
62 "Choose whether to rebin when bins are different, or fail "
63 "(fail behaviour defined in FailBehaviour option).");
66 "Choose whether to skip the file and continue, or stop and "
67 "throw and error, when encountering a failure.");
83 const std::vector<std::string> inputs_orig =
getProperty(
"InputWorkspaces");
87 if (inputs.size() == 1) {
103 const auto numOutputSpectra = outWS->getNumberHistograms() + addeeWS->getNumberHistograms();
106 DataObjects::create<MatrixWorkspace>(*outWS, numOutputSpectra, outWS->histogram(0).binEdges());
108 newOutWS->mutableComponentInfo().merge(addeeWS->componentInfo());
110 if (newOutWS->detectorInfo().size() * newOutWS->detectorInfo().scanCount() ==
111 outWS->detectorInfo().size() * outWS->detectorInfo().scanCount()) {
114 g_log.
information() <<
"Workspaces had identical detector scan information and were "
116 return outWS + addeeWS;
117 }
else if (newOutWS->detectorInfo().size() * newOutWS->detectorInfo().scanCount() != numOutputSpectra) {
118 throw std::runtime_error(
"Unexpected DetectorInfo size. Merging workspaces "
119 "with some, but not all overlapping scan "
120 "intervals is not currently supported.");
123 g_log.
information() <<
"Workspaces had different, non-overlapping scan intervals "
124 "so spectra will be appended.";
126 auto outSpecDefs = *(outWS->indexInfo().spectrumDefinitions());
127 const auto &addeeSpecDefs = *(addeeWS->indexInfo().spectrumDefinitions());
129 const auto newAddeeSpecDefs =
buildScanIntervals(addeeSpecDefs, addeeWS->detectorInfo(), newOutWS->detectorInfo());
131 outSpecDefs.insert(outSpecDefs.end(), newAddeeSpecDefs.begin(), newAddeeSpecDefs.end());
133 auto newIndexInfo = Indexing::IndexInfo(numOutputSpectra);
134 newIndexInfo.setSpectrumDefinitions(std::move(outSpecDefs));
135 newOutWS->setIndexInfo(newIndexInfo);
137 for (
size_t i = 0; i < outWS->getNumberHistograms(); ++i)
138 newOutWS->setHistogram(i, outWS->histogram(i));
140 for (
size_t i = 0; i < addeeWS->getNumberHistograms(); ++i)
141 newOutWS->setHistogram(i + outWS->getNumberHistograms(), addeeWS->histogram(i));
151 throw std::invalid_argument(
"MergeRuns: No workspaces found to merge.");
158 auto lhs_nhist =
static_cast<int>(lhs->getNumberHistograms());
162 lhs_det_to_wi = lhs->getDetectorIDToWorkspaceIndexMap(
true);
163 }
catch (std::runtime_error &) {
170 for (
size_t workspaceNum = 1; workspaceNum <
m_inEventWS.size(); workspaceNum++) {
181 std::size_t nhist = ews->getNumberHistograms();
182 table.reserve(nhist);
183 for (
int inWI = 0; inWI < static_cast<int>(nhist); inWI++) {
185 auto &inDets = ews->getSpectrum(inWI).getDetectorIDs();
192 if (outWI < lhs_nhist)
194 auto &outDets = lhs->getSpectrum(outWI).getDetectorIDs();
197 if (std::includes(outDets.begin(), outDets.end(), inDets.begin(), inDets.end())) {
199 table.emplace_back(inWI, outWI);
204 if (!done && !lhs_det_to_wi.empty() && (inDets.size() == 1)) {
208 auto inDets_it = inDets.begin();
209 detid_t rhs_detector_ID = *inDets_it;
213 detid2index_map::const_iterator map_it = lhs_det_to_wi.find(rhs_detector_ID);
214 if (map_it != lhs_det_to_wi.cend()) {
216 outWI =
static_cast<int>(map_it->second);
222 table.emplace_back(inWI, outWI);
230 for (outWI = 0; outWI < lhs_nhist; outWI++) {
231 const auto &outDets2 = lhs->getSpectrum(outWI).getDetectorIDs();
233 if (std::includes(outDets2.begin(), outDets2.end(), inDets.begin(), inDets.end())) {
235 table.emplace_back(inWI, outWI);
250 table.emplace_back(inWI, -1);
261 throw std::runtime_error(
"MergeRuns::buildAdditionTables: Mismatch between "
262 "the number of addition tables and the number of "
277 auto outWS = create<EventWorkspace>(*inputWS,
m_outputSize, inputWS->binEdges(0));
278 const auto inputSize = inputWS->getNumberHistograms();
279 for (
size_t i = 0; i < inputSize; ++i)
280 outWS->getSpectrum(i) = inputWS->getSpectrum(i);
283 m_progress = std::make_unique<Progress>(
this, 0.0, 1.0,
n);
286 auto current = inputSize;
287 for (
size_t workspaceNum = 1; workspaceNum <
m_inEventWS.size(); workspaceNum++) {
289 const auto &table =
m_tables[workspaceNum - 1];
292 for (
auto const &WI : table) {
293 int64_t inWI = WI.first;
294 int64_t outWI = WI.second;
296 outWS->getSpectrum(outWI) += addee.getSpectrum(inWI);
298 outWS->getSpectrum(current) = addee.getSpectrum(inWI);
304 outWS->mutableRun() += addee.run();
323 const std::string sampleLogsFailBehaviour =
getProperty(
"FailBehaviour");
333 outWS = this->
rebinInput(outWS, *rebinParams);
344 auto isScanning = outWS->detectorInfo().isScanning();
347 m_progress = std::make_unique<Progress>(
this, 0.0, 1.0, numberOfWSs - 1);
367 outWS = outWS + addee;
370 }
catch (std::invalid_argument &e) {
372 g_log.
error() <<
"Could not merge run: " << it->get()->getName() <<
". Reason: \"" << e.what()
373 <<
"\". MergeRuns will continue but this run will be skipped.\n";
376 throw std::invalid_argument(e);
405 for (
size_t i = 0; i < inputWorkspaces.size(); ++i) {
419 if (!compatibility.empty()) {
420 g_log.
error(
"Input workspaces are not compatible: " + compatibility);
421 throw std::invalid_argument(
"Input workspaces are not compatible: " + compatibility);
436 const std::string rebinBehaviour =
getProperty(
"RebinBehaviour");
437 const std::string sampleLogsFailBehaviour =
getProperty(
"FailBehaviour");
441 std::sort(inputsSortedByX.begin(), inputsSortedByX.end(),
443 return ws1->x(0).front() < ws2->x(0).front();
445 auto it = inputsSortedByX.cbegin();
446 g_log.
notice() <<
"Using run '" << (*it)->getName() <<
"' as a reference to determine possible rebinning.\n";
447 std::optional<std::vector<double>> rebinParams{std::nullopt};
448 std::vector<double> bins{(*it)->x(0).rawData()};
449 for (++it; it != inputsSortedByX.cend(); ++it) {
453 g_log.
error() <<
"Could not merge run: " << (*it)->getName()
454 <<
". Binning is different from the reference run. "
455 "MergeRuns will continue but this run will be "
460 throw std::invalid_argument(
"Could not merge run: " + (*it)->getName() +
461 ". Binning is different from the reference run.");
480 std::span<double const>
const bins2) {
481 std::vector<double> newParams;
484 newParams.reserve(1 + 2 * (bins1.size() - 1) + 2 + 2 * (bins2.size() - 1));
486 bool const oldIsFirst = bins1.front() < bins2.front();
487 auto const &smallerX = oldIsFirst ? bins1 : bins2;
488 auto const &greaterX = oldIsFirst ? bins2 : bins1;
489 double const end1 = smallerX.back();
490 double const start2 = greaterX.front();
491 double const end2 = greaterX.back();
493 if (end1 <= start2) {
498 newParams.emplace_back(smallerX.front());
500 for (i = 1; smallerX[i] <= start2; ++i) {
501 newParams.emplace_back(smallerX[i] - smallerX[i - 1]);
502 newParams.emplace_back(smallerX[i]);
524 std::vector<double> ¶ms) {
526 for (
size_t i = 1; i < X1.size(); ++i) {
527 params.emplace_back(X1[i - 1]);
528 params.emplace_back(X1[i] - X1[i - 1]);
531 if (X1.back() < X2.front()) {
532 params.emplace_back(X1.back());
533 params.emplace_back(X2.front() - X1.back());
536 for (
size_t j = 1; j < X2.size(); ++j) {
537 params.emplace_back(X2[j - 1]);
538 params.emplace_back(X2[j] - X2[j - 1]);
540 params.emplace_back(X2.back());
554 std::vector<double> ¶ms) {
557 auto const overlapbins1 = X1.size() - i;
558 auto const iterX2 = std::lower_bound(X2.begin(), X2.end(), X1.back());
559 if (iterX2 == X2.end()) {
560 throw std::runtime_error(
"MergerRuns::intersectionParams: no intersection "
561 "between the histograms.");
563 auto const overlapbins2 = std::distance(X2.begin(), iterX2);
565 if (overlapbins1 <
static_cast<size_t>(overlapbins2)) {
567 for (; i < X1.size(); ++i) {
568 params.emplace_back(X1[i] - X1[i - 1]);
569 params.emplace_back(X1[i]);
575 for (
size_t j = overlapbins2; j < X2.size(); ++j) {
576 params.emplace_back(X2[j] - params.back());
577 params.emplace_back(X2[j]);
581 for (
size_t j = 1; j < X2.size(); ++j) {
582 params.emplace_back(X2[j] - params.back());
583 params.emplace_back(X2[j]);
600 std::vector<double> ¶ms) {
603 const auto iterX1 = std::lower_bound(X1.begin() + i, X1.end(), X2.back());
604 if (iterX1 == X1.end()) {
605 throw std::runtime_error(
"MergeRuns::inclusionParams: no overlap between the histograms");
607 auto const overlapbins1 = std::distance(X1.begin(), iterX1) - i;
608 auto const overlapbins2 = X2.size() - 1;
612 if (overlapbins1 + 1 <= overlapbins2) {
615 for (; i < X1.size(); ++i) {
616 params.emplace_back(X1[i] - X1[i - 1]);
617 params.emplace_back(X1[i]);
622 for (
size_t j = 1; j < X2.size() - 1; ++j) {
623 params.emplace_back(X2[j] - params.back());
624 params.emplace_back(X2[j]);
628 for (; i < X1.size(); ++i) {
629 params.emplace_back(X1[i] - params.back());
630 params.emplace_back(X1[i]);
643 const std::vector<double> ¶ms) {
647 rebin->setProperty(
"Params", params);
648 rebin->executeAsChildAlg();
649 return rebin->getProperty(
"OutputWorkspace");
658 copyHistoryFromInputWorkspaces<std::vector<EventWorkspace_sptr>>(
m_inEventWS);
660 copyHistoryFromInputWorkspaces<std::list<MatrixWorkspace_sptr>>(
m_inMatrixWS);
675 std::vector<SpectrumDefinition> newAddeeSpecDefs(addeeSpecDefs.size());
681 for (int64_t i = 0; i < int64_t(addeeSpecDefs.size()); ++i) {
682 for (
auto const &
index : addeeSpecDefs[i]) {
683 SpectrumDefinition newSpecDef;
684 for (
size_t time_index = 0; time_index < newOutDetInfo.
scanCount(); time_index++) {
685 if (addeeScanIntervals[
index.second] == newOutScanIntervals[time_index]) {
686 newSpecDef.add(
index.first, time_index);
689 newAddeeSpecDefs[i] = newSpecDef;
693 return newAddeeSpecDefs;
#define DECLARE_ALGORITHM(classname)
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_FOR_NO_WSP_CHECK()
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.
API::MatrixWorkspace_sptr rebinInput(const API::MatrixWorkspace_sptr &workspace, const std::vector< double > ¶ms)
Calls the Rebin algorithm as a ChildAlgorithm.
std::string fetchInputPropertyName() const override
Method to provide the name for the input workspace property.
size_t m_outputSize
Total number of histograms in the output workspace.
void buildAdditionTables()
Build up addition tables for merging eventlists together.
void exec() override
Executes the algorithm.
static void noOverlapParams(std::span< double const > X1, std::span< double const > X2, std::vector< double > ¶ms)
Calculates the rebin paramters in the case where the two input workspaces do not overlap at all.
std::vector< SpectrumDefinition > buildScanIntervals(const std::vector< SpectrumDefinition > &addeeSpecDefs, const Geometry::DetectorInfo &addeeDetInfo, const Geometry::DetectorInfo &newOutDetInfo)
std::vector< Mantid::DataObjects::EventWorkspace_sptr > m_inEventWS
List of input EVENT workspaces.
std::unique_ptr< API::Progress > m_progress
Progress reporting.
void init() override
Initialisation method.
void execEvent()
Executes the algorithm for EventWorkspaces.
static std::vector< double > calculateRebinParams(std::span< double const > bins1, std::span< double const > bins2)
Calculates the parameters to hand to the Rebin algorithm.
std::vector< AdditionTable > m_tables
Addition tables for event workspaces.
bool useCustomInputPropertyName() const override
Method to indicate that a non-standard property is taken as the input, so will be specified via fetch...
std::optional< std::vector< double > > checkRebinning()
Checks if the workspaces need to be rebinned and if so, returns the rebinning parameters for the Rebi...
static void intersectionParams(std::span< double const > X1, size_t &i, std::span< double const > X2, std::vector< double > ¶ms)
Calculates the rebin parameters in the case where the bins of the two workspaces intersect.
bool validateInputsForEventWorkspaces(const std::vector< std::string > &inputWorkspaces)
Validate the input event workspaces.
static void inclusionParams(std::span< double const > X1, size_t &i, std::span< double const > X2, std::vector< double > ¶ms)
Calculates the rebin parameters in the case where the range of the second workspace is entirely withi...
void fillHistory() override
Overriden fillHistory method to correctly store history from merged workspaces.
API::MatrixWorkspace_sptr buildScanningOutputWorkspace(const API::MatrixWorkspace_sptr &outWS, const API::MatrixWorkspace_sptr &addee)
std::list< API::MatrixWorkspace_sptr > m_inMatrixWS
List of input matrix workspace.
std::vector< std::pair< int, int > > AdditionTable
An addition table is a list of pairs: First int = workspace index in the EW being added,...
void execHistogram(const std::vector< std::string > &inputs)
static std::vector< std::string > unWrapGroups(const std::vector< std::string > &)
Flattens the list of group workspaces (if any) into list of workspaces.
std::list< API::MatrixWorkspace_sptr > validateInputWorkspaces(const std::vector< std::string > &inputWorkspaces, Kernel::Logger &g_log)
Checks that the input workspace all exist, that they are the same size, have the same units and the s...
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.
SampleLogsBehaviour : This class holds information relating to the behaviour of the sample log mergin...
static const std::string LIST_DOC
static const std::string FAIL_DOC
static const std::string WARN_DOC
void removeSampleLogsFromWorkspace(const API::MatrixWorkspace_sptr &addeeWS)
When doing a time series merge we need to remove, then add back the sample log in the addee workspace...
static const std::string FAIL_PROP
static const std::string LIST_PROP
static const std::string TIME_SERIES_PROP
static const std::string TIME_SERIES_DOC
static const std::string SUM_DOC
static const std::string WARN_TOL_PROP
void readdSampleLogToWorkspace(const API::MatrixWorkspace_sptr &addeeWS)
When doing a time series merge we need to remove, then add back the sample log in the addee workspace...
static const std::string FAIL_TOL_DOC
void setUpdatedSampleLogs(const API::MatrixWorkspace_sptr &outWS)
Set the values in the map to be the same as those in the output workspace.
static const std::string WARN_PROP
void resetSampleLogs(const API::MatrixWorkspace_sptr &ws)
Resets the sample logs in the workspace to the values in the map.
void mergeSampleLogs(const API::MatrixWorkspace_sptr &addeeWS, const API::MatrixWorkspace_sptr &outWS)
Create and update sample logs according to instrument parameters.
static const std::string FAIL_TOL_PROP
static const std::string SUM_PROP
static const std::string WARN_TOL_DOC
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
size_t scanCount() const
Returns the scan count of the detector with given detector index.
const std::vector< std::pair< Types::Core::DateAndTime, Types::Core::DateAndTime > > scanIntervals() const
Returns the scan interval of the detector with given index.
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.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static const std::string FAIL_MERGE_TOLERANCES
static const std::string WARN_MERGE_TOLERANCES
static const std::string WARN_MERGE
static const std::string FAIL_MERGE
static const std::string SUM_MERGE
MergeRuns parameter names of the paramter file for sample log merging.
static const std::string TIME_SERIES_MERGE
static const std::string LIST_MERGE
static const std::string STOP_BEHAVIOUR
static const std::string REBIN_BEHAVIOUR
static const std::string FAIL_BEHAVIOUR
static const std::string SKIP_BEHAVIOUR
Kernel::Logger g_log("DetermineSpinStateOrder")
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
void MANTID_KERNEL_DLL rebin(std::span< double const > xold, std::span< double const > yold, std::span< double const > eold, std::span< double const > xnew, std::span< double > ynew, std::span< double > enew, bool distribution, bool addition=false)
The input and output ranges are taken as spans so that the size-checked histogram data types,...
std::size_t MANTID_KERNEL_DLL createAxisFromRebinParams(const std::vector< double > ¶ms, std::vector< double > &xnew, const bool resize_xnew=true, const bool full_bins_only=false, const double xMinHint=std::nan(""), const double xMaxHint=std::nan(""), const bool useReverseLogarithmic=false, const double power=-1)
Creates a new output X array given a 'standard' set of rebinning parameters.
int32_t detid_t
Typedef for a detector ID.
std::unordered_map< detid_t, size_t > detid2index_map
Map with key = detector ID, value = workspace index.
static bool matchingBins(const std::shared_ptr< const MatrixWorkspace > &ws1, const std::shared_ptr< const MatrixWorkspace > &ws2, const bool firstOnly=false)
Checks whether the bins (X values) of two workspace are the same.
std::string sampleLogsWarnTolerances
std::string sampleLogsWarn
std::string sampleLogsFail
std::string sampleLogsSum
std::string sampleLogsList
std::string sampleLogsTimeSeries
std::string sampleLogsFailTolerances
@ Output
An output workspace.