Mantid
Loading...
Searching...
No Matches
WorkspaceCreation.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2016 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#pragma once
8
9#include "MantidDataObjects/DllConfig.h"
10#include "MantidHistogramData/Histogram.h"
11
12#include <memory>
13#include <type_traits>
14
15namespace Mantid {
16namespace Indexing {
17class IndexInfo;
18}
19namespace Geometry {
20class Instrument;
21}
22namespace API {
23class MatrixWorkspace;
24class HistoWorkspace;
25} // namespace API
26namespace DataObjects {
27class EventWorkspace;
28class Workspace2D;
29
92namespace detail {
93MANTID_DATAOBJECTS_DLL HistogramData::Histogram stripData(HistogramData::Histogram histogram);
94
95template <class T> std::unique_ptr<T> createHelper() { return std::make_unique<T>(); }
96
97template <class T> std::unique_ptr<T> createConcreteHelper() { return std::make_unique<T>(); }
98
99template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::HistoWorkspace> createHelper();
100
101// Dummy specialization, should never be called, must exist for compilation.
102template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<EventWorkspace> createHelper();
103// Dummy specialization, should never be called, must exist for compilation.
104template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::MatrixWorkspace> createHelper();
105
106// Dummy specialization, should never be called, must exist for compilation.
107template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::MatrixWorkspace> createConcreteHelper();
108// Dummy specialization, should never be called, must exist for compilation.
109template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::HistoWorkspace> createConcreteHelper();
110
111template <class HistArg> void fixDistributionFlag(API::MatrixWorkspace &, const HistArg &) {}
112
113template <>
114MANTID_DATAOBJECTS_DLL void fixDistributionFlag(API::MatrixWorkspace &workspace,
115 const HistogramData::Histogram &histArg);
116
117template <class T> struct IsIndexInfo {
118 using type = std::false_type;
119};
120template <> struct IsIndexInfo<Indexing::IndexInfo> {
121 using type = std::true_type;
122};
123template <class UseIndexInfo>
125} // namespace detail
126
130template <class T, class P, class IndexArg, class HistArg,
131 class = typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type>
132std::unique_ptr<T> create(const P &parent, const IndexArg &indexArg, const HistArg &histArg) {
133 // Figure out (dynamic) target type:
134 // - Type is same as parent if T is base of parent
135 // - If T is not base of parent, conversion may occur. Currently only
136 // supported for EventWorkspace
137 std::unique_ptr<T> ws;
138 if (std::is_base_of<API::HistoWorkspace, T>::value && parent.id() == "EventWorkspace") {
139 // Drop events, create Workspace2D or T whichever is more derived.
140 ws = detail::createHelper<T>();
141 } else {
142 try {
143 // If parent is more derived than T: create type(parent)
144 ws = dynamic_cast<const T &>(parent).cloneEmpty();
145 } catch (std::bad_cast &) {
146 // If T is more derived than parent: create T
147 ws = detail::createConcreteHelper<T>();
148 }
149 }
150
151 // The instrument is also copied by initializeFromParent, but if indexArg is
152 // IndexInfo and contains non-empty spectrum definitions the initialize call
153 // will fail due to invalid indices in the spectrum definitions. Therefore, we
154 // copy the instrument first. This should be cleaned up once we figure out the
155 // future of WorkspaceFactory.
156 ws->setInstrument(parent.getInstrument());
157 ws->initialize(indexArg, HistogramData::Histogram(histArg));
158 detail::initializeFromParent<typename detail::IsIndexInfo<IndexArg>::type>(parent, *ws);
159 // initializeFromParent sets the distribution flag to the same value as
160 // parent. In case histArg is an actual Histogram that is not the correct
161 // behavior so we have to set it back to the value given by histArg.
162 detail::fixDistributionFlag(*ws, histArg);
163 return ws;
164}
165
166template <class T, class IndexArg, class HistArg,
167 typename std::enable_if<!std::is_base_of<API::MatrixWorkspace, IndexArg>::value>::type * = nullptr>
168std::unique_ptr<T> create(const IndexArg &indexArg, const HistArg &histArg) {
169 auto ws = std::make_unique<T>();
170 ws->initialize(indexArg, HistogramData::Histogram(histArg));
171 return ws;
172}
173
174template <class T, class IndexArg, class HistArg,
175 typename std::enable_if<!std::is_base_of<API::MatrixWorkspace, IndexArg>::value>::type * = nullptr>
176std::unique_ptr<T> create(const std::shared_ptr<const Geometry::Instrument> &instrument, const IndexArg &indexArg,
177 const HistArg &histArg) {
178 auto ws = std::make_unique<T>();
179 ws->setInstrument(std::move(instrument));
180 ws->initialize(indexArg, HistogramData::Histogram(histArg));
181 return ws;
182}
183
184template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
185std::unique_ptr<T> createRagged(const P &parent) {
186 const auto numHistograms = parent.getNumberHistograms();
187
188 // make a temporary histogram that will be used for initialization. Can't be 0 size so resize.
189 auto histArg = HistogramData::Histogram(parent.histogram(0).xMode(), parent.histogram(0).yMode());
190 histArg.resize(1);
191 auto ws = create<T>(parent, numHistograms, histArg);
192 for (size_t i = 0; i < numHistograms; ++i) {
193 ws->resizeHistogram(i, parent.histogramSize(i));
194 ws->setSharedX(i, parent.sharedX(i));
195 }
196 return ws;
197}
198
199template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
200std::unique_ptr<T> create(const P &parent) {
201 if (parent.isRaggedWorkspace())
202 return createRagged<T>(parent);
203
204 const auto numHistograms = parent.getNumberHistograms();
205 auto ws = create<T>(parent, numHistograms, detail::stripData(parent.histogram(0)));
206 for (size_t i = 0; i < numHistograms; ++i) {
207 ws->setSharedX(i, parent.sharedX(i));
208 }
209 return ws;
210}
211
212// Templating with HistArg clashes with the IndexArg template above. Could be
213// fixed with many enable_if cases, but for now we simply provide 3 variants
214// (Histogram, BinEdges, Points) by hand.
215template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
216std::unique_ptr<T> create(const P &parent, const HistogramData::Histogram &histogram) {
217 return create<T>(parent, parent.getNumberHistograms(), histogram);
218}
219
220template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
221std::unique_ptr<T> create(const P &parent, const HistogramData::BinEdges &binEdges) {
222 return create<T>(parent, parent.getNumberHistograms(), binEdges);
223}
224
225template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
226std::unique_ptr<T> create(const P &parent, const HistogramData::Points &points) {
227 return create<T>(parent, parent.getNumberHistograms(), points);
228}
229
230} // namespace DataObjects
231} // namespace Mantid
IPeaksWorkspace_sptr workspace
Base MatrixWorkspace Abstract Class.
MANTID_DATAOBJECTS_DLL HistogramData::Histogram stripData(HistogramData::Histogram histogram)
void initializeFromParent(const API::MatrixWorkspace &parent, API::MatrixWorkspace &workspace)
Initialize a MatrixWorkspace from its parent including instrument, unit, number of spectra and Run.
std::unique_ptr< T > createHelper()
std::unique_ptr< T > createConcreteHelper()
void fixDistributionFlag(API::MatrixWorkspace &, const HistArg &)
std::unique_ptr< T > createRagged(const P &parent)
std::unique_ptr< T > create(const P &parent, const IndexArg &indexArg, const HistArg &histArg)
This is the create() method that all the other create() methods call.
Helper class which provides the Collimation Length for SANS instruments.