30#include "MantidNexus/NexusFile.h"
35double wavelengthToTOF(
const double lambda,
const double l1,
const double l2) {
44constexpr double degToRad(
const double x) {
return x * M_PI / 180.; }
50constexpr double radToDeg(
const double x) {
return x * 180. / M_PI; }
56constexpr double mmToMeter(
const double x) {
return x * 1.e-3; }
66 for (
size_t i = 0; i < nHisto; ++i) {
67 if (!spectrumInfo.isMonitor(i)) {
72 int end =
static_cast<int>(nHisto) - 1;
73 for (ptrdiff_t i =
static_cast<ptrdiff_t
>(nHisto) - 1; i != 0; --i) {
74 if (!spectrumInfo.isMonitor(i)) {
79 return std::pair<int, int>{begin, end};
83enum class RotationPlane { horizontal, vertical };
91Mantid::Kernel::V3D detectorPosition(
const RotationPlane plane,
const double distance,
const double angle) {
92 const double a = degToRad(angle);
93 double x = 0,
y = 0,
z = 0;
95 case RotationPlane::horizontal:
96 x = distance * std::sin(a);
97 z = distance * std::cos(a);
99 case RotationPlane::vertical:
100 y = distance * std::sin(a);
101 z = distance * std::cos(a);
116 case RotationPlane::horizontal:
119 case RotationPlane::vertical:
131using namespace Kernel;
133using namespace Nexus;
134using Mantid::Types::Core::DateAndTime;
148 if ((descriptor.isEntry(
"/entry0/wavelength") ||
149 descriptor.isEntry(
"/entry0/theta"))
150 && descriptor.isEntry(
"/entry0/experiment_identifier") && descriptor.isEntry(
"/entry0/mode") &&
151 (descriptor.isEntry(
"/entry0/instrument/VirtualChopper") ||
152 descriptor.isEntry(
"/entry0/instrument/Theta"))
163 "Name of the Nexus file to load");
165 "Name of the output workspace");
167 "Foreground peak position in fractional workspace "
168 "index (if not given the peak is searched for and fitted).");
170 "The fractional workspace index of the geometric centre of "
171 "the detector at incident beam axis (127.5 for D17 and Figaro).");
172 const std::vector<std::string> measurements({
"DirectBeam",
"ReflectedBeam"});
173 declareProperty(
"Measurement",
"DirectBeam", std::make_unique<StringListValidator>(measurements),
174 "Load as direct or reflected beam.");
177 "Start workspace index used for peak fitting.");
179 "End workspace index used for peak fitting.");
180 declareProperty(
"FitRangeLower", -1.,
"Minimum wavelength used for peak fitting.");
181 declareProperty(
"FitRangeUpper", -1.,
"Maximum wavelength used for peak fitting.");
182 const std::vector<std::string> availableUnits{
"Wavelength",
"TimeOfFlight"};
183 declareProperty(
"XUnit",
"Wavelength", std::make_shared<StringListValidator>(availableUnits),
184 "X unit of the OutputWorkspace");
186 "A dictionary of key-pair values for logs to be replaced.");
220 std::string instrumentName = entry.
getString(instrumentNameAddress.append(
"/name"));
221 if (instrumentName.empty())
222 throw std::runtime_error(
"Cannot set the instrument name from the Nexus file!");
223 boost::to_lower(instrumentName);
224 if (instrumentName ==
"d17") {
226 }
else if (instrumentName ==
"figaro") {
229 std::ostringstream str;
230 str <<
"Unsupported instrument: " << instrumentName <<
'.';
231 throw std::runtime_error(str.str());
233 g_log.
debug() <<
"Instrument name: " << instrumentName <<
'\n';
242 NXInt firstChopper = entry.
openNXInt(
"instrument/ChopperSetting/firstChopper");
244 NXInt secondChopper = entry.
openNXInt(
"instrument/ChopperSetting/secondChopper");
245 secondChopper.
load();
264 convertToWavelength->initialize();
267 convertToWavelength->setPropertyValue(
"Target",
"Wavelength");
268 convertToWavelength->executeAsChildAlg();
280 g_log.
debug() <<
"Number of monitors: " << monitorNames.size() <<
'\n';
281 for (
size_t i = 0; i < monitorNames.size(); ++i) {
283 g_log.
debug() <<
"Data size of monitor ID " << i <<
" is " << monitorNames[i].size() <<
'\n';
290 m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create(
"TOF");
331 throw std::runtime_error(
"The log with the given name does not exist " + entryName);
342 const std::vector<std::string> monitors{
"monitor1/data",
"monitor2/data"};
354 std::vector<double> xVals;
358 if (run.hasProperty(
"Distance.edelay_delay"))
360 else if (run.hasProperty(
"Theta.edelay_delay"))
362 else if (run.hasProperty(
"MainParameters.edelay_delay")) {
365 g_log.
warning() <<
"Unable to find edelay_delay from the file\n";
369 std::string chopper{
"Chopper"};
370 double chop1Speed{0.0}, chop1Phase{0.0}, chop2Speed{0.0}, chop2Phase{0.0};
373 std::string chop1SpeedName, chop1PhaseName, chop2SpeedName, chop2PhaseName;
374 if (duration > 30.0) {
375 chop1SpeedName = instrument->getStringParameter(
"chopper1_speed")[0];
376 chop1PhaseName = instrument->getStringParameter(
"chopper1_phase")[0];
377 chop2SpeedName = instrument->getStringParameter(
"chopper2_speed")[0];
378 chop2PhaseName = instrument->getStringParameter(
"chopper2_phase")[0];
380 chop1SpeedName = instrument->getStringParameter(
"chopper1_speed_alt")[0];
381 chop1PhaseName = instrument->getStringParameter(
"chopper1_phase_alt")[0];
382 chop2SpeedName = instrument->getStringParameter(
"chopper2_speed_alt")[0];
383 chop2PhaseName = instrument->getStringParameter(
"chopper2_phase_alt")[0];
389 if (chop1Phase > 360.) {
392 std::swap(chop1Phase, chop2Speed);
397 if (chop1Phase > 360.0)
403 }
else if (run.hasProperty(
m_offsetFrom +
".pickup_offset")) {
406 throw std::runtime_error(
"Unable to find chopper pickup offset");
411 }
else if (run.hasProperty(
m_offsetFrom +
".openOffset")) {
414 throw std::runtime_error(
"Unable to find chopper open offset");
418 chopper =
"Virtual chopper";
427 g_log.
debug() <<
"Open offset: " << openOffset <<
'\n';
428 g_log.
debug() <<
"Chopper 1 phase: " << chop1Phase <<
'\n';
429 g_log.
debug() << chopper <<
" 1 speed: " << chop1Speed <<
'\n';
430 g_log.
debug() << chopper <<
" 2 phase: " << chop2Phase <<
'\n';
431 g_log.
debug() << chopper <<
" 2 speed: " << chop2Speed <<
'\n';
433 if (chop1Speed <= 0.0) {
434 g_log.
error() <<
"First chopper velocity " << chop1Speed <<
". Check you NeXus file.\n";
437 const double chopWindow = instrument->getNumberParameter(
"chopper_window_opening")[0];
438 m_localWorkspace->mutableRun().addProperty(
"ChopperWindow", chopWindow,
"degree",
true);
439 g_log.
debug() <<
"Chopper Opening Window [degrees]" << chopWindow <<
'\n';
441 const double t_TOF2 =
m_tofDelay - 1.e+6 * 60.0 * (POFF - chopWindow + chop2Phase - chop1Phase + openOffset) /
442 (2.0 * 360 * chop1Speed);
443 g_log.
debug() <<
"t_TOF2: " << t_TOF2 <<
'\n';
445 for (
int channelIndex = 0; channelIndex < static_cast<int>(
m_numberOfChannels) + 1; ++channelIndex) {
447 xVals.emplace_back(t_TOF1 + t_TOF2);
450 g_log.
debug(
"Time channel index for axis description \n");
452 xVals.emplace_back(
static_cast<double>(t));
466 const std::vector<double> &xVals) {
469 const int nb_monitors =
static_cast<int>(monitorNames.size());
471 if (!xVals.empty()) {
476 for (
auto im = 0; im < nb_monitors; ++im) {
477 const std::string monitorDataSetName(
"monitor" +
std::to_string(im + 1) +
"/data");
503 auto const bgs3 =
m_localWorkspace->mutableRun().getLogAsSingleValue(
"BGS3.value");
510 if (logsToReplace !=
nullptr && logsToReplace->propertyCount() > 0) {
511 for (
auto *prop : logsToReplace->getProperties()) {
512 if (prop->type() ==
"number") {
513 runDetails.
addProperty(prop->name(), std::stod(prop->value()),
true);
515 runDetails.
addProperty(prop->name(), prop->value(),
true);
527 if (!
isDefault(
"ForegroundPeakCentre")) {
531 auto startIndex = autoIndices.first;
532 auto endIndex = autoIndices.second;
533 if (!
isDefault(
"FitStartWorkspaceIndex")) {
534 startIndex =
getProperty(
"FitStartWorkspaceIndex");
536 if (!
isDefault(
"FitEndWorkspaceIndex")) {
541 findLine->setProperty(
"StartWorkspaceIndex", startIndex);
542 findLine->setProperty(
"EndWorkspaceIndex", endIndex);
543 findLine->setProperty(
"BackgroundType",
"Linear");
544 findLine->setProperty(
"AcceptChangesInFunctionTooSmall",
false);
545 findLine->setProperty(
"AcceptChangesInParameterTooSmall",
false);
547 findLine->setProperty(
"RangeLower",
551 findLine->setProperty(
"RangeUpper",
555 return findLine->getProperty(
"LineCentre");
563 m_localWorkspace->mutableRun().addProperty(
"reduction.line_position", peakCentre,
true);
564 const double detectorCentre =
getProperty(
"DetectorCentreFractionalIndex");
567 if (measurement ==
"ReflectedBeam") {
570 g_log.
warning(
"Sample angle is either 0 or doesn't exist in the file. "
571 "Please specify BraggAngle manually for reflected beams.");
590 std::string entryName;
592 if (entry.
isValid(
"instrument/SAN/value")) {
593 entryName =
"instrument/SAN/value";
594 }
else if (entry.
isValid(
"instrument/san/value")) {
595 entryName =
"instrument/san/value";
598 if (entry.
isValid(
"instrument/Theta/wanted_theta")) {
599 entryName =
"instrument/Theta/wanted_theta";
602 if (!entryName.empty()) {
612 if (!componentInfo.uniqueName(
"detector")) {
613 throw std::runtime_error(
"IDF should have a single 'detector' component.");
615 const size_t detectorIndex = componentInfo.indexOfAny(
"detector");
616 const auto grid = componentInfo.pixelGridComponent(
detectorIndex);
629 const std::string componentName =
"detector";
631 const auto newpos = detectorPosition(rotPlane,
m_detectorDistance, detectorRotationAngle);
634 const auto rotation = detectorFaceRotation(rotPlane, detectorRotationAngle);
640 double slit1ToSample{0.0};
641 double slit2ToSample{0.0};
645 const double offset =
m_sampleZOffset / std::cos(degToRad(deflectionAngle));
646 if (run.hasProperty(
"Distance.S2_Sample")) {
647 slit1ToSample = mmToMeter(
doubleFromRun(
"Distance.S2_Sample"));
649 throw std::runtime_error(
"Unable to find slit 2 to sample distance");
651 if (run.hasProperty(
"Distance.S3_Sample")) {
652 slit2ToSample = mmToMeter(
doubleFromRun(
"Distance.S3_Sample"));
654 throw std::runtime_error(
"Unable to find slit 3 to sample distance");
656 slit2ToSample += offset;
657 slit1ToSample += offset;
659 if (run.hasProperty(
"Distance.S2toSample")) {
660 slit1ToSample = mmToMeter(
doubleFromRun(
"Distance.S2toSample"));
661 }
else if (run.hasProperty(
"Distance.S2_Sample")) {
662 slit1ToSample = mmToMeter(
doubleFromRun(
"Distance.S2_Sample"));
664 throw std::runtime_error(
"Unable to find slit 2 to sample distance");
666 if (run.hasProperty(
"Distance.S3toSample")) {
667 slit2ToSample = mmToMeter(
doubleFromRun(
"Distance.S3toSample"));
668 }
else if (run.hasProperty(
"Distance.S3_Sample")) {
669 slit2ToSample = mmToMeter(
doubleFromRun(
"Distance.S3_Sample"));
671 throw std::runtime_error(
"Unable to find slit 3 to sample distance");
674 V3D pos{0.0, 0.0, -slit1ToSample};
676 pos = {0.0, 0.0, -slit2ToSample};
683 const std::string source =
"chopper1";
700 const double detectorDistance)
const {
701 const double offsetWidth = (detectorCentre - peakCentre) *
m_pixelWidth;
705 return sign * radToDeg(std::atan2(offsetWidth, detectorDistance));
712 std::string distanceEntry;
714 distanceEntry =
"det.value";
716 distanceEntry =
"Distance.Sample_CenterOfDetector_distance";
724 std::string offsetEntry;
726 if (run.hasProperty(
"Theta.sampleHorizontalOffset"))
727 offsetEntry =
"Theta.sampleHorizontalOffset";
728 else if (run.hasProperty(
"Distance.sampleHorizontalOffset")) {
729 offsetEntry =
"Distance.sampleHorizontalOffset";
730 }
else if (run.hasProperty(
"Distance.sample_changer_horizontal_offset")) {
731 offsetEntry =
"Distance.sample_changer_horizontal_offset";
732 }
else if (run.hasProperty(
"Theta.sample_horizontal_offset")) {
733 offsetEntry =
"Theta.sample_horizontal_offset";
735 throw std::runtime_error(
"Unable to find sample horizontal offset in the file");
747 const std::string chopperGapUnit =
m_localWorkspace->getInstrument()->getStringParameter(
"chopper_gap_unit")[0];
748 const double scale = (chopperGapUnit ==
"cm") ? 0.01 : (chopperGapUnit ==
"mm") ? 0.001 : 1.;
750 double pairSeparation;
751 if (run.hasProperty(
"VirtualChopper.dist_chop_samp")) {
755 m_localWorkspace->mutableRun().addProperty(
"VirtualChopper.dist_chop_samp", pairCentre,
"meter",
true);
756 pairSeparation =
doubleFromRun(
"Distance.ChopperGap") * scale;
759 pairCentre -= 0.5 * pairSeparation;
760 }
else if (run.hasProperty(
"VirtualChopper.MidChopper_Sample_distance")) {
763 pairCentre = mmToMeter(
doubleFromRun(
"VirtualChopper.MidChopper_Sample_distance"));
764 pairSeparation =
doubleFromRun(
"Distance.ChopperGap") * scale;
765 m_localWorkspace->mutableRun().addProperty(
"VirtualChopper.MidChopper_Sample_distance", pairCentre,
"meter",
767 }
else if (run.hasProperty(
"Distance.Chopper1_Sample")) {
769 pairCentre = mmToMeter(
doubleFromRun(
"Distance.MidChopper_Sample"));
770 pairSeparation =
doubleFromRun(
"Distance.ChopperGap") * scale;
771 m_localWorkspace->mutableRun().addProperty(
"VirtualChopper.MidChopper_Sample_distance", pairCentre,
"meter",
774 throw std::runtime_error(
"Unable to extract chopper to sample distance");
778 m_localWorkspace->mutableRun().addProperty(
"Distance.ChopperGap", pairSeparation,
"meter",
true);
781 if (run.hasProperty(
"ChopperSetting.chopperpair_sample_distance")) {
782 const double chopperDist = mmToMeter(
doubleFromRun(
"ChopperSetting.chopperpair_sample_distance"));
783 std::string entryName =
"correct_chopper_sample_distance";
784 bool correctChopperSampleDistance =
m_localWorkspace->getInstrument()->getBoolParameter(entryName)[0];
786 if (correctChopperSampleDistance) {
790 return chopperDist + offset;
791 }
else if (run.hasProperty(
"Distance.MidChopper_Sample")) {
792 return mmToMeter(
doubleFromRun(
"Distance.MidChopper_Sample"));
794 throw std::runtime_error(
"Unable to extract chopper to sample distance");
const std::vector< double > * lambda
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
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Base MatrixWorkspace Abstract Class.
virtual std::size_t getNumberHistograms() const =0
Returns the number of histograms in the workspace.
Helper class for reporting progress from algorithms.
This class stores information regarding an experimental run as a series of log entries.
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
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.
Mantid::Types::Core::DateAndTime m_startTime
std::vector< std::string > getMonitorNames()
Load monitor data.
void initPixelWidth()
Initialize m_pixelWidth from the IDF as the step of rectangular detector.
void sampleHorizontalOffset()
Return the horizontal offset along the z axis.
void convertTofToWavelength()
Call child algorithm ConvertUnits for conversion from TOF to wavelength Note that DAN calibration is ...
void initNames(const Nexus::NXEntry &entry)
Init names of sample logs based on instrument specific NeXus file entries.
void sampleAngle(const Nexus::NXEntry &entry)
Sets the sample angle (i.e.
void initWorkspace(const std::vector< std::string > &monitorNames)
Creates the workspace and initialises member variables with the corresponding values.
void placeDetector()
Update detector position according to data file.
size_t m_numberOfHistograms
API::MatrixWorkspace_sptr m_localWorkspace
std::string m_sampleAngleName
void loadDataDetails(const Nexus::NXEntry &entry)
Load Data details (number of tubes, channels, etc)
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 placeSlits()
Update the slit positions.
void loadData(const Nexus::NXEntry &entry, const std::vector< std::string > &monitorNames, const std::vector< double > &xVals)
Load data from nexus file.
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.
The concrete, templated class for properties.
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)
Class that provides for a standard Nexus exception.
std::string getString(const std::string &name) const
Returns a string.
NXFloat openNXFloat(const std::string &name) const
Creates and opens a float dataset.
void close()
Close this class.
NXInt openNXInt(const std::string &name) const
Creates and opens an integer dataset.
bool isValid(const std::string &address) const
Check if a address exists relative to the current class address.
Templated class implementation of NXDataSet.
void load()
Read all of the datablock in.
Implements NXentry Nexus class.
Implements NXroot Nexus class.
NXEntry openFirstEntry()
Open the first NXentry in the file.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void addNexusFieldsToWsRun(Nexus::File &filehandle, API::Run &runDetails, const std::string &entryName="", bool useFullAddress=false)
Add properties from a nexus file to the workspace run.
void rotateComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName, const Kernel::Quat &rot)
LoadHelper::rotateComponent.
Nexus::NXInt getIntDataset(const Nexus::NXEntry &, const std::string &)
Fetches NXInt data from the requested group name in the entry provided.
void moveComponent(const API::MatrixWorkspace_sptr &ws, const std::string &componentName, const Kernel::V3D &newPos)
LoadHelper::moveComponent.
void fillStaticWorkspace(const API::MatrixWorkspace_sptr &, const Mantid::Nexus::NXInt &, const std::vector< double > &xAxis, int64_t initialSpectrum=0, bool pointData=false, const std::vector< detid_t > &detectorIDs=std::vector< int >(), const std::set< detid_t > &acceptedID=std::set< int >(), const std::tuple< short, short, short > &axisOrder=std::tuple< short, short, short >(0, 1, 2))
Fills workspace with histogram data from provided data structure.
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...
void loadEmptyInstrument(const API::MatrixWorkspace_sptr &ws, const std::string &instrumentName, const std::string &instrumentAddress="")
Loads empty instrument of chosen name into a provided workspace.
std::string findInstrumentNexusAddress(const Mantid::Nexus::NXEntry &)
Finds the address for the instrument name in the nexus file Usually of the form: entry0/<NXinstrument...
std::shared_ptr< const PropertyManager > PropertyManager_const_sptr
shared pointer to Mantid::Kernel::PropertyManager(const version)
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.