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