Skip to content
Snippets Groups Projects
WorkspaceFactory.cpp 7.73 KiB
Newer Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceOpOverloads.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidKernel/ConfigService.h"
#include "MantidAPI/NumericAxis.h"
#include "MantidAPI/TextAxis.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/IPeaksWorkspace.h"
namespace Mantid {
namespace API {
namespace {
/// static logger object
Kernel::Logger g_log("WorkspaceFactory");
}
Peterson, Peter's avatar
Peterson, Peter committed
using std::size_t;

/// Private constructor for singleton class
WorkspaceFactoryImpl::WorkspaceFactoryImpl()
    : Mantid::Kernel::DynamicFactory<Workspace>() {
  g_log.debug() << "WorkspaceFactory created." << std::endl;
 *  Prevents client from calling 'delete' on the pointer handed
WorkspaceFactoryImpl::~WorkspaceFactoryImpl() {}
/** Create a new instance of the same type of workspace as that given as
 * argument.
 *  If the optional size parameters are given, the workspace will be initialised
 * using
 *  those; otherwise it will be initialised to the same size as the parent.
 *  This method should be used when you want to carry over the Workspace data
 * members
 *  relating to the Instrument, Spectra-Detector Map, Sample & Axes to the new
 * workspace.
 *  If the workspace is the same size as its parent, then the X data, axes and
 * mask list are
 *  copied. If its a different size then they are not.
 *  @param  parent    A shared pointer to the parent workspace
 *  @param  NVectors  (Optional) The number of vectors/histograms/detectors in
 * the workspace
 *  @param  XLength   (Optional) The number of X data points/bin boundaries in
 * each vector (must all be the same)
 *  @param  YLength   (Optional) The number of data/error points in each vector
 * (must all be the same)
 *  @return A shared pointer to the newly created instance
 *  @throw  std::out_of_range If invalid (0 or less) size arguments are given
 *  @throw  NotFoundException If the class is not registered in the factory
 */
MatrixWorkspace_sptr
WorkspaceFactoryImpl::create(const MatrixWorkspace_const_sptr &parent,
                             size_t NVectors, size_t XLength,
                             size_t YLength) const {
  bool differentSize(true);
  // Use the parent sizes if new ones are not specified
  if (NVectors == size_t(-1))
    NVectors = parent->getNumberHistograms();
  if (XLength == size_t(-1))
    XLength = parent->dataX(0).size();
  if (YLength == size_t(-1)) {
  // If the parent is an EventWorkspace, we want it to spawn a Workspace2D (or
  // managed variant) as a child
  std::string id(parent->id());
  if (id == "EventWorkspace")
    id = "Workspace2D";
  // Create an 'empty' workspace of the appropriate type and size
  MatrixWorkspace_sptr ws = create(id, NVectors, XLength, YLength);
  initializeFromParent(parent, ws, differentSize);
/** Initialise a workspace from its parent
 * This sets values such as title, instrument, units, sample, spectramap.
 * This does NOT copy any data.
 *
 * @param parent :: the parent workspace
 * @param child :: the child workspace
 * @param differentSize :: A flag to indicate if the two workspace will be
 *different sizes
void WorkspaceFactoryImpl::initializeFromParent(
    const MatrixWorkspace_const_sptr parent, const MatrixWorkspace_sptr child,
    const bool differentSize) const {
  child->setTitle(parent->getTitle());
  child->setComment(parent->getComment());
  child->setInstrument(parent->getInstrument()); // This call also copies the
                                                 // SHARED POINTER to the
                                                 // parameter map
  // This call will (should) perform a COPY of the parameter map.
  child->instrumentParameters();
  child->setYUnit(parent->m_YUnit);
  child->setYUnitLabel(parent->m_YUnitLabel);
  child->isDistribution(parent->isDistribution());

  // Only copy the axes over if new sizes are not given
  if (!differentSize) {
    // Only copy mask map if same size for now. Later will need to check
    // continued validity.
  // Same number of histograms = copy over the spectra data
  if (parent->getNumberHistograms() == child->getNumberHistograms()) {
    for (size_t wi = 0; wi < parent->getNumberHistograms(); wi++) {
      ISpectrum *childSpec = child->getSpectrum(wi);
      const ISpectrum *parentSpec = parent->getSpectrum(wi);
      // Copy spectrum number and detector IDs
      childSpec->copyInfoFrom(*parentSpec);
    }
  }

  // deal with axis
  for (size_t i = 0; i < parent->m_axes.size(); ++i) {
Peterson, Peter's avatar
Peterson, Peter committed
    const size_t newAxisLength = child->getAxis(i)->length();
    const size_t oldAxisLength = parent->getAxis(i)->length();
    if (!differentSize || newAxisLength == oldAxisLength) {
      // Need to delete the existing axis created in init above
      // Now set to a copy of the parent workspace's axis
      child->m_axes[i] = parent->m_axes[i]->clone(child.get());
    } else {
      if (!parent->getAxis(i)->isSpectra()) // WHY???
        delete child->m_axes[i];
        // Call the 'different length' clone variant
        child->m_axes[i] = parent->m_axes[i]->clone(newAxisLength, child.get());
Dickon Champion's avatar
Dickon Champion committed

/** Creates a new instance of the class with the given name, and allocates
 * memory for the arrays
 *  @param  className The name of the class you wish to create
 *  @param  NVectors  The number of vectors/histograms/detectors in the
 * workspace
 *  @param  XLength   The number of X data points/bin boundaries in each vector
 * (must all be the same)
 *  @param  YLength   The number of data/error points in each vector (must all
 * be the same)
 *  @return A shared pointer to the newly created instance
 *  @throw  std::out_of_range If invalid (0 or less) size arguments are given
 *  @throw  NotFoundException If the class is not registered in the factory
 */
MatrixWorkspace_sptr WorkspaceFactoryImpl::create(const std::string &className,
                                                  const size_t &NVectors,
                                                  const size_t &XLength,
                                                  const size_t &YLength) const {
  MatrixWorkspace_sptr ws =
      boost::dynamic_pointer_cast<MatrixWorkspace>(this->create(className));

  if (!ws) {
    g_log.error("Workspace was not created");
    throw std::runtime_error("Workspace was not created");
  ws->initialize(NVectors, XLength, YLength);
ITableWorkspace_sptr
WorkspaceFactoryImpl::createTable(const std::string &className) const {
  ITableWorkspace_sptr ws;
  try {
    ws = boost::dynamic_pointer_cast<ITableWorkspace>(this->create(className));
    if (!ws) {
      throw std::runtime_error("Class " + className +
                               " cannot be cast to ITableWorkspace");
  } catch (Kernel::Exception::NotFoundError &) {
    throw;
  }
  return ws;
IPeaksWorkspace_sptr
WorkspaceFactoryImpl::createPeaks(const std::string &className) const {
  IPeaksWorkspace_sptr ws;
  try {
    ws = boost::dynamic_pointer_cast<IPeaksWorkspace>(this->create(className));
    if (!ws) {
      throw std::runtime_error("Class " + className +
                               " cannot be cast to IPeaksWorkspace");
  } catch (Kernel::Exception::NotFoundError &) {
    throw;
  }
  return ws;