Newer
Older
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/IPeaksWorkspace.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/MatrixWorkspace.h"
Michael Whitty
committed
#include "MantidAPI/NumericAxis.h"
#include "MantidAPI/TextAxis.h"
#include "MantidAPI/Workspace.h"
#include "MantidAPI/WorkspaceOpOverloads.h"
#include "MantidKernel/ConfigService.h"
Michael Whitty
committed
namespace Mantid {
namespace API {
namespace {
/// static logger object
Kernel::Logger g_log("WorkspaceFactory");
/// Private constructor for singleton class
WorkspaceFactoryImpl::WorkspaceFactoryImpl()
: Mantid::Kernel::DynamicFactory<Workspace>() {
g_log.debug() << "WorkspaceFactory created.\n";
/** 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
Russell Taylor
committed
* 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
Russell Taylor
committed
* copied. If its a different size then they are not.
*
* @deprecated Replaced by functions in MantidDataObjects/WorkspaceCreation.h
Russell Taylor
committed
* @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)
Russell Taylor
committed
* @return A shared pointer to the newly created instance
Russell Taylor
committed
* @throw std::out_of_range If invalid (0 or less) size arguments are given
Russell Taylor
committed
* @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)) {
differentSize = false;
Russell Taylor
committed
YLength = parent->blocksize();
}
// 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";
Russell Taylor
committed
// Create an 'empty' workspace of the appropriate type and size
MatrixWorkspace_sptr ws = create(id, NVectors, XLength, YLength);
Russell Taylor
committed
// Copy over certain parent data members
initializeFromParent(*parent, *ws, differentSize);
Russell Taylor
committed
return ws;
}
/** Initialize a workspace from its parent
* This sets values such as title, instrument, units, sample, spectramap.
* This does NOT copy any data.
* @deprecated Replaced by functions in MantidDataObjects/WorkspaceCreation.h
* @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 &parent, MatrixWorkspace &child,
const bool differentSize) const {
child.setTitle(parent.getTitle());
child.setComment(parent.getComment());
child.copyExperimentInfoFrom(&parent);
child.setYUnit(parent.m_YUnit);
child.setYUnitLabel(parent.m_YUnitLabel);
child.setDistribution(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.
child.m_masks = parent.m_masks;
Janik Zikovsky
committed
// Same number of histograms = copy over the spectra data
if (parent.getNumberHistograms() == child.getNumberHistograms()) {
child.m_isInitialized = false;
for (size_t i = 0; i < parent.getNumberHistograms(); ++i)
child.getSpectrum(i).copyInfoFrom(parent.getSpectrum(i));
child.m_isInitialized = true;
// We use this variant without ISpectrum update to avoid costly rebuilds
// triggered by setIndexInfo(). ISpectrum::copyInfoFrom sets invalid flags
// for spectrum definitions, so it is important to call this *afterwards*,
// since it clears the flags:
child.setIndexInfoWithoutISpectrumUpdate(parent.indexInfo());
Janik Zikovsky
committed
}
for (size_t i = 0; i < parent.m_axes.size(); ++i) {
const bool isBinEdge =
dynamic_cast<const BinEdgeAxis *const>(parent.m_axes[i]) != nullptr;
const size_t newAxisLength = child.m_axes[i]->length() + (isBinEdge ? 1 : 0);
const size_t oldAxisLength = parent.m_axes[i]->length();
Michael Whitty
committed
if (!differentSize && newAxisLength == oldAxisLength) {
// Need to delete the existing axis created in init above
delete child.m_axes[i];
// Now set to a copy of the parent workspace's axis
child.m_axes[i] = parent.m_axes[i]->clone(&child);
if (!parent.getAxis(i)->isSpectra()) // WHY???
delete child.m_axes[i];
Russell Taylor
committed
// Call the 'different length' clone variant
child.m_axes[i] = parent.m_axes[i]->clone(newAxisLength, &child);
Russell Taylor
committed
}
}
Russell Taylor
committed
}
/** Creates a new instance of the class with the given name, and allocates
* memory for the arrays
*
* @deprecated Replaced by functions in MantidDataObjects/WorkspaceCreation.h
Russell Taylor
committed
* @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)
Russell Taylor
committed
* @return A shared pointer to the newly created instance
Russell Taylor
committed
* @throw std::out_of_range If invalid (0 or less) size arguments are given
Russell Taylor
committed
* @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");
Roman Tolchenov
committed
}
ws->initialize(NVectors, XLength, YLength);
Russell Taylor
committed
return ws;
}
Peterson, Peter
committed
/// Create a ITableWorkspace
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");
Roman Tolchenov
committed
}
} catch (Kernel::Exception::NotFoundError &) {
throw;
}
return ws;
Peterson, Peter
committed
}
Roman Tolchenov
committed
/// Create a IPeaksWorkspace
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");
Roman Tolchenov
committed
}
} catch (Kernel::Exception::NotFoundError &) {
throw;
}
return ws;
Roman Tolchenov
committed
}
Russell Taylor
committed
} // namespace API
} // Namespace Mantid