Mantid
Loading...
Searching...
No Matches
IntegratePeaksCWSD.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 +
10#include "MantidAPI/Run.h"
18
19namespace Mantid::MDAlgorithms {
20
21// Register the algorithm into the AlgorithmFactory
22DECLARE_ALGORITHM(IntegratePeaksCWSD)
23
24using namespace Mantid::Kernel;
25using namespace Mantid::API;
26using namespace Mantid::DataObjects;
27using namespace Mantid::Geometry;
28
30
34 : m_haveMultipleRun(false), m_useSinglePeakCenterFmUser(false), m_peakRadius(), m_doMergePeak(false),
35 m_normalizeByMonitor(false), m_normalizeByTime(false), m_scaleFactor(0), m_haveInputPeakWS(false) {
36 deprecatedDate("2025-05-07");
37}
38
42 declareProperty(std::make_unique<WorkspaceProperty<IMDEventWorkspace>>("InputWorkspace", "", Direction::Input),
43 "An input MDEventWorkspace.");
44
45 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("PeaksWorkspace", "", Direction::Input,
47 "A PeaksWorkspace containing the peaks to integrate.");
48
49 declareProperty(std::make_unique<WorkspaceProperty<PeaksWorkspace>>("OutputWorkspace", "", Direction::Output),
50 "The output PeaksWorkspace will be a copy of the input PeaksWorkspace "
51 "with the peaks' integrated intensities.");
52
55 "Output Masking Workspace");
56
57 declareProperty(std::make_unique<ArrayProperty<double>>("PeakCentre"),
58 "A comma separated list for peak centre in Q-sample frame. "
59 "Its length is either 3 (Qx, Qy, Qz) or 0. "
60 "If peak center is defined, then all the data among all the runs will be "
61 "integrated in respect to this peak center. Otherwise, the peaks that "
62 "will "
63 "be integrated shall be found in the given peak workspace.");
64
65 declareProperty("PeakRadius", EMPTY_DBL(), "Radius of a peak.");
66
67 declareProperty("MergePeaks", true,
68 "In case that there are more than 1 run number in the given "
69 "PeaksWorkspace "
70 "and MDEVentWorkspace, if it is set to true, then the peaks' intensities "
71 "will be merged.");
72
73 declareProperty("NormalizeByMonitor", false,
74 "If selected, then all the signals will be normalized by monitor counts."
75 "Otherwise, the output peak intensity will be just simple addition of "
76 "peak intensity."
77 "It is only applied to the situation that Mergepeaks is not selected.");
78
79 declareProperty("NormalizeByTime", true,
80 "It selected, then all the signals will be normalized by time "
81 "in the case that the counting time is very short and thus the beam "
82 "monitor "
83 "is not accurate.");
84
85 declareProperty("ScaleFactor", 1000.,
86 "If NormalizeByMonitor or NormalizeByTime is selected, the intensity "
87 "will be scaled by this factor.");
88}
89
90//----------------------------------------------------------------------------------------------
95 // Process input & check
97
98 // Integrate peak with simple algorithm
100
101 // Merge peak if necessary
102 if (m_doMergePeak)
103 mergePeaks();
104 else
105 normalizePeaksIntensities(); // normalize the intensity of each Pt.
106
107 // Output
110
111 setProperty("OutputWorkspace", outws);
112}
113
114//----------------------------------------------------------------------------------------------
118 // Required input workspaces
119 m_inputWS = getProperty("InputWorkspace");
120
121 // Input peaks
122 std::vector<double> peak_center = getProperty("PeakCentre");
123 if (!peak_center.empty()) {
124 // assigned peak center
125 if (peak_center.size() != 3)
126 throw std::invalid_argument("PeakCentre must have 3 elements.");
127 m_peakCenter.setX(peak_center[0]);
128 m_peakCenter.setY(peak_center[1]);
129 m_peakCenter.setZ(peak_center[2]);
130 // no use input peak workspace
131 m_haveInputPeakWS = false;
133 } else {
134 // use input peak workspace
135 std::string peakWSName = getPropertyValue("PeaksWorkspace");
136 if (peakWSName.length() == 0)
137 throw std::invalid_argument("It is not allowed that neither peak center "
138 "nor PeaksWorkspace is specified.");
139 m_peaksWS = getProperty("PeaksWorkspace");
140 m_haveInputPeakWS = true;
142 }
143 m_doMergePeak = getProperty("MergePeaks");
144 if (m_haveInputPeakWS && m_peaksWS->getNumberPeaks() > 1 && m_doMergePeak)
145 throw std::invalid_argument("It is not allowed to merge peaks when there are "
146 "multiple peaks present in PeaksWorkspace.");
147
148 m_normalizeByMonitor = getProperty("NormalizeByMonitor");
149 m_normalizeByTime = getProperty("NormalizeByTime");
151 throw std::invalid_argument("It is not allowed to select to be normalized both "
152 "by time and by monitor counts.");
154 throw std::invalid_argument("Either being normalized by time or being normalized "
155 "by monitor must be selected if merge-peak is selected.");
156 m_scaleFactor = getProperty("ScaleFactor");
157 g_log.warning() << "[DB...BAT] Scale factor = " << m_scaleFactor << "\n";
158
159 // monitor counts
162 else if (m_normalizeByTime)
164
165 // go through peak
169
170 // peak related
171 m_peakRadius = getProperty("PeakRadius");
172 if (m_peakRadius == EMPTY_DBL())
173 throw std::invalid_argument("Peak radius cannot be left empty.");
174
175 // optional mask workspace
176 std::string maskwsname = getPropertyValue("MaskWorkspace");
177 if (!maskwsname.empty()) {
178 // process mask workspace
179 m_maskWS = getProperty("MaskWorkspace");
181 }
182}
183
184//----------------------------------------------------------------------------------------------
196void IntegratePeaksCWSD::simplePeakIntegration(const std::vector<detid_t> &vecMaskedDetID,
197 const std::map<int, signal_t> &run_monitor_map) {
198 // Check requirements
199 if (!m_inputWS)
200 throw std::runtime_error("MDEventWorkspace is not defined.");
201
202 // Go through to get value
203 auto mditer = m_inputWS->createIterator();
204 size_t nextindex = 1;
205 bool scancell = true;
206 // size_t currindex = 0;
207
208 // Assuming that MDEvents are grouped by run number, there is no need to
209 // loop up the map for peak center and monitor counts each time
210 int current_run_number = -1;
211 signal_t current_monitor_counts = 0;
212 Kernel::V3D current_peak_center = m_peakCenter;
213
214 // signal_t total_signal = 0;
215 double min_distance = 10000000;
216 double max_distance = -1;
217
218 while (scancell) {
219 // Go through all the MDEvents in one cell.
220 size_t numeventincell = mditer->getNumEvents();
221
222 for (size_t iev = 0; iev < numeventincell; ++iev) {
223 // Get signal to add and skip if signal is zero
224 signal_t signal = mditer->getInnerSignal(iev);
225 if (signal <= THRESHOLD_SIGNAL)
226 continue;
227
228 uint16_t run_number = mditer->getInnerExpInfoIndex(iev);
229 auto run_number_i = static_cast<int>(run_number);
230
231 /* debug: record raw signals
232 if (run_number_i % 1000 == testrunnumber)
233 {
234 total_signal += signal;
235 ++ num_det;
236 }
237 // ... debug */
238
239 // Check whether this detector is masked
240 if (!vecMaskedDetID.empty()) {
241 detid_t detid = mditer->getInnerDetectorID(iev);
242 std::vector<detid_t>::const_iterator it;
243
244 it = find(vecMaskedDetID.begin(), vecMaskedDetID.end(), detid);
245 if (it != vecMaskedDetID.end()) {
246 // The detector ID is found among masked detector IDs
247 // Skip this event and move to next
248
249 /* debug: record masked detectors
250 if (run_number_i % 1000 == testrunnumber)
251 {
252 num_masked_det += 1;
253 g_log.warning() << "Masked detector ID = " << detid << ", Signal = "
254 << signal << "\n";
255 }
256 // ... debug */
257
258 continue;
259 }
260 }
261
262 /* debug: record unmasked detectors
263 if (run_number_i % 1000 == testrunnumber)
264 num_unmasked_det += 1;
265 // ... debug */
266
267 // Check whether to update monitor counts and peak center
268 if (current_run_number != run_number_i) {
269 // update run number
270 current_run_number = run_number_i;
271 // update monitor counts
273 auto m_finder = run_monitor_map.find(current_run_number);
274 if (m_finder != run_monitor_map.end())
275 current_monitor_counts = m_finder->second;
276 else {
277 std::stringstream errss;
278 errss << "Unable to find run number " << current_run_number << " in monitor counts map";
279 throw std::runtime_error(errss.str());
280 }
281 } else {
282 current_monitor_counts = 1.;
283 }
284
285 // update peak center
287 current_peak_center = m_runPeakCenterMap[current_run_number];
288 }
289
290 // calculate distance
291 float tempx = mditer->getInnerPosition(iev, 0);
292 float tempy = mditer->getInnerPosition(iev, 1);
293 float tempz = mditer->getInnerPosition(iev, 2);
294 Kernel::V3D pixel_pos(tempx, tempy, tempz);
295 double distance = current_peak_center.distance(pixel_pos);
296
297 /* debug: record unmasked signal
298 if (run_number_i % 1000 == testrunnumber)
299 {
300 total_unmasked_signal += signal;
301 }
302 // ... debug */
303
304 if (distance < m_peakRadius) {
305 // FIXME - Is it very costly to use map each time???
306 // total_signal += signal/current_monitor_counts;
307 m_runPeakCountsMap[run_number] += signal / current_monitor_counts;
308 } else {
309 g_log.debug() << "Out of radius " << distance << " > " << m_peakRadius
310 << ": Center = " << current_peak_center.toString() << ", Pixel = " << pixel_pos.toString()
311 << "\n";
312 }
313
314 if (distance < min_distance)
315 min_distance = distance;
316 if (distance > max_distance)
317 max_distance = distance;
318 }
319
320 // Advance to next cell
321 if (mditer->next()) {
322 // advance to next cell
323 mditer->jumpTo(nextindex);
324 ++nextindex;
325 } else {
326 // break the loop
327 scancell = false;
328 }
329 } // END-WHILE (scan-cell)
330
331 // Summarize
332 g_log.notice() << "Distance range is " << min_distance << ", " << max_distance << "\n";
333
334 /*
335 g_log.warning() << "Debug output: run 13: Number masked detectors = " <<
336 num_masked_det
337 << ", Total signal = " << total_signal << "\n";
338 g_log.warning() << " Number of unmasked detectors = " << num_unmasked_det
339 << ", Total unmasked signal = " << total_unmasked_signal <<
340 "\n";
341 g_log.warning() << " Number of total detectors = " << num_det << "\n";
342 */
343}
344
345//----------------------------------------------------------------------------------------------
353 std::vector<detid_t> vecMaskedDetID;
354
355 // Add the detector IDs of all masked detector to a vector
356 size_t numspec = maskws->getNumberHistograms();
357 const auto &specInfo = maskws->spectrumInfo();
358 for (size_t iws = 0; iws < numspec; ++iws) {
359 const auto &vecY = maskws->y(iws);
360 if (vecY[0] > 0.1) {
361 // vecY[] > 0 is masked. det->isMasked() may not be reliable.
362 const detid_t detid = specInfo.detector(iws).getID();
363 vecMaskedDetID.emplace_back(detid);
364 }
365 }
366
367 // Sort the vector for future lookup
368 if (vecMaskedDetID.size() > 1)
369 std::sort(vecMaskedDetID.begin(), vecMaskedDetID.end());
370
371 g_log.warning() << "[DB] There are " << vecMaskedDetID.size() << " detectors masked."
372 << "\n";
373
374 return vecMaskedDetID;
375}
376
377//----------------------------------------------------------------------------------------------
382 double total_intensity = 0;
383 double total_monitor_counts = 0.;
384
385 // sum over all runs
386 std::map<int, signal_t>::iterator mon_iter;
387 for (mon_iter = m_runNormMap.begin(); mon_iter != m_runNormMap.end(); ++mon_iter) {
388 int run_number_i = mon_iter->first;
389 signal_t monitor_i = mon_iter->second;
390 double intensity_i = m_runPeakCountsMap[run_number_i];
391 total_intensity += monitor_i * intensity_i;
392 total_monitor_counts += monitor_i;
393 }
394
395 // final merged intensity
396 double merged_intensity = total_intensity / total_monitor_counts;
397
398 // set the merged intensity to each peak
399 std::map<int, double>::iterator count_iter;
400 for (count_iter = m_runPeakCountsMap.begin(); count_iter != m_runPeakCountsMap.end(); ++count_iter)
401 count_iter->second = merged_intensity;
402}
403
404//----------------------------------------------------------------------------------------------
410 // clone the original peaks workspace
411 DataObjects::PeaksWorkspace_sptr outws = std::shared_ptr<DataObjects::PeaksWorkspace>(m_peaksWS->clone().release());
412
413 size_t num_peaks = outws->getNumberPeaks();
414 for (size_t i_peak = 0; i_peak < num_peaks; ++i_peak) {
415 DataObjects::Peak &peak_i = outws->getPeak(static_cast<int>(i_peak));
416 int run_number_i = peak_i.getRunNumber();
417 double intensity_i = m_runPeakCountsMap[run_number_i];
418 peak_i.setIntensity(intensity_i);
419 }
420
421 return outws;
422}
423
424//----------------------------------------------------------------------------------------------
432 const API::IMDEventWorkspace_sptr &mdws) {
433 g_log.notice("Create peak workspace for output ... ...");
434 // new peak workspace
435 DataObjects::PeaksWorkspace_sptr peakws = std::make_shared<DataObjects::PeaksWorkspace>();
436
437 // get number of runs
438 size_t numruns = mdws->getNumExperimentInfo();
439 for (size_t i_run = 0; i_run < numruns; ++i_run) {
440 // get experiment info for run number, instrument and peak count
441 API::ExperimentInfo_const_sptr expinfo = mdws->getExperimentInfo(static_cast<uint16_t>(i_run));
442 int runnumber = expinfo->getRunNumber();
443 // FIXME - This is a hack for HB3A's run number issue
444 auto miter = m_runPeakCountsMap.find(runnumber % 1000);
445 double peakcount(0);
446 if (miter != m_runPeakCountsMap.end()) {
447 peakcount = miter->second;
448 g_log.notice() << "[DB] Get peak count of run " << runnumber << " as " << peakcount << "\n";
449 } else {
450 g_log.notice() << "[DB] Unable to find run " << runnumber << " in peak count map."
451 << "\n";
452 }
453
454 // Create and add a new peak to peak workspace
455 DataObjects::Peak newpeak;
456 try {
457 Geometry::Instrument_const_sptr instrument = expinfo->getInstrument();
458 newpeak.setInstrument(instrument);
459 newpeak.setGoniometerMatrix(expinfo->run().getGoniometerMatrix());
460 } catch (const std::exception &) {
461 throw std::runtime_error("Unable to set instrument and goniometer matrix.");
462 }
463
464 newpeak.setQSampleFrame(peakCenter);
465 newpeak.setRunNumber(runnumber);
466 newpeak.setIntensity(peakcount * m_scaleFactor);
467
468 peakws->addPeak(newpeak);
469 }
470
471 g_log.notice("Peak workspace is generated.... ");
472 return peakws;
473}
474
475//----------------------------------------------------------------------------------------------
480std::map<int, signal_t> IntegratePeaksCWSD::getMonitorCounts() {
481 std::map<int, signal_t> run_monitor_map;
482
483 uint16_t num_expinfo = m_inputWS->getNumExperimentInfo();
484 for (size_t iexpinfo = 0; iexpinfo < num_expinfo; ++iexpinfo) {
485 ExperimentInfo_const_sptr expinfo = m_inputWS->getExperimentInfo(static_cast<uint16_t>(iexpinfo));
486 std::string run_str = expinfo->run().getProperty("run_number")->value();
487 g_log.information() << "run number of exp " << iexpinfo << " is " << run_str << "\n";
488 int run_number = std::stoi(run_str);
489 // FIXME - HACK FOE HB3A
490 run_number = run_number % 1000;
491 std::string mon_str = expinfo->run().getProperty("monitor")->value();
492 auto monitor = static_cast<signal_t>(std::stod(mon_str));
493 run_monitor_map.insert(std::make_pair(run_number, monitor));
494 g_log.information() << "From MD workspace add run " << run_number << ", monitor = " << monitor << "\n";
495 }
496
497 return run_monitor_map;
498}
499
500//----------------------------------------------------------------------------------------------
506std::map<int, double> IntegratePeaksCWSD::getMeasureTime() {
507 std::map<int, double> run_time_map;
508
509 uint16_t num_expinfo = m_inputWS->getNumExperimentInfo();
510 for (size_t iexpinfo = 0; iexpinfo < num_expinfo; ++iexpinfo) {
511 ExperimentInfo_const_sptr expinfo = m_inputWS->getExperimentInfo(static_cast<uint16_t>(iexpinfo));
512 std::string run_str = expinfo->run().getProperty("run_number")->value();
513 int run_number = std::stoi(run_str);
514
515 // FIXME - HACK FOE HB3A
516 run_number = run_number % 1000;
517 std::string duration_str = expinfo->run().getProperty("duration")->value();
518 double duration = std::stod(duration_str);
519 run_time_map.insert(std::make_pair(run_number, duration));
520 g_log.warning() << "MD workspace exp info " << iexpinfo << ": run " << run_number
521 << ", measuring time = " << duration << "\n";
522 }
523
524 return run_time_map;
525}
526
527//----------------------------------------------------------------------------------------------
531 m_vecPeaks = m_peaksWS->getPeaks();
532 size_t numpeaks = m_vecPeaks.size();
533 for (size_t ipeak = 0; ipeak < numpeaks; ++ipeak) {
534 DataObjects::Peak &peak = m_vecPeaks[ipeak];
535 int run_number = peak.getRunNumber();
536 Mantid::Kernel::V3D qsample = peak.getQSampleFrame();
537 m_runPeakCenterMap.insert(std::make_pair(run_number, qsample));
538
539 // set up the data structure to store integrated peaks' counts
540 m_runPeakCountsMap.insert(std::make_pair(run_number, 0.));
541
542 g_log.information() << "From peak workspace: peak " << ipeak << " Center (Qsample) = " << qsample.toString()
543 << "\n";
544 }
545}
546
547//----------------------------------------------------------------------------------------------
552 // go over each peak (of run)
553 std::map<int, double>::iterator count_iter;
554 for (count_iter = m_runPeakCountsMap.begin(); count_iter != m_runPeakCountsMap.end(); ++count_iter) {
555 int run_number_i = count_iter->first;
556 // get monitor value
557 auto mon_iter = m_runNormMap.find(run_number_i);
558 // normalize peak intensities stored in m_runNormMap
559 if (mon_iter != m_runNormMap.end()) {
560 signal_t monitor_i = mon_iter->second;
561 count_iter->second /= monitor_i;
562 }
563 } // END-FOR
564
565 return;
566}
567
568} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
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
void deprecatedDate(const std::string &)
The date the algorithm was deprecated on.
A property class for workspaces.
void setRunNumber(int m_runNumber) override
Set the run number that measured this peak.
Definition BasePeak.cpp:81
int getRunNumber() const override
Return the run number this peak was measured at.
Definition BasePeak.cpp:77
void setIntensity(double m_intensity) override
Set the integrated peak intensity.
Definition BasePeak.cpp:197
void setGoniometerMatrix(const Mantid::Kernel::Matrix< double > &goniometerMatrix) override
Set the goniometer rotation matrix at which this peak was measured.
Definition BasePeak.cpp:219
Structure describing a single-crystal peak.
Definition Peak.h:34
void setQSampleFrame(const Mantid::Kernel::V3D &QSampleFrame, std::optional< double > detectorDistance=std::nullopt) override
Set the peak using the peak's position in reciprocal space, in the sample frame.
Definition Peak.cpp:502
Geometry::Instrument_const_sptr getInstrument() const
Return a shared ptr to the instrument for this peak.
Definition Peak.cpp:320
Mantid::Kernel::V3D getQSampleFrame() const override
Return the Q change (of the lattice, k_i - k_f) for this peak.
Definition Peak.cpp:482
void setInstrument(const Geometry::Instrument_const_sptr &inst)
Set the instrument (and save the source/sample pos).
Definition Peak.cpp:294
Support for a property that holds an array of values.
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 notice(const std::string &msg)
Logs at notice level.
Definition Logger.cpp:126
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
Class for 3D vectors.
Definition V3D.h:34
double distance(const V3D &v) const noexcept
Calculates the distance between two vectors.
Definition V3D.h:293
std::string toString() const
Definition V3D.cpp:332
void setZ(const double zz) noexcept
Set is z position.
Definition V3D.h:236
void setX(const double xx) noexcept
Set is x position.
Definition V3D.h:224
void setY(const double yy) noexcept
Set is y position.
Definition V3D.h:230
std::map< int, signal_t > getMonitorCounts()
Get the run/monitor counts map.
Mantid::DataObjects::PeaksWorkspace_sptr m_peaksWS
Input PeaksWorkspace.
void exec() override
Run the algorithm.
Mantid::API::IMDEventWorkspace_sptr m_inputWS
Input MDEventWorkspace.
void init() override
Initialise the properties.
std::map< int, double > getMeasureTime()
Get the run/measuring time map.
std::map< int, double > m_runPeakCountsMap
Integrated peaks' intensity per run number.
void processInputs()
Process and check input properties.
DataObjects::PeaksWorkspace_sptr createOutputs()
Create otuput workspace.
DataObjects::PeaksWorkspace_sptr createPeakworkspace(Kernel::V3D peakCenter, const API::IMDEventWorkspace_sptr &mdws)
IntegratePeaksCWSD::createPeakworkspace.
std::vector< detid_t > processMaskWorkspace(const DataObjects::MaskWorkspace_const_sptr &maskws)
Purpose: Process mask workspace Requirement: m_maskWS is not None Guarantees: an array will be set up...
std::map< int, Kernel::V3D > m_runPeakCenterMap
void mergePeaks()
Merge the peaks' counts.
DataObjects::MaskWorkspace_sptr m_maskWS
std::vector< DataObjects::Peak > m_vecPeaks
Peaks.
std::map< int, double > m_runNormMap
a map for run number and normalization value (monitor or time)
void normalizePeaksIntensities()
Implement this method to normalize the intensity of each Pt.
void simplePeakIntegration(const std::vector< detid_t > &vecMaskedDetID, const std::map< int, signal_t > &run_monitor_map)
IntegratePeaksCWSD::simplePeakIntegration Purpose: Integrate a single crystal peak with the simplest ...
void getPeakInformation()
Get peak information from peaks workspace.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< const ExperimentInfo > ExperimentInfo_const_sptr
Shared pointer to const ExperimentInfo.
std::shared_ptr< const MaskWorkspace > MaskWorkspace_const_sptr
shared pointer to a const MaskWorkspace
std::shared_ptr< PeaksWorkspace > PeaksWorkspace_sptr
Typedef for a shared pointer to a peaks workspace.
std::shared_ptr< const Instrument > Instrument_const_sptr
Shared pointer to an const instrument object.
const signal_t THRESHOLD_SIGNAL
int32_t detid_t
Typedef for a detector ID.
double signal_t
Typedef for the signal recorded in a MDBox, etc.
Definition MDTypes.h:36
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54