36double wavelengthToTOF(
const double lambda,
const double l1,
const double l2) {
45constexpr double degToRad(
const double x) {
return x * M_PI / 180.; }
51constexpr double radToDeg(
const double x) {
return x * 180. / M_PI; }
57constexpr double mmToMeter(
const double x) {
return x * 1.e-3; }
67 for (
size_t i = 0; i < nHisto; ++i) {
68 if (!spectrumInfo.isMonitor(i)) {
73 int end =
static_cast<int>(nHisto) - 1;
74 for (ptrdiff_t i =
static_cast<ptrdiff_t
>(nHisto) - 1; i != 0; --i) {
75 if (!spectrumInfo.isMonitor(i)) {
80 return std::pair<int, int>{begin, end};
88 std::iota(xs.begin(), xs.end(), 0.0);
92enum class RotationPlane { horizontal, vertical };
100Mantid::Kernel::V3D detectorPosition(
const RotationPlane plane,
const double distance,
const double angle) {
101 const double a = degToRad(angle);
104 case RotationPlane::horizontal:
105 x = distance * std::sin(a);
107 z = distance * std::cos(a);
109 case RotationPlane::vertical:
111 y = distance * std::sin(a);
112 z = distance * std::cos(a);
127 case RotationPlane::horizontal:
131 case RotationPlane::vertical:
144using namespace Kernel;
146using namespace NeXus;
147using Mantid::Types::Core::DateAndTime;
161 if ((descriptor.pathExists(
"/entry0/wavelength") ||
162 descriptor.pathExists(
"/entry0/theta"))
163 && descriptor.pathExists(
"/entry0/experiment_identifier") && descriptor.pathExists(
"/entry0/mode") &&
164 (descriptor.pathExists(
"/entry0/instrument/VirtualChopper") ||
165 descriptor.pathExists(
"/entry0/instrument/Theta"))
176 "Name of the Nexus file to load");
178 "Name of the output workspace");
180 "Foreground peak position in fractional workspace "
181 "index (if not given the peak is searched for and fitted).");
183 "The fractional workspace index of the geometric centre of "
184 "the detector at incident beam axis (127.5 for D17 and Figaro).");
185 const std::vector<std::string> measurements({
"DirectBeam",
"ReflectedBeam"});
186 declareProperty(
"Measurement",
"DirectBeam", std::make_unique<StringListValidator>(measurements),
187 "Load as direct or reflected beam.");
190 "Start workspace index used for peak fitting.");
192 "End workspace index used for peak fitting.");
193 declareProperty(
"FitRangeLower", -1.,
"Minimum wavelength used for peak fitting.");
194 declareProperty(
"FitRangeUpper", -1.,
"Maximum wavelength used for peak fitting.");
195 const std::vector<std::string> availableUnits{
"Wavelength",
"TimeOfFlight"};
196 declareProperty(
"XUnit",
"Wavelength", std::make_shared<StringListValidator>(availableUnits),
197 "X unit of the OutputWorkspace");
206 std::vector<std::vector<int>> monitorsData{
loadMonitors(firstEntry)};
227 loadInst->setPropertyValue(
"InstrumentName", instrumentName);
230 loadInst->executeAsChildAlg();
241 std::string instrumentName = entry.
getString(instrumentNamePath.append(
"/name"));
242 if (instrumentName.empty())
243 throw std::runtime_error(
"Cannot set the instrument name from the Nexus file!");
244 boost::to_lower(instrumentName);
245 if (instrumentName ==
"d17") {
247 }
else if (instrumentName ==
"figaro") {
250 std::ostringstream str;
251 str <<
"Unsupported instrument: " << instrumentName <<
'.';
252 throw std::runtime_error(str.str());
254 g_log.
debug() <<
"Instrument name: " << instrumentName <<
'\n';
263 NXInt firstChopper = entry.
openNXInt(
"instrument/ChopperSetting/firstChopper");
265 NXInt secondChopper = entry.
openNXInt(
"instrument/ChopperSetting/secondChopper");
266 secondChopper.
load();
285 convertToWavelength->initialize();
288 convertToWavelength->setPropertyValue(
"Target",
"Wavelength");
289 convertToWavelength->executeAsChildAlg();
301 g_log.
debug() <<
"Number of monitors: " << monitorsData.size() <<
'\n';
302 for (
size_t i = 0; i < monitorsData.size(); ++i) {
304 g_log.
debug() <<
"Data size of monitor ID " << i <<
" is " << monitorsData[i].size() <<
'\n';
352 throw std::runtime_error(
"The log with the given name does not exist " + entryName);
368 return std::vector<int>(data(), data() + data.
size());
380 const std::vector<std::vector<int>> monitors{
loadSingleMonitor(entry,
"monitor1/data"),
393 std::vector<double> xVals;
397 if (run.hasProperty(
"Distance.edelay_delay"))
399 else if (run.hasProperty(
"Theta.edelay_delay"))
401 else if (run.hasProperty(
"MainParameters.edelay_delay")) {
404 g_log.
warning() <<
"Unable to find edelay_delay from the file\n";
408 std::string chopper{
"Chopper"};
409 double chop1Speed{0.0}, chop1Phase{0.0}, chop2Speed{0.0}, chop2Phase{0.0};
412 std::string chop1SpeedName, chop1PhaseName, chop2SpeedName, chop2PhaseName;
413 if (duration > 30.0) {
414 chop1SpeedName = instrument->getStringParameter(
"chopper1_speed")[0];
415 chop1PhaseName = instrument->getStringParameter(
"chopper1_phase")[0];
416 chop2SpeedName = instrument->getStringParameter(
"chopper2_speed")[0];
417 chop2PhaseName = instrument->getStringParameter(
"chopper2_phase")[0];
419 chop1SpeedName = instrument->getStringParameter(
"chopper1_speed_alt")[0];
420 chop1PhaseName = instrument->getStringParameter(
"chopper1_phase_alt")[0];
421 chop2SpeedName = instrument->getStringParameter(
"chopper2_speed_alt")[0];
422 chop2PhaseName = instrument->getStringParameter(
"chopper2_phase_alt")[0];
428 if (chop1Phase > 360.) {
431 std::swap(chop1Phase, chop2Speed);
436 if (chop1Phase > 360.0)
442 }
else if (run.hasProperty(
m_offsetFrom +
".pickup_offset")) {
445 throw std::runtime_error(
"Unable to find chopper pickup offset");
450 }
else if (run.hasProperty(
m_offsetFrom +
".openOffset")) {
453 throw std::runtime_error(
"Unable to find chopper open offset");
457 chopper =
"Virtual chopper";
466 g_log.
debug() <<
"Open offset: " << openOffset <<
'\n';
467 g_log.
debug() <<
"Chopper 1 phase: " << chop1Phase <<
'\n';
468 g_log.
debug() << chopper <<
" 1 speed: " << chop1Speed <<
'\n';
469 g_log.
debug() << chopper <<
" 2 phase: " << chop2Phase <<
'\n';
470 g_log.
debug() << chopper <<
" 2 speed: " << chop2Speed <<
'\n';
472 if (chop1Speed <= 0.0) {
473 g_log.
error() <<
"First chopper velocity " << chop1Speed <<
". Check you NeXus file.\n";
476 const double chopWindow = instrument->getNumberParameter(
"chopper_window_opening")[0];
477 m_localWorkspace->mutableRun().addProperty(
"ChopperWindow", chopWindow,
"degree",
true);
478 g_log.
debug() <<
"Chopper Opening Window [degrees]" << chopWindow <<
'\n';
480 const double t_TOF2 =
m_tofDelay - 1.e+6 * 60.0 * (POFF - chopWindow + chop2Phase - chop1Phase + openOffset) /
481 (2.0 * 360 * chop1Speed);
482 g_log.
debug() <<
"t_TOF2: " << t_TOF2 <<
'\n';
484 for (
int channelIndex = 0; channelIndex < static_cast<int>(
m_numberOfChannels) + 1; ++channelIndex) {
486 xVals.emplace_back(t_TOF1 + t_TOF2);
489 g_log.
debug(
"Time channel index for axis description \n");
491 xVals.emplace_back(
static_cast<double>(t));
505 const std::vector<double> &xVals) {
509 const size_t nb_monitors = monitorsData.size();
511 if (!xVals.empty()) {
512 HistogramData::BinEdges binEdges(xVals);
515 const int *data_p = &data(0,
static_cast<int>(j), 0);
521 for (
size_t im = 0; im < nb_monitors; ++im) {
522 const int *monitor_p = monitorsData[im].data();
539 NXstatus stat = NXopen(filename.c_str(), NXACC_READ, &nxfileID);
540 if (stat == NX_ERROR)
545 auto const bgs3 =
m_localWorkspace->mutableRun().getLogAsSingleValue(
"BGS3.value");
560 if (!
isDefault(
"ForegroundPeakCentre")) {
564 auto startIndex = autoIndices.first;
565 auto endIndex = autoIndices.second;
566 if (!
isDefault(
"FitStartWorkspaceIndex")) {
567 startIndex =
getProperty(
"FitStartWorkspaceIndex");
569 if (!
isDefault(
"FitEndWorkspaceIndex")) {
573 integration->initialize();
575 integration->setProperty(
"OutputWorkspace",
"__unused_for_child");
576 integration->setProperty(
"StartWorkspaceIndex", startIndex);
577 integration->setProperty(
"EndWorkspaceIndex", endIndex);
579 integration->setProperty(
"RangeLower",
583 integration->setProperty(
"RangeUpper",
586 integration->execute();
589 transpose->initialize();
590 transpose->setProperty(
"InputWorkspace", integralWS);
591 transpose->setProperty(
"OutputWorkspace",
"__unused_for_child");
592 transpose->execute();
593 integralWS = transpose->getProperty(
"OutputWorkspace");
594 rebinIntegralWorkspace(*integralWS);
596 const auto maxValueIt = std::max_element(integralWS->y(0).cbegin(), integralWS->y(0).cend());
597 const double height = *maxValueIt;
599 const size_t maxIndex = std::distance(integralWS->y(0).cbegin(), maxValueIt);
600 const auto centreByMax =
static_cast<double>(maxIndex);
601 const auto &ys = integralWS->y(0);
602 auto lessThanHalfMax = [
height](
const double x) {
return x < 0.5 *
height; };
603 using IterType = HistogramData::HistogramY::const_iterator;
604 std::reverse_iterator<IterType> revMaxValueIt{maxValueIt};
605 auto revMinFwhmIt = std::find_if(revMaxValueIt, ys.crend(), lessThanHalfMax);
606 auto maxFwhmIt = std::find_if(maxValueIt, ys.cend(), lessThanHalfMax);
607 std::reverse_iterator<IterType> revMaxFwhmIt{maxFwhmIt};
608 if (revMinFwhmIt == ys.crend() || maxFwhmIt == ys.cend()) {
609 return centreByMax + startIndex;
611 const auto fwhm =
static_cast<double>(std::distance(revMaxFwhmIt, revMinFwhmIt) + 1);
614 auto sum = std::dynamic_pointer_cast<API::CompositeFunction>(func);
616 auto gaussian = std::dynamic_pointer_cast<API::IPeakFunction>(func);
617 gaussian->setHeight(
height);
618 gaussian->setCentre(centreByMax);
619 gaussian->setFwhm(fwhm);
620 sum->addFunction(gaussian);
622 func->setParameter(
"A0", 0.);
623 func->setParameter(
"A1", 0.);
624 sum->addFunction(func);
628 fit->setProperty(
"Function", std::dynamic_pointer_cast<API::IFunction>(sum));
629 fit->setProperty(
"InputWorkspace", integralWS);
630 fit->setProperty(
"StartX", centreByMax - 3 * fwhm);
631 fit->setProperty(
"EndX", centreByMax + 3 * fwhm);
633 const std::string fitStatus = fit->getProperty(
"OutputStatus");
634 if (fitStatus !=
"success") {
635 g_log.
warning(
"Fit not successful, using position of max value.\n");
636 return centreByMax + startIndex;
638 const auto centre = gaussian->centre();
639 return centre + startIndex;
647 m_localWorkspace->mutableRun().addProperty(
"reduction.line_position", peakCentre,
true);
648 const double detectorCentre =
getProperty(
"DetectorCentreFractionalIndex");
651 if (measurement ==
"ReflectedBeam") {
654 g_log.
warning(
"Sample angle is either 0 or doesn't exist in the file. "
655 "Please specify BraggAngle manually for reflected beams.");
672 std::string entryName;
674 if (entry.
isValid(
"instrument/SAN/value")) {
675 entryName =
"instrument/SAN/value";
676 }
else if (entry.
isValid(
"instrument/san/value")) {
677 entryName =
"instrument/san/value";
680 if (entry.
isValid(
"instrument/Theta/wanted_theta")) {
681 entryName =
"instrument/Theta/wanted_theta";
684 if (!entryName.empty()) {
694 const auto &detectorPanels = instrument->getAllComponentsWithName(
"detector");
695 if (detectorPanels.size() != 1) {
696 throw std::runtime_error(
"IDF should have a single 'detector' component.");
698 const auto &detector = std::dynamic_pointer_cast<const Geometry::RectangularDetector>(detectorPanels.front());
711 const std::string componentName =
"detector";
713 const auto newpos = detectorPosition(rotPlane,
m_detectorDistance, detectorRotationAngle);
716 const auto rotation = detectorFaceRotation(rotPlane, detectorRotationAngle);
722 double slit1ToSample{0.0};
723 double slit2ToSample{0.0};
727 const double offset =
m_sampleZOffset / std::cos(degToRad(deflectionAngle));
728 if (run.hasProperty(
"Distance.S2_Sample")) {
729 slit1ToSample = mmToMeter(
doubleFromRun(
"Distance.S2_Sample"));
731 throw std::runtime_error(
"Unable to find slit 2 to sample distance");
733 if (run.hasProperty(
"Distance.S3_Sample")) {
734 slit2ToSample = mmToMeter(
doubleFromRun(
"Distance.S3_Sample"));
736 throw std::runtime_error(
"Unable to find slit 3 to sample distance");
738 slit2ToSample += offset;
739 slit1ToSample += offset;
741 if (run.hasProperty(
"Distance.S2toSample")) {
742 slit1ToSample = mmToMeter(
doubleFromRun(
"Distance.S2toSample"));
743 }
else if (run.hasProperty(
"Distance.S2_Sample")) {
744 slit1ToSample = mmToMeter(
doubleFromRun(
"Distance.S2_Sample"));
746 throw std::runtime_error(
"Unable to find slit 2 to sample distance");
748 if (run.hasProperty(
"Distance.S3toSample")) {
749 slit2ToSample = mmToMeter(
doubleFromRun(
"Distance.S3toSample"));
750 }
else if (run.hasProperty(
"Distance.S3_Sample")) {
751 slit2ToSample = mmToMeter(
doubleFromRun(
"Distance.S3_Sample"));
753 throw std::runtime_error(
"Unable to find slit 3 to sample distance");
756 V3D pos{0.0, 0.0, -slit1ToSample};
758 pos = {0.0, 0.0, -slit2ToSample};
765 const std::string source =
"chopper1";
782 const double detectorDistance)
const {
783 const double offsetWidth = (detectorCentre - peakCentre) *
m_pixelWidth;
787 return sign * radToDeg(std::atan2(offsetWidth, detectorDistance));
794 std::string distanceEntry;
796 distanceEntry =
"det.value";
798 distanceEntry =
"Distance.Sample_CenterOfDetector_distance";
806 std::string offsetEntry;
808 if (run.hasProperty(
"Theta.sampleHorizontalOffset"))
809 offsetEntry =
"Theta.sampleHorizontalOffset";
810 else if (run.hasProperty(
"Distance.sampleHorizontalOffset")) {
811 offsetEntry =
"Distance.sampleHorizontalOffset";
812 }
else if (run.hasProperty(
"Distance.sample_changer_horizontal_offset")) {
813 offsetEntry =
"Distance.sample_changer_horizontal_offset";
814 }
else if (run.hasProperty(
"Theta.sample_horizontal_offset")) {
815 offsetEntry =
"Theta.sample_horizontal_offset";
817 throw std::runtime_error(
"Unable to find sample horizontal offset in the file");
828 const std::string chopperGapUnit =
m_localWorkspace->getInstrument()->getStringParameter(
"chopper_gap_unit")[0];
829 const double scale = (chopperGapUnit ==
"cm") ? 0.01 : (chopperGapUnit ==
"mm") ? 0.001 : 1.;
832 double pairSeparation;
833 if (run.hasProperty(
"VirtualChopper.dist_chop_samp")) {
837 m_localWorkspace->mutableRun().addProperty(
"VirtualChopper.dist_chop_samp", pairCentre,
"meter",
true);
838 pairSeparation =
doubleFromRun(
"Distance.ChopperGap") * scale;
841 pairCentre -= 0.5 * pairSeparation;
842 }
else if (run.hasProperty(
"VirtualChopper.MidChopper_Sample_distance")) {
845 pairCentre = mmToMeter(
doubleFromRun(
"VirtualChopper.MidChopper_Sample_distance"));
846 pairSeparation =
doubleFromRun(
"Distance.ChopperGap") * scale;
847 m_localWorkspace->mutableRun().addProperty(
"VirtualChopper.MidChopper_Sample_distance", pairCentre,
"meter",
849 }
else if (run.hasProperty(
"Distance.Chopper1_Sample")) {
851 pairCentre = mmToMeter(
doubleFromRun(
"Distance.MidChopper_Sample"));
852 pairSeparation =
doubleFromRun(
"Distance.ChopperGap") * scale;
853 m_localWorkspace->mutableRun().addProperty(
"VirtualChopper.MidChopper_Sample_distance", pairCentre,
"meter",
856 throw std::runtime_error(
"Unable to extract chopper to sample distance");
860 m_localWorkspace->mutableRun().addProperty(
"Distance.ChopperGap", pairSeparation,
"meter",
true);
863 const double chopperDist = mmToMeter(
doubleFromRun(
"ChopperSetting.chopperpair_sample_distance"));
864 std::string entryName =
"correct_chopper_sample_distance";
865 bool correctChopperSampleDistance =
m_localWorkspace->getInstrument()->getBoolParameter(entryName)[0];
867 if (correctChopperSampleDistance) {
871 return chopperDist + offset;
const std::vector< double > * lambda
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
Mantid::Kernel::Quat(ComponentInfo::* rotation)(const size_t) const
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
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.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
bool isDefault(const std::string &name) const
const SpectrumInfo & spectrumInfo() const
Return a reference to the SpectrumInfo object.
@ Load
allowed here which will be passed to the algorithm
Base MatrixWorkspace Abstract Class.
HistogramData::HistogramX & mutableX(const size_t index) &
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
Helper class for reporting progress from algorithms.
A property class for workspaces.
LoadILLReflectometry : Loads an ILL reflectometry Nexus data file.
size_t m_numberOfChannels
(1: TOF (default), 0: monochromatic)
void exec() override
Execute the algorithm.
double doubleFromRun(const std::string &entryName) const
LoadILLReflectometry::doubleFromRun Returns a sample log a single double.
void loadNexusEntriesIntoProperties()
Use the LoadHelper utility to load most of the nexus entries into workspace sample log properties.
std::string m_chopper1Name
std::vector< int > loadSingleMonitor(const NeXus::NXEntry &entry, const std::string &monitor_data)
Load single monitor.
double detectorRotation()
Compute the detector rotation angle around origin.
double offsetAngle(const double peakCentre, const double detectorCentre, const double detectorDistance) const
Calculate the offset angle between detector center and peak.
double sampleDetectorDistance() const
Return the sample to detector distance for the current instrument.
double m_detectorDistance
double sourceSampleDistance() const
Return the source to sample distance for the current instrument.
void loadInstrument()
Run the Child Algorithm LoadInstrument.
Mantid::Types::Core::DateAndTime m_startTime
void initPixelWidth()
Initialize m_pixelWidth from the IDF as the step of rectangular detector.
void initWorkspace(const std::vector< std::vector< int > > &monitorsData)
Creates the workspace and initialises member variables with the corresponding values.
void sampleHorizontalOffset()
Return the horizontal offset along the z axis.
void initNames(const NeXus::NXEntry &entry)
Init names of sample logs based on instrument specific NeXus file entries.
void convertTofToWavelength()
Call child algorithm ConvertUnits for conversion from TOF to wavelength Note that DAN calibration is ...
void sampleAngle(const NeXus::NXEntry &entry)
Sets the sample angle (i.e.
std::vector< std::vector< int > > loadMonitors(const NeXus::NXEntry &entry)
Load monitor data.
void placeDetector()
Update detector position according to data file.
size_t m_numberOfHistograms
API::MatrixWorkspace_sptr m_localWorkspace
std::string m_sampleAngleName
std::vector< double > getXValues()
Determine x values (unit time-of-flight)
double reflectometryPeak()
Gaussian fit to determine peak position if no user position given.
void placeSource()
Update source position.
double collimationAngle() const
Return the incident neutron deflection angle.
void loadData(const NeXus::NXEntry &entry, const std::vector< std::vector< int > > &monitorsData, const std::vector< double > &xVals)
Load data from nexus file.
void loadDataDetails(const NeXus::NXEntry &entry)
Load Data details (number of tubes, channels, etc)
void placeSlits()
Update the slit positions.
void init() override
Initialize the algorithm's properties.
std::string m_chopper2Name
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
Records the filename and the description of failure.
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.
void error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
OptionalBool : Tri-state bool.
The concrete, templated class for properties.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
static double run(const std::string &src, const std::string &dest, const double srcValue, const double l1, const double l2, const double theta, const DeltaEMode::Type emode, const double efixed)
Convert a single value between the given units (as strings)
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
void close()
Close this class.
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
bool isValid(const std::string &path) const
Check if a path exists relative to the current class path.
std::string getString(const std::string &name) const
Returns a string.
Templated class implementation of NXDataSet.
void load(const int blocksize=1, int i=-1, int j=-1, int k=-1, int l=-1) override
Implementation of the virtual NXDataSet::load(...) method.
int size() const
Returns the size of the data buffer.
Implements NXdata Nexus class.
NXInt openIntData()
Opens data of int type.
Implements NXentry Nexus class.
NXData openNXData(const std::string &name) const
Opens a NXData.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void rotateComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName, const Kernel::Quat &rot)
LoadHelper::rotateComponent.
void addNexusFieldsToWsRun(NXhandle nxfileID, API::Run &runDetails, const std::string &entryName="", bool useFullPath=false)
Add properties from a nexus file to the workspace run.
std::string findInstrumentNexusPath(const Mantid::NeXus::NXEntry &)
Finds the path for the instrument name in the nexus file Usually of the form: entry0/<NXinstrument cl...
void moveComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName, const Kernel::V3D &newPos)
LoadHelper::moveComponent.
std::string dateTimeInIsoFormat(const std::string &)
Parses the date as formatted at the ILL: 29-Jun-12 11:27:26 and converts it to the ISO format used in...
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
int32_t specnum_t
Typedef for a spectrum Number.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.