diff --git a/Framework/API/CMakeLists.txt b/Framework/API/CMakeLists.txt index b55181a53ebb..98381c075d70 100644 --- a/Framework/API/CMakeLists.txt +++ b/Framework/API/CMakeLists.txt @@ -396,6 +396,7 @@ set(TEST_FILES FileBackedExperimentInfoTest.h FileFinderTest.h FilePropertyTest.h + FileLoaderRegistryTest.h FrameworkManagerTest.h FuncMinimizerFactoryTest.h FunctionAttributeTest.h diff --git a/Framework/API/test/FileLoaderRegistryTest.h b/Framework/API/test/FileLoaderRegistryTest.h new file mode 100644 index 000000000000..c8acb8f3e615 --- /dev/null +++ b/Framework/API/test/FileLoaderRegistryTest.h @@ -0,0 +1,69 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#pragma once + +#include "MantidAPI/FileFinder.h" +#include "MantidAPI/FileLoaderRegistry.h" +#include + +#include + +using namespace Mantid::Kernel; +using namespace Mantid::API; + +class FileLoaderRegistryTest : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor (& destructor) isn't called when running other tests + static FileLoaderRegistryTest *createSuite() { return new FileLoaderRegistryTest(); } + static void destroySuite(FileLoaderRegistryTest *suite) { delete suite; } + + FileLoaderRegistryTest() {} + + ~FileLoaderRegistryTest() override {} + + void runCheck(const std::string &filename, const std::string &alg_expected, const int version_expected) { + std::string path = FileFinder::Instance().getFullPath(filename); + + TSM_ASSERT("File not found: " + filename, !path.empty()); + + // get the right algorithm + try { + const auto loader = FileLoaderRegistry::Instance().chooseLoader(path); + if (loader) { + TSM_ASSERT_EQUALS(filename, loader->name(), alg_expected); + TSM_ASSERT_EQUALS(filename, loader->version(), version_expected); + } else { + TS_FAIL("Failed to find a loader for " + filename); + } + } catch (const std::runtime_error &e) { + TS_FAIL(e.what()); // no exception should be thrown + } + } + + void testMuon() { + runCheck("MUSR00022725.nxs", "LoadMuonNexus", 1); + runCheck("emu00006473.nxs", "LoadMuonNexus", 1); + } + + void testILL() { + // IN5 tests + const std::string path("ILL/IN5/"); + runCheck(path + "095893.nxs", "LoadILLTOF", 2); // hdf4 + runCheck(path + "104007.nxs", "LoadILLTOF", 3); // hdf5 + } + + void testSNS() { + runCheck("TOPAZ_3007.peaks.nxs", "LoadNexusProcessed", 2); + runCheck("PG3_733.nxs", "LoadNexusProcessed", 2); + + runCheck("REF_L_183110.nxs.h5", "LoadEventNexus", 1); + runCheck("CNCS_7860_event.nxs", "LoadEventNexus", 1); + } + +private: +}; diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt index fd3f90290014..233e5c0c233a 100644 --- a/Framework/DataHandling/CMakeLists.txt +++ b/Framework/DataHandling/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC_FILES src/LoadILLSALSA.cpp src/LoadILLSANS.cpp src/LoadILLTOF2.cpp + src/LoadILLTOF3.cpp src/LoadISISNexus2.cpp src/LoadISISNexusHelper.cpp src/LoadISISPolarizationEfficiencies.cpp @@ -293,6 +294,7 @@ set(INC_FILES inc/MantidDataHandling/LoadILLSALSA.h inc/MantidDataHandling/LoadILLSANS.h inc/MantidDataHandling/LoadILLTOF2.h + inc/MantidDataHandling/LoadILLTOF3.h inc/MantidDataHandling/LoadISISNexus2.h inc/MantidDataHandling/LoadISISNexusHelper.h inc/MantidDataHandling/LoadISISPolarizationEfficiencies.h @@ -506,6 +508,7 @@ set(TEST_FILES LoadILLSALSATest.h LoadILLSANSTest.h LoadILLTOF2Test.h + LoadILLTOF3Test.h LoadILLTest.h LoadISISNexusTest.h LoadISISPolarizationEfficienciesTest.h @@ -685,7 +688,7 @@ target_link_libraries( Mantid::Indexing Mantid::Parallel Mantid::Muon - PRIVATE Mantid::Json Boost::filesystem Mantid::NexusGeometry + PRIVATE Mantid::Json Boost::filesystem Mantid::NexusGeometry Mantid::LegacyNexus ) # Lib3mf is technically a public dependency as it is in our public headers. We are assuming here that it won't be used. diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h index 44f63995a15c..946e95db284e 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF2.h @@ -9,15 +9,18 @@ #include "MantidAPI/IFileLoader.h" #include "MantidDataHandling/DllConfig.h" #include "MantidGeometry/IDTypes.h" -#include "MantidKernel/NexusDescriptor.h" -#include "MantidNexus/NexusClasses_fwd.h" +#include "MantidKernel/LegacyNexusDescriptor.h" namespace Mantid { +// forward declares +namespace LegacyNexus { +class NXEntry; +} namespace DataHandling { /** Loads an ILL IN4/5/6/Panther NeXus file into a Mantid workspace. */ -class MANTID_DATAHANDLING_DLL LoadILLTOF2 : public API::IFileLoader { +class MANTID_DATAHANDLING_DLL LoadILLTOF2 : public API::IFileLoader { public: /// Constructor LoadILLTOF2(); @@ -33,7 +36,7 @@ class MANTID_DATAHANDLING_DLL LoadILLTOF2 : public API::IFileLoader &monitorList, bool convertToTOF); - void fillScanWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList); + void fillStaticWorkspace(const LegacyNexus::NXEntry &entry, const std::vector &monitorList, + bool convertToTOF); + void fillScanWorkspace(const LegacyNexus::NXEntry &entry, const std::vector &monitorList); - std::vector getMonitorInfo(const NeXus::NXEntry &firstEntry); - void initWorkspace(const NeXus::NXEntry &entry); + std::vector getMonitorInfo(const LegacyNexus::NXEntry &firstEntry); + void initWorkspace(const LegacyNexus::NXEntry &entry); - void loadInstrumentDetails(const NeXus::NXEntry &); - void loadTimeDetails(const NeXus::NXEntry &entry); + void loadInstrumentDetails(const LegacyNexus::NXEntry &); + void loadTimeDetails(const LegacyNexus::NXEntry &entry); - std::vector prepareAxis(const NeXus::NXEntry &entry, bool convertToTOF); + std::vector prepareAxis(const LegacyNexus::NXEntry &entry, bool convertToTOF); API::MatrixWorkspace_sptr m_localWorkspace; diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF3.h b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF3.h new file mode 100644 index 000000000000..1afcb77a4512 --- /dev/null +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadILLTOF3.h @@ -0,0 +1,81 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2025 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#pragma once + +#include "MantidAPI/IFileLoader.h" +#include "MantidDataHandling/DllConfig.h" +#include "MantidGeometry/IDTypes.h" +#include "MantidKernel/NexusDescriptor.h" +#include "MantidNexus/NexusClasses.h" + +namespace Mantid { +namespace DataHandling { +/** + Loads an ILL IN4/5/6/Panther NeXus file into a Mantid workspace. + */ +class MANTID_DATAHANDLING_DLL LoadILLTOF3 : public API::IFileLoader { +public: + /// Constructor + LoadILLTOF3(); + /// Algorithm's name + const std::string name() const override { return "LoadILLTOF"; } + /// Summary of algorithms purpose + const std::string summary() const override { return "Loads an ILL TOF NeXus file."; } + + /// Algorithm's version + int version() const override { return 3; } + const std::vector seeAlso() const override { return {"LoadNexus"}; } + /// Algorithm's category for identification + const std::string category() const override { return "DataHandling\\Nexus;ILL\\Direct"; } + + /// Returns a confidence value that this algorithm can load a file + int confidence(Kernel::NexusDescriptor &descriptor) const override; + +private: + // Initialisation code + void init() override; + // Execution code + void exec() override; + + void addAllNexusFieldsAsProperties(const std::string &filename); + void addEnergyToRun(); + void addFacility(); + void addPulseInterval(); + + void fillStaticWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList, bool convertToTOF); + void fillScanWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList); + + std::vector getMonitorInfo(const NeXus::NXEntry &firstEntry); + void initWorkspace(const NeXus::NXEntry &entry); + + void loadInstrumentDetails(const NeXus::NXEntry &); + void loadTimeDetails(const NeXus::NXEntry &entry); + + std::vector prepareAxis(const NeXus::NXEntry &entry, bool convertToTOF); + + API::MatrixWorkspace_sptr m_localWorkspace; + + std::string m_instrumentName; ///< Name of the instrument + std::string m_instrumentPath; ///< Name of the instrument path + + // Variables describing the data in the detector + size_t m_numberOfTubes; // number of tubes - X + size_t m_numberOfPixelsPerTube; // number of pixels per tube - Y + size_t m_numberOfChannels; // time channels - Z + size_t m_numberOfHistograms; // number of histograms (individual detectors) + size_t m_numberOfMonitors; // number of monitors + + // Values parsed from the nexus file + double m_wavelength; + double m_channelWidth; + double m_timeOfFlightDelay; + std::string m_monitorName; + bool m_isScan; // whether the loaded data is a scan measurement +}; + +} // namespace DataHandling +} // namespace Mantid diff --git a/Framework/DataHandling/src/LoadHelper.cpp b/Framework/DataHandling/src/LoadHelper.cpp index 777b987708f2..d55f20d78665 100644 --- a/Framework/DataHandling/src/LoadHelper.cpp +++ b/Framework/DataHandling/src/LoadHelper.cpp @@ -36,11 +36,13 @@ using namespace API; * Usually of the form: entry0/\/name */ std::string LoadHelper::findInstrumentNexusPath(const Mantid::NeXus::NXEntry &firstEntry) { + std::string result(""); std::vector v = firstEntry.groups(); const auto it = std::find_if(v.cbegin(), v.cend(), [](const auto &group) { return group.nxclass == "NXinstrument"; }); if (it != v.cend()) - return it->nxname; - return ""; + result = it->nxname; + + return result; } std::string LoadHelper::getStringFromNexusPath(const Mantid::NeXus::NXEntry &firstEntry, const std::string &nexusPath) { diff --git a/Framework/DataHandling/src/LoadILLTOF2.cpp b/Framework/DataHandling/src/LoadILLTOF2.cpp index 10fdf9976b6b..1253770e046f 100644 --- a/Framework/DataHandling/src/LoadILLTOF2.cpp +++ b/Framework/DataHandling/src/LoadILLTOF2.cpp @@ -15,23 +15,301 @@ #include "MantidDataHandling/LoadHelper.h" #include "MantidGeometry/Instrument.h" #include "MantidKernel/UnitFactory.h" -#include "MantidNexus/NeXusException.hpp" -#include "MantidNexus/NeXusFile.hpp" -#include "MantidNexus/NexusClasses.h" +#include "MantidLegacyNexus/NeXusException.hpp" +#include "MantidLegacyNexus/NeXusFile.hpp" +#include "MantidLegacyNexus/NexusClasses.h" namespace { /// An array containing the supported instrument names const std::array SUPPORTED_INSTRUMENTS = {{"IN4", "IN5", "IN6", "PANTHER", "SHARP"}}; + +/// static logger +Mantid::Kernel::Logger legacyhelperlog("LegacyLoadHelper"); + +const std::string NXINSTRUMENT("NXinstrument"); +const std::string SDS("SDS"); // denotes data field +const std::string EMPTY_STR(""); + } // namespace namespace Mantid::DataHandling { using namespace Kernel; using namespace API; -using namespace NeXus; +using namespace LegacyNexus; using namespace HistogramData; -DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF2) +DECLARE_LEGACY_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF2) + +namespace LegacyLoadHelper { // these methods are copied from LoadHelper +/** + * Finds the path for the instrument name in the nexus file + * Usually of the form: entry0/\/name + */ +std::string findInstrumentNexusPath(const NXEntry &firstEntry) { + std::string result(""); + std::vector v = firstEntry.groups(); + const auto it = std::find_if(v.cbegin(), v.cend(), [](const auto &group) { return group.nxclass == NXINSTRUMENT; }); + if (it != v.cend()) + result = it->nxname; + + return result; +} + +/** + * Fetches NXInt data from the requested group name in the entry provided. + * @param entry NXEntry where desired data can be found + * @param groupName Full name of the data group + * @return NXInt data object + */ +NXInt getIntDataset(const NXEntry &entry, const std::string &groupName) { + auto dataGroup = entry.openNXData(groupName); + return dataGroup.openIntData(); +} + +/** + * Fetches NXDouble data from the requested group name in the entry provided. + * @param entry NXEntry where desired data can be found + * @param groupName Full name of the data group + * @return NXDouble data object + */ +NXDouble getDoubleDataset(const NXEntry &entry, const std::string &groupName) { + auto dataGroup = entry.openNXData(groupName); + return dataGroup.openDoubleData(); +} + +/** + * Fills workspace with histogram data from provided data structure + * @param ws A MatrixWorkspace to be filled with data + * @param data Data object to extract counts from + * @param xAxis X axis values to be assigned to each spectrum + * @param initialSpectrum Initial spectrum number, optional and defaults to 0 + * @param pointData Switch to decide whether the data is going to be a histogram or point data, defaults to false + * (histogram) + * @param detectorIDs Vector of detector IDs to override the default spectrum number, defaults to empty (IDs equal to + * index) + * @param acceptedDetectorIDs Set of accepted detector IDs, defaults to empty (all accepted) + * @param axisOrder Tuple containing information at which position in data one can find tubes, pixels, and channels + * (scans), defaults to 0,1,2 meaning default order of tube-pixel-channel + */ +void fillStaticWorkspace(const API::MatrixWorkspace_sptr &ws, const NXInt &data, const std::vector &xAxis, + int64_t initialSpectrum = 0, bool pointData = false, + const std::vector &detectorIDs = std::vector(), + const std::set &acceptedDetectorIDs = std::set(), + const std::tuple &axisOrder = std::tuple(0, 1, 2)) { + const bool customDetectorIDs = detectorIDs.size() != 0; + const bool excludeDetectorIDs = acceptedDetectorIDs.size() != 0; + + std::array dims = {data.dim0(), data.dim1(), data.dim2()}; + const auto nTubes = dims[std::get<0>(axisOrder)]; + const auto nPixels = dims[std::get<1>(axisOrder)]; + const auto nChannels = dims[std::get<2>(axisOrder)]; + + int loadOrder[3] = {0, 1, 2}; + LoadHelper::loadingOrder(axisOrder, loadOrder); + + HistogramData::Points histoPoints; + HistogramData::BinEdges binEdges; + if (pointData) + histoPoints = HistogramData::Points(xAxis); + else + binEdges = HistogramData::BinEdges(xAxis); + int nSkipped = 0; + +#pragma omp parallel for if (!excludeDetectorIDs && Kernel::threadSafe(*ws)) + for (specnum_t tube_no = 0; tube_no < static_cast(nTubes); ++tube_no) { + for (specnum_t pixel_no = 0; pixel_no < nPixels; ++pixel_no) { + specnum_t currentSpectrum = + static_cast(initialSpectrum) + tube_no * static_cast(nPixels) + pixel_no; + if (excludeDetectorIDs != 0 && std::find(acceptedDetectorIDs.cbegin(), acceptedDetectorIDs.cend(), + currentSpectrum) == acceptedDetectorIDs.end()) { + nSkipped++; + continue; + } + currentSpectrum -= nSkipped; + + std::vector spectrum(nChannels); + for (auto channel_no = 0; channel_no < nChannels; ++channel_no) { + const int dataIndices[3] = {tube_no, pixel_no, channel_no}; + spectrum[channel_no] = data(dataIndices[loadOrder[0]], dataIndices[loadOrder[1]], dataIndices[loadOrder[2]]); + } + const HistogramData::Counts counts(spectrum.begin(), spectrum.end()); + const HistogramData::CountVariances countVariances(spectrum.begin(), spectrum.end()); + if (pointData) { + ws->setCounts(currentSpectrum, counts); + ws->setCountVariances(currentSpectrum, countVariances); + ws->setPoints(currentSpectrum, histoPoints); + } else { + ws->setHistogram(currentSpectrum, binEdges, counts); + } + const specnum_t detectorID = customDetectorIDs ? detectorIDs[currentSpectrum] : currentSpectrum; + ws->getSpectrum(currentSpectrum).setSpectrumNo(detectorID); + } + } +} + +template +void addNumericProperty(LegacyNexus::File &filehandle, const LegacyNexus::Info &nxinfo, + const std::string &property_name, API::Run &runDetails) { + if (!runDetails.hasProperty(property_name)) { + legacyhelperlog.warning() << "Property " << property_name + << " was set twice. Please check the Nexus file and your inputs."; + } + // this assumes all values are rank==1 + + // Look for "units" + std::string units; // empty string + if (filehandle.hasAttr("units")) + filehandle.getAttr("units", units); + + // read the field + std::vector data_vec; + data_vec.reserve(nxinfo.dims.front()); + filehandle.getDataCoerce(data_vec); + + // create the property on the run objects + const auto dim1size = data_vec.size(); + if (dim1size == 1) { + if (units.empty()) + runDetails.addProperty(property_name, data_vec.front()); + else + runDetails.addProperty(property_name, data_vec.front(), units); + } else { + // create a bunch of little properties + for (size_t index = 0; index < dim1size; ++index) { + const auto property_name_indexed = property_name + "_" + std::to_string(index); + if (units.empty()) + runDetails.addProperty(property_name_indexed, data_vec[index]); + else + runDetails.addProperty(property_name_indexed, data_vec[index], units); + } + } +} + +/** + * Recursively add properties from a nexus file to the workspace run. + * + * @param filehandle :: Nexus file handle to be parsed, just after an NXopengroup + * @param runDetails :: where to add properties + * @param parent_name :: nexus caller name + * @param parent_class :: nexus caller class + * @param level :: current level in nexus tree + */ +void recurseAndAddNexusFieldsToWsRun(LegacyNexus::File &filehandle, API::Run &runDetails, + const std::string &parent_name, const std::string &parent_class, int level) { + for (const auto &entry : filehandle.getEntries()) { + const auto nxname = entry.first; + const auto nxclass = entry.second; + if (nxclass == SDS) { + if ((parent_class != "NXData") && parent_class != "NXMonitor" && (nxname != "data")) { // create a property + filehandle.openData(nxname); + const auto nxinfo = filehandle.getInfo(); // get information about the open data + const auto rank = nxinfo.dims.size(); + + // Note, we choose to only build properties on small float arrays filter logic is below + bool read_property = (rank == 1); + switch (nxinfo.type) { + case (NXnumtype::CHAR): + break; // everything is fine + case (NXnumtype::FLOAT32): + case (NXnumtype::FLOAT64): + // some 1d float arrays may be loaded + read_property = (nxinfo.dims[0] <= 9); + break; + case (NXnumtype::INT16): + case (NXnumtype::INT32): + case (NXnumtype::UINT16): + // only read scalar values for everything else - e.g. integers + read_property = (nxinfo.dims.front() == 1); + break; + default: + read_property = false; + } + + if (read_property) { + // generate a name for the property + const std::string property_name = (parent_name.empty() ? nxname : parent_name + "." + nxname); + + switch (nxinfo.type) { + case (NXnumtype::CHAR): { + std::string property_value = filehandle.getStrData(); + if (property_name.ends_with("_time")) { + // That's a time value! Convert to Mantid standard + property_value = LoadHelper::dateTimeInIsoFormat(property_value); + if (runDetails.hasProperty(property_name)) + runDetails.getProperty(property_name)->setValue(property_value); + else + runDetails.addProperty(property_name, property_value); + } else { + if (!runDetails.hasProperty(property_name)) { + runDetails.addProperty(property_name, property_value); + } else { + legacyhelperlog.warning() + << "Property " << property_name << " was set twice. Please check the Nexus file and your inputs.\n"; + } + } + break; + } + case (NXnumtype::FLOAT32): + case (NXnumtype::FLOAT64): + addNumericProperty(filehandle, nxinfo, property_name, runDetails); + break; + case (NXnumtype::INT16): + case (NXnumtype::INT32): + case (NXnumtype::UINT16): + addNumericProperty(filehandle, nxinfo, property_name, runDetails); + break; + default: + std::stringstream msg; + msg << "Encountered unknown type: " << static_cast(nxinfo.type); + throw std::runtime_error(msg.str()); + break; + } + } + filehandle.closeData(); + } + } else { + if ((nxclass != "ILL_data_scan_vars") && (nxclass != "NXill_data_scan_vars")) { + // open the group and recurse down, if the group is known to nexus + filehandle.openGroup(nxname, nxclass); + + // current names can be useful for next level + recurseAndAddNexusFieldsToWsRun(filehandle, runDetails, nxname, nxclass, level + 1); + + filehandle.closeGroup(); + } + } + } +} + +/** + * Add properties from a nexus file to the workspace run. + * API entry for recursive routine below + * + * @param filehandle :: Nexus file handle to be parsed, just after an NXopengroup + * @param runDetails :: where to add properties + */ +void addNexusFieldsToWsRun(LegacyNexus::File &filehandle, API::Run &runDetails) { + // As a workaround against some "not so good" old ILL nexus files (ILLIN5_Vana_095893.nxs for example) by default we + // begin the parse on the first entry (entry0), or from a chosen entryName. This allow to avoid the bogus entries that + // follows + std::string entryNameActual(""); + try { + const auto entryNameAndClass = filehandle.getNextEntry(); + entryNameActual = entryNameAndClass.first; + } catch (const LegacyNexus::Exception &) { /* ignore */ + } + + // open the group and parse down + if (!entryNameActual.empty()) { + constexpr int LEVEL_RECURSE{1}; + filehandle.openGroup(entryNameActual, "NXentry"); + recurseAndAddNexusFieldsToWsRun(filehandle, runDetails, EMPTY_STR, EMPTY_STR, LEVEL_RECURSE); + filehandle.closeGroup(); + } +} + +} // namespace LegacyLoadHelper /** * Return the confidence with with this algorithm can load the file @@ -41,25 +319,25 @@ DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF2) * @return An integer specifying the confidence level. 0 indicates it will not * be used */ -int LoadILLTOF2::confidence(Kernel::NexusDescriptor &descriptor) const { +int LoadILLTOF2::confidence(Kernel::LegacyNexusDescriptor &descriptor) const { // fields existent only at the ILL - if ((descriptor.isEntry("/entry0/wavelength") && descriptor.isEntry("/entry0/experiment_identifier") && - descriptor.isEntry("/entry0/mode") && !descriptor.isEntry("/entry0/dataSD") // This one is for - // LoadILLIndirect - && !descriptor.isEntry("/entry0/instrument/VirtualChopper") // This one is for - // LoadILLReflectometry - && !descriptor.isEntry("/entry0/instrument/Tx")) // This eliminates SALSA data - || (descriptor.isEntry("/entry0/data_scan") && - descriptor.isEntry("/entry0/instrument/Detector")) // The last one is scan mode of PANTHER and SHARP + if ((descriptor.pathExists("/entry0/wavelength") && descriptor.pathExists("/entry0/experiment_identifier") && + descriptor.pathExists("/entry0/mode") && !descriptor.pathExists("/entry0/dataSD") // This one is for + // LoadILLIndirect + && !descriptor.pathExists("/entry0/instrument/VirtualChopper") // This one is for + // LoadILLReflectometry + && !descriptor.pathExists("/entry0/instrument/Tx")) // This eliminates SALSA data + || (descriptor.pathExists("/entry0/data_scan") && + descriptor.pathExists("/entry0/instrument/Detector")) // The last one is scan mode of PANTHER and SHARP ) { - return 80; + return 79; // return 79 since LoadILLTOF3 will return 80 if file is hdf5 based } else { return 0; } } -LoadILLTOF2::LoadILLTOF2() : API::IFileLoader() {} +LoadILLTOF2::LoadILLTOF2() : API::IFileLoader() {} /** * Initialises the algorithm @@ -82,7 +360,7 @@ void LoadILLTOF2::exec() { bool convertToTOF = getProperty("convertToTOF"); // open the root node - NeXus::NXRoot dataRoot(filenameData); + LegacyNexus::NXRoot dataRoot(filenameData); NXEntry dataFirstEntry = dataRoot.openFirstEntry(); m_isScan = dataFirstEntry.containsGroup("data_scan"); @@ -116,7 +394,7 @@ void LoadILLTOF2::exec() { * * @return List of monitor data */ -std::vector LoadILLTOF2::getMonitorInfo(const NeXus::NXEntry &firstEntry) { +std::vector LoadILLTOF2::getMonitorInfo(const LegacyNexus::NXEntry &firstEntry) { std::vector monitorList; if (m_isScan) { // in case of a scan, there is only one monitor and its data are stored per scan step @@ -140,15 +418,15 @@ std::vector LoadILLTOF2::getMonitorInfo(const NeXus::NXEntry &first * * @param firstEntry The NeXus entry */ -void LoadILLTOF2::loadInstrumentDetails(const NeXus::NXEntry &firstEntry) { +void LoadILLTOF2::loadInstrumentDetails(const LegacyNexus::NXEntry &firstEntry) { - m_instrumentPath = LoadHelper::findInstrumentNexusPath(firstEntry); + m_instrumentPath = LegacyLoadHelper::findInstrumentNexusPath(firstEntry); if (m_instrumentPath.empty()) { throw std::runtime_error("Cannot set the instrument name from the Nexus file!"); } - m_instrumentName = LoadHelper::getStringFromNexusPath(firstEntry, m_instrumentPath + "/name"); + m_instrumentName = firstEntry.getString(m_instrumentPath + "/name"); if (std::find(SUPPORTED_INSTRUMENTS.begin(), SUPPORTED_INSTRUMENTS.end(), m_instrumentName) == SUPPORTED_INSTRUMENTS.end()) { @@ -175,11 +453,11 @@ void LoadILLTOF2::loadInstrumentDetails(const NeXus::NXEntry &firstEntry) { * * @param entry The NeXus entry */ -void LoadILLTOF2::initWorkspace(const NeXus::NXEntry &entry) { +void LoadILLTOF2::initWorkspace(const LegacyNexus::NXEntry &entry) { // read in the data const std::string dataName = m_isScan ? "data_scan/detector_data/data" : "data"; - auto data = LoadHelper::getIntDataset(entry, dataName); + auto data = LegacyLoadHelper::getIntDataset(entry, dataName); // default order is: tubes - pixels - channels, but for scans it is scans - tubes - pixels m_numberOfTubes = static_cast(m_isScan ? data.dim1() : data.dim0()); @@ -191,7 +469,7 @@ void LoadILLTOF2::initWorkspace(const NeXus::NXEntry &entry) { */ size_t numberOfTubesInRosace = 0; if (m_instrumentName == "IN4") { - auto dataRosace = LoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data"); + auto dataRosace = LegacyLoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data"); numberOfTubesInRosace += static_cast(dataRosace.dim0()); } @@ -229,11 +507,11 @@ void LoadILLTOF2::initWorkspace(const NeXus::NXEntry &entry) { * * @param entry :: The Nexus entry */ -void LoadILLTOF2::loadTimeDetails(const NeXus::NXEntry &entry) { +void LoadILLTOF2::loadTimeDetails(const LegacyNexus::NXEntry &entry) { m_wavelength = entry.getFloat("wavelength"); - NeXus::NXClass monitorEntry = entry.openNXGroup(m_monitorName); + LegacyNexus::NXClass monitorEntry = entry.openNXGroup(m_monitorName); if (monitorEntry.containsDataSet("time_of_flight")) { @@ -265,9 +543,9 @@ void LoadILLTOF2::addAllNexusFieldsAsProperties(const std::string &filename) { // Open NeXus file try { - ::NeXus::File nxfileID(filename, NXACC_READ); - LoadHelper::addNexusFieldsToWsRun(nxfileID, runDetails); - } catch (const ::NeXus::Exception &) { + LegacyNexus::File nxfileID(filename, NXACC_READ); + LegacyLoadHelper::addNexusFieldsToWsRun(nxfileID, runDetails); + } catch (const LegacyNexus::Exception &) { g_log.debug() << "convertNexusToProperties: Error loading " << filename; throw Kernel::Exception::FileError("Unable to open File:", filename); } @@ -332,7 +610,7 @@ void LoadILLTOF2::addPulseInterval() { * @param convertToTOF Should the bin edges be converted to time of flight or keep the channel indices * @return Vector of doubles containing bin edges or point centres positions */ -std::vector LoadILLTOF2::prepareAxis(const NeXus::NXEntry &entry, bool convertToTOF) { +std::vector LoadILLTOF2::prepareAxis(const LegacyNexus::NXEntry &entry, bool convertToTOF) { std::vector xAxis(m_localWorkspace->readX(0).size()); if (m_isScan) { @@ -346,7 +624,7 @@ std::vector LoadILLTOF2::prepareAxis(const NeXus::NXEntry &entry, bool c break; } } - auto axis = LoadHelper::getDoubleDataset(entry, "data_scan/scanned_variables/data"); + auto axis = LegacyLoadHelper::getDoubleDataset(entry, "data_scan/scanned_variables/data"); axis.load(); for (int index = 0; index < axis.dim1(); index++) { xAxis[index] = axis(scannedVarId, index); @@ -381,7 +659,7 @@ std::vector LoadILLTOF2::prepareAxis(const NeXus::NXEntry &entry, bool c * @param convertToTOF Should the bin edges be converted to time of flight or * keep the channel indexes */ -void LoadILLTOF2::fillStaticWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList, +void LoadILLTOF2::fillStaticWorkspace(const LegacyNexus::NXEntry &entry, const std::vector &monitorList, bool convertToTOF) { g_log.debug() << "Loading data into the workspace...\n"; @@ -393,10 +671,10 @@ void LoadILLTOF2::fillStaticWorkspace(const NeXus::NXEntry &entry, const std::ve int64_t spec = 0; std::vector detectorIDs = m_localWorkspace->getInstrument()->getDetectorIDs(false); - auto data = LoadHelper::getIntDataset(entry, "data"); + auto data = LegacyLoadHelper::getIntDataset(entry, "data"); data.load(); - LoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, spec, false, detectorIDs); + LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, spec, false, detectorIDs); spec = static_cast(m_numberOfTubes * m_numberOfPixelsPerTube); // IN4 Rosace detectors are in a different NeXus entry @@ -404,17 +682,17 @@ void LoadILLTOF2::fillStaticWorkspace(const NeXus::NXEntry &entry, const std::ve g_log.debug() << "Loading data into the workspace: IN4 Rosace!\n"; // read in the data // load the counts from the file into memory - auto dataRosace = LoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data"); + auto dataRosace = LegacyLoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data"); dataRosace.load(); - LoadHelper::fillStaticWorkspace(m_localWorkspace, dataRosace, xAxis, spec, false, detectorIDs); + LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, dataRosace, xAxis, spec, false, detectorIDs); spec += dataRosace.dim0(); } for (const auto &monitorName : monitorList) { detectorIDs[spec] = static_cast(spec) + 1; - auto monitorData = LoadHelper::getIntDataset(entry, monitorName); + auto monitorData = LegacyLoadHelper::getIntDataset(entry, monitorName); monitorData.load(); - LoadHelper::fillStaticWorkspace(m_localWorkspace, monitorData, xAxis, spec, false, detectorIDs); + LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, monitorData, xAxis, spec, false, detectorIDs); spec++; } } @@ -424,21 +702,21 @@ void LoadILLTOF2::fillStaticWorkspace(const NeXus::NXEntry &entry, const std::ve * @param entry The Nexus entry to load the data from * @param monitorList Vector containing paths to monitor data */ -void LoadILLTOF2::fillScanWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList) { +void LoadILLTOF2::fillScanWorkspace(const LegacyNexus::NXEntry &entry, const std::vector &monitorList) { // Prepare X-axis array auto xAxis = prepareAxis(entry, false); - auto data = LoadHelper::getIntDataset(entry, "data_scan/detector_data/data"); + auto data = LegacyLoadHelper::getIntDataset(entry, "data_scan/detector_data/data"); data.load(); // Load scan data const std::vector detectorIDs = m_localWorkspace->getInstrument()->getDetectorIDs(false); const std::tuple dimOrder{1, 2, 0}; - LoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, 0, true, detectorIDs, std::set(), dimOrder); + LegacyLoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, 0, true, detectorIDs, std::set(), dimOrder); // Load monitor data, there is only one monitor const std::vector monitorIDs = m_localWorkspace->getInstrument()->getMonitors(); const auto spectrumNo = data.dim1() * data.dim2(); - auto monitorData = LoadHelper::getDoubleDataset(entry, monitorList[0]); + auto monitorData = LegacyLoadHelper::getDoubleDataset(entry, monitorList[0]); monitorData.load(); for (int index = 0; index < monitorData.dim1(); index++) { // monitor is always the 4th row, if that ever changes, a name search for 'monitor1' would be necessary among diff --git a/Framework/DataHandling/src/LoadILLTOF3.cpp b/Framework/DataHandling/src/LoadILLTOF3.cpp new file mode 100644 index 000000000000..335e9af4db3d --- /dev/null +++ b/Framework/DataHandling/src/LoadILLTOF3.cpp @@ -0,0 +1,454 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2025 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#include "MantidDataHandling/LoadILLTOF3.h" + +#include "MantidAPI/Axis.h" +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/RegisterFileLoader.h" +#include "MantidAPI/Run.h" +#include "MantidAPI/WorkspaceFactory.h" +#include "MantidDataHandling/LoadHelper.h" +#include "MantidGeometry/Instrument.h" +#include "MantidKernel/UnitFactory.h" +#include "MantidNexus/NeXusException.hpp" +#include "MantidNexus/NeXusFile.hpp" + +namespace { +/// An array containing the supported instrument names +const std::array SUPPORTED_INSTRUMENTS = {{"IN4", "IN5", "IN6", "PANTHER", "SHARP"}}; +} // namespace + +namespace Mantid::DataHandling { + +using namespace Kernel; +using namespace API; +using namespace NeXus; +using namespace HistogramData; + +DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadILLTOF3) + +/** + * Return the confidence with with this algorithm can load the file + * + * @param descriptor A descriptor for the file + * + * @return An integer specifying the confidence level. 0 indicates it will not + * be used + */ +int LoadILLTOF3::confidence(Kernel::NexusDescriptor &descriptor) const { + + // fields existent only at the ILL + if ((descriptor.isEntry("/entry0/wavelength") && descriptor.isEntry("/entry0/experiment_identifier") && + descriptor.isEntry("/entry0/mode") && !descriptor.isEntry("/entry0/dataSD") // This one is for + // LoadILLIndirect + && !descriptor.isEntry("/entry0/instrument/VirtualChopper") // This one is for + // LoadILLReflectometry + && !descriptor.isEntry("/entry0/instrument/Tx")) // This eliminates SALSA data + || (descriptor.isEntry("/entry0/data_scan") && + descriptor.isEntry("/entry0/instrument/Detector")) // The last one is scan mode of PANTHER and SHARP + ) { + return 80; + } else { + return 0; + } +} + +LoadILLTOF3::LoadILLTOF3() : API::IFileLoader() {} + +/** + * Initialises the algorithm + */ +void LoadILLTOF3::init() { + declareProperty(std::make_unique("Filename", "", FileProperty::Load, ".nxs"), + "File path of the Data file to load"); + + declareProperty(std::make_unique>("OutputWorkspace", "", Direction::Output), + "The name to use for the output workspace"); + declareProperty("ConvertToTOF", false, "Convert the bin edges to time-of-flight", Direction::Input); +} + +/** + * Executes the algorithm + */ +void LoadILLTOF3::exec() { + // Retrieve filename + const std::string filenameData = getPropertyValue("Filename"); + bool convertToTOF = getProperty("convertToTOF"); + + // open the root node + NeXus::NXRoot dataRoot(filenameData); + NXEntry dataFirstEntry = dataRoot.openFirstEntry(); + m_isScan = dataFirstEntry.containsGroup("data_scan"); + + loadInstrumentDetails(dataFirstEntry); + loadTimeDetails(dataFirstEntry); + + const auto monitorList = getMonitorInfo(dataFirstEntry); + initWorkspace(dataFirstEntry); + + addAllNexusFieldsAsProperties(filenameData); + addFacility(); + // load the instrument from the IDF if it exists + LoadHelper::loadEmptyInstrument(m_localWorkspace, m_instrumentName); + + if (m_isScan) { + fillScanWorkspace(dataFirstEntry, monitorList); + } else { + fillStaticWorkspace(dataFirstEntry, monitorList, convertToTOF); + } + addEnergyToRun(); + addPulseInterval(); + + // Set the output workspace property + setProperty("OutputWorkspace", m_localWorkspace); +} + +/** + * Finds monitor data names and stores them in a vector + * + * @param firstEntry The NeXus entry + * + * @return List of monitor data + */ +std::vector LoadILLTOF3::getMonitorInfo(const NeXus::NXEntry &firstEntry) { + std::vector monitorList; + if (m_isScan) { + // in case of a scan, there is only one monitor and its data are stored per scan step + // in "data_scan/scanned_variables/data", if that changes, a search for the "monitor" name + // may be required in the "data_scan/scanned_variables/variables_names" + monitorList.push_back("data_scan/scanned_variables/data"); + } else { + for (std::vector::const_iterator it = firstEntry.groups().begin(); it != firstEntry.groups().end(); + ++it) { + if (it->nxclass == "NXmonitor" || it->nxname.starts_with("monitor")) { + monitorList.push_back(it->nxname + "/data"); + } + } + } + m_numberOfMonitors = monitorList.size(); + return monitorList; +} + +/** + * Sets the instrument name along with its path in the nexus file + * + * @param firstEntry The NeXus entry + */ +void LoadILLTOF3::loadInstrumentDetails(const NeXus::NXEntry &firstEntry) { + + m_instrumentPath = LoadHelper::findInstrumentNexusPath(firstEntry); + + if (m_instrumentPath.empty()) { + throw std::runtime_error("Cannot set the instrument name from the Nexus file!"); + } + + m_instrumentName = LoadHelper::getStringFromNexusPath(firstEntry, m_instrumentPath + "/name"); + + if (std::find(SUPPORTED_INSTRUMENTS.begin(), SUPPORTED_INSTRUMENTS.end(), m_instrumentName) == + SUPPORTED_INSTRUMENTS.end()) { + std::string message = "The instrument " + m_instrumentName + " is not valid for this loader!"; + throw std::runtime_error(message); + } + + // Monitor can be monitor (IN5, PANTHER) or monitor1 (IN6) + if (firstEntry.containsGroup("monitor")) + m_monitorName = "monitor"; + else if (firstEntry.containsGroup("monitor1")) + m_monitorName = "monitor1"; + else { + std::string message("Cannot find monitor[1] in the Nexus file!"); + throw std::runtime_error(message); + } + + g_log.debug() << "Instrument name set to: " + m_instrumentName << '\n'; +} + +/** + * Creates the workspace and initialises member variables with + * the corresponding values + * + * @param entry The NeXus entry + */ +void LoadILLTOF3::initWorkspace(const NeXus::NXEntry &entry) { + + // read in the data + const std::string dataName = m_isScan ? "data_scan/detector_data/data" : "data"; + auto data = LoadHelper::getIntDataset(entry, dataName); + + // default order is: tubes - pixels - channels, but for scans it is scans - tubes - pixels + m_numberOfTubes = static_cast(m_isScan ? data.dim1() : data.dim0()); + m_numberOfPixelsPerTube = static_cast(m_isScan ? data.dim2() : data.dim1()); + m_numberOfChannels = static_cast(m_isScan ? data.dim0() : data.dim2()); + + /** + * IN4 : Rosace detector is in a different field. + */ + size_t numberOfTubesInRosace = 0; + if (m_instrumentName == "IN4") { + auto dataRosace = LoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data"); + numberOfTubesInRosace += static_cast(dataRosace.dim0()); + } + + // dim0 * m_numberOfPixelsPerTube is the total number of detectors + m_numberOfHistograms = (m_numberOfTubes + numberOfTubesInRosace) * m_numberOfPixelsPerTube; + + g_log.debug() << "NumberOfTubes: " << m_numberOfTubes << '\n'; + g_log.debug() << "NumberOfPixelsPerTube: " << m_numberOfPixelsPerTube << '\n'; + g_log.debug() << "NumberOfChannels: " << m_numberOfChannels << '\n'; + + // Now create the output workspace + // total number of spectra + number of monitors, + // bin boundaries = m_numberOfChannels + 1 if diffraction or TOF mode, m_numberOfChannels for scans + // Z/time dimension + const auto numberOfChannels = m_isScan ? m_numberOfChannels : m_numberOfChannels + 1; + m_localWorkspace = WorkspaceFactory::Instance().create("Workspace2D", m_numberOfHistograms + m_numberOfMonitors, + numberOfChannels, m_numberOfChannels); + if (m_isScan) { + m_localWorkspace->setYUnitLabel("Counts"); + } else { + NXClass monitor = entry.openNXGroup(m_monitorName); + if (monitor.containsDataSet("time_of_flight")) { + m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("TOF"); + m_localWorkspace->setYUnitLabel("Counts"); + } else { + g_log.debug("PANTHER diffraction mode"); + m_localWorkspace->getAxis(0)->unit() = UnitFactory::Instance().create("Wavelength"); + m_localWorkspace->setYUnitLabel("Counts"); + } + } +} + +/** + * Load the time details from the nexus file. + * + * @param entry :: The Nexus entry + */ +void LoadILLTOF3::loadTimeDetails(const NeXus::NXEntry &entry) { + + m_wavelength = entry.getFloat("wavelength"); + + NeXus::NXClass monitorEntry = entry.openNXGroup(m_monitorName); + + if (monitorEntry.containsDataSet("time_of_flight")) { + + NXFloat time_of_flight_data = entry.openNXFloat(m_monitorName + "/time_of_flight"); + time_of_flight_data.load(); + + // The entry "monitor/time_of_flight", has 3 fields: + // channel width , number of channels, Time of flight delay + m_channelWidth = time_of_flight_data[0]; + m_timeOfFlightDelay = time_of_flight_data[2]; + + g_log.debug("Nexus Data:"); + g_log.debug() << " ChannelWidth: " << m_channelWidth << '\n'; + g_log.debug() << " TimeOfFlightDelay: " << m_timeOfFlightDelay << '\n'; + g_log.debug() << " Wavelength: " << m_wavelength << '\n'; + } // the other case is the diffraction mode for PANTHER, where nothing is + // needed here +} + +/** + * Goes through all the fields of the NeXus file and adds them + * as parameters in the workspace + * + * @param filename The NeXus file + */ +void LoadILLTOF3::addAllNexusFieldsAsProperties(const std::string &filename) { + + API::Run &runDetails = m_localWorkspace->mutableRun(); + + // Open NeXus file + try { + ::NeXus::File nxfileID(filename, NXACC_READ); + LoadHelper::addNexusFieldsToWsRun(nxfileID, runDetails); + } catch (const ::NeXus::Exception &) { + g_log.debug() << "convertNexusToProperties: Error loading " << filename; + throw Kernel::Exception::FileError("Unable to open File:", filename); + } + + runDetails.addProperty("run_list", runDetails.getPropertyValueAsType("run_number")); + g_log.debug() << "End parsing properties from : " << filename << '\n'; +} + +/** + * Calculates the incident energy from the wavelength and adds + * it as sample log 'Ei' + */ +void LoadILLTOF3::addEnergyToRun() { + + API::Run &runDetails = m_localWorkspace->mutableRun(); + const double ei = LoadHelper::calculateEnergy(m_wavelength); + runDetails.addProperty("Ei", ei, true); // overwrite +} + +/** + * Adds facility info to the sample logs + */ +void LoadILLTOF3::addFacility() { + API::Run &runDetails = m_localWorkspace->mutableRun(); + runDetails.addProperty("Facility", std::string("ILL")); +} + +/** + * Calculates and adds the pulse intervals for the run + */ +void LoadILLTOF3::addPulseInterval() { + API::Run &runDetails = m_localWorkspace->mutableRun(); + double n_pulses = -1; + double fermiChopperSpeed = -1; + + if (m_instrumentName == "IN4") { + fermiChopperSpeed = runDetails.getPropertyAsSingleValue("FC.rotation_speed"); + const double bkgChopper1Speed = runDetails.getPropertyAsSingleValue("BC1.rotation_speed"); + const double bkgChopper2Speed = runDetails.getPropertyAsSingleValue("BC2.rotation_speed"); + + if (std::abs(bkgChopper1Speed - bkgChopper2Speed) > 1) { + throw std::invalid_argument("Background choppers 1 and 2 have different speeds"); + } + + n_pulses = fermiChopperSpeed / bkgChopper1Speed / 4; + } else if (m_instrumentName == "IN6") { + fermiChopperSpeed = runDetails.getPropertyAsSingleValue("Fermi.rotation_speed"); + const double suppressorSpeed = runDetails.getPropertyAsSingleValue("Suppressor.rotation_speed"); + + n_pulses = fermiChopperSpeed / suppressorSpeed; + } else { + return; + } + + const double pulseInterval = 60.0 / (2 * fermiChopperSpeed) * n_pulses; + runDetails.addProperty("pulse_interval", pulseInterval); +} + +/** + * Prepares X axis for the workspace being loaded + * @param entry NeXus entry used to get scanned parameter values in the scan case + * @param convertToTOF Should the bin edges be converted to time of flight or keep the channel indices + * @return Vector of doubles containing bin edges or point centres positions + */ +std::vector LoadILLTOF3::prepareAxis(const NeXus::NXEntry &entry, bool convertToTOF) { + + std::vector xAxis(m_localWorkspace->readX(0).size()); + if (m_isScan) { + // read which variable is going to be the axis + NXInt scannedAxis = entry.openNXInt("data_scan/scanned_variables/variables_names/axis"); + scannedAxis.load(); + int scannedVarId = 0; + for (int index = 0; index < scannedAxis.dim0(); index++) { + if (scannedAxis[index] == 1) { + scannedVarId = index; + break; + } + } + auto axis = LoadHelper::getDoubleDataset(entry, "data_scan/scanned_variables/data"); + axis.load(); + for (int index = 0; index < axis.dim1(); index++) { + xAxis[index] = axis(scannedVarId, index); + } + } else { + NXClass moni = entry.openNXGroup(m_monitorName); + if (moni.containsDataSet("time_of_flight")) { + if (convertToTOF) { + for (size_t i = 0; i < m_numberOfChannels + 1; ++i) { + xAxis[i] = m_timeOfFlightDelay + m_channelWidth * static_cast(i) + + m_channelWidth / 2; // to make sure the bin centre is positive + } + } else { + for (size_t i = 0; i < m_numberOfChannels + 1; ++i) { + xAxis[i] = static_cast(i); // just take the channel index + } + } + } else { + // Diffraction PANTHER + xAxis[0] = m_wavelength * 0.9; + xAxis[1] = m_wavelength * 1.1; + } + } + return xAxis; +} + +/** + * Fills the non-scan measurement data into the workspace, including that from the monitor + * + * @param entry The Nexus entry + * @param monitorList Vector containing paths to monitor data + * @param convertToTOF Should the bin edges be converted to time of flight or + * keep the channel indexes + */ +void LoadILLTOF3::fillStaticWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList, + bool convertToTOF) { + + g_log.debug() << "Loading data into the workspace...\n"; + + // Prepare X-axis array + auto xAxis = prepareAxis(entry, convertToTOF); + + // The binning for monitors is considered the same as for detectors + int64_t spec = 0; + std::vector detectorIDs = m_localWorkspace->getInstrument()->getDetectorIDs(false); + + auto data = LoadHelper::getIntDataset(entry, "data"); + data.load(); + + LoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, spec, false, detectorIDs); + spec = static_cast(m_numberOfTubes * m_numberOfPixelsPerTube); + + // IN4 Rosace detectors are in a different NeXus entry + if (m_instrumentName == "IN4") { + g_log.debug() << "Loading data into the workspace: IN4 Rosace!\n"; + // read in the data + // load the counts from the file into memory + auto dataRosace = LoadHelper::getIntDataset(entry, "instrument/Detector_Rosace/data"); + dataRosace.load(); + LoadHelper::fillStaticWorkspace(m_localWorkspace, dataRosace, xAxis, spec, false, detectorIDs); + spec += dataRosace.dim0(); + } + + for (const auto &monitorName : monitorList) { + detectorIDs[spec] = static_cast(spec) + 1; + auto monitorData = LoadHelper::getIntDataset(entry, monitorName); + monitorData.load(); + LoadHelper::fillStaticWorkspace(m_localWorkspace, monitorData, xAxis, spec, false, detectorIDs); + spec++; + } +} + +/** + * Fills scan workspace with data and monitor data counts + * @param entry The Nexus entry to load the data from + * @param monitorList Vector containing paths to monitor data + */ +void LoadILLTOF3::fillScanWorkspace(const NeXus::NXEntry &entry, const std::vector &monitorList) { + // Prepare X-axis array + auto xAxis = prepareAxis(entry, false); + auto data = LoadHelper::getIntDataset(entry, "data_scan/detector_data/data"); + data.load(); + + // Load scan data + const std::vector detectorIDs = m_localWorkspace->getInstrument()->getDetectorIDs(false); + const std::tuple dimOrder{1, 2, 0}; + LoadHelper::fillStaticWorkspace(m_localWorkspace, data, xAxis, 0, true, detectorIDs, std::set(), dimOrder); + + // Load monitor data, there is only one monitor + const std::vector monitorIDs = m_localWorkspace->getInstrument()->getMonitors(); + const auto spectrumNo = data.dim1() * data.dim2(); + auto monitorData = LoadHelper::getDoubleDataset(entry, monitorList[0]); + monitorData.load(); + for (int index = 0; index < monitorData.dim1(); index++) { + // monitor is always the 4th row, if that ever changes, a name search for 'monitor1' would be necessary among + // scanned_variables + const auto counts = monitorData(3, index); + m_localWorkspace->mutableY(spectrumNo)[index] = counts; + m_localWorkspace->mutableE(spectrumNo)[index] = sqrt(counts); + m_localWorkspace->mutableX(spectrumNo)[index] = xAxis[index]; + } + // finally, we need to set the correct detector ID for the monitor + m_localWorkspace->getSpectrum(spectrumNo).setDetectorID(monitorIDs[0]); +} + +} // namespace Mantid::DataHandling diff --git a/Framework/DataHandling/src/LoadNexus.cpp b/Framework/DataHandling/src/LoadNexus.cpp index 27c073d0d859..4bce3c096ceb 100644 --- a/Framework/DataHandling/src/LoadNexus.cpp +++ b/Framework/DataHandling/src/LoadNexus.cpp @@ -18,9 +18,9 @@ #include "MantidDataObjects/Workspace2D.h" #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/BoundedValidator.h" -#include "MantidNexus/NeXusException.hpp" -#include "MantidNexus/NeXusFile.hpp" -#include "MantidNexus/NexusClasses.h" +#include "MantidLegacyNexus/NeXusException.hpp" +#include "MantidLegacyNexus/NeXusFile.hpp" +#include "MantidLegacyNexus/NexusClasses.h" #include #include @@ -100,10 +100,10 @@ void LoadNexus::exec() { } else if (entryName[0] == "raw_data_1") { runLoadIsisNexus(); } else { - Mantid::NeXus::NXRoot root(m_filename); - Mantid::NeXus::NXEntry entry = root.openEntry(root.groups().front().nxname); + Mantid::LegacyNexus::NXRoot root(m_filename); + Mantid::LegacyNexus::NXEntry entry = root.openEntry(root.groups().front().nxname); try { - Mantid::NeXus::NXChar nxc = entry.openNXChar("instrument/SNSdetector_calibration_id"); + Mantid::LegacyNexus::NXChar nxc = entry.openNXChar("instrument/SNSdetector_calibration_id"); } catch (...) { g_log.error("File " + m_filename + " is a currently unsupported type of NeXus file"); throw Exception::FileError("Unable to read File:", m_filename); @@ -274,11 +274,11 @@ void LoadNexus::setOutputWorkspace(const API::IAlgorithm_sptr &loader) { */ int LoadNexus::getNexusEntryTypes(const std::string &fileName, std::vector &entryName, std::vector &definition) { - std::unique_ptr<::NeXus::File> fileH; + std::unique_ptr fileH; try { - fileH = std::make_unique<::NeXus::File>(fileName); - } catch (::NeXus::Exception &) { + fileH = std::make_unique(fileName); + } catch (Mantid::LegacyNexus::Exception &) { return -1; } entryName.clear(); @@ -293,7 +293,7 @@ int LoadNexus::getNexusEntryTypes(const std::string &fileName, std::vector entry; while (true) { entry = fileH->getNextEntry(); - if (entry == ::NeXus::EOD_ENTRY) + if (entry == LegacyNexus::EOD_ENTRY) break; if (entry.second == "NXentry") @@ -308,7 +308,7 @@ int LoadNexus::getNexusEntryTypes(const std::string &fileName, std::vectorgetNextEntry(); - if (entry == ::NeXus::EOD_ENTRY) + if (entry == LegacyNexus::EOD_ENTRY) break; // if a data field if (entry.second == "SDS") { diff --git a/Framework/DataHandling/test/LoadDetectorInfoTest.h b/Framework/DataHandling/test/LoadDetectorInfoTest.h index 79744665ba73..857c4b8cc30d 100644 --- a/Framework/DataHandling/test/LoadDetectorInfoTest.h +++ b/Framework/DataHandling/test/LoadDetectorInfoTest.h @@ -262,7 +262,7 @@ class LoadDetectorInfoTest : public CxxTest::TestSuite { makeTestWorkspace(SmallTestDatFile::NDETECTS, NBINS, m_InoutWS); loadDetInfo.setPropertyValue("Workspace", m_InoutWS); - loadDetInfo.setPropertyValue("DataFilename", "argus0026287.nxs"); + loadDetInfo.setPropertyValue("DataFilename", "ARGUS00073601.nxs"); TS_ASSERT_THROWS(loadDetInfo.execute(), const std::invalid_argument &); AnalysisDataService::Instance().remove(m_InoutWS); diff --git a/Framework/DataHandling/test/LoadILLTOF2Test.h b/Framework/DataHandling/test/LoadILLTOF2Test.h index 466752673530..a6086a48045f 100644 --- a/Framework/DataHandling/test/LoadILLTOF2Test.h +++ b/Framework/DataHandling/test/LoadILLTOF2Test.h @@ -84,7 +84,7 @@ class LoadILLTOF2Test : public CxxTest::TestSuite { if (convertToTOF) { for (size_t channelIndex = 0; channelIndex != xs.size(); ++channelIndex) { const double binEdge = tofDelay + static_cast(channelIndex) * tofChannelWidth + tofChannelWidth / 2; - TS_ASSERT_DELTA(xs[channelIndex], binEdge, 1e-3) + TS_ASSERT_DELTA(xs[channelIndex], binEdge, 1e-3); } } else { for (size_t channelIndex = 0; channelIndex != xs.size(); ++channelIndex) { @@ -130,7 +130,7 @@ class LoadILLTOF2Test : public CxxTest::TestSuite { TS_ASSERT_EQUALS(runList->value(), "84446") } - void test_IN5_load() { + void test_IN5_hdf5_load() { // From the input test file. const double tofDelay = 5982.856; const double tofChannelWidth = 14.6349; @@ -143,7 +143,23 @@ class LoadILLTOF2Test : public CxxTest::TestSuite { auto const run = ws->run(); TS_ASSERT(run.hasProperty("run_list")) const auto runList = run.getLogData("run_list"); - TS_ASSERT_EQUALS(runList->value(), "104007") + TS_ASSERT_EQUALS(runList->value(), "104007"); + } + + void test_IN5_hdf4_load() { + // From the input test file. + const double tofDelay = 5129.9414; // ? + const double tofChannelWidth = 6.9084; // ? + const size_t channelCount = 1024; + const size_t histogramCount = 98305; + const size_t monitorCount = 1; + const bool convertToTOF = true; + MatrixWorkspace_sptr ws = loadDataFile("ILL/IN5/095893.nxs", histogramCount, monitorCount, channelCount, tofDelay, + tofChannelWidth, convertToTOF); + auto const run = ws->run(); + TS_ASSERT(run.hasProperty("run_list")) + const auto runList = run.getLogData("run_list"); + TS_ASSERT_EQUALS(runList->value(), "95893"); } void test_IN6_load() { diff --git a/Framework/DataHandling/test/LoadILLTOF3Test.h b/Framework/DataHandling/test/LoadILLTOF3Test.h new file mode 100644 index 000000000000..803acf6b2de1 --- /dev/null +++ b/Framework/DataHandling/test/LoadILLTOF3Test.h @@ -0,0 +1,443 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2025 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#pragma once + +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/Run.h" +#include "MantidAPI/SpectrumInfo.h" +#include "MantidDataHandling/LoadILLTOF3.h" +#include "MantidGeometry/Instrument/DetectorInfo.h" +#include "MantidTypes/Core/DateAndTimeHelpers.h" + +#include + +using namespace Mantid::API; +using Mantid::DataHandling::LoadILLTOF3; + +class LoadILLTOF3Test : public CxxTest::TestSuite { +public: + // This pair of boilerplate methods prevent the suite being created statically + // This means the constructor isn't called when running other tests + static LoadILLTOF3Test *createSuite() { return new LoadILLTOF3Test(); } + static void destroySuite(LoadILLTOF3Test *suite) { delete suite; } + + void tearDown() override { AnalysisDataService::Instance().clear(); } + + void testName() { + LoadILLTOF3 loader; + TS_ASSERT_EQUALS(loader.name(), "LoadILLTOF") + } + + void testVersion() { + LoadILLTOF3 loader; + TS_ASSERT_EQUALS(loader.version(), 3) + } + + void testInit() { + LoadILLTOF3 loader; + loader.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(loader.initialize()) + TS_ASSERT(loader.isInitialized()) + } + + /* + * This test only loads the Sample Data + * The elastic peak is obtained on the fly from the sample data. + */ + MatrixWorkspace_sptr loadDataFile(const std::string &dataFile, const size_t numberOfHistograms, + const size_t numberOfMonitors, const size_t numberOfChannels, const double tofDelay, + const double tofChannelWidth, const bool convertToTOF) { + LoadILLTOF3 loader; + loader.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(loader.initialize()) + TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", dataFile)) + TS_ASSERT_THROWS_NOTHING(loader.setProperty("convertToTOF", convertToTOF)) + + std::string outputSpace = "LoadILLTOFTest_out"; + TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("OutputWorkspace", outputSpace)) + TS_ASSERT_THROWS_NOTHING(loader.execute()) + + MatrixWorkspace_sptr output = AnalysisDataService::Instance().retrieveWS(outputSpace); + + TS_ASSERT(output->run().hasProperty("start_time")); + TS_ASSERT( + Mantid::Types::Core::DateAndTimeHelpers::stringIsISO8601(output->run().getProperty("start_time")->value())); + + TS_ASSERT_EQUALS(output->getNumberHistograms(), numberOfHistograms) + const auto &spectrumInfo = output->spectrumInfo(); + for (size_t wsIndex = 0; wsIndex != output->getNumberHistograms(); ++wsIndex) { + if (wsIndex < numberOfHistograms - numberOfMonitors) { + TS_ASSERT(!spectrumInfo.isMonitor(wsIndex)) + } else { + TS_ASSERT(spectrumInfo.isMonitor(wsIndex)) + } + const auto histogram = output->histogram(wsIndex); + TS_ASSERT_EQUALS(histogram.xMode(), Mantid::HistogramData::Histogram::XMode::BinEdges) + TS_ASSERT_EQUALS(histogram.yMode(), Mantid::HistogramData::Histogram::YMode::Counts) + TS_ASSERT_EQUALS(histogram.size(), numberOfChannels) + const auto &xs = histogram.x(); + if (convertToTOF) { + for (size_t channelIndex = 0; channelIndex != xs.size(); ++channelIndex) { + const double binEdge = tofDelay + static_cast(channelIndex) * tofChannelWidth + tofChannelWidth / 2; + TS_ASSERT_DELTA(xs[channelIndex], binEdge, 1e-3) + } + } else { + for (size_t channelIndex = 0; channelIndex != xs.size(); ++channelIndex) { + TS_ASSERT_EQUALS(xs[channelIndex], channelIndex) + } + } + const auto &ys = histogram.y(); + const auto &es = histogram.e(); + for (size_t channelIndex = 0; channelIndex != es.size(); ++channelIndex) { + TS_ASSERT_EQUALS(es[channelIndex], std::sqrt(ys[channelIndex])) + } + } + + // Check all detectors have a defined detector ID >= 0 + Mantid::detid2index_map detectorMap; + TS_ASSERT_THROWS_NOTHING(detectorMap = output->getDetectorIDToWorkspaceIndexMap(true)) + + // Check all detectors have a unique detector ID + TS_ASSERT_EQUALS(detectorMap.size(), output->getNumberHistograms()) + + for (const auto value : detectorMap) { + TS_ASSERT(value.first >= 0) + } + + return output; + } + + void test_IN4_load() { + // From the input test file. + const double tofDelay = 238.34; + const double tofChannelWidth = 5.85; + const size_t channelCount = 512; + const size_t histogramCount = 397; + const size_t monitorCount = 1; + const bool convertToTOF = true; + MatrixWorkspace_sptr ws = loadDataFile("ILL/IN4/084446.nxs", histogramCount, monitorCount, channelCount, tofDelay, + tofChannelWidth, convertToTOF); + auto const run = ws->run(); + const double pulseInterval = run.getLogAsSingleValue("pulse_interval"); + TS_ASSERT_DELTA(0.003, pulseInterval, 1e-10) + TS_ASSERT(run.hasProperty("run_list")) + const auto runList = run.getLogData("run_list"); + TS_ASSERT_EQUALS(runList->value(), "84446") + } + + void test_IN5_hdf5_load() { + // From the input test file. + const double tofDelay = 5982.856; + const double tofChannelWidth = 14.6349; + const size_t channelCount = 512; + const size_t histogramCount = 98305; + const size_t monitorCount = 1; + const bool convertToTOF = true; + MatrixWorkspace_sptr ws = loadDataFile("ILL/IN5/104007.nxs", histogramCount, monitorCount, channelCount, tofDelay, + tofChannelWidth, convertToTOF); + auto const run = ws->run(); + TS_ASSERT(run.hasProperty("run_list")) + const auto runList = run.getLogData("run_list"); + TS_ASSERT_EQUALS(runList->value(), "104007"); + } + + void test_IN6_load() { + // From the input test file. + const double tofDelay = 430; + const double tofChannelWidth = 5.8; + const size_t channelCount = 1024; + const size_t histogramCount = 340; + const size_t monitorCount = 3; + const bool convertToTOF = true; + MatrixWorkspace_sptr ws = loadDataFile("ILL/IN6/164192.nxs", histogramCount, monitorCount, channelCount, tofDelay, + tofChannelWidth, convertToTOF); + + auto const run = ws->run(); + const double pulseInterval = run.getLogAsSingleValue("pulse_interval"); + TS_ASSERT_DELTA(0.0060337892, pulseInterval, 1e-10) + TS_ASSERT(run.hasProperty("run_list")) + const auto runList = run.getLogData("run_list"); + TS_ASSERT_EQUALS(runList->value(), "164192") + } + + void test_PANTHER_diffraction_load() { + const double wavelength = 7.; + const size_t histogram_count = 73729; + const size_t monitor_count = 1; + + // mostly the same code as loadDataFile, but some of the TOF features cant + // be called + LoadILLTOF3 loader; + loader.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(loader.initialize()) + TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", "ILL/PANTHER/001036.nxs")) + + std::string outputSpace = "LoadILLTOFTest_out"; + TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("OutputWorkspace", outputSpace)) + TS_ASSERT_THROWS_NOTHING(loader.execute()) + + MatrixWorkspace_sptr output = AnalysisDataService::Instance().retrieveWS(outputSpace); + + TS_ASSERT_EQUALS(output->getNumberHistograms(), histogram_count) + const auto &spectrumInfo = output->spectrumInfo(); + for (size_t wsIndex = 0; wsIndex != output->getNumberHistograms(); ++wsIndex) { + if (wsIndex < histogram_count - monitor_count) { + TS_ASSERT(!spectrumInfo.isMonitor(wsIndex)) + } else { + TS_ASSERT(spectrumInfo.isMonitor(wsIndex)) + } + const auto histogram = output->histogram(wsIndex); + TS_ASSERT_EQUALS(histogram.xMode(), Mantid::HistogramData::Histogram::XMode::BinEdges) + TS_ASSERT_EQUALS(histogram.yMode(), Mantid::HistogramData::Histogram::YMode::Counts) + TS_ASSERT_EQUALS(histogram.size(), 1) + + const auto &xs = histogram.x(); + TS_ASSERT_DELTA(xs[0], 0.9 * wavelength, 1E-5) + TS_ASSERT_DELTA(xs[1], 1.1 * wavelength, 1E-5) + + const auto &ys = histogram.y(); + const auto &es = histogram.e(); + TS_ASSERT_EQUALS(es[0], std::sqrt(ys[0])) + } + // Check all detectors have a defined detector ID >= 0 + Mantid::detid2index_map detectorMap; + TS_ASSERT_THROWS_NOTHING(detectorMap = output->getDetectorIDToWorkspaceIndexMap(true)) + + // Check all detectors have a unique detector ID + TS_ASSERT_EQUALS(detectorMap.size(), output->getNumberHistograms()) + + for (const auto value : detectorMap) { + TS_ASSERT(value.first >= 0) + } + } + + void test_PANTHER_load() { + // From the input test file. + const double tofDelay = 350; + const double tofChannelWidth = 4.88; + const size_t channelCount = 512; + const size_t histogramCount = 73729; + const size_t monitorCount = 1; + const bool convertToTOF = false; + MatrixWorkspace_sptr ws = loadDataFile("ILL/PANTHER/001723.nxs", histogramCount, monitorCount, channelCount, + tofDelay, tofChannelWidth, convertToTOF); + auto const run = ws->run(); + TS_ASSERT(run.hasProperty("run_list")) + const auto runList = run.getLogData("run_list"); + TS_ASSERT_EQUALS(runList->value(), "1723") + } + + void test_convertToTOF() { + // From the input test file. + const double tofDelay = 0; + const double tofChannelWidth = 0; // should not be usesd + const size_t channelCount = 512; + const size_t histogramCount = 98305; + const size_t monitorCount = 1; + const bool convertToTOF = false; + loadDataFile("ILL/IN5/104007.nxs", histogramCount, monitorCount, channelCount, tofDelay, tofChannelWidth, + convertToTOF); + } + + void test_SHARP_load() { + // From the input test file. + const double tofDelay = 0; + const double tofChannelWidth = 0; + const size_t channelCount = 1; + const size_t histogramCount = 61441; + const size_t monitorCount = 1; + const bool convertToTOF = false; + MatrixWorkspace_sptr ws = loadDataFile("ILL/SHARP/000102.nxs", histogramCount, monitorCount, channelCount, tofDelay, + tofChannelWidth, convertToTOF); + auto const run = ws->run(); + TS_ASSERT(run.hasProperty("run_list")) + const auto runList = run.getLogData("run_list"); + TS_ASSERT_EQUALS(runList->value(), "102") + } + + void test_SHARP_TOF_load() { + // From the input test file. + const double tofDelay = 4942.31; + const double tofChannelWidth = 14.6484; + const size_t channelCount = 512; + const size_t histogramCount = 61441; + const size_t monitorCount = 1; + const bool convertToTOF = true; + loadDataFile("ILL/SHARP/000103.nxs", histogramCount, monitorCount, channelCount, tofDelay, tofChannelWidth, + convertToTOF); + } + + void test_IN5_omega_scan() { + // Tests the omega-scan case for IN5 + + LoadILLTOF3 alg; + // Don't put output in ADS by default + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "ILL/IN5/199857.nxs")) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "_unused_for_child")) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + + MatrixWorkspace_sptr outputWS = alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS) + TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 98305) + TS_ASSERT_EQUALS(outputWS->blocksize(), 17) + TS_ASSERT(outputWS->detectorInfo().isMonitor(98304)) + TS_ASSERT(!outputWS->isHistogramData()) + TS_ASSERT(!outputWS->isDistribution()) + + TS_ASSERT_DELTA(outputWS->x(0)[0], 276.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(0)[0], 0.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(0)[0], 0.00, 0.01) + + TS_ASSERT_DELTA(outputWS->x(65)[15], 279.75, 0.01) + TS_ASSERT_DELTA(outputWS->y(65)[15], 1.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(65)[15], 1.00, 0.01) + + TS_ASSERT_DELTA(outputWS->x(98304)[0], 276.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(98304)[0], 2471.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(98304)[0], 49.71, 0.01) + + TS_ASSERT_DELTA(outputWS->x(98304)[16], 280.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(98304)[16], 513.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(98304)[16], 22.65, 0.01) + + const auto &run = outputWS->run(); + TS_ASSERT(run.hasProperty("Ei")) + TS_ASSERT(run.hasProperty("run_list")) + + const auto ei = run.getLogAsSingleValue("wavelength"); + const auto runList = run.getLogData("run_list"); + + TS_ASSERT_DELTA(ei, 4.80, 0.01) + TS_ASSERT_EQUALS(runList->value(), "199857") + } + + void test_PANTHER_omega_scan() { + // Tests the omega-scan case for PANTHER + + LoadILLTOF3 alg; + // Don't put output in ADS by default + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "ILL/PANTHER/010578.nxs")) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "_unused_for_child")) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + + MatrixWorkspace_sptr outputWS = alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS) + TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 73729) + TS_ASSERT_EQUALS(outputWS->blocksize(), 16) + TS_ASSERT(outputWS->detectorInfo().isMonitor(73728)) + TS_ASSERT(!outputWS->isHistogramData()) + TS_ASSERT(!outputWS->isDistribution()) + + TS_ASSERT_DELTA(outputWS->x(0)[0], 0.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(0)[0], 0.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(0)[0], 0.00, 0.01) + + TS_ASSERT_DELTA(outputWS->x(65)[15], 30.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(65)[15], 3.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(65)[15], 1.73, 0.01) + + TS_ASSERT_DELTA(outputWS->x(73728)[0], 0.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(73728)[0], 497.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(73728)[0], 22.29, 0.01) + + TS_ASSERT_DELTA(outputWS->x(73728)[15], 30.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(73728)[15], 504.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(73728)[15], 22.45, 0.01) + + const auto &run = outputWS->run(); + TS_ASSERT(run.hasProperty("Ei")) + TS_ASSERT(run.hasProperty("run_list")) + + const auto ei = run.getLogAsSingleValue("wavelength"); + const auto runList = run.getLogData("run_list"); + + TS_ASSERT_DELTA(ei, 1.5288, 0.0001) + TS_ASSERT_EQUALS(runList->value(), "10578") + } + + void test_SHARP_omega_scan() { + // Tests the omega-scan case for SHARP + + LoadILLTOF3 alg; + // Don't put output in ADS by default + alg.setChild(true); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Filename", "ILL/SHARP/000104.nxs")) + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("OutputWorkspace", "_unused_for_child")) + TS_ASSERT_THROWS_NOTHING(alg.execute()) + TS_ASSERT(alg.isExecuted()) + + MatrixWorkspace_sptr outputWS = alg.getProperty("OutputWorkspace"); + TS_ASSERT(outputWS) + TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 61441) + TS_ASSERT_EQUALS(outputWS->blocksize(), 8) + TS_ASSERT(outputWS->detectorInfo().isMonitor(61440)) + TS_ASSERT(!outputWS->isHistogramData()) + TS_ASSERT(!outputWS->isDistribution()) + + TS_ASSERT_DELTA(outputWS->x(0)[0], 60.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(0)[0], 163.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(0)[0], 12.77, 0.01) + + TS_ASSERT_DELTA(outputWS->x(65)[7], 62.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(65)[7], 222.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(65)[7], 14.90, 0.01) + + TS_ASSERT_DELTA(outputWS->x(61440)[0], 60.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(61440)[0], 128.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(61440)[0], 11.31, 0.01) + + TS_ASSERT_DELTA(outputWS->x(61440)[7], 62.00, 0.01) + TS_ASSERT_DELTA(outputWS->y(61440)[7], 128.00, 0.01) + TS_ASSERT_DELTA(outputWS->e(61440)[7], 11.31, 0.01) + + const auto &run = outputWS->run(); + TS_ASSERT(run.hasProperty("Ei")) + TS_ASSERT(run.hasProperty("run_list")) + + const auto ei = run.getLogAsSingleValue("wavelength"); + const auto runList = run.getLogData("run_list"); + + TS_ASSERT_DELTA(ei, 5.12, 0.01) + TS_ASSERT_EQUALS(runList->value(), "104") + } +}; + +//------------------------------------------------------------------------------ +// Performance test +//------------------------------------------------------------------------------ + +class LoadILLTOF3TestPerformance : public CxxTest::TestSuite { +public: + LoadILLTOF3TestPerformance() : m_dataFile("ILL/IN5/104007.nxs") {} + + void testDefaultLoad() { + Mantid::DataHandling::LoadILLTOF3 loader; + loader.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(loader.initialize()) + TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("Filename", m_dataFile)) + TS_ASSERT_THROWS_NOTHING(loader.setPropertyValue("OutputWorkspace", "ws")) + TS_ASSERT_THROWS_NOTHING(loader.execute()) + TS_ASSERT(loader.isExecuted()) + } + +private: + std::string m_dataFile; +}; diff --git a/Framework/DataHandling/test/StartAndEndTimeFromNexusFileExtractorTest.h b/Framework/DataHandling/test/StartAndEndTimeFromNexusFileExtractorTest.h index 3ae2da9e2665..3ad48aa15a66 100644 --- a/Framework/DataHandling/test/StartAndEndTimeFromNexusFileExtractorTest.h +++ b/Framework/DataHandling/test/StartAndEndTimeFromNexusFileExtractorTest.h @@ -32,14 +32,6 @@ class StartAndEndTimeFromNexusFileExtractorTest : public CxxTest::TestSuite { extractEndTime(filename)); } - void test_that_times_can_be_extracted_from_muon_file() { - const std::string filename("emu00006473.nxs"); - const std::string startTime = "2006-11-21T07:04:30"; - const std::string endTime = "2006-11-21T09:29:28"; - - do_test(filename, startTime, endTime); - } - void test_that_times_can_be_extracted_from_isis_file() { const std::string filename("POLREF00014966.nxs"); const std::string startTime = "2015-10-13T05:34:32"; diff --git a/Framework/LegacyNexus/CMakeLists.txt b/Framework/LegacyNexus/CMakeLists.txt index eb6c3f90bb34..807309b67e73 100644 --- a/Framework/LegacyNexus/CMakeLists.txt +++ b/Framework/LegacyNexus/CMakeLists.txt @@ -4,6 +4,7 @@ set(SRC_FILES src/napi.cpp src/napi4.cpp src/napi5.cpp + src/NexusClasses.cpp src/NeXusException.cpp src/NeXusFile.cpp src/nxstack.cpp @@ -17,6 +18,7 @@ set(INC_FILES inc/MantidLegacyNexus/napi5.h inc/MantidLegacyNexus/napiconfig.h inc/MantidLegacyNexus/napi_internal.h + inc/MantidLegacyNexus/NexusClasses.h inc/MantidLegacyNexus/NeXusException.hpp inc/MantidLegacyNexus/NeXusFile.hpp inc/MantidLegacyNexus/nx_stptok.h @@ -32,12 +34,7 @@ target_include_directories( ) # Set the name of the generated library -set_target_properties( - LegacyNexus - PROPERTIES OUTPUT_NAME MantidLegacyNexus - COMPILE_DEFINITIONS IN_MANTID_NEXUSCPP - WITH_HDF4 WITH_HDF5 -) +set_target_properties(LegacyNexus PROPERTIES OUTPUT_NAME MantidLegacyNexus COMPILE_DEFINITIONS IN_MANTID_NEXUSCPP) # H5_BUILT_AS_DYNAMIC_LIB required https://github.com/conda-forge/hdf5-feedstock/issues/58 target_compile_definitions(LegacyNexus PUBLIC -DH5_BUILT_AS_DYNAMIC_LIB) target_link_libraries(LegacyNexus PUBLIC ${HDF4_DF_LIBRARY} ${HDF4_MFHDF_LIBRARY} ${HDF5_LIBRARIES}) diff --git a/Framework/LegacyNexus/inc/MantidLegacyNexus/NeXusFile.hpp b/Framework/LegacyNexus/inc/MantidLegacyNexus/NeXusFile.hpp index d6c7a9d0fbd7..ffe12d5d879a 100644 --- a/Framework/LegacyNexus/inc/MantidLegacyNexus/NeXusFile.hpp +++ b/Framework/LegacyNexus/inc/MantidLegacyNexus/NeXusFile.hpp @@ -17,6 +17,8 @@ namespace Mantid::LegacyNexus { +static std::pair const EOD_ENTRY("NULL", "NULL"); + /** * The available compression types. These are all ignored in xml files. * \li NONE no compression diff --git a/Framework/Muon/inc/MantidMuon/LegacyNexusClasses.h b/Framework/LegacyNexus/inc/MantidLegacyNexus/NexusClasses.h similarity index 98% rename from Framework/Muon/inc/MantidMuon/LegacyNexusClasses.h rename to Framework/LegacyNexus/inc/MantidLegacyNexus/NexusClasses.h index e527cf426115..160ff45332a8 100644 --- a/Framework/Muon/inc/MantidMuon/LegacyNexusClasses.h +++ b/Framework/LegacyNexus/inc/MantidLegacyNexus/NexusClasses.h @@ -6,9 +6,9 @@ // SPDX - License - Identifier: GPL - 3.0 + #pragma once +#include "MantidLegacyNexus/DllConfig.h" #include "MantidLegacyNexus/NeXusFile_fwd.h" #include "MantidLegacyNexus/napi.h" -#include "MantidMuon/DllConfig.h" #include #include @@ -63,7 +63,7 @@ const int g_processed_blocksize = 8; /** Nexus attributes. The type of each attribute is NX_CHAR */ -class MANTID_MUON_DLL NXAttributes { +class MANTID_LEGACYNEXUS_DLL NXAttributes { public: int n() const { return int(m_values.size()); } ///< number of attributes std::vector names() const; ///< Returns the list of attribute names @@ -83,7 +83,7 @@ class NXClass; /** The base abstract class for NeXus classes and data sets. * NX classes and data sets are defined at www.nexusformat.org */ -class MANTID_MUON_DLL NXObject { +class MANTID_LEGACYNEXUS_DLL NXObject { friend class NXDataSet; ///< a friend class declaration friend class NXClass; ///< a friend class declaration friend class NXRoot; ///< a friend class declaration @@ -125,7 +125,7 @@ class MANTID_MUON_DLL NXObject { * There is no need to free the memory allocated by the NXDataSet as it is done * at the destruction. */ -class MANTID_MUON_DLL NXDataSet : public NXObject { +class MANTID_LEGACYNEXUS_DLL NXDataSet : public NXObject { public: // Constructor NXDataSet(const NXClass &parent, const std::string &name); @@ -477,7 +477,7 @@ using NXUInt = NXDataSetTyped; * (groups) can be created and loaded from * NeXus files. */ -class MANTID_MUON_DLL NXClass : public NXObject { +class MANTID_LEGACYNEXUS_DLL NXClass : public NXObject { friend class NXRoot; public: @@ -619,7 +619,7 @@ class MANTID_MUON_DLL NXClass : public NXObject { /** Implements NXdata Nexus class. */ -class MANTID_MUON_DLL NXData : public NXClass { +class MANTID_LEGACYNEXUS_DLL NXData : public NXClass { public: /** Constructor. * @param parent :: The parent Nexus class. In terms of HDF it is the group @@ -661,7 +661,7 @@ class MANTID_MUON_DLL NXData : public NXClass { /** Implements NXdetector Nexus class. */ -class MANTID_MUON_DLL NXDetector : public NXClass { +class MANTID_LEGACYNEXUS_DLL NXDetector : public NXClass { public: /** Constructor. * @param parent :: The parent Nexus class. In terms of HDF it is the group @@ -681,7 +681,7 @@ class MANTID_MUON_DLL NXDetector : public NXClass { /** Implements NXinstrument Nexus class. */ -class MANTID_MUON_DLL NXInstrument : public NXClass { +class MANTID_LEGACYNEXUS_DLL NXInstrument : public NXClass { public: /** Constructor. * @param parent :: The parent Nexus class. In terms of HDF it is the group @@ -700,7 +700,7 @@ class MANTID_MUON_DLL NXInstrument : public NXClass { /** Implements NXentry Nexus class. */ -class MANTID_MUON_DLL NXEntry : public NXClass { +class MANTID_LEGACYNEXUS_DLL NXEntry : public NXClass { public: /** Constructor. * @param parent :: The parent Nexus class. In terms of HDF it is the group @@ -724,7 +724,7 @@ class MANTID_MUON_DLL NXEntry : public NXClass { /** Implements NXroot Nexus class. */ -class MANTID_MUON_DLL NXRoot : public NXClass { +class MANTID_LEGACYNEXUS_DLL NXRoot : public NXClass { public: // Constructor NXRoot(std::string fname); diff --git a/Framework/LegacyNexus/inc/MantidLegacyNexus/napi.h b/Framework/LegacyNexus/inc/MantidLegacyNexus/napi.h index e5a751e4be3e..37bef71a4c0e 100644 --- a/Framework/LegacyNexus/inc/MantidLegacyNexus/napi.h +++ b/Framework/LegacyNexus/inc/MantidLegacyNexus/napi.h @@ -169,9 +169,6 @@ using namespace Mantid::LegacyNexus; * */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ /** * Open a NeXus file. * NXopen honours full path file names. But it also searches @@ -824,10 +821,6 @@ MANTID_LEGACYNEXUS_DLL char *NXIformatNeXusTime(); */ MANTID_LEGACYNEXUS_DLL Mantid::LegacyNexus::NXstatus NXsetcache(long newVal); -#ifdef __cplusplus -}; -#endif /* __cplusplus */ - /** * Freddie Akeroyd 11/8/2009 * Add NeXus schema support - this uses BASE.xsd as the initial file diff --git a/Framework/LegacyNexus/src/NeXusFile.cpp b/Framework/LegacyNexus/src/NeXusFile.cpp index 8d99cc7b0c37..7c3cd2b22d56 100644 --- a/Framework/LegacyNexus/src/NeXusFile.cpp +++ b/Framework/LegacyNexus/src/NeXusFile.cpp @@ -19,9 +19,9 @@ using std::vector; * The implementation of the NeXus C++ API */ -static const string NULL_STR = "NULL"; - namespace { // anonymous namespace to keep it in the file +const std::string NULL_STR("NULL"); + template static string toString(const vector &data) { stringstream result; result << "["; @@ -728,7 +728,7 @@ pair File::getNextEntry() { string str_class(class_name); return pair(str_name, str_class); } else if (status == NXstatus::NX_EOD) { - return pair(NULL_STR, NULL_STR); // TODO return the correct thing + return EOD_ENTRY; // TODO return the correct thing } else { throw Exception("NXgetnextentry failed", status); } @@ -746,7 +746,7 @@ void File::getEntries(std::map &result) { pair temp; while (true) { temp = this->getNextEntry(); - if (temp.first == NULL_STR && temp.second == NULL_STR) { // TODO this needs to be changed when getNextEntry is fixed + if (temp == EOD_ENTRY) { // TODO this needs to be changed when getNextEntry is fixed break; } else { result.insert(temp); diff --git a/Framework/Muon/src/LegacyNexusClasses.cpp b/Framework/LegacyNexus/src/NexusClasses.cpp similarity index 98% rename from Framework/Muon/src/LegacyNexusClasses.cpp rename to Framework/LegacyNexus/src/NexusClasses.cpp index 3593168f075c..3ac49603b4d2 100644 --- a/Framework/Muon/src/LegacyNexusClasses.cpp +++ b/Framework/LegacyNexus/src/NexusClasses.cpp @@ -4,11 +4,10 @@ // NScD Oak Ridge National Laboratory, European Spallation Source, // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + -#include "MantidMuon/LegacyNexusClasses.h" - -#include "MantidKernel/Exception.h" -#include "MantidKernel/PropertyWithValue.h" +#include "MantidLegacyNexus/NexusClasses.h" +#include "MantidLegacyNexus/NeXusException.hpp" +#include #include #include @@ -306,7 +305,7 @@ NXRoot::NXRoot(std::string fname) : m_filename(std::move(fname)) { NXstatus stat = NXopen(m_filename.c_str(), NXACC_READ, &m_fileID); if (stat == NXstatus::NX_ERROR) { std::cout << "NXRoot: Error loading " << m_filename; - throw Kernel::Exception::FileError("Unable to open File:", m_filename); + throw Exception("Unable to open File: " + m_filename); } readAllInfo(); } @@ -321,7 +320,7 @@ NXRoot::NXRoot(std::string fname, const std::string &entry) : m_filename(std::mo // Open NeXus file NXstatus stat = NXopen(m_filename.c_str(), NXACC_CREATE5, &m_fileID); if (stat == NXstatus::NX_ERROR) { - throw Kernel::Exception::FileError("Unable to open File:", m_filename); + throw Exception("Unable to open File: " + m_filename); } } diff --git a/Framework/Muon/CMakeLists.txt b/Framework/Muon/CMakeLists.txt index e2fa68d2107f..a722b8398573 100644 --- a/Framework/Muon/CMakeLists.txt +++ b/Framework/Muon/CMakeLists.txt @@ -26,7 +26,6 @@ set(SRC_FILES src/PlotAsymmetryByLogValue.cpp src/RemoveExpDecay.cpp src/RRFMuon.cpp - src/LegacyNexusClasses.cpp src/MuonNexusReader.cpp ) @@ -58,7 +57,6 @@ set(INC_FILES inc/MantidMuon/PlotAsymmetryByLogValue.h inc/MantidMuon/RemoveExpDecay.h inc/MantidMuon/RRFMuon.h - inc/MantidMuon/LegacyNexusClasses.h inc/MantidMuon/MuonNexusReader.h ) diff --git a/Framework/Muon/inc/MantidMuon/LoadMuonNexus2.h b/Framework/Muon/inc/MantidMuon/LoadMuonNexus2.h index b8d622062894..e3347f9ce22e 100644 --- a/Framework/Muon/inc/MantidMuon/LoadMuonNexus2.h +++ b/Framework/Muon/inc/MantidMuon/LoadMuonNexus2.h @@ -12,8 +12,8 @@ #include "MantidDataObjects/Histogram1D.h" #include "MantidKernel/DateAndTimeHelpers.h" #include "MantidKernel/TimeSeriesProperty.h" +#include "MantidLegacyNexus/NexusClasses.h" #include "MantidMuon/DllConfig.h" -#include "MantidMuon/LegacyNexusClasses.h" #include "MantidMuon/LoadMuonNexus.h" namespace Mantid { diff --git a/Framework/Muon/src/LoadMuonNexus1.cpp b/Framework/Muon/src/LoadMuonNexus1.cpp index 9835bf0f19e2..164ff63f2963 100644 --- a/Framework/Muon/src/LoadMuonNexus1.cpp +++ b/Framework/Muon/src/LoadMuonNexus1.cpp @@ -30,7 +30,7 @@ #include "MantidKernel/UnitLabelTypes.h" #include "MantidLegacyNexus/NeXusException.hpp" #include "MantidLegacyNexus/NeXusFile.hpp" -#include "MantidMuon/LegacyNexusClasses.h" +#include "MantidLegacyNexus/NexusClasses.h" #include "MantidMuon/MuonNexusReader.h" #include diff --git a/Framework/Muon/src/LoadMuonNexus2.cpp b/Framework/Muon/src/LoadMuonNexus2.cpp index 53eec68beaa6..e5c77eff5729 100644 --- a/Framework/Muon/src/LoadMuonNexus2.cpp +++ b/Framework/Muon/src/LoadMuonNexus2.cpp @@ -19,13 +19,14 @@ #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/ConfigService.h" #include "MantidKernel/DateAndTimeHelpers.h" +#include "MantidKernel/PropertyWithValue.h" #include "MantidKernel/TimeSeriesProperty.h" #include "MantidKernel/Unit.h" #include "MantidKernel/UnitFactory.h" #include "MantidKernel/UnitLabelTypes.h" #include "MantidLegacyNexus/NeXusException.hpp" #include "MantidLegacyNexus/NeXusFile.hpp" -#include "MantidMuon/LegacyNexusClasses.h" +#include "MantidLegacyNexus/NexusClasses.h" #include #include diff --git a/Framework/Muon/src/LoadMuonNexus3.cpp b/Framework/Muon/src/LoadMuonNexus3.cpp index 71345dddc866..18cfd68d2886 100644 --- a/Framework/Muon/src/LoadMuonNexus3.cpp +++ b/Framework/Muon/src/LoadMuonNexus3.cpp @@ -11,7 +11,7 @@ #include "MantidAPI/Progress.h" #include "MantidAPI/RegisterFileLoader.h" #include "MantidKernel/Logger.h" -#include "MantidMuon/LegacyNexusClasses.h" +#include "MantidLegacyNexus/NexusClasses.h" #include #include diff --git a/Framework/Nexus/CMakeLists.txt b/Framework/Nexus/CMakeLists.txt index b4f622db62e5..3defe67f3328 100644 --- a/Framework/Nexus/CMakeLists.txt +++ b/Framework/Nexus/CMakeLists.txt @@ -2,7 +2,6 @@ set(SRC_FILES src/H5Util.cpp src/NexusClasses.cpp src/napi.cpp - src/napi4.cpp src/napi5.cpp src/NeXusException.cpp src/NeXusFile.cpp @@ -16,7 +15,6 @@ set(INC_FILES inc/MantidNexus/NexusIOHelper.h inc/MantidNexus/NeXusFile_fwd.h inc/MantidNexus/napi.h - inc/MantidNexus/napi4.h inc/MantidNexus/napi5.h inc/MantidNexus/napiconfig.h inc/MantidNexus/napi_internal.h @@ -47,7 +45,7 @@ set_target_properties(Nexus PROPERTIES OUTPUT_NAME MantidNexus COMPILE_DEFINITIO # H5_BUILT_AS_DYNAMIC_LIB required https://github.com/conda-forge/hdf5-feedstock/issues/58 target_compile_definitions(Nexus PUBLIC -DH5_BUILT_AS_DYNAMIC_LIB) -target_link_libraries(Nexus PRIVATE ${HDF4_DF_LIBRARY} ${HDF4_MFHDF_LIBRARY} ${HDF5_LIBRARIES}) +target_link_libraries(Nexus PRIVATE ${HDF5_LIBRARIES}) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set_target_properties(Nexus PROPERTIES INSTALL_RPATH "@loader_path/../MacOS;@loader_path/../Frameworks") diff --git a/Framework/Nexus/inc/MantidNexus/napi4.h b/Framework/Nexus/inc/MantidNexus/napi4.h deleted file mode 100644 index 271889841c8a..000000000000 --- a/Framework/Nexus/inc/MantidNexus/napi4.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#define NXSIGNATURE 959697 - -#include "mfhdf.h" - -/* - * HDF4 interface - */ - -extern NXstatus NX4open(CONSTCHAR *filename, NXaccess access_method, NXhandle *pHandle); -extern NXstatus NX4close(NXhandle *pHandle); -extern NXstatus NX4flush(NXhandle *pHandle); - -extern NXstatus NX4makegroup(NXhandle handle, CONSTCHAR *Vgroup, CONSTCHAR *NXclass); -extern NXstatus NX4opengroup(NXhandle handle, CONSTCHAR *Vgroup, CONSTCHAR *NXclass); -extern NXstatus NX4closegroup(NXhandle handle); - -extern NXstatus NX4makedata64(NXhandle handle, CONSTCHAR *label, NXnumtype datatype, int rank, int64_t dim[]); -extern NXstatus NX4compmakedata64(NXhandle handle, CONSTCHAR *label, NXnumtype datatype, int rank, int64_t dim[], - int comp_typ, int64_t const bufsize[]); -extern NXstatus NX4compress(NXhandle handle, int compr_type); -extern NXstatus NX4opendata(NXhandle handle, CONSTCHAR *label); - -extern NXstatus NX4closedata(NXhandle handle); - -extern NXstatus NX4getdata(NXhandle handle, void *data); -extern NXstatus NX4getslab64(NXhandle handle, void *data, const int64_t start[], const int64_t size[]); -extern NXstatus NX4getattr(NXhandle handle, const char *name, void *data, int *iDataLen, NXnumtype *iType); - -extern NXstatus NX4putdata(NXhandle handle, const void *data); -extern NXstatus NX4putslab64(NXhandle handle, const void *data, const int64_t start[], const int64_t size[]); -extern NXstatus NX4putattr(NXhandle handle, CONSTCHAR *name, const void *data, int iDataLen, NXnumtype iType); - -extern NXstatus NX4getinfo64(NXhandle handle, int *rank, int64_t dimension[], NXnumtype *datatype); -extern NXstatus NX4getgroupinfo(NXhandle handle, int *no_items, NXname name, NXname nxclass); -extern NXstatus NX4initgroupdir(NXhandle handle); -extern NXstatus NX4getnextentry(NXhandle handle, NXname name, NXname nxclass, NXnumtype *datatype); -extern NXstatus NX4getattrinfo(NXhandle handle, int *no_items); -extern NXstatus NX4initattrdir(NXhandle handle); -extern NXstatus NX4getnextattr(NXhandle handle, NXname pName, int *iLength, NXnumtype *iType); - -extern NXstatus NX4getgroupID(NXhandle handle, NXlink *pLink); -extern NXstatus NX4getdataID(NXhandle handle, NXlink *pLink); -extern NXstatus NX4makelink(NXhandle handle, NXlink *pLink); -extern NXstatus NX4printlink(NXhandle handle, NXlink *pLink); - -extern NXstatus NX4putattra(NXhandle handle, CONSTCHAR *name, const void *data, const int rank, const int dim[], - const NXnumtype iType); -extern NXstatus NX4getnextattra(NXhandle handle, NXname pName, int *rank, int dim[], NXnumtype *iType); -extern NXstatus NX4getattra(NXhandle handle, const char *name, void *data); -extern NXstatus NX4getattrainfo(NXhandle handle, NXname pName, int *rank, int dim[], NXnumtype *iType); - -void NX4assignFunctions(pNexusFunction fHandle); - -/* - * HDF changed from MAX_VAR_DIMS to H4_MAX_VAR_DIMS aronud 9/5/2007 - * to avoid potential conflicts with NetCDF-3 library - */ -#ifndef H4_MAX_VAR_DIMS -#define H4_MAX_VAR_DIMS MAX_VAR_DIMS -#endif diff --git a/Framework/Nexus/inc/MantidNexus/napiconfig.h b/Framework/Nexus/inc/MantidNexus/napiconfig.h index 9b6c505bf7d5..6237166774a7 100644 --- a/Framework/Nexus/inc/MantidNexus/napiconfig.h +++ b/Framework/Nexus/inc/MantidNexus/napiconfig.h @@ -4,9 +4,6 @@ #include #endif /* _WIN32 */ -#define HAVE_HDF4 -#define WITH_HDF4 - #define HAVE_HDF5 #define WITH_HDF5 diff --git a/Framework/Nexus/src/napi.cpp b/Framework/Nexus/src/napi.cpp index 371021417013..7ef6ea221ba5 100644 --- a/Framework/Nexus/src/napi.cpp +++ b/Framework/Nexus/src/napi.cpp @@ -245,9 +245,6 @@ void NXReportError(const char *string) { UNUSED_ARG(string); } #ifdef WITH_HDF5 #include "MantidNexus/napi5.h" #endif -#ifdef WITH_HDF4 -#include "MantidNexus/napi4.h" -#endif /* ---------------------------------------------------------------------- Definition of NeXus API @@ -270,12 +267,6 @@ static int determineFileTypeImpl(CONSTCHAR *filename) { if (iRet > 0) { return NXACC_CREATE5; } -#endif -#ifdef WITH_HDF4 - iRet = Hishdf(static_cast(filename)); - if (iRet > 0) { - return NXACC_CREATE4; - } #endif /* file type not recognized @@ -401,24 +392,8 @@ static NXstatus NXinternalopenImpl(CONSTCHAR *userfilename, NXaccess am, pFileSt NXstatus retstat = NXstatus::NX_ERROR; if (backend_type == NXACC_CREATE4) { /* HDF4 type */ -#ifdef WITH_HDF4 - NXhandle hdf4_handle = NULL; - retstat = NX4open(static_cast(filename), am, &hdf4_handle); - if (retstat != NXstatus::NX_OK) { - free(fHandle); - free(filename); - return retstat; - } - fHandle->pNexusData = hdf4_handle; - fHandle->access_mode = backend_type || (NXACC_READ && am); - NX4assignFunctions(fHandle); - pushFileStack(fileStack, fHandle, filename); -#else NXReportError("ERROR: Attempt to create HDF4 file when not linked with HDF4"); retstat = NXstatus::NX_ERROR; -#endif /* HDF4 */ - free(filename); - return retstat; } else if (backend_type == NXACC_CREATE5) { /* HDF5 type */ #ifdef WITH_HDF5 diff --git a/Framework/Nexus/src/napi4.cpp b/Framework/Nexus/src/napi4.cpp deleted file mode 100644 index 916af0d4bab6..000000000000 --- a/Framework/Nexus/src/napi4.cpp +++ /dev/null @@ -1,1771 +0,0 @@ -/*--------------------------------------------------------------------------- - NeXus - Neutron & X-ray Common Data Format - - Application Program Interface (HDF4) Routines - - Copyright (C) 1997-2006 Mark Koennecke, Przemek Klosowski - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - For further information, see - - $Id$ - -----------------------------------------------------------------------------*/ - -#include "MantidNexus/napiconfig.h" - -#ifdef WITH_HDF4 - -#include -#include -#include -#include -#include - -// clang-format off -#include "MantidNexus/napi.h" -#include "MantidNexus/napi_internal.h" -#include "MantidNexus/napi4.h" -// clang-format on - -extern void *NXpData; - -typedef struct __NexusFile { - struct iStack { - int32 *iRefDir; - int32 *iTagDir; - int32 iVref; - int32 __iStack_pad; - int iNDir; - int iCurDir; - } iStack[NXMAXSTACK]; - struct iStack iAtt; - int32 iVID; - int32 iSID; - int32 iCurrentVG; - int32 iCurrentSDS; - int iNXID; - int iStackPtr; - char iAccess[2]; -} NexusFile, *pNexusFile; - -/*-------------------------------------------------------------------*/ - -static int nxToHDF4Type(NXnumtype datatype) { - int type; - switch (datatype) { - case NXnumtype::CHAR: { - type = DFNT_CHAR8; - break; - } - case NXnumtype::INT8: { - type = DFNT_INT8; - break; - } - case NXnumtype::UINT8: { - type = DFNT_UINT8; - break; - } - case NXnumtype::INT16: { - type = DFNT_INT16; - break; - } - case NXnumtype::UINT16: { - type = DFNT_UINT16; - break; - } - case NXnumtype::INT32: { - type = DFNT_INT32; - break; - } - case NXnumtype::UINT32: { - type = DFNT_UINT8; - break; - } - case NXnumtype::FLOAT32: { - type = DFNT_FLOAT32; - break; - } - case NXnumtype::FLOAT64: { - type = DFNT_FLOAT64; - break; - } - default: { - NXReportError("ERROR: nxToHDF4Type: unknown type"); - type = -1; - } - } - return type; -} - -/*-------------------------------------------------------------------*/ - -static pNexusFile NXIassert(NXhandle fid) { - pNexusFile pRes; - - assert(fid != NULL); - pRes = static_cast(fid); - assert(pRes->iNXID == NXSIGNATURE); - return pRes; -} -/*----------------------------------------------------------------------*/ -static int findNapiClass(pNexusFile pFile, int groupRef, NXname nxclass) { - NXname classText; - int32 tags[2], attID, linkID, groupID; - - groupID = Vattach(pFile->iVID, groupRef, "r"); - Vgetclass(groupID, classText); - if (strcmp(classText, "NAPIlink") != 0) { - /* normal group */ - strcpy(nxclass, classText); - Vdetach(groupID); - return groupRef; - } else { - /* code for linked renamed groups */ - attID = Vfindattr(groupID, "NAPIlink"); - if (attID >= 0) { - Vgetattr(groupID, attID, tags); - linkID = Vattach(pFile->iVID, tags[1], "r"); - NXname linkClass; - Vgetclass(linkID, linkClass); - Vdetach(groupID); - Vdetach(linkID); - strcpy(nxclass, linkClass); - return tags[1]; - } else { - /* this allows for finding the NAPIlink group in NXmakenamedlink */ - strcpy(nxclass, classText); - Vdetach(groupID); - return groupRef; - } - } -} -/* --------------------------------------------------------------------- */ - -static int32 NXIFindVgroup(pNexusFile pFile, CONSTCHAR *name, CONSTCHAR *nxclass) { - int const NX_EOD = static_cast(NXstatus::NX_EOD); - int32 iNew, iRef, iTag; - int iN, i; - int32 *pArray = NULL; - NXname pText; - - assert(pFile != NULL); - - if (pFile->iCurrentVG == 0) { /* root level */ - /* get the number and ID's of all lone Vgroups in the file */ - iN = Vlone(pFile->iVID, NULL, 0); - if (iN == 0) { - return NX_EOD; - } - pArray = static_cast(malloc(static_cast(iN) * sizeof(int32))); - if (!pArray) { - NXReportError("ERROR: out of memory in NXIFindVgroup"); - return NX_EOD; - } - Vlone(pFile->iVID, pArray, iN); - - /* loop and check */ - for (i = 0; i < iN; i++) { - iNew = Vattach(pFile->iVID, pArray[i], "r"); - Vgetname(iNew, pText); - Vdetach(iNew); - if (strcmp(pText, name) == 0) { - pArray[i] = findNapiClass(pFile, pArray[i], pText); - if (strcmp(pText, nxclass) == 0) { - /* found ! */ - iNew = pArray[i]; - free(pArray); - return iNew; - } - } - } - /* nothing found */ - free(pArray); - return NX_EOD; - } else { /* case in Vgroup */ - iN = Vntagrefs(pFile->iCurrentVG); - for (i = 0; i < iN; i++) { - Vgettagref(pFile->iCurrentVG, i, &iTag, &iRef); - if (iTag == DFTAG_VG) { - iNew = Vattach(pFile->iVID, iRef, "r"); - Vgetname(iNew, pText); - Vdetach(iNew); - if (strcmp(pText, name) == 0) { - iRef = findNapiClass(pFile, iRef, pText); - if (strcmp(pText, nxclass) == 0) { - return iRef; - } - } - } - } /* end for */ - } /* end else */ - /* not found */ - return NX_EOD; -} - -/*----------------------------------------------------------------------*/ - -static int32 NXIFindSDS(NXhandle fid, CONSTCHAR *name) { - int const NX_EOD = static_cast(NXstatus::NX_EOD); - pNexusFile self; - int32 iNew, iRet, iTag, iRef; - int32 i, iN, iA, iD1, iD2; - NXname pNam; - int32 iDim[H4_MAX_VAR_DIMS]; - - self = NXIassert(fid); - - /* root level search */ - if (self->iCurrentVG == 0) { - i = SDfileinfo(self->iSID, &iN, &iA); - if (i < 0) { - NXReportError("ERROR: failure to read file information"); - return NX_EOD; - } - for (i = 0; i < iN; i++) { - iNew = SDselect(self->iSID, i); - SDgetinfo(iNew, pNam, &iA, iDim, &iD1, &iD2); - if (strcmp(pNam, name) == 0) { - iRet = SDidtoref(iNew); - SDendaccess(iNew); - return iRet; - } else { - SDendaccess(iNew); - } - } - /* not found */ - return NX_EOD; - } - /* end root level */ - else { /* search in a Vgroup */ - iN = Vntagrefs(self->iCurrentVG); - for (i = 0; i < iN; i++) { - Vgettagref(self->iCurrentVG, i, &iTag, &iRef); - /* we are now writing using DFTAG_NDG, but need others for backward compatability */ - if ((iTag == DFTAG_SDG) || (iTag == DFTAG_NDG) || (iTag == DFTAG_SDS)) { - iNew = SDreftoindex(self->iSID, iRef); - iNew = SDselect(self->iSID, iNew); - SDgetinfo(iNew, pNam, &iA, iDim, &iD1, &iD2); - if (strcmp(pNam, name) == 0) { - SDendaccess(iNew); - return iRef; - } - SDendaccess(iNew); - } - } /* end for */ - } /* end Vgroup */ - /* we get here, only if nothing found */ - return NX_EOD; -} - -/*----------------------------------------------------------------------*/ - -static NXstatus NXIInitDir(pNexusFile self) { - int32 iTag, iRef; - int iStackPtr; - - /* - * Note: the +1 to various malloc() operations is to avoid a - * malloc(0), which is an error on some operating systems - */ - iStackPtr = self->iStackPtr; - if (self->iCurrentVG == 0 && self->iStack[iStackPtr].iRefDir == NULL) { /* root level */ - /* get the number and ID's of all lone Vgroups in the file */ - self->iStack[iStackPtr].iNDir = Vlone(self->iVID, NULL, 0); - self->iStack[iStackPtr].iRefDir = - static_cast(malloc(static_cast(self->iStack[iStackPtr].iNDir) * sizeof(int32) + 1)); - if (!self->iStack[iStackPtr].iRefDir) { - NXReportError("ERROR: out of memory in NXIInitDir"); - return NXstatus::NX_EOD; - } - Vlone(self->iVID, self->iStack[self->iStackPtr].iRefDir, self->iStack[self->iStackPtr].iNDir); - } else { - /* Vgroup level */ - self->iStack[iStackPtr].iNDir = Vntagrefs(self->iCurrentVG); - self->iStack[iStackPtr].iRefDir = - static_cast(malloc(static_cast(self->iStack[iStackPtr].iNDir) * sizeof(int32) + 1)); - self->iStack[iStackPtr].iTagDir = - static_cast(malloc(static_cast(self->iStack[iStackPtr].iNDir) * sizeof(int32) + 1)); - if ((!self->iStack[iStackPtr].iRefDir) || (!self->iStack[iStackPtr].iTagDir)) { - NXReportError("ERROR: out of memory in NXIInitDir"); - return NXstatus::NX_EOD; - } - for (int i = 0; i < self->iStack[self->iStackPtr].iNDir; i++) { - Vgettagref(self->iCurrentVG, i, &iTag, &iRef); - self->iStack[iStackPtr].iRefDir[i] = iRef; - self->iStack[iStackPtr].iTagDir[i] = iTag; - } - } - self->iStack[iStackPtr].iCurDir = 0; - return NXstatus::NX_OK; -} - -/*----------------------------------------------------------------------*/ - -static void NXIKillDir(pNexusFile self) { - if (self->iStack[self->iStackPtr].iRefDir) { - free(self->iStack[self->iStackPtr].iRefDir); - self->iStack[self->iStackPtr].iRefDir = NULL; - } - if (self->iStack[self->iStackPtr].iTagDir) { - free(self->iStack[self->iStackPtr].iTagDir); - self->iStack[self->iStackPtr].iTagDir = NULL; - } - self->iStack[self->iStackPtr].iCurDir = 0; - self->iStack[self->iStackPtr].iNDir = 0; -} - -/*-------------------------------------------------------------------------*/ - -static NXstatus NXIInitAttDir(pNexusFile pFile) { - int iRet; - int32 iData, iAtt, iRank, iType; - int32 iDim[H4_MAX_VAR_DIMS]; - - pFile->iAtt.iCurDir = 0; - if (pFile->iCurrentSDS != 0) { /* SDS level */ - NXname pNam; - iRet = SDgetinfo(pFile->iCurrentSDS, pNam, &iRank, iDim, &iType, &iAtt); - } else { - if (pFile->iCurrentVG == 0) { - /* global level */ - iRet = SDfileinfo(pFile->iSID, &iData, &iAtt); - } else { - /* group attribute */ - iRet = Vnattrs(pFile->iCurrentVG); - iAtt = iRet; - } - } - if (iRet < 0) { - NXReportError("ERROR: HDF cannot read attribute numbers"); - pFile->iAtt.iNDir = 0; - return NXstatus::NX_ERROR; - } - pFile->iAtt.iNDir = iAtt; - return NXstatus::NX_OK; -} - -/* --------------------------------------------------------------------- */ - -static void NXIKillAttDir(pNexusFile self) { - if (self->iAtt.iRefDir) { - free(self->iAtt.iRefDir); - self->iAtt.iRefDir = NULL; - } - if (self->iAtt.iTagDir) { - free(self->iAtt.iTagDir); - self->iAtt.iTagDir = NULL; - } - self->iAtt.iCurDir = 0; - self->iAtt.iNDir = 0; -} -/*------------------------------------------------------------------*/ -static void NXIbuildPath(pNexusFile pFile, char *buffer, int bufLen) { - int i; - int32 groupID, iA, iD1, iD2, iDim[H4_MAX_VAR_DIMS]; - NXname pText; - - buffer[0] = '\0'; - for (i = 1; i <= pFile->iStackPtr; i++) { - strncat(buffer, "/", bufLen - strlen(buffer)); - groupID = Vattach(pFile->iVID, pFile->iStack[i].iVref, "r"); - if (groupID != -1) { - if (Vgetname(groupID, pText) != -1) { - strncat(buffer, pText, bufLen - strlen(buffer)); - } else { - NXReportError("ERROR: NXIbuildPath cannot get vgroup name"); - } - Vdetach(groupID); - } else { - NXReportError("ERROR: NXIbuildPath cannot attach to vgroup"); - } - } - if (pFile->iCurrentSDS != 0) { - if (SDgetinfo(pFile->iCurrentSDS, pText, &iA, iDim, &iD1, &iD2) != -1) { - strncat(buffer, "/", bufLen - strlen(buffer)); - strncat(buffer, pText, bufLen - strlen(buffer)); - } else { - NXReportError("ERROR: NXIbuildPath cannot read SDS"); - } - } -} -/* ---------------------------------------------------------------------- - - Definition of NeXus API - - ---------------------------------------------------------------------*/ - -NXstatus NX4open(CONSTCHAR *filename, NXaccess am, NXhandle *pHandle) { - pNexusFile pNew = NULL; - char pBuffer[512]; - char *time_puffer = NULL; - char HDF_VERSION[64]; - uint32 lmajor, lminor, lrelease; - int32 am1 = 0; - - *pHandle = NULL; - - /* mask off any options for now */ - am = (NXaccess)(am & NXACCMASK_REMOVEFLAGS); - /* map Nexus NXaccess types to HDF4 types */ - if (am == NXACC_CREATE) { - am1 = DFACC_CREATE; - } else if (am == NXACC_CREATE4) { - am1 = DFACC_CREATE; - } else if (am == NXACC_READ) { - am1 = DFACC_READ; - } else if (am == NXACC_RDWR) { - am1 = DFACC_RDWR; - } - /* get memory */ - pNew = static_cast(malloc(sizeof(NexusFile))); - if (!pNew) { - NXReportError("ERROR: no memory to create File datastructure"); - return NXstatus::NX_ERROR; - } - memset(pNew, 0, sizeof(NexusFile)); - -#if WRITE_OLD_IDENT /* not used at moment */ - /* - * write something that can be used by OLE - */ - - if (am == NXACC_CREATE || am == NXACC_CREATE4) { - if ((file_id = Hopen(filename, am1, 0)) == -1) { - sprintf(pBuffer, "ERROR: cannot open file_a: %s", filename); - NXReportError(pBuffer); - free(pNew); - return NXstatus::NX_ERROR; - } - an_id = ANstart(file_id); - ann_id = ANcreatef(an_id, AN_FILE_LABEL); /* AN_FILE_DESC */ - ANwriteann(ann_id, "NeXus", 5); - ANendaccess(ann_id); - ANend(an_id); - if (Hclose(file_id) == -1) { - sprintf(pBuffer, "ERROR: cannot close file: %s", filename); - NXReportError(pBuffer); - free(pNew); - return NXstatus::NX_ERROR; - } - am = NXACC_RDWR; - } -#endif /* WRITE_OLD_IDENT */ - - /* start SDS interface */ - pNew->iSID = SDstart(filename, am1); - if (pNew->iSID <= 0) { - sprintf(pBuffer, "ERROR: cannot open file_b: %s", filename); - NXReportError(pBuffer); - free(pNew); - return NXstatus::NX_ERROR; - } - /* - * need to create global attributes file_name file_time NeXus_version - * at some point for new files - */ - if (am == NXACC_CREATE || am == NXACC_CREATE4) { - /* set the NeXus_version attribute*/ - if (SDsetattr(pNew->iSID, "NeXus_version", DFNT_CHAR8, static_cast(strlen(NEXUS_VERSION)), NEXUS_VERSION) < - 0) { - NXReportError("ERROR: HDF failed to store NeXus_version attribute "); - free(pNew); - return NXstatus::NX_ERROR; - } - - /* set the HDF4 version attribute */ - Hgetlibversion(&lmajor, &lminor, &lrelease, HDF_VERSION); - if (SDsetattr(pNew->iSID, "HDF_version", DFNT_CHAR8, static_cast(strlen(HDF_VERSION)), HDF_VERSION) < 0) { - NXReportError("ERROR: HDF failed to store HDF_version attribute "); - free(pNew); - return NXstatus::NX_ERROR; - } - - /* set the filename attribute */ - if (SDsetattr(pNew->iSID, "file_name", DFNT_CHAR8, static_cast(strlen(filename)), - static_cast(filename)) < 0) { - NXReportError("ERROR: HDF failed to store file_name attribute "); - free(pNew); - return NXstatus::NX_ERROR; - } - - /* set the file_time attribute */ - time_puffer = NXIformatNeXusTime(); - if (time_puffer != NULL) { - if (SDsetattr(pNew->iSID, "file_time", DFNT_CHAR8, static_cast(strlen(time_puffer)), time_puffer) < 0) { - NXReportError("ERROR: HDF failed to store file_time attribute "); - free(pNew); - free(time_puffer); - return NXstatus::NX_ERROR; - } - free(time_puffer); - } - - if (SDsetattr(pNew->iSID, "NX_class", DFNT_CHAR8, 7, "NXroot") < 0) { - NXReportError("ERROR: HDF failed to store NX_class attribute "); - free(pNew); - return NXstatus::NX_ERROR; - } - } - - /* - * Otherwise we try to create the file two times which makes HDF - * Throw up on us. - */ - // cppcheck-suppress duplicateCondition - if (am == NXACC_CREATE || am == NXACC_CREATE4) { - am = NXACC_RDWR; - am1 = DFACC_RDWR; - } - - /* Set Vgroup access mode */ - if (am == NXACC_READ) { - strcpy(pNew->iAccess, "r"); - } else { - strcpy(pNew->iAccess, "w"); - } - - /* start Vgroup API */ - - pNew->iVID = Hopen(filename, am1, 100); - if (pNew->iVID <= 0) { - sprintf(pBuffer, "ERROR: cannot open file_c: %s", filename); - NXReportError(pBuffer); - free(pNew); - return NXstatus::NX_ERROR; - } - Vstart(pNew->iVID); - pNew->iNXID = NXSIGNATURE; - pNew->iStack[0].iVref = 0; /* root! */ - - *pHandle = static_cast(pNew); - return NXstatus::NX_OK; -} - -/*-----------------------------------------------------------------------*/ - -NXstatus NX4close(NXhandle *fid) { - pNexusFile pFile = NULL; - int iRet; - - pFile = NXIassert(*fid); - iRet = 0; - /* close links into vGroups or SDS */ - if (pFile->iCurrentVG != 0) { - Vdetach(pFile->iCurrentVG); - } - if (pFile->iCurrentSDS != 0) { - iRet = SDendaccess(pFile->iCurrentSDS); - } - if (iRet < 0) { - NXReportError("ERROR: ending access to SDS"); - } - /* close the SDS and Vgroup API's */ - Vend(pFile->iVID); - iRet = SDend(pFile->iSID); - if (iRet < 0) { - NXReportError("ERROR: HDF cannot close SDS interface"); - } - iRet = Hclose(pFile->iVID); - if (iRet < 0) { - NXReportError("ERROR: HDF cannot close HDF file"); - } - /* release memory */ - NXIKillDir(pFile); - free(pFile); - *fid = NULL; - return NXstatus::NX_OK; -} - -/*-----------------------------------------------------------------------*/ - -NXstatus NX4makegroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { - pNexusFile pFile; - int32 iNew, iRet; - char pBuffer[256]; - - pFile = NXIassert(fid); - /* - * Make sure that a group with the same name and nxclass does not - * already exist. - */ - if ((iRet = NXIFindVgroup(pFile, static_cast(name), nxclass)) >= 0) { - sprintf(pBuffer, "ERROR: Vgroup %s, class %s already exists", name, nxclass); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - /* create and configure the group */ - iNew = Vattach(pFile->iVID, -1, "w"); - if (iNew < 0) { - sprintf(pBuffer, "ERROR: HDF could not create Vgroup %s, class %s", name, nxclass); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - Vsetname(iNew, name); - Vsetclass(iNew, nxclass); - - /* Insert it into the hierarchy, when appropriate */ - iRet = 0; - if (pFile->iCurrentVG != 0) { - iRet = Vinsert(pFile->iCurrentVG, iNew); - } - Vdetach(iNew); - if (iRet < 0) { - NXReportError("ERROR: HDF failed to insert Vgroup"); - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/*------------------------------------------------------------------------*/ -NXstatus NX4opengroup(NXhandle fid, CONSTCHAR *name, CONSTCHAR *nxclass) { - pNexusFile pFile; - int32 iRef; - - pFile = NXIassert(fid); - - iRef = NXIFindVgroup(pFile, static_cast(name), nxclass); - if (iRef < 0) { - char pBuffer[256]; - sprintf(pBuffer, "ERROR: Vgroup \"%s\", class \"%s\" NOT found", name, nxclass); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - /* are we at root level ? */ - if (pFile->iCurrentVG == 0) { - pFile->iCurrentVG = Vattach(pFile->iVID, iRef, pFile->iAccess); - pFile->iStackPtr++; - pFile->iStack[pFile->iStackPtr].iVref = iRef; - } else { - Vdetach(pFile->iCurrentVG); - pFile->iStackPtr++; - pFile->iStack[pFile->iStackPtr].iVref = iRef; - pFile->iCurrentVG = Vattach(pFile->iVID, pFile->iStack[pFile->iStackPtr].iVref, pFile->iAccess); - } - NXIKillDir(pFile); - return NXstatus::NX_OK; -} -/* ------------------------------------------------------------------- */ - -NXstatus NX4closegroup(NXhandle fid) { - pNexusFile pFile; - - pFile = NXIassert(fid); - - /* first catch the trivial case: we are at root and cannot get - deeper into a negative directory hierarchy (anti-directory) - */ - if (pFile->iCurrentVG == 0) { - NXIKillDir(pFile); - return NXstatus::NX_OK; - } else { /* Sighhh. Some work to do */ - /* close the current VG and decrement stack */ - Vdetach(pFile->iCurrentVG); - NXIKillDir(pFile); - pFile->iStackPtr--; - if (pFile->iStackPtr <= 0) { /* we hit root */ - pFile->iStackPtr = 0; - pFile->iCurrentVG = 0; - } else { - /* attach to the lower Vgroup */ - pFile->iCurrentVG = Vattach(pFile->iVID, pFile->iStack[pFile->iStackPtr].iVref, pFile->iAccess); - } - } - return NXstatus::NX_OK; -} - -/* --------------------------------------------------------------------- */ - -NXstatus NX4makedata64(NXhandle fid, CONSTCHAR *name, NXnumtype datatype, int rank, int64_t dimensions[]) { - pNexusFile pFile; - int32 iNew; - char pBuffer[256]; - int i, iRet, type; - int32 myDim[H4_MAX_VAR_DIMS]; - - pFile = NXIassert(fid); - - if (dimensions[0] == NX_UNLIMITED) { - dimensions[0] = SD_UNLIMITED; - } - - if ((iNew = NXIFindSDS(fid, name)) >= 0) { - sprintf(pBuffer, "ERROR: SDS %s already exists at this level", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - type = nxToHDF4Type(datatype); - if (type == -1) { - NXReportError("ERROR: invalid type in NX4makedata"); - return NXstatus::NX_ERROR; - } - - if (rank <= 0) { - sprintf(pBuffer, "ERROR: invalid rank specified for SDS %s", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - /* - Check dimensions for consistency. The first dimension may be 0 - thus denoting an unlimited dimension. - */ - for (i = 1; i < rank; i++) { - if (dimensions[i] <= 0) { - sprintf(pBuffer, "ERROR: invalid dimension %d, value %lld given for SDS %s", i, (long long)dimensions[i], name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - } - - /* cast the dimensions array properly for non 32-bit ints */ - for (i = 0; i < rank; i++) { - myDim[i] = (int32)dimensions[i]; - } - - /* behave nicely, if there is still an SDS open */ - if (pFile->iCurrentSDS != 0) { - SDendaccess(pFile->iCurrentSDS); - pFile->iCurrentSDS = 0; - } - - /* Do not allow creation of SDS's at the root level */ - if (pFile->iCurrentVG == 0) { - sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted"); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - /* dataset creation */ - iNew = - SDcreate(pFile->iSID, static_cast(name), static_cast(type), static_cast(rank), myDim); - if (iNew < 0) { - sprintf(pBuffer, "ERROR: cannot create SDS %s, check arguments", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - /* link into Vgroup, if in one */ - if (pFile->iCurrentVG != 0) { - Vaddtagref(pFile->iCurrentVG, DFTAG_NDG, SDidtoref(iNew)); - } - iRet = SDendaccess(iNew); - if (iRet < 0) { - NXReportError("ERROR: HDF cannot end access to SDS"); - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/* --------------------------------------------------------------------- */ - -NXstatus NX4compmakedata64(NXhandle fid, CONSTCHAR *name, NXnumtype datatype, int rank, int64_t dimensions[], - int compress_type, int64_t const chunk_size[]) { - UNUSED_ARG(chunk_size); - pNexusFile pFile; - int32 iNew, iRet, type; - char pBuffer[256]; - int i, compress_level; - int32 myDim[H4_MAX_VAR_DIMS]; - comp_info compstruct; - - pFile = NXIassert(fid); - - if (dimensions[0] == NX_UNLIMITED) { - dimensions[0] = SD_UNLIMITED; - } - - if ((iNew = NXIFindSDS(fid, name)) >= 0) { - sprintf(pBuffer, "ERROR: SDS %s already exists at this level", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - type = nxToHDF4Type(datatype); - if (type == -1) { - NXReportError("ERROR: invalid datatype in NX4compmakedata"); - return NXstatus::NX_ERROR; - } - - if (rank <= 0) { - sprintf(pBuffer, "ERROR: invalid rank specified for SDS %s", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - /* - Check dimensions for consistency. The first dimension may be 0 - thus denoting an unlimited dimension. - */ - for (i = 1; i < rank; i++) { - if (dimensions[i] <= 0) { - sprintf(pBuffer, "ERROR: invalid dimension %d, value %lld given for SDS %s", i, (long long)dimensions[i], name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - } - - /* cast the dimensions array properly for non 32-bit ints */ - for (i = 0; i < rank; i++) { - myDim[i] = (int32)dimensions[i]; - } - - /* behave nicely, if there is still an SDS open */ - if (pFile->iCurrentSDS != 0) { - SDendaccess(pFile->iCurrentSDS); - pFile->iCurrentSDS = 0; - } - - /* Do not allow creation of SDS's at the root level */ - if (pFile->iCurrentVG == 0) { - sprintf(pBuffer, "ERROR: SDS creation at root level is not permitted"); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - /* dataset creation */ - iNew = - SDcreate(pFile->iSID, static_cast(name), static_cast(type), static_cast(rank), myDim); - if (iNew < 0) { - sprintf(pBuffer, "ERROR: cannot create SDS %s, check arguments", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - - /* compress SD data set */ - compress_level = 6; - if ((compress_type / 100) == NX_COMP_LZW) { - compress_level = compress_type % 100; - compress_type = NX_COMP_LZW; - } - - if (compress_type == NX_COMP_LZW) { - compstruct.deflate.level = compress_level; - iRet = SDsetcompress(iNew, COMP_CODE_DEFLATE, &compstruct); - if (iRet < 0) { - NXReportError("Deflate-Compression failure!"); - return NXstatus::NX_ERROR; - } - } else if (compress_type == NX_COMP_RLE) { - iRet = SDsetcompress(iNew, COMP_CODE_RLE, &compstruct); - if (iRet < 0) { - NXReportError("RLE-Compression failure!"); - return NXstatus::NX_ERROR; - } - } else if (compress_type == NX_COMP_HUF) { - compstruct.skphuff.skp_size = DFKNTsize(type); - iRet = SDsetcompress(iNew, COMP_CODE_SKPHUFF, &compstruct); - if (iRet < 0) { - NXReportError("HUF-Compression failure!"); - return NXstatus::NX_ERROR; - } - } else if (compress_type == NX_COMP_NONE) { - /* */ - } else { - NXReportError("Unknown compression method!"); - return NXstatus::NX_ERROR; - } - /* link into Vgroup, if in one */ - if (pFile->iCurrentVG != 0) { - Vaddtagref(pFile->iCurrentVG, DFTAG_NDG, SDidtoref(iNew)); - } - iRet = SDendaccess(iNew); - if (iRet < 0) { - NXReportError("ERROR: HDF cannot end access to SDS"); - return NXstatus::NX_ERROR; - } - - return NXstatus::NX_OK; -} - -/* --------------------------------------------------------------------- */ - -NXstatus NX4compress(NXhandle fid, int compress_type) { - pNexusFile pFile; - int32 iRank, iAtt, iType; - int32 iSize[H4_MAX_VAR_DIMS]; - comp_coder_t compress_typei = COMP_CODE_NONE; - NXname pBuffer; - comp_info compstruct; - int compress_level = 6; - - pFile = NXIassert(fid); - - /* check if there is an SDS open */ - if (pFile->iCurrentSDS == 0) { - NXReportError("ERROR: no SDS open"); - return NXstatus::NX_ERROR; - } - - if (compress_type == NX_COMP_NONE) { - compress_typei = COMP_CODE_NONE; - } else if (compress_type == NX_COMP_LZW) { - compress_typei = COMP_CODE_DEFLATE; - } else if ((compress_type / 100) == NX_COMP_LZW) { - compress_typei = COMP_CODE_DEFLATE; - compress_level = compress_type % 100; - compress_type = NX_COMP_LZW; - } else if (compress_type == NX_COMP_RLE) { - compress_typei = COMP_CODE_RLE; - } else if (compress_type == NX_COMP_HUF) { - compress_typei = COMP_CODE_SKPHUFF; - } - - /* first read dimension information */ - SDgetinfo(pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt); - - /* - according to compression type initialize compression - information - */ - if (compress_type == NX_COMP_LZW) { - compstruct.deflate.level = compress_level; - } else if (compress_type == NX_COMP_HUF) { - compstruct.skphuff.skp_size = DFKNTsize(iType); - } - - const int32 iRet = SDsetcompress(pFile->iCurrentSDS, compress_typei, &compstruct); - if (iRet < 0) { - char pError[512]; - sprintf(pError, "ERROR: failure to compress data to %s", pBuffer); - NXReportError(pError); - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/* --------------------------------------------------------------------- */ - -NXstatus NX4opendata(NXhandle fid, CONSTCHAR *name) { - pNexusFile pFile; - int32 iNew, attID, tags[2]; - pFile = NXIassert(fid); - - /* First find the reference number of the SDS */ - iNew = NXIFindSDS(fid, name); - if (iNew < 0) { - char pBuffer[256]; - sprintf(pBuffer, "ERROR: SDS \"%s\" not found at this level", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - /* Be nice: properly close the old open SDS silently if there is - * still an SDS open. - */ - if (pFile->iCurrentSDS) { - const int iRet = SDendaccess(pFile->iCurrentSDS); - if (iRet < 0) { - NXReportError("ERROR: HDF cannot end access to SDS"); - } - } - /* clear pending attribute directories first */ - NXIKillAttDir(pFile); - - /* open the SDS, thereby watching for linked SDS under a different name */ - iNew = SDreftoindex(pFile->iSID, iNew); - pFile->iCurrentSDS = SDselect(pFile->iSID, iNew); - attID = SDfindattr(pFile->iCurrentSDS, "NAPIlink"); - if (attID >= 0) { - SDreadattr(pFile->iCurrentSDS, attID, tags); - SDendaccess(pFile->iCurrentSDS); - iNew = SDreftoindex(pFile->iSID, tags[1]); - pFile->iCurrentSDS = SDselect(pFile->iSID, iNew); - } - - if (pFile->iCurrentSDS < 0) { - NXReportError("ERROR: HDF error opening SDS"); - pFile->iCurrentSDS = 0; - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/* ----------------------------------------------------------------- */ - -NXstatus NX4closedata(NXhandle fid) { - pNexusFile pFile; - pFile = NXIassert(fid); - - if (pFile->iCurrentSDS != 0) { - int iRet = SDendaccess(pFile->iCurrentSDS); - pFile->iCurrentSDS = 0; - if (iRet < 0) { - NXReportError("ERROR: HDF cannot end access to SDS"); - return NXstatus::NX_ERROR; - } - } else { - NXReportError("ERROR: no SDS open --> nothing to do"); - return NXstatus::NX_ERROR; - } - NXIKillAttDir(pFile); /* for attribute data */ - return NXstatus::NX_OK; -} - -/* ------------------------------------------------------------------- */ - -NXstatus NX4putdata(NXhandle fid, const void *data) { - pNexusFile pFile; - int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS], iStride[H4_MAX_VAR_DIMS]; - NXname pBuffer; - int32 iRank, iAtt, iType; - - pFile = NXIassert(fid); - - /* check if there is an SDS open */ - if (pFile->iCurrentSDS == 0) { - NXReportError("ERROR: no SDS open"); - return NXstatus::NX_ERROR; - } - /* first read dimension information */ - memset(iStart, 0, H4_MAX_VAR_DIMS * sizeof(int32)); - SDgetinfo(pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt); - - /* initialise stride to 1 */ - for (int i = 0; i < iRank; i++) { - iStride[i] = 1; - } - - /* actually write */ - int32 iRet = - SDwritedata(pFile->iCurrentSDS, iStart, iStride, iSize, const_cast(static_cast(data))); - if (iRet < 0) { - /* HEprint(stdout,0); */ - char pError[512]; - sprintf(pError, "ERROR: failure to write data to %s", pBuffer); - NXReportError(pError); - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/* ------------------------------------------------------------------- */ - -NXstatus NX4putattr(NXhandle fid, CONSTCHAR *name, const void *data, int datalen, NXnumtype iType) { - pNexusFile pFile; - int iRet, type; - - pFile = NXIassert(fid); - type = nxToHDF4Type(iType); - if (type == -1) { - NXReportError("ERROR: Invalid data type for HDF attribute"); - return NXstatus::NX_ERROR; - } - if (pFile->iCurrentSDS != 0) { - /* SDS attribute */ - iRet = SDsetattr(pFile->iCurrentSDS, static_cast(name), static_cast(type), - static_cast(datalen), data); - } else { - if (pFile->iCurrentVG == 0) { - /* global attribute */ - iRet = SDsetattr(pFile->iSID, static_cast(name), static_cast(type), - static_cast(datalen), data); - } else { - /* group attribute */ - iRet = Vsetattr(pFile->iCurrentVG, static_cast(name), static_cast(type), - static_cast(datalen), data); - } - } - // iType = type; // TODO what is the intention here? - if (iRet < 0) { - NXReportError("ERROR: HDF failed to store attribute "); - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/* ------------------------------------------------------------------- */ - -NXstatus NX4putslab64(NXhandle fid, const void *data, const int64_t iStart[], const int64_t iSize[]) { - pNexusFile pFile; - int iRet; - int32 iStride[H4_MAX_VAR_DIMS]; - int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS]; - int32 i, iRank, iType, iAtt; - NXname pBuffer; - - pFile = NXIassert(fid); - - /* check if there is an SDS open */ - if (pFile->iCurrentSDS == 0) { - NXReportError("ERROR: no SDS open"); - return NXstatus::NX_ERROR; - } - /* initialise stride to 1 */ - for (i = 0; i < H4_MAX_VAR_DIMS; i++) { - iStride[i] = 1; - } - - SDgetinfo(pFile->iCurrentSDS, pBuffer, &iRank, myStart, &iType, &iAtt); - for (i = 0; i < iRank; i++) { - myStart[i] = (int32)iStart[i]; - mySize[i] = (int32)iSize[i]; - } - /* finally write */ - iRet = SDwritedata(pFile->iCurrentSDS, myStart, iStride, mySize, const_cast(static_cast(data))); - - /* deal with HDF errors */ - if (iRet < 0) { - NXReportError("ERROR: writing slab failed"); - return NXstatus::NX_ERROR; - } - return NXstatus::NX_OK; -} - -/* ------------------------------------------------------------------- */ - -NXstatus NX4getdataID(NXhandle fid, NXlink *sRes) { - pNexusFile pFile; - int datalen; - NXnumtype type = NXnumtype::CHAR; - - pFile = NXIassert(fid); - - if (pFile->iCurrentSDS == 0) { - sRes->iTag = static_cast(NXstatus::NX_ERROR); - return NXstatus::NX_ERROR; - } else { - sRes->iTag = DFTAG_NDG; - sRes->iRef = SDidtoref(pFile->iCurrentSDS); - datalen = 1024; - memset(&sRes->targetPath, 0, 1024); - if (NX4getattr(fid, "target", &sRes->targetPath, &datalen, &type) != NXstatus::NX_OK) { - NXIbuildPath(pFile, sRes->targetPath, 1024); - } - return NXstatus::NX_OK; - } - sRes->iTag = static_cast(NXstatus::NX_ERROR); - return NXstatus::NX_ERROR; /* not reached */ -} - -/* ------------------------------------------------------------------- */ - -NXstatus NX4makelink(NXhandle fid, NXlink *sLink) { - pNexusFile pFile; - int32 dataID, type = DFNT_CHAR8; - char name[] = "target"; - - pFile = NXIassert(fid); - - if (pFile->iCurrentVG == 0) { /* root level, can not link here */ - return NXstatus::NX_ERROR; - } - Vaddtagref(pFile->iCurrentVG, static_cast(sLink->iTag), static_cast(sLink->iRef)); - int32 length = static_cast(strlen(sLink->targetPath)); - if (sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG || sLink->iTag == DFTAG_SDS) { - dataID = SDreftoindex(pFile->iSID, static_cast(sLink->iRef)); - dataID = SDselect(pFile->iSID, dataID); - SDsetattr(dataID, name, type, length, sLink->targetPath); - SDendaccess(dataID); - } else { - dataID = Vattach(pFile->iVID, static_cast(sLink->iRef), "w"); - Vsetattr(dataID, static_cast(name), type, (int32)length, sLink->targetPath); - Vdetach(dataID); - } - return NXstatus::NX_OK; -} -/* ------------------------------------------------------------------- */ - -NXstatus NX4makenamedlink(NXhandle fid, CONSTCHAR *newname, NXlink *sLink) { - pNexusFile pFile; - int32 dataID, type = DFNT_CHAR8, rank = 1; - NXnumtype dataType = NXnumtype::CHAR, attType = NXnumtype::INT32; - char name[] = "target"; - int tags[2]; - - pFile = NXIassert(fid); - - if (pFile->iCurrentVG == 0) { /* root level, can not link here */ - return NXstatus::NX_ERROR; - } - - tags[0] = static_cast(sLink->iTag); - tags[1] = static_cast(sLink->iRef); - - int32 length = static_cast(strlen(sLink->targetPath)); - if (sLink->iTag == DFTAG_SDG || sLink->iTag == DFTAG_NDG || sLink->iTag == DFTAG_SDS) { - int64_t iDim[1] = {1}; - NX4makedata64(fid, newname, dataType, rank, iDim); - NX4opendata(fid, newname); - NX4putattr(fid, "NAPIlink", tags, 2, attType); - NX4closedata(fid); - dataID = SDreftoindex(pFile->iSID, static_cast(sLink->iRef)); - dataID = SDselect(pFile->iSID, dataID); - SDsetattr(dataID, name, type, length, sLink->targetPath); - SDendaccess(dataID); - } else { - NX4makegroup(fid, newname, "NAPIlink"); - NX4opengroup(fid, newname, "NAPIlink"); - NX4putattr(fid, "NAPIlink", tags, 2, attType); - NX4closegroup(fid); - dataID = Vattach(pFile->iVID, static_cast(sLink->iRef), "w"); - Vsetattr(dataID, static_cast(name), type, (int32)length, sLink->targetPath); - Vdetach(dataID); - } - return NXstatus::NX_OK; -} - -/*----------------------------------------------------------------------*/ - -NXstatus NX4printlink(NXhandle fid, NXlink const *sLink) { - NXIassert(fid); - printf("HDF4 link: iTag = %ld, iRef = %ld, target=\"%s\"\n", sLink->iTag, sLink->iRef, sLink->targetPath); - return NXstatus::NX_OK; -} - -/*----------------------------------------------------------------------*/ - -NXstatus NX4flush(NXhandle *pHandle) { - char *pFileName, *pCopy = NULL; - int access, dummy, i, iStack; - NXstatus iRet; - pNexusFile pFile = NULL; - NXaccess ac; - int *iRefs = NULL; - - pFile = NXIassert(*pHandle); - - /* - The HDF4-API does not support a flush. We help ourselves with - inquiring the name and access type of the file, closing it and - opening it again. This is also the reason why this needs a pointer - to the handle structure as the handle changes. The other thing we - do is to store the refs of all open vGroups in a temporary array - in order to recover the position in the vGroup hierarchy before the - flush. - */ - iRet = static_cast(Hfidinquire(pFile->iVID, &pFileName, &access, &dummy)); - if (iRet == NXstatus::NX_EOD) { - NXReportError("ERROR: Failed to inquire file name for HDF file"); - return NXstatus::NX_ERROR; - } - if (pFile->iAccess[0] == 'r') { - ac = NXACC_READ; - } else if (pFile->iAccess[0] == 'w') { - ac = NXACC_RDWR; - } else { - NXReportError("ERROR: NX4flush failed to determine file access mode"); - return NXstatus::NX_ERROR; - } - pCopy = static_cast(malloc((strlen(pFileName) + 10) * sizeof(char))); - if (!pCopy) { - NXReportError("ERROR: Failed to allocate data for filename copy"); - return NXstatus::NX_ERROR; - } - memset(pCopy, 0, strlen(pFileName) + 10); - strcpy(pCopy, pFileName); - - /* get refs for recovering vGroup position */ - iStack = 0; - if (pFile->iStackPtr > 0) { - iStack = pFile->iStackPtr + 1; - iRefs = static_cast(malloc(iStack * sizeof(int))); - if (!iRefs) { - free(pCopy); // do not leak memory - NXReportError("ERROR: Failed to allocate data for hierarchy copy"); - return NXstatus::NX_ERROR; - } - for (i = 0; i < iStack; i++) { - iRefs[i] = pFile->iStack[i].iVref; - } - } - - NX4close(pHandle); - - iRet = NX4open(pCopy, ac, pHandle); - free(pCopy); - - /* return to position in vGroup hierarchy */ - pFile = NXIassert(*pHandle); - if (iStack > 0) { - pFile->iStackPtr = iStack - 1; - for (i = 0; i < iStack; i++) { - pFile->iStack[i].iVref = iRefs[i]; - } - free(iRefs); - pFile->iCurrentVG = Vattach(pFile->iVID, pFile->iStack[pFile->iStackPtr].iVref, pFile->iAccess); - } - - return iRet; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getnextentry(NXhandle fid, NXname name, NXname nxclass, NXnumtype *datatype) { - pNexusFile pFile; - int iStackPtr, iCurDir; - int32 iTemp, iD1, iD2, iA; - int32 iDim[H4_MAX_VAR_DIMS]; - - pFile = NXIassert(fid); - - iStackPtr = pFile->iStackPtr; - iCurDir = pFile->iStack[pFile->iStackPtr].iCurDir; - - /* first case to check for: no directory entry */ - if (pFile->iStack[pFile->iStackPtr].iRefDir == NULL) { - if (NXIInitDir(pFile) == NXstatus::NX_EOD) { - NXReportError("ERROR: no memory to store directory info"); - return NXstatus::NX_EOD; - } - } - - /* Next case: end of directory */ - if (iCurDir >= pFile->iStack[pFile->iStackPtr].iNDir) { - NXIKillDir(pFile); - return NXstatus::NX_EOD; - } - - /* Next case: we have data! supply it and increment counter */ - if (pFile->iCurrentVG == 0) { /* root level */ - iTemp = Vattach(pFile->iVID, pFile->iStack[iStackPtr].iRefDir[iCurDir], "r"); - if (iTemp < 0) { - NXReportError("ERROR: HDF cannot attach to Vgroup"); - return NXstatus::NX_ERROR; - } - Vgetname(iTemp, name); - Vdetach(iTemp); - findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass); - *datatype = static_cast(DFTAG_VG); - pFile->iStack[pFile->iStackPtr].iCurDir++; - return NXstatus::NX_OK; - } else { /* in Vgroup */ - if (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_VG) { /* Vgroup */ - iTemp = Vattach(pFile->iVID, pFile->iStack[iStackPtr].iRefDir[iCurDir], "r"); - if (iTemp < 0) { - NXReportError("ERROR: HDF cannot attach to Vgroup"); - return NXstatus::NX_ERROR; - } - Vgetname(iTemp, name); - Vdetach(iTemp); - findNapiClass(pFile, pFile->iStack[pFile->iStackPtr].iRefDir[iCurDir], nxclass); - *datatype = static_cast(DFTAG_VG); - pFile->iStack[pFile->iStackPtr].iCurDir++; - Vdetach(iTemp); - return NXstatus::NX_OK; - /* we are now writing using DFTAG_NDG, but need others for backward compatability */ - } else if ((pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDG) || - (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_NDG) || - (pFile->iStack[iStackPtr].iTagDir[iCurDir] == DFTAG_SDS)) { - iTemp = SDreftoindex(pFile->iSID, pFile->iStack[iStackPtr].iRefDir[iCurDir]); - iTemp = SDselect(pFile->iSID, iTemp); - SDgetinfo(iTemp, name, &iA, iDim, &iD1, &iD2); - strcpy(nxclass, "SDS"); - *datatype = static_cast(iD1); - SDendaccess(iTemp); - pFile->iStack[pFile->iStackPtr].iCurDir++; - return NXstatus::NX_OK; - } else { /* unidentified */ - strcpy(name, "UNKNOWN"); - strcpy(nxclass, "UNKNOWN"); - *datatype = static_cast(pFile->iStack[iStackPtr].iTagDir[iCurDir]); - pFile->iStack[pFile->iStackPtr].iCurDir++; - return NXstatus::NX_OK; - } - } - return NXstatus::NX_ERROR; /* not reached */ -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getdata(NXhandle fid, void *data) { - pNexusFile pFile; - int32 iStart[H4_MAX_VAR_DIMS], iSize[H4_MAX_VAR_DIMS]; - NXname pBuffer; - int32 iRank, iAtt, iType; - - pFile = NXIassert(fid); - - /* check if there is an SDS open */ - if (pFile->iCurrentSDS == 0) { - NXReportError("ERROR: no SDS open"); - return NXstatus::NX_ERROR; - } - /* first read dimension information */ - memset(iStart, 0, H4_MAX_VAR_DIMS * sizeof(int32)); - SDgetinfo(pFile->iCurrentSDS, pBuffer, &iRank, iSize, &iType, &iAtt); - /* actually read */ - SDreaddata(pFile->iCurrentSDS, iStart, NULL, iSize, data); - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getinfo64(NXhandle fid, int *rank, int64_t dimension[], NXnumtype *iType) { - pNexusFile pFile; - NXname pBuffer; - int32 iAtt, myDim[H4_MAX_VAR_DIMS], i, iRank, mType; - - pFile = NXIassert(fid); - - /* check if there is an SDS open */ - if (pFile->iCurrentSDS == 0) { - NXReportError("ERROR: no SDS open"); - return NXstatus::NX_ERROR; - } - /* read information */ - SDgetinfo(pFile->iCurrentSDS, pBuffer, &iRank, myDim, &mType, &iAtt); - - /* conversion to proper ints for the platform */ - *iType = static_cast(mType); - *rank = (int)iRank; - for (i = 0; i < iRank; i++) { - dimension[i] = (int)myDim[i]; - } - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getslab64(NXhandle fid, void *data, const int64_t iStart[], const int64_t iSize[]) { - pNexusFile pFile; - int32 myStart[H4_MAX_VAR_DIMS], mySize[H4_MAX_VAR_DIMS]; - int32 i, iRank, iType, iAtt; - NXname pBuffer; - - pFile = NXIassert(fid); - - /* check if there is an SDS open */ - if (pFile->iCurrentSDS == 0) { - NXReportError("ERROR: no SDS open"); - return NXstatus::NX_ERROR; - } - - SDgetinfo(pFile->iCurrentSDS, pBuffer, &iRank, myStart, &iType, &iAtt); - for (i = 0; i < iRank; i++) { - myStart[i] = (int32)iStart[i]; - mySize[i] = (int32)iSize[i]; - } - /* finally read */ - SDreaddata(pFile->iCurrentSDS, myStart, NULL, mySize, data); - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getnextattr(NXhandle fileid, NXname pName, int *iLength, NXnumtype *iType) { - pNexusFile pFile; - NXstatus iRet; - int32 iPType, iCount, count; - - pFile = NXIassert(fileid); - - /* first check if we have to start a new attribute search */ - if (pFile->iAtt.iNDir == 0) { - iRet = NXIInitAttDir(pFile); - if (iRet == NXstatus::NX_ERROR) { - return NXstatus::NX_ERROR; - } - } - /* are we done ? */ - if (pFile->iAtt.iCurDir >= pFile->iAtt.iNDir) { - NXIKillAttDir(pFile); - return NXstatus::NX_EOD; - } - /* well, there must be data to copy */ - if (pFile->iCurrentSDS == 0) { - if (pFile->iCurrentVG == 0) { - /* global attribute */ - iRet = static_cast(SDattrinfo(pFile->iSID, pFile->iAtt.iCurDir, pName, &iPType, &iCount)); - } else { - /* group attribute */ - iRet = static_cast(Vattrinfo(pFile->iCurrentVG, pFile->iAtt.iCurDir, pName, &iPType, &iCount, &count)); - } - } else { - iRet = static_cast(SDattrinfo(pFile->iCurrentSDS, pFile->iAtt.iCurDir, pName, &iPType, &iCount)); - } - if (iRet == NXstatus::NX_EOD) { - NXReportError("ERROR: HDF cannot read attribute info"); - return NXstatus::NX_ERROR; - } - *iLength = iCount; - *iType = static_cast(iPType); - pFile->iAtt.iCurDir++; - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getattr(NXhandle fid, const char *name, void *data, int *datalen, NXnumtype *iType) { - pNexusFile pFile; - int32 iNew, iType32, count; - void *pData = NULL; - int32 iLen, iRet; - int type; - char pBuffer[256]; - NXname pNam; - - type = nxToHDF4Type(*iType); - *datalen = (*datalen) * DFKNTsize(type); - pFile = NXIassert(fid); - - /* find attribute */ - if (pFile->iCurrentSDS != 0) { - /* SDS attribute */ - iNew = SDfindattr(pFile->iCurrentSDS, name); - } else { - if (pFile->iCurrentVG == 0) { - /* global attribute */ - iNew = SDfindattr(pFile->iSID, name); - } else { - /* group attribute */ - iNew = Vfindattr(pFile->iCurrentVG, name); - } - } - if (iNew < 0) { - sprintf(pBuffer, "ERROR: attribute \"%s\" not found", name); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - /* get more info, allocate temporary data space */ - iType32 = (int32)type; - if (pFile->iCurrentSDS != 0) { - iRet = SDattrinfo(pFile->iCurrentSDS, iNew, pNam, &iType32, &iLen); - } else { - if (pFile->iCurrentVG == 0) { - iRet = SDattrinfo(pFile->iSID, iNew, pNam, &iType32, &iLen); - } else { - iRet = Vattrinfo(pFile->iCurrentVG, iNew, pNam, &iType32, &count, &iLen); - } - } - if (iRet < 0) { - sprintf(pBuffer, "ERROR: HDF could not read attribute info"); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - *iType = static_cast(iType32); - iLen = iLen * DFKNTsize(type); - if (*iType == NXnumtype::CHAR) { - iLen += 1; - } - pData = malloc(iLen); - if (!pData) { - NXReportError("ERROR: allocating memory in NXgetattr"); - return NXstatus::NX_ERROR; - } - memset(pData, 0, iLen); - - /* finally read the data */ - if (pFile->iCurrentSDS != 0) { - iRet = SDreadattr(pFile->iCurrentSDS, iNew, pData); - } else { - if (pFile->iCurrentVG == 0) { - iRet = SDreadattr(pFile->iSID, iNew, pData); - } else { - iRet = Vgetattr(pFile->iCurrentVG, iNew, pData); - } - } - if (iRet < 0) { - sprintf(pBuffer, "ERROR: HDF could not read attribute data"); - NXReportError(pBuffer); - return NXstatus::NX_ERROR; - } - /* copy data to caller */ - memset(data, 0, *datalen); - if ((*datalen <= iLen) && (type == DFNT_UINT8 || type == DFNT_CHAR8 || type == DFNT_UCHAR8)) { - iLen = *datalen - 1; /* this enforces NULL termination regardless of size of datalen */ - } - memcpy(data, pData, iLen); - *datalen = iLen / DFKNTsize(type); - free(pData); - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getattrinfo(NXhandle fid, int *iN) { - pNexusFile pFile; - int iRet; - int32 iData, iAtt, iRank, iType; - int32 iDim[H4_MAX_VAR_DIMS]; - - pFile = NXIassert(fid); - if (pFile->iCurrentSDS != 0) { /* SDS level */ - NXname pNam; - iRet = SDgetinfo(pFile->iCurrentSDS, pNam, &iRank, iDim, &iType, &iAtt); - } else { - if (pFile->iCurrentVG == 0) { - /* global level */ - iRet = SDfileinfo(pFile->iSID, &iData, &iAtt); - } else { - iRet = Vnattrs(pFile->iCurrentVG); - iAtt = iRet; - } - } - if (iRet < 0) { - NXReportError("NX_ERROR: HDF cannot read attribute numbers"); - *iN = 0; - return NXstatus::NX_ERROR; - } - *iN = iAtt; - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getgroupID(NXhandle fileid, NXlink *sRes) { - pNexusFile pFile; - - pFile = NXIassert(fileid); - - if (pFile->iCurrentVG == 0) { - sRes->iTag = static_cast(NXstatus::NX_ERROR); - return NXstatus::NX_ERROR; - } else { - sRes->iTag = DFTAG_VG; - sRes->iRef = VQueryref(pFile->iCurrentVG); - NXIbuildPath(pFile, sRes->targetPath, 1024); - return NXstatus::NX_OK; - } - /* not reached */ - sRes->iTag = static_cast(NXstatus::NX_ERROR); - return NXstatus::NX_ERROR; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4getgroupinfo(NXhandle fid, int *iN, NXname pName, NXname pClass) { - pNexusFile pFile; - - pFile = NXIassert(fid); - /* check if there is a group open */ - if (pFile->iCurrentVG == 0) { - *iN = Vlone(pFile->iVID, NULL, 0); - strcpy(pName, "root"); - strcpy(pClass, "NXroot"); - } else { - *iN = Vntagrefs(pFile->iCurrentVG); - Vgetname(pFile->iCurrentVG, pName); - Vgetclass(pFile->iCurrentVG, pClass); - } - return NXstatus::NX_OK; -} - -/* ------------------------------------------------------------------- */ - -NXstatus NX4sameID(NXhandle fileid, NXlink const *pFirstID, NXlink const *pSecondID) { - NXIassert(fileid); - if ((pFirstID->iTag == pSecondID->iTag) & (pFirstID->iRef == pSecondID->iRef)) { - return NXstatus::NX_OK; - } else { - return NXstatus::NX_ERROR; - } -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4initattrdir(NXhandle fid) { - pNexusFile pFile; - NXstatus iRet; - - pFile = NXIassert(fid); - NXIKillAttDir(pFile); - iRet = NXIInitAttDir(pFile); - if (iRet == NXstatus::NX_ERROR) - return NXstatus::NX_ERROR; - return NXstatus::NX_OK; -} - -/*-------------------------------------------------------------------------*/ - -NXstatus NX4initgroupdir(NXhandle fid) { - pNexusFile pFile; - NXstatus iRet; - - pFile = NXIassert(fid); - NXIKillDir(pFile); - iRet = NXIInitDir(pFile); - if (iRet == NXstatus::NX_EOD) { - NXReportError("NX_ERROR: no memory to store directory info"); - return NXstatus::NX_EOD; - } - return NXstatus::NX_OK; -} - -/*--------------------------------------------------------------------*/ -NXstatus NX4putattra(NXhandle handle, CONSTCHAR *name, const void *data, const int rank, const int dim[], - const NXnumtype iType) { - if (rank > 1) { - NXReportError("This is a HDF4 file, there is only rudimentary support for attribute arrays wirh rank <=1"); - return NXstatus::NX_ERROR; - } - - return NX4putattr(handle, name, data, dim[0], iType); -} - -/*--------------------------------------------------------------------*/ -NXstatus NX4getnextattra(NXhandle handle, NXname pName, int *rank, int dim[], NXnumtype *iType) { - NXstatus ret = NX4getnextattr(handle, pName, dim, iType); - if (ret != NXstatus::NX_OK) - return ret; - (*rank) = 1; - if (dim[0] <= 1) - (*rank) = 0; - return NXstatus::NX_OK; -} - -/*--------------------------------------------------------------------*/ -NXstatus NX4getattra(NXhandle, const char *, void *) { - NXReportError("This is a HDF4 file, attribute array API is not supported here"); - return NXstatus::NX_ERROR; -} - -/*--------------------------------------------------------------------*/ -NXstatus NX4getattrainfo(NXhandle, NXname, int *, int[], NXnumtype *) { - NXReportError("This is a HDF4 file, attribute array API is not supported here"); - return NXstatus::NX_ERROR; -} - -/*--------------------------------------------------------------------*/ -void NX4assignFunctions(pNexusFunction fHandle) { - fHandle->nxclose = NX4close; - fHandle->nxreopen = NULL; - fHandle->nxflush = NX4flush; - fHandle->nxmakegroup = NX4makegroup; - fHandle->nxopengroup = NX4opengroup; - fHandle->nxclosegroup = NX4closegroup; - fHandle->nxmakedata64 = NX4makedata64; - fHandle->nxcompmakedata64 = NX4compmakedata64; - fHandle->nxcompress = NX4compress; - fHandle->nxopendata = NX4opendata; - fHandle->nxclosedata = NX4closedata; - fHandle->nxputdata = NX4putdata; - fHandle->nxputattr = NX4putattr; - fHandle->nxputslab64 = NX4putslab64; - fHandle->nxgetdataID = NX4getdataID; - fHandle->nxmakelink = NX4makelink; - fHandle->nxmakenamedlink = NX4makenamedlink; - fHandle->nxgetdata = NX4getdata; - fHandle->nxgetinfo64 = NX4getinfo64; - fHandle->nxgetnextentry = NX4getnextentry; - fHandle->nxgetslab64 = NX4getslab64; - fHandle->nxgetnextattr = NX4getnextattr; - fHandle->nxgetattr = NX4getattr; - fHandle->nxgetattrinfo = NX4getattrinfo; - fHandle->nxgetgroupID = NX4getgroupID; - fHandle->nxgetgroupinfo = NX4getgroupinfo; - fHandle->nxsameID = NX4sameID; - fHandle->nxinitgroupdir = NX4initgroupdir; - fHandle->nxinitattrdir = NX4initattrdir; - fHandle->nxprintlink = NX4printlink; - fHandle->nxnativeexternallink = NULL; - fHandle->nxputattra = NX4putattra; - fHandle->nxgetnextattra = NX4getnextattra; - fHandle->nxgetattra = NX4getattra; - fHandle->nxgetattrainfo = NX4getattrainfo; -} - -#endif /*HDF4*/ diff --git a/Framework/Nexus/test/CMakeLists.txt b/Framework/Nexus/test/CMakeLists.txt index ede67305df0f..c9d29e01b590 100644 --- a/Framework/Nexus/test/CMakeLists.txt +++ b/Framework/Nexus/test/CMakeLists.txt @@ -27,20 +27,6 @@ add_executable(napi_test_cpp-hdf5 EXCLUDE_FROM_ALL napi_test_cpp.cpp napi_test_u target_link_libraries(napi_test_cpp-hdf5 PRIVATE Mantid::Nexus) add_test(NAME "${TEST_PREFIX}-Cpp-HDF5-test" COMMAND napi_test_cpp-hdf5) -# #### HDF4 -add_executable(napi_test_hdf4 EXCLUDE_FROM_ALL napi_test.cpp napi_test_util.cpp napi_test_util.h) -target_link_libraries(napi_test_hdf4 PRIVATE Mantid::Nexus) -add_test(NAME "${TEST_PREFIX}-C-HDF4-test" COMMAND napi_test_hdf4) - -add_executable(napi_attra_test_hdf4 EXCLUDE_FROM_ALL napi_attra_test.cpp napi_test_util.cpp napi_test_util.h) -target_link_libraries(napi_attra_test_hdf4 PRIVATE Mantid::Nexus) -add_test(NAME "${TEST_PREFIX}-C-HDF4-attra-test" COMMAND napi_attra_test_hdf4) -set_tests_properties("${TEST_PREFIX}-C-HDF4-attra-test" PROPERTIES WILL_FAIL TRUE) - -add_executable(napi_test_cpp-hdf4 EXCLUDE_FROM_ALL napi_test_cpp.cpp napi_test_util.cpp napi_test_util.h) -target_link_libraries(napi_test_cpp-hdf4 PRIVATE Mantid::Nexus) -add_test(NAME "${TEST_PREFIX}-Cpp-HDF4-test" COMMAND napi_test_cpp-hdf4) - # #### test for unlimited dimensions add_executable(napi_test_nxunlimited EXCLUDE_FROM_ALL test_nxunlimited.cpp) target_link_libraries(napi_test_nxunlimited PRIVATE Mantid::Nexus) @@ -66,9 +52,6 @@ add_custom_target( DEPENDS napi_test_hdf5 napi_attra_test_hdf5 napi_test_cpp-hdf5 - napi_test_hdf4 - napi_attra_test_hdf4 - napi_test_cpp-hdf4 napi_test_nxunlimited napi_leak_test1 napi_leak_test2 diff --git a/Framework/Nexus/test/test_nxunlimited.cpp b/Framework/Nexus/test/test_nxunlimited.cpp index 42969c6171a7..9eafe3ac6c68 100644 --- a/Framework/Nexus/test/test_nxunlimited.cpp +++ b/Framework/Nexus/test/test_nxunlimited.cpp @@ -62,12 +62,6 @@ int test_unlimited(int file_type, const char *filename) { int main() { time_t tim; -#ifdef WITH_HDF4 - printf("Testing HDF4\n"); - time(&tim); - test_unlimited(NXACC_CREATE4, "test_unlimited.nx4"); - printf("Took %u seconds\n", (unsigned)(time(NULL) - tim)); -#endif #ifdef WITH_HDF5 printf("Testing HDF5\n"); diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DirectILLCollectData.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DirectILLCollectData.py index bb6ef4046df9..174748c16dd5 100644 --- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DirectILLCollectData.py +++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/DirectILLCollectData.py @@ -819,7 +819,6 @@ def _inputWS(self): mainWS = LoadAndMerge( Filename=inputFiles, OutputWorkspace=mergedWSName, - LoaderName="LoadILLTOF", LoaderOptions={"ConvertToTOF": True}, EnableLogging=self._subalgLogging, ) diff --git a/Testing/Data/UnitTest/ILL/IN5/095893.nxs.md5 b/Testing/Data/UnitTest/ILL/IN5/095893.nxs.md5 new file mode 100644 index 000000000000..81c46029f290 --- /dev/null +++ b/Testing/Data/UnitTest/ILL/IN5/095893.nxs.md5 @@ -0,0 +1 @@ +0b1622b169d428387a21490c01293883 diff --git a/docs/source/algorithms/LoadILLTOF-v3.rst b/docs/source/algorithms/LoadILLTOF-v3.rst new file mode 100644 index 000000000000..3e27519e70c8 --- /dev/null +++ b/docs/source/algorithms/LoadILLTOF-v3.rst @@ -0,0 +1,87 @@ +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +Loads an ILL TOF NeXus file into a :ref:`Workspace2D ` with the given name. + +To date this algorithm only supports: IN4, IN5, IN6, PANTHER, and SHARP. + +By default, this algorithm loads the data indexed by channels. To convert to time-of-flight, use the `ConvertToTOF` option. + +This algorithm also supports diffraction mode. In this case, the unit of the output workspace will be wavelength instead of time-of-flight or channel. + +The support for the omega scan measurement mode for IN5, PANTHER, and SHARP is also handled by this loader, with the assumption that only one monitor exists. The X-axis +unit is `Label` with values provided by the scanned parameter. In this case, the setting to convert to the time-of-flight with `ConvertToTOF` has no effect. + +.. note:: + The initial time-of-flight axis is set up using the 'time_of_flight' field in the NeXus file. Therefore the conversion from 'TOF' to 'DeltaE' may not give the correct zero-energy transfer. + +.. note:: + LoadILLTOF3 uses HDF5 and cannot read former HDF4-based NeXus files. Please use LoadILLTOF2 in that case. + +Pulse Intervals +--------------- + +For IN4 and IN6 the algorithm also calculates the pulse interval. + +For the number of pulses: + +* **IN4:** :math:`n_{pulses} = \frac{v_{fc}}{4 v_{bc}}` + where :math:`n_{pulses}` is the number of pulses from the chopper per rotation, :math:`v_{fc}` the Fermi chopper speed and :math:`v_{bc}` the background chopper speed. Background chopper 1 and background chopper 2 must have the same speeds. All speeds are in units of rpm. + +* **IN6:** :math:`n_{pulses} = \frac{v_{fc}}{v_{sc}}` + where :math:`n_{pulses}` is the number of pulses from the chopper per rotation, :math:`v_{fc}` the Fermi chopper speed and :math:`v_{sc}` the suppressor chopper speed. All speeds are in units of rpm. + +The pulse interval, :math:`T_{pulse}` in seconds, is then given by, + +:math:`T_{pulse} = \frac{60 \textrm{s}}{2 v_{fc}} n_{pulses}`. + +Usage +----- + +.. include:: ../usagedata-note.txt + +**Example - Load a regular histogram NeXus file:** + +.. testcode:: ExLoad + + # Regular data file. + dataRegular = 'ILL/IN5/104007.nxs' + + # Load ILL dataset + ws = Load(dataRegular) + + numDimensions = ws.getNumDims() + numHistograms = ws.getNumberHistograms() + print('This workspace has {0} dimensions and {1} histograms.'.format(numDimensions, numHistograms)) + +Output: + +.. testoutput:: ExLoad + + This workspace has 2 dimensions and 98305 histograms. + +**Example - Loading IN5 data scan** + +.. testcode:: LoadILLTOF3IN5ScanExample + + ws = LoadILLTOF(Filename='ILL/IN5/199857.nxs') + + print('The output has {0} bin (omega scan) and {1} spectra'.format(ws.blocksize(), ws.getNumberHistograms())) + +Output: + +.. testoutput:: LoadILLTOF3IN5ScanExample + + The output has 17 bin (omega scan) and 98305 spectra + +.. categories:: + +.. sourcelink::