-
Notifications
You must be signed in to change notification settings - Fork 122
/
CreateLogPropertyTable.cpp
321 lines (270 loc) · 11 KB
/
CreateLogPropertyTable.cpp
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
// 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 & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidAlgorithms/CreateLogPropertyTable.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/Run.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidDataObjects/TableWorkspace.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/ListValidator.h"
#include "MantidKernel/MandatoryValidator.h"
#include "MantidKernel/VisibleWhenProperty.h"
#include "boost/shared_ptr.hpp"
#include <cassert>
#include <map>
#include <vector>
namespace Mantid {
namespace Algorithms {
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(CreateLogPropertyTable)
using namespace Kernel;
using namespace API;
namespace {
enum GroupPolicy { ALL, FIRST, NONE };
// Forward declarations.
std::vector<MatrixWorkspace_sptr> retrieveMatrixWsList(const std::vector<std::string> &wsNames,
GroupPolicy groupPolicy);
GroupPolicy getGroupPolicyByName(const std::string &name);
std::set<std::string> getAllGroupPolicyNames();
Math::StatisticType getStatisticTypeByName(const std::string &name);
std::set<std::string> getAllStatisticTypeNames();
} // namespace
/**
* Initialise the algorithm's properties.
*/
void CreateLogPropertyTable::init() {
// Input workspaces
declareProperty(std::make_unique<ArrayProperty<std::string>>(
"InputWorkspaces", std::make_shared<MandatoryValidator<std::vector<std::string>>>()),
"Name of the Input Workspaces from which to get log properties.");
// Output workspace
declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("OutputWorkspace", "", Direction::Output),
"Name of the output ITableWorkspace.");
// Which log properties to use
declareProperty(std::make_unique<ArrayProperty<std::string>>(
"LogPropertyNames", std::make_shared<MandatoryValidator<std::vector<std::string>>>()),
"The names of the log properties to place in table.");
// How to handle time series logs
const std::set<std::string> statisticNames = getAllStatisticTypeNames();
declareProperty("TimeSeriesStatistic", "Mean", std::make_shared<StringListValidator>(statisticNames),
"The statistic to use when adding a time series log.");
// How to handle workspace groups
const std::set<std::string> groupPolicies = getAllGroupPolicyNames();
declareProperty("GroupPolicy", "First", std::make_shared<StringListValidator>(groupPolicies),
"The policy by which to handle GroupWorkspaces. \"All\" "
"will include all children in the table, \"First\" will "
"include "
"the first child, and \"None\" will not include any.");
}
/**
* Execute the algorithm.
*/
void CreateLogPropertyTable::exec() {
std::vector<std::string> wsNames = this->getProperty("InputWorkspaces");
// Retrieve a list of MatrixWorkspace pointers, using the given "GroupPolicy".
const std::string groupPolicyName = this->getPropertyValue("GroupPolicy");
const GroupPolicy groupPolicy = getGroupPolicyByName(groupPolicyName);
const std::vector<MatrixWorkspace_sptr> matrixWsList = retrieveMatrixWsList(wsNames, groupPolicy);
// Get the names of the properties that will be stored.
const std::vector<std::string> propNames = this->getProperty("LogPropertyNames");
// Make sure all workspaces contain the properties.
for (const auto &matrixWs : matrixWsList) {
const Run &run = matrixWs->run();
const std::string wsName = matrixWs->getName();
// Throw if a run does not have a property.
for (const auto &propName : propNames)
if (!run.hasProperty(propName))
throw std::runtime_error("\"" + wsName + "\" does not have a run property of \"" + propName + "\".");
}
// Set up output table.
auto outputTable = std::make_shared<DataObjects::TableWorkspace>();
// One column for each property.
for (const auto &propName : propNames)
outputTable->addColumn("str", propName);
// One row for each workspace.
for (size_t i = 0; i < matrixWsList.size(); ++i)
outputTable->appendRow();
// Set the first column to X and all others to Y
// This is to reduce the number of steps required to plot the data
for (size_t i = 0; i < outputTable->columnCount(); ++i)
outputTable->getColumn(i)->setPlotType(i == 0 ? 1 : 2);
const std::string timeSeriesStatName = this->getPropertyValue("TimeSeriesStatistic");
const Math::StatisticType timeSeriesStat = getStatisticTypeByName(timeSeriesStatName);
// Populate output table with the requested run properties.
for (size_t i = 0; i < outputTable->rowCount(); ++i) {
TableRow row = outputTable->getRow(i);
MatrixWorkspace_sptr matrixWs = matrixWsList[i];
for (const auto &propName : propNames) {
Property *prop = matrixWs->run().getProperty(propName);
std::stringstream propValue;
if (prop->type().find("TimeValue") != std::string::npos) {
propValue << matrixWs->run().getLogAsSingleValue(propName, timeSeriesStat);
} else {
propValue << prop->value();
}
row << propValue.str();
}
}
this->setProperty("OutputWorkspace", outputTable);
}
namespace {
/**
* Given a list of workspace names, will retrieve pointers to the corresponding
*workspaces in the ADS.
* Only MatrixWorkspaces or the children of groups of MatrixWorkspaces are
*retrieved. GroupWorkspaces
* are dealt with according to m_groupPolicy:
*
* "All" - Retrieve pointers to all the children of a group.
* "First" - Only retrieve a pointer to the first child of a group.
* "None" - No pointers are retreived.
*
* @param wsNames :: the list of workspaces to retrieve pointers to.
* @param groupPolicy :: the policy by which to deal with group workspaces.
*
* @return the retrieved MatrixWorkspace pointers
*/
std::vector<MatrixWorkspace_sptr> retrieveMatrixWsList(const std::vector<std::string> &wsNames,
GroupPolicy groupPolicy) {
std::vector<MatrixWorkspace_sptr> matrixWsList;
// Get all the workspaces which are to be inspected for log proeprties.
auto &ADS = AnalysisDataService::Instance();
for (const auto &wsName : wsNames) {
WorkspaceGroup_sptr wsGroup = std::dynamic_pointer_cast<WorkspaceGroup>(ADS.retrieve(wsName));
MatrixWorkspace_sptr matrixWs = std::dynamic_pointer_cast<MatrixWorkspace>(ADS.retrieve(wsName));
if (wsGroup) {
const std::vector<std::string> childNames = wsGroup->getNames();
// If there are no child workspaces in the group (is this possible?), just
// ignore it.
if (childNames.empty())
break;
// Retrieve pointers to all the child workspaces.
std::vector<MatrixWorkspace_sptr> childWsList;
childWsList.reserve(childNames.size());
std::transform(childNames.begin(), childNames.end(), std::back_inserter(childWsList),
[&ADS](const auto &childName) { return ADS.retrieveWS<MatrixWorkspace>(childName); });
// Deal with child workspaces according to policy.
switch (groupPolicy) {
case ALL: {
// Append all the children to the list.
std::move(childWsList.cbegin(), childWsList.cend(), std::back_inserter(matrixWsList));
break;
}
case FIRST:
// Append only the first child to the list.
matrixWsList.emplace_back(childWsList[0]);
break;
case NONE:
// Add nothing to the list.
break;
default:
// We should never reach here.
assert(false);
}
} else if (matrixWs) {
matrixWsList.emplace_back(matrixWs);
}
}
return matrixWsList;
}
/**
* Returns a constant reference to a static map, which maps group policy
* names to actual GroupPolicy enum members.
*
* @returns map of group policy names to GroupPolicy enum members.
*/
const std::map<std::string, GroupPolicy> &getGroupPolicyMap() {
static std::map<std::string, GroupPolicy> map;
// Populate the map if empty.
if (map.empty()) {
map.emplace("All", ALL);
map.emplace("First", FIRST);
map.emplace("None", NONE);
}
return map;
}
/**
* Given a group policy name, will return the corresponding GroupPolicy enum
*member.
*
* @param name :: name of group policy.
*
* @returns the corresponding GroupPolicy enum member.
*/
GroupPolicy getGroupPolicyByName(const std::string &name) {
const std::map<std::string, GroupPolicy> &map = getGroupPolicyMap();
// If we can find a policy with the given name, return it.
auto policy = map.find(name);
if (policy != map.end())
return policy->second;
// Else return ALL as default. Assert since we should never reach here.
assert(false);
return ALL;
}
/**
* Returns a set of all group policy names.
*
* @returns a set of all group policy names.
*/
std::set<std::string> getAllGroupPolicyNames() {
const std::map<std::string, GroupPolicy> &map = getGroupPolicyMap();
std::set<std::string> groupPolicyNames;
for (const auto &policy : map)
groupPolicyNames.insert(policy.first);
return groupPolicyNames;
}
/**
* Returns a constant reference to a static map, which maps statistic
* names to Kernel::Math::StatisticType members.
*
* @returns map of statistic names and StatisticType members
*/
const std::map<std::string, Math::StatisticType> &getStatisticTypeMap() {
static std::map<std::string, Math::StatisticType> map;
// Populate the map if empty.
if (map.empty()) {
map.emplace("FirstValue", Math::StatisticType::FirstValue);
map.emplace("LastValue", Math::StatisticType::LastValue);
map.emplace("Minimum", Math::StatisticType::Minimum);
map.emplace("Maximum", Math::StatisticType::Maximum);
map.emplace("Mean", Math::StatisticType::Mean);
map.emplace("Median", Math::StatisticType::Median);
}
return map;
}
/**
* Given a statistic type name, will return the corresponding StatisticType.
*
* @param name :: name of statistic
* @returns StatisticType
*/
Math::StatisticType getStatisticTypeByName(const std::string &name) {
const std::map<std::string, Math::StatisticType> &map = getStatisticTypeMap();
// If we can find a policy with the given name, return it.
auto policy = map.find(name);
if (policy != map.end())
return policy->second;
// Else return ALL as default. Assert since we should never reach here.
return Math::StatisticType::Mean;
}
/**
* Returns a set of all statistic type names.
*
* @returns a set of all statistic type names.
*/
std::set<std::string> getAllStatisticTypeNames() {
const std::map<std::string, Math::StatisticType> &map = getStatisticTypeMap();
std::set<std::string> statisticTypeNames;
for (const auto &policy : map)
statisticTypeNames.insert(policy.first);
return statisticTypeNames;
}
} // namespace
} // namespace Algorithms
} // namespace Mantid