forked from npshub/mantid
-
Notifications
You must be signed in to change notification settings - Fork 0
/
WorkspaceCreation.h
209 lines (181 loc) · 9.19 KB
/
WorkspaceCreation.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2016 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source,
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#pragma once
#include "MantidDataObjects/DllConfig.h"
#include "MantidHistogramData/Histogram.h"
#include <memory>
#include <type_traits>
namespace Mantid {
namespace Indexing {
class IndexInfo;
}
namespace Geometry {
class Instrument;
}
namespace API {
class MatrixWorkspace;
class HistoWorkspace;
} // namespace API
namespace DataObjects {
class EventWorkspace;
class Workspace2D;
/** Factory methods for creating MatrixWorkspaces. A template parameter T
specifies the type of (or a base type of) the created workspace:
- The type of the output workspace is identical to T for the variants without
parent.
- The type of the output workspace is the dynamic type of the parent if T is a
base of the parents dynamic type.
- The type of the output workspace is T if the dynamic type of the parent is a
base of T.
- If T is not a base of the parents dynamic type, a conversion is attempted.
Currently this is the case only for EventWorkspace:
- If the dynamic type of the parent is EventWorkspace but T is not, either a
Workspace2D or T is created, whichever is more derived. For example, a
typical use-case is to drop events and create a Workspace2D from an
EventWorkspace. This can be achieved as follows:
~~~{.cpp}
auto ws = create<HistoWorkspace>(parent);
~~~
This is equivalent to the old way of using
WorkspaceFactory::create(parent). In this case, Workspace2D is more
derived than HistoWorkspace, so a Workspace2D is created.
- If the dynamic type of the parent is derived from HistoWorkspace, and
EventWorkspace can be created from it.
Other arguments can include:
- The instrument.
- The desired number of spectra (NumSpectra) to be created in the output
workspace.
- A reference to an IndexInfo object, defining the number of spectra and
spectrum number and detector IDs.
- A reference to a Histogram object (or alternatively BinEdges or Points),
defining the size of the histograms as well as whether the workspace stores
point data or histogram data. This is a replacement for an independent
specification of the X and Y lengths. This is also used to initialize the
workspace with X data and (optionally) Y and E data.
Available variants are:
~~~{.cpp}
create<T>(NumSpectra, Histogram)
create<T>(IndexInfo, Histogram)
create<T>(Instrument, NumSpectra, Histogram)
create<T>(Instrument, IndexInfo, Histogram)
create<T>(ParentWS)
create<T>(ParentWS, Histogram)
create<T>(ParentWS, NumSpectra, Histogram)
create<T>(ParentWS, IndexInfo, Histogram)
~~~
- If neither NumSpectra nor IndexInfo is given, or if the new size is
identical to the size of the parent, the created workspace has the same
number of spectra as the parent workspace and spectrum number as well as
detector ID information is copied from the parent.
- If only ParentWS is given, the created workspace has X identical to the
parent workspace and Y and E are initialized to 0.
- If a Histogram with 'NULL' Y and E is given, Y and E are initialized to 0.
In all cases a (smart) pointer to T is returned.
@author Simon Heybrock
@date 2016
*/
namespace detail {
MANTID_DATAOBJECTS_DLL HistogramData::Histogram stripData(HistogramData::Histogram histogram);
template <class T> std::unique_ptr<T> createHelper() { return std::make_unique<T>(); }
template <class T> std::unique_ptr<T> createConcreteHelper() { return std::make_unique<T>(); }
template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::HistoWorkspace> createHelper();
// Dummy specialization, should never be called, must exist for compilation.
template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<EventWorkspace> createHelper();
// Dummy specialization, should never be called, must exist for compilation.
template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::MatrixWorkspace> createHelper();
// Dummy specialization, should never be called, must exist for compilation.
template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::MatrixWorkspace> createConcreteHelper();
// Dummy specialization, should never be called, must exist for compilation.
template <> MANTID_DATAOBJECTS_DLL std::unique_ptr<API::HistoWorkspace> createConcreteHelper();
template <class HistArg> void fixDistributionFlag(API::MatrixWorkspace &, const HistArg &) {}
template <>
MANTID_DATAOBJECTS_DLL void fixDistributionFlag(API::MatrixWorkspace &workspace,
const HistogramData::Histogram &histArg);
template <class T> struct IsIndexInfo { using type = std::false_type; };
template <> struct IsIndexInfo<Indexing::IndexInfo> { using type = std::true_type; };
template <class UseIndexInfo>
void initializeFromParent(const API::MatrixWorkspace &parent, API::MatrixWorkspace &workspace);
} // namespace detail
/** This is the create() method that all the other create() methods call.
* And it is also called directly.
*/
template <class T, class P, class IndexArg, class HistArg,
class = typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type>
std::unique_ptr<T> create(const P &parent, const IndexArg &indexArg, const HistArg &histArg) {
// Figure out (dynamic) target type:
// - Type is same as parent if T is base of parent
// - If T is not base of parent, conversion may occur. Currently only
// supported for EventWorkspace
std::unique_ptr<T> ws;
if (std::is_base_of<API::HistoWorkspace, T>::value && parent.id() == "EventWorkspace") {
// Drop events, create Workspace2D or T whichever is more derived.
ws = detail::createHelper<T>();
} else {
try {
// If parent is more derived than T: create type(parent)
ws = dynamic_cast<const T &>(parent).cloneEmpty();
} catch (std::bad_cast &) {
// If T is more derived than parent: create T
ws = detail::createConcreteHelper<T>();
}
}
// The instrument is also copied by initializeFromParent, but if indexArg is
// IndexInfo and contains non-empty spectrum definitions the initialize call
// will fail due to invalid indices in the spectrum definitions. Therefore, we
// copy the instrument first. This should be cleaned up once we figure out the
// future of WorkspaceFactory.
ws->setInstrument(parent.getInstrument());
ws->initialize(indexArg, HistogramData::Histogram(histArg));
detail::initializeFromParent<typename detail::IsIndexInfo<IndexArg>::type>(parent, *ws);
// initializeFromParent sets the distribution flag to the same value as
// parent. In case histArg is an actual Histogram that is not the correct
// behavior so we have to set it back to the value given by histArg.
detail::fixDistributionFlag(*ws, histArg);
return ws;
}
template <class T, class IndexArg, class HistArg,
typename std::enable_if<!std::is_base_of<API::MatrixWorkspace, IndexArg>::value>::type * = nullptr>
std::unique_ptr<T> create(const IndexArg &indexArg, const HistArg &histArg) {
auto ws = std::make_unique<T>();
ws->initialize(indexArg, HistogramData::Histogram(histArg));
return ws;
}
template <class T, class IndexArg, class HistArg,
typename std::enable_if<!std::is_base_of<API::MatrixWorkspace, IndexArg>::value>::type * = nullptr>
std::unique_ptr<T> create(const std::shared_ptr<const Geometry::Instrument> &instrument, const IndexArg &indexArg,
const HistArg &histArg) {
auto ws = std::make_unique<T>();
ws->setInstrument(std::move(instrument));
ws->initialize(indexArg, HistogramData::Histogram(histArg));
return ws;
}
template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
std::unique_ptr<T> create(const P &parent) {
const auto numHistograms = parent.getNumberHistograms();
auto ws = create<T>(parent, numHistograms, detail::stripData(parent.histogram(0)));
for (size_t i = 0; i < numHistograms; ++i) {
ws->setSharedX(i, parent.sharedX(i));
}
return ws;
}
// Templating with HistArg clashes with the IndexArg template above. Could be
// fixed with many enable_if cases, but for now we simply provide 3 variants
// (Histogram, BinEdges, Points) by hand.
template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
std::unique_ptr<T> create(const P &parent, const HistogramData::Histogram &histogram) {
return create<T>(parent, parent.getNumberHistograms(), histogram);
}
template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
std::unique_ptr<T> create(const P &parent, const HistogramData::BinEdges &binEdges) {
return create<T>(parent, parent.getNumberHistograms(), binEdges);
}
template <class T, class P, typename std::enable_if<std::is_base_of<API::MatrixWorkspace, P>::value>::type * = nullptr>
std::unique_ptr<T> create(const P &parent, const HistogramData::Points &points) {
return create<T>(parent, parent.getNumberHistograms(), points);
}
} // namespace DataObjects
} // namespace Mantid