Mantid
Loading...
Searching...
No Matches
LoadMcStas.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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 +
21#include "MantidKernel/Unit.h"
23#include "MantidNexus/H5Util.h"
25
26#include <H5Cpp.h>
27
28namespace Mantid::DataHandling {
29using namespace Kernel;
30using namespace API;
31using namespace DataObjects;
32using namespace Nexus;
33
34// Register the algorithm into the AlgorithmFactory
36
37//----------------------------------------------------------------------------------------------
38// Algorithm's name for identification. @see Algorithm::name
39const std::string LoadMcStas::name() const { return "LoadMcStas"; }
40
41// Algorithm's version for identification. @see Algorithm::version
42int LoadMcStas::version() const { return 1; }
43
44// Algorithm's category for identification. @see Algorithm::category
45const std::string LoadMcStas::category() const { return "DataHandling\\Nexus"; }
46
47//----------------------------------------------------------------------------------------------
48
49//----------------------------------------------------------------------------------------------
53 const std::vector<std::string> exts{".h5", ".nxs"};
54 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::Load, exts),
55 "The name of the Nexus file to load");
56
57 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("OutputWorkspace", "", Direction::Output),
58 "An output workspace.");
59
60 declareProperty("ErrorBarsSetTo1", false,
61 "When this property is set to false errors are set equal to data values, "
62 "and when set to true all errors are set equal to one. This property "
63 "defaults to false");
64
65 declareProperty("OutputOnlySummedEventWorkspace", true,
66 "When true the algorithm only outputs the sum of all event data into "
67 "one eventworkspace EventData + _ + name of the OutputWorkspace. "
68 "If false eventworkspaces are also returned for each individual "
69 "McStas components storing event data");
70}
71
72//----------------------------------------------------------------------------------------------
76 std::string filename = getPropertyValue("Filename");
77 H5::H5File file(filename, H5F_ACC_RDONLY, Nexus::H5Util::defaultFileAcc());
78
79 Nexus::NexusDescriptor const descriptor(filename);
80 std::set<std::string> const entries = descriptor.allAddressesOfType(Nexus::SCIENTIFIC_DATA_SET);
81 if (entries.empty()) {
82 throw std::runtime_error("Could not find any entries.");
83 }
84
85 const char *attributeName = "long_name";
86 std::vector<std::string> eventEntries;
87 std::map<std::string, std::vector<std::string>> histogramEntries;
88 for (std::string const &entry : entries) {
89 if (entry.find("/entry1/data") == std::string::npos) {
90 continue;
91 }
92
93 Nexus::NexusAddress const address(entry);
94 Nexus::NexusAddress const groupAddress = address.parent_path();
95 std::string const datasetName = address.stem();
96
97 if (groupAddress.stem() == "content_nxs")
98 continue;
99
100 H5::DataSet const dataset = file.openDataSet(address);
101
102 if (!H5Util::hasAttribute(dataset, attributeName)) {
103 continue;
104 }
105
106 std::string nameAttrValue;
107 H5Util::readStringAttribute(dataset, attributeName, nameAttrValue);
108 if (nameAttrValue.find("Neutron_ID") != std::string::npos) {
109 eventEntries.emplace_back(groupAddress);
110 } else if (histogramEntries.find(groupAddress) == histogramEntries.cend()) {
111 histogramEntries[groupAddress] = {datasetName};
112 } else {
113 histogramEntries[groupAddress].emplace_back(datasetName);
114 }
115 }
116
117 std::vector<std::string> scatteringWSNames;
118 if (!eventEntries.empty()) {
119 scatteringWSNames = readEventData(eventEntries, file);
120 }
121 const auto histoWSNames = readHistogramData(histogramEntries, file);
122 file.close();
123
124 // join two vectors together
125 scatteringWSNames.insert(scatteringWSNames.end(), histoWSNames.cbegin(), histoWSNames.cend());
126
127 setProperty("OutputWorkspace", groupWorkspaces(scatteringWSNames));
128}
129
135API::WorkspaceGroup_sptr LoadMcStas::groupWorkspaces(const std::vector<std::string> &workspaces) const {
136 auto groupAlgorithm = API::AlgorithmManager::Instance().createUnmanaged("GroupWorkspaces");
137 groupAlgorithm->setChild(true);
138 groupAlgorithm->setLogging(false);
139 groupAlgorithm->initialize();
140 groupAlgorithm->setProperty("InputWorkspaces", workspaces);
141 groupAlgorithm->setProperty("OutputWorkspace", "__grouped");
142 groupAlgorithm->execute();
143 return groupAlgorithm->getProperty("OutputWorkspace");
144}
145
152std::vector<std::string> LoadMcStas::readEventData(const std::vector<std::string> &eventEntries,
153 const H5::H5File &file) {
154
155 // vector to store output workspaces
156 std::vector<std::string> scatteringWSNames;
157
158 std::string filename = getPropertyValue("Filename");
159 const bool errorBarsSetTo1 = getProperty("ErrorBarsSetTo1");
160
161 Geometry::Instrument_sptr instrument;
162
163 // Initialize progress reporting
164 int reports = 2;
165 const double progressFractionInitial = 0.1;
166 Progress progInitial(this, 0.0, progressFractionInitial, reports);
167
168 std::string instrumentXML;
169 progInitial.report("Loading instrument");
170 try {
171 const H5::Group group = file.openGroup("/entry1/instrument/instrument_xml");
172 const H5::DataSet dataset = group.openDataSet("data");
173 instrumentXML = H5Util::readString(dataset);
174 } catch (...) {
175 g_log.warning() << "\nCould not find the instrument description in the Nexus file:" << filename
176 << " Ignore eventdata from the Nexus file\n";
177 return scatteringWSNames;
178 ;
179 }
180
181 try {
182 std::string instrumentName = "McStas";
183 Geometry::InstrumentDefinitionParser parser(filename, instrumentName, instrumentXML);
184 std::string instrumentNameMangled = parser.getMangledName();
185
186 // Check whether the instrument is already in the InstrumentDataService
187 if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) {
188 // If it does, just use the one from the one stored there
189 instrument = InstrumentDataService::Instance().retrieve(instrumentNameMangled);
190 } else {
191 // Really create the instrument
192 instrument = parser.parseXML(nullptr);
193 // Add to data service for later retrieval
194 InstrumentDataService::Instance().add(instrumentNameMangled, instrument);
195 }
197 g_log.warning() << "When trying to read the instrument description in the Nexus file: " << filename
198 << " the following error is reported: " << e.what() << " Ignore eventdata from the Nexus file\n";
199 return scatteringWSNames;
200 ;
201 } catch (...) {
202 g_log.warning() << "Could not parse instrument description in the Nexus file: " << filename
203 << " Ignore eventdata from the Nexus file\n";
204 return scatteringWSNames;
205 ;
206 }
207
208 // create and prepare an event workspace ready to receive the mcstas events
209 progInitial.report("Set up EventWorkspace");
210 EventWorkspace_sptr eventWS(new EventWorkspace());
211 // initialize, where create up front number of eventlists = number of
212 // detectors
213 eventWS->initialize(instrument->getNumberDetectors(), 1, 1);
214 // Set the units
215 eventWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
216 eventWS->setYUnit("Counts");
217 // set the instrument
218 eventWS->setInstrument(instrument);
219 // assign detector ID to eventlists
220
221 std::vector<detid_t> detIDs = instrument->getDetectorIDs();
222
223 for (size_t i = 0; i < instrument->getNumberDetectors(); i++) {
224 eventWS->getSpectrum(i).addDetectorID(detIDs[i]);
225 // spectrum number are treated as equal to detector IDs for McStas data
226 eventWS->getSpectrum(i).setSpectrumNo(detIDs[i]);
227 }
228 // the one is here for the moment for backward compatibility
229 eventWS->rebuildSpectraMapping(true);
230 const auto detIDtoWSIndex = eventWS->getDetectorIDToWorkspaceIndexMap(true);
231
232 bool isAnyNeutrons = false;
233 // to store shortest and longest recorded TOF
234 double shortestTOF(0.0);
235 double longestTOF(0.0);
236
237 // create vector container all the event output workspaces needed
238 const size_t numEventEntries = eventEntries.size();
239 std::string nameOfGroupWS = getProperty("OutputWorkspace");
240 const auto eventDataTotalName = "EventData_" + nameOfGroupWS;
241 std::vector<std::pair<EventWorkspace_sptr, std::string>> allEventWS = {{eventWS, eventDataTotalName}};
242 // if numEventEntries > 1 also create separate event workspaces
243 const bool onlySummedEventWorkspace = getProperty("OutputOnlySummedEventWorkspace");
244 if (!onlySummedEventWorkspace && numEventEntries > 1) {
245 for (const auto &eventEntry : eventEntries) {
246 NexusAddress address(eventEntry);
247 std::string const groupName = address.stem();
248 // create container to hold partial event data
249 // plus the name users will see for it
250 const auto ws_name = groupName + "_" + nameOfGroupWS;
251 allEventWS.emplace_back(eventWS->clone(), ws_name);
252 }
253 }
254
255 Progress progEntries(this, progressFractionInitial, 1.0, numEventEntries * 2);
256
257 // Refer to entry in allEventWS. The first non-summed workspace index is 1
258 auto eventWSIndex = 1u;
259 // Loop over McStas event data components
260 for (const auto &groupAddress : eventEntries) {
261 const H5::Group group = file.openGroup(groupAddress);
262 const H5::DataSet dataset = group.openDataSet("events");
263
264 // open second level entry
265 std::vector<double> data;
266 progEntries.report("read event data from nexus");
267
268 // Need to take into account that the nexus readData method reads a
269 // multi-column data entry
270 // into a vector
271 // The number of data column for each neutron is here hardcoded to (p, x,
272 // y, n, id, t)
273 // Thus we have
274 // column 0 : p neutron wight
275 // column 1 : x x coordinate
276 // column 2 : y y coordinate
277 // column 3 : n accumulated number of neutrons
278 // column 4 : id pixel id
279 // column 5 : t time
280
281 // get info about event data
282 const H5::DataSpace dataspace = dataset.getSpace();
283 const auto rank = dataspace.getSimpleExtentNdims();
284
285 std::vector<hsize_t> dims(rank);
286 dataspace.getSimpleExtentDims(dims.data());
287 if (dims.size() != 2) {
288 g_log.error() << "Event data in McStas nexus file not loaded. Expected "
289 "event data block to be two dimensional\n";
290 return scatteringWSNames;
291 }
292 hsize_t nNeutrons = dims[0];
293 hsize_t numberOfDataColumn = dims[1];
294 if (nNeutrons && numberOfDataColumn != 6) {
295 g_log.error() << "Event data in McStas nexus file expecting 6 columns\n";
296 return scatteringWSNames;
297 ;
298 }
299 if (!isAnyNeutrons && nNeutrons > 0)
300 isAnyNeutrons = true;
301
302 hsize_t start[2];
303 hsize_t step[2];
304
305 // read the event data in blocks. 1 million event is 1000000*6*8 doubles
306 // about 50Mb
307 hsize_t nNeutronsInBlock = 1000000;
308 hsize_t nOfFullBlocks = nNeutrons / nNeutronsInBlock;
309 hsize_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock;
310 // sum over number of blocks + 1 to cover the remainder
311 for (hsize_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) {
312 if (iBlock == nOfFullBlocks) {
313 // read remaining neutrons
314 start[0] = nOfFullBlocks * nNeutronsInBlock;
315 start[1] = 0;
316 step[0] = nRemainingNeutrons;
317 step[1] = numberOfDataColumn;
318 } else {
319 // read neutrons in a full block
320 start[0] = iBlock * nNeutronsInBlock;
321 start[1] = 0;
322 step[0] = nNeutronsInBlock;
323 step[1] = numberOfDataColumn;
324 }
325 const hsize_t nNeutronsForthisBlock = step[0]; // number of neutrons read for this block
326 data.resize(nNeutronsForthisBlock * numberOfDataColumn);
327
328 // Check that the type is what it is supposed to be
329 const H5::DataType datatype = dataset.getDataType();
330 if (datatype.getClass() != H5T_FLOAT) {
331 g_log.warning() << "Entry event field is not H5T_FLOAT! It will be skipped.\n";
332 continue;
333 }
334
335 H5::DataSpace memspace(rank, step);
336 dataspace.selectHyperslab(H5S_SELECT_SET, step, start);
337
338 dataset.read(data.data(), H5::PredType::NATIVE_DOUBLE, memspace, dataspace);
339
340 // populate workspace with McStas events
341 progEntries.report("read event data into workspace");
342 for (hsize_t in = 0; in < nNeutronsForthisBlock; in++) {
343 const auto detectorID = static_cast<int>(data[4 + numberOfDataColumn * in]);
344 const double detector_time = data[5 + numberOfDataColumn * in] * 1.0e6; // convert to microseconds
345 if (in == 0 && iBlock == 0) {
346 shortestTOF = detector_time;
347 longestTOF = detector_time;
348 } else {
349 if (detector_time < shortestTOF)
350 shortestTOF = detector_time;
351 if (detector_time > longestTOF)
352 longestTOF = detector_time;
353 }
354
355 const size_t workspaceIndex = detIDtoWSIndex.find(detectorID)->second;
356
357 int64_t pulse_time = 0;
358 WeightedEvent weightedEvent;
359 if (errorBarsSetTo1) {
360 weightedEvent = WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in], 1.0);
361 } else {
362 weightedEvent = WeightedEvent(detector_time, pulse_time, data[numberOfDataColumn * in],
363 data[numberOfDataColumn * in] * data[numberOfDataColumn * in]);
364 }
365 allEventWS[0].first->getSpectrum(workspaceIndex) += weightedEvent;
366 if (!onlySummedEventWorkspace && numEventEntries > 1) {
367 allEventWS[eventWSIndex].first->getSpectrum(workspaceIndex) += weightedEvent;
368 }
369 }
370 eventWSIndex++;
371 } // end reading over number of blocks of an event dataset
372 } // end reading over number of event datasets
373
374 // Create a default TOF-vector for histogramming, for now just 2 bins
375 // 2 bins is the standard. However for McStas simulation data it may make
376 // sense to
377 // increase this number for better initial visual effect
378
379 auto axis = HistogramData::BinEdges{shortestTOF - 1, longestTOF + 1};
380
381 // ensure that specified name is given to workspace (eventWS) when added to
382 // outputGroup
383 for (const auto &wsAndName : allEventWS) {
384 const auto ws = wsAndName.first;
385 ws->setAllX(axis);
386 AnalysisDataService::Instance().addOrReplace(wsAndName.second, ws);
387 scatteringWSNames.emplace_back(wsAndName.second);
388 }
389 return scatteringWSNames;
390}
391
398std::vector<std::string>
399LoadMcStas::readHistogramData(const std::map<std::string, std::vector<std::string>> &histogramEntries,
400 const H5::H5File &file) {
401
402 std::string nameAttrValueYLABEL;
403 std::vector<std::string> histoWSNames;
404
405 for (const auto &entry : histogramEntries) {
406 const auto groupAddress = entry.first;
407 const H5::Group group = file.openGroup(groupAddress);
408
409 std::string nameAttrValueTITLE;
410 H5Util::readStringAttribute(group, "filename", nameAttrValueTITLE);
411
412 if (H5Util::hasAttribute(group, "ylabel")) {
413 H5Util::readStringAttribute(group, "ylabel", nameAttrValueYLABEL);
414 }
415
416 // Find the axis names
417 std::string axis1Name, axis2Name;
418 for (const auto &datasetName : entry.second) {
419 if (datasetName == "ncount")
420 continue;
421 H5::DataSet dataset = group.openDataSet(datasetName);
422
423 if (H5Util::hasAttribute(dataset, "axis")) {
424 const auto axisNo = H5Util::readNumAttributeCoerce<int>(dataset, "axis");
425 if (axisNo == 1)
426 axis1Name = datasetName;
427 else if (axisNo == 2)
428 axis2Name = datasetName;
429 else
430 throw std::invalid_argument("Unknown axis number");
431 }
432 }
433
434 std::vector<double> axis1Values;
435 H5Util::readArray1DCoerce(group, axis1Name, axis1Values);
436 std::vector<double> axis2Values;
437
438 if (axis2Name.length() == 0) {
439 axis2Name = nameAttrValueYLABEL;
440 axis2Values.emplace_back(0.0);
441 } else {
442 H5Util::readArray1DCoerce(group, axis2Name, axis2Values);
443 }
444
445 const size_t axis1Length = axis1Values.size();
446 const size_t axis2Length = axis2Values.size();
447 g_log.debug() << "Axis lengths=" << axis1Length << " " << axis2Length << '\n';
448
449 // Require "data" field
450 std::vector<double> data;
451 H5Util::readArray1DCoerce(group, "data", data);
452
453 // Optional errors field
454 std::vector<double> errors;
455 if (group.exists("errors")) {
456 H5Util::readArray1DCoerce(group, "errors", errors);
457 }
458
459 MatrixWorkspace_sptr ws = WorkspaceFactory::Instance().create("Workspace2D", axis2Length, axis1Length, axis1Length);
460 Axis *axis1 = ws->getAxis(0);
461 axis1->title() = axis1Name;
462 // Set caption
463 auto lblUnit = std::make_shared<Units::Label>();
464 lblUnit->setLabel(axis1Name, "");
465 axis1->unit() = lblUnit;
466
467 auto axis2 = std::make_unique<NumericAxis>(axis2Length);
468 auto axis2Raw = axis2.get();
469 axis2->title() = axis2Name;
470 // Set caption
471 lblUnit = std::make_shared<Units::Label>();
472 lblUnit->setLabel(axis2Name, "");
473 axis2->unit() = lblUnit;
474
475 ws->setYUnit(axis2Name);
476 ws->replaceAxis(1, std::move(axis2));
477
478 for (size_t wsIndex = 0; wsIndex < axis2Length; ++wsIndex) {
479 auto &dataX = ws->mutableX(wsIndex);
480 auto &dataY = ws->mutableY(wsIndex);
481 auto &dataE = ws->mutableE(wsIndex);
482
483 for (size_t j = 0; j < axis1Length; ++j) {
484 // Data is stored in column-major order so we are translating to
485 // row major for Mantid
486 const size_t fileDataIndex = j * axis2Length + wsIndex;
487
488 dataX[j] = axis1Values[j];
489 dataY[j] = data[fileDataIndex];
490 if (!errors.empty())
491 dataE[j] = errors[fileDataIndex];
492 }
493 axis2Raw->setValue(wsIndex, axis2Values[wsIndex]);
494 }
495
496 // set the workspace title
497 ws->setTitle(nameAttrValueTITLE);
498
499 // use the workspace title to create the workspace name
500 std::replace(nameAttrValueTITLE.begin(), nameAttrValueTITLE.end(), ' ', '_');
501
502 // ensure that specified name is given to workspace (eventWS) when added to
503 // outputGroup
504 const std::string outputWS = getProperty("OutputWorkspace");
505 const std::string nameUserSee = nameAttrValueTITLE + "_" + outputWS;
506 AnalysisDataService::Instance().addOrReplace(nameUserSee, ws);
507
508 histoWSNames.emplace_back(ws->getName());
509 }
510 return histoWSNames;
511}
512
520 if (!descriptor.isEntry("/entry1/simulation/name", Nexus::SCIENTIFIC_DATA_SET)) {
521 return 0;
522 }
523 std::string value = descriptor.getStrData("/entry1/simulation/name");
524 std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return std::toupper(c); });
525 if (value == "MCCODE") {
526 return 98;
527 }
528 return 0;
529}
530
531} // namespace Mantid::DataHandling
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
uint64_t hsize_t
#define DECLARE_NEXUS_LAZY_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_LAZY_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM mac...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:422
Class to represent the axis of a workspace.
Definition Axis.h:30
const std::string & title() const
Returns the user-defined title for this axis.
Definition Axis.cpp:20
const std::shared_ptr< Kernel::Unit > & unit() const
The unit for this axis.
Definition Axis.cpp:28
@ Load
allowed here which will be passed to the algorithm
Helper class for reporting progress from algorithms.
Definition Progress.h:25
A property class for workspaces.
void init() override
Initialize the algorithm's properties.
std::vector< std::string > readHistogramData(const std::map< std::string, std::vector< std::string > > &histogramEntries, const H5::H5File &file)
Read histogram data.
API::WorkspaceGroup_sptr groupWorkspaces(const std::vector< std::string > &workspaces) const
Group workspaces.
void exec() override
Execute the algorithm.
std::vector< std::string > readEventData(const std::vector< std::string > &eventEntries, const H5::H5File &file)
Read Event Data.
const std::string category() const override
function to return a category of the algorithm.
int version() const override
function to return a version of the algorithm, must be overridden in all algorithms
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Returns a confidence value that this algorithm can load a file.
This class is intended to fulfill the design specified in <https://github.com/mantidproject/documents...
Info about a single neutron detection event, including a weight and error value:
Definition Events.h:39
Creates an instrument data from a XML instrument description file.
std::shared_ptr< Instrument > parseXML(Kernel::ProgressBase *progressReporter)
Parse XML contents.
std::string getMangledName()
Handle used in the singleton constructor for instrument file should append the value file sha-1 check...
Exception for errors associated with the instrument definition.
Definition Exception.h:220
const char * what() const noexcept override
Writes out the range and limits.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
This simple class encapsulates some methods for working with paths inside a Nexus file.
NexusAddress parent_path() const
NexusAddress stem() const
std::string getStrData(std::string const &address)
Get string data from a dataset at address.
bool isEntry(std::string const &entryName, std::string const &groupClass) const
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
std::set< std::string > allAddressesOfType(const std::string &type) const
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
std::shared_ptr< Instrument > Instrument_sptr
Shared pointer to an instrument object.
MANTID_NEXUS_DLL void readStringAttribute(const H5::H5Object &object, const std::string &attributeName, std::string &output)
Definition H5Util.cpp:342
MANTID_NEXUS_DLL std::string readString(H5::H5File &file, const std::string &address)
Definition H5Util.cpp:266
MANTID_NEXUS_DLL bool hasAttribute(const H5::H5Object &object, const char *attributeName)
Definition H5Util.cpp:337
MANTID_NEXUS_DLL H5::FileAccPropList defaultFileAcc()
Default file access is H5F_CLOSE_STRONG.
Definition H5Util.cpp:119
void readArray1DCoerce(const H5::Group &group, const std::string &name, std::vector< NumT > &output)
std::string const SCIENTIFIC_DATA_SET("SDS")
STL namespace.
@ Output
An output workspace.
Definition Property.h:54