Skip to content
Snippets Groups Projects
AppendSpectra.cpp 5.56 KiB
Newer Older
#include "MantidAlgorithms/AppendSpectra.h"
#include "MantidAPI/CommonBinsValidator.h"
#include "MantidAPI/WorkspaceOpOverloads.h"
#include "MantidDataObjects/EventWorkspace.h"
Dan Nixon's avatar
Dan Nixon committed
#include "MantidKernel/BoundedValidator.h"
#include "MantidKernel/SingletonHolder.h"
#include "MantidIndexing/IndexInfo.h"
#include "MantidIndexing/MakeRange.h"
using namespace Mantid::Indexing;
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::DataObjects;

namespace Mantid {
namespace Algorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(AppendSpectra)

/// Algorithm's name for identification. @see Algorithm::name
const std::string AppendSpectra::name() const { return "AppendSpectra"; }

/// Algorithm's version for identification. @see Algorithm::version
int AppendSpectra::version() const { return 1; }

/** Initialize the algorithm's properties.
 */
void AppendSpectra::init() {
  declareProperty(make_unique<WorkspaceProperty<>>(
                      "InputWorkspace1", "", Direction::Input,
                      boost::make_shared<CommonBinsValidator>()),
                  "The name of the first input workspace");
  declareProperty(make_unique<WorkspaceProperty<>>(
                      "InputWorkspace2", "", Direction::Input,
                      boost::make_shared<CommonBinsValidator>()),
                  "The name of the second input workspace");
  declareProperty(
      "ValidateInputs", true,
      "Perform a set of checks that the two input workspaces are compatible.");
Dan Nixon's avatar
Dan Nixon committed
  declareProperty("Number", 1,
Dan Nixon's avatar
Dan Nixon committed
                  boost::make_shared<BoundedValidator<int>>(1, EMPTY_INT()),
                  "Append the spectra from InputWorkspace2 multiple times (for "
                  "MatrixWorkspaces only)");
  declareProperty(make_unique<WorkspaceProperty<>>("OutputWorkspace", "",
                                                   Direction::Output),
                  "The name of the output workspace");
  declareProperty("MergeLogs", false,
                  "Whether to combine the logs of the two input workspaces");
}

/** Execute the algorithm.
 */
void AppendSpectra::exec() {
  // Retrieve the input workspaces
  MatrixWorkspace_const_sptr ws1 = getProperty("InputWorkspace1");
  MatrixWorkspace_const_sptr ws2 = getProperty("InputWorkspace2");
  event_ws1 = boost::dynamic_pointer_cast<const EventWorkspace>(ws1);
  event_ws2 = boost::dynamic_pointer_cast<const EventWorkspace>(ws2);

  // Make sure that we are not mis-matching EventWorkspaces and other types of
  // workspaces
  if (((event_ws1) && (!event_ws2)) || ((!event_ws1) && (event_ws2))) {
    const std::string message("Only one of the input workspaces are of type "
                              "EventWorkspace; please use matching workspace "
                              "types (both EventWorkspace's or both "
                              "Workspace2D's).");
    g_log.error(message);
    throw std::invalid_argument(message);
  bool ValidateInputs = this->getProperty("ValidateInputs");
  if (ValidateInputs) {
    // Check that the input workspaces meet the requirements for this algorithm
    this->validateInputs(ws1, ws2);
  const bool mergeLogs = getProperty("MergeLogs");
Dan Nixon's avatar
Dan Nixon committed
  const int number = getProperty("Number");
  if (event_ws1 && event_ws2) {
    // Both are event workspaces. Use the special method
    MatrixWorkspace_sptr output = this->execEvent();
    if (number > 1)
Dan Nixon's avatar
Dan Nixon committed
      g_log.warning("Number property is ignored for event workspaces");
    if (mergeLogs)
      combineLogs(ws1->run(), ws2->run(), output->mutableRun());
    // Set the output workspace
    setProperty("OutputWorkspace", output);
    return;
  // So it is a workspace 2D.

  // The only restriction, even with ValidateInputs=false
  if (ws1->blocksize() != ws2->blocksize())
    throw std::runtime_error(
        "Workspace2D's must have the same number of bins.");

  MatrixWorkspace_sptr output = execWS2D(ws1, ws2);
Dan Nixon's avatar
Dan Nixon committed
  for (int i = 1; i < number; i++)
    output = execWS2D(output, ws2);
  if (mergeLogs)
    combineLogs(ws1->run(), ws2->run(), output->mutableRun());

  // Set the output workspace
  setProperty("OutputWorkspace",
              boost::dynamic_pointer_cast<MatrixWorkspace>(output));
}

/** If there is an overlap in spectrum numbers between ws1 and ws2,
 * then the spectrum numbers are reset as a simple 1-1 correspondence
 * with the workspace index.
 *
 * @param ws1 The first workspace supplied to the algorithm.
 * @param ws2 The second workspace supplied to the algorithm.
 * @param output The workspace that is going to be returned by the algorithm.
 */
void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
                                       API::MatrixWorkspace_const_sptr ws2,
                                       API::MatrixWorkspace_sptr output) {
  specnum_t ws1min;
  specnum_t ws1max;
  getMinMax(ws1, ws1min, ws1max);

  specnum_t ws2min;
  specnum_t ws2max;
  getMinMax(ws2, ws2min, ws2max);

  // is everything possibly ok?
  if (ws2min > ws1max)
    return;

  auto indexInfo = output->indexInfo();
  // change the axis by adding the maximum existing spectrum number to the
  // current value
      makeRange(0, static_cast<specnum_t>(output->getNumberHistograms() - 1)));
  output->setIndexInfo(indexInfo);
}

void AppendSpectra::combineLogs(const API::Run &lhs, const API::Run &rhs,
                                API::Run &ans) {
  // No need to worry about ordering here as for Plus - they have to be
  // different workspaces
  if (&lhs != &rhs) {
    ans = lhs;
    ans += rhs;
  }
}
} // namespace Mantid
} // namespace Algorithms