diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt index 7db38254628aa5ce3be44399c4166a4a2b0e6c63..d1d6b69016858201fda69f7e2d8d1e792a314352 100644 --- a/Framework/DataHandling/CMakeLists.txt +++ b/Framework/DataHandling/CMakeLists.txt @@ -47,18 +47,17 @@ set(SRC_FILES src/LoadDetectorsGroupingFile.cpp src/LoadDiffCal.cpp src/LoadDspacemap.cpp - src/LoadEmptyInstrument.cpp src/LoadEMU.cpp - src/LoadOff.cpp - src/LoadPLN.cpp + src/LoadEmptyInstrument.cpp src/LoadEventNexus.cpp src/LoadEventNexusIndexSetup.cpp src/LoadEventPreNexus2.cpp src/LoadFITS.cpp src/LoadFullprofResolution.cpp - src/LoadGeometry.cpp src/LoadGSASInstrumentFile.cpp src/LoadGSS.cpp + src/LoadGeometry.cpp + src/LoadHFIRSANS.cpp src/LoadHelper.cpp src/LoadIDFFromNexus.cpp src/LoadILLDiffraction.cpp @@ -91,11 +90,13 @@ set(SRC_FILES src/LoadNexusMonitors.cpp src/LoadNexusMonitors2.cpp src/LoadNexusProcessed.cpp + src/LoadOff.cpp src/LoadPDFgetNFile.cpp + src/LoadPLN.cpp + src/LoadPSIMuonBin.cpp src/LoadParameterFile.cpp src/LoadPreNexus.cpp src/LoadPreNexusMonitors.cpp - src/LoadPSIMuonBin.cpp src/LoadQKK.cpp src/LoadRKH.cpp src/LoadRaw/byte_rel_comp.cpp @@ -107,21 +108,20 @@ set(SRC_FILES src/LoadRawBin0.cpp src/LoadRawHelper.cpp src/LoadRawSpectrum0.cpp - src/LoadSampleShape.cpp - src/LoadSampleEnvironment.cpp src/LoadSESANS.cpp src/LoadSINQFocus.cpp src/LoadSNSspec.cpp src/LoadSPE.cpp src/LoadSampleDetailsFromRaw.cpp + src/LoadSampleEnvironment.cpp + src/LoadSampleShape.cpp src/LoadSassena.cpp src/LoadSpec.cpp src/LoadSpice2D.cpp - src/LoadHFIRSANS.cpp src/LoadSpiceAscii.cpp src/LoadSpiceXML2DDet.cpp - src/LoadSwans.cpp src/LoadStl.cpp + src/LoadSwans.cpp src/LoadTBL.cpp src/LoadTOFRawNexus.cpp src/LoadVulcanCalFile.cpp @@ -170,6 +170,7 @@ set(SRC_FILES src/SaveNXTomo.cpp src/SaveNXcanSAS.cpp src/SaveNexus.cpp + src/SaveNexusGeometry.cpp src/SaveNexusProcessed.cpp src/SaveOpenGenieAscii.cpp src/SavePAR.cpp @@ -177,12 +178,12 @@ set(SRC_FILES src/SavePHX.cpp src/SaveParameterFile.cpp src/SaveRKH.cpp - src/SaveReflectometryAscii.cpp src/SaveReflCustomAscii.cpp src/SaveReflThreeColumnAscii.cpp - src/SaveSampleEnvironmentAndShape.cpp + src/SaveReflectometryAscii.cpp src/SaveSESANS.cpp src/SaveSPE.cpp + src/SaveSampleEnvironmentAndShape.cpp src/SaveStl.cpp src/SaveTBL.cpp src/SaveToSNSHistogramNexus.cpp @@ -246,18 +247,17 @@ set(INC_FILES inc/MantidDataHandling/LoadDetectorsGroupingFile.h inc/MantidDataHandling/LoadDiffCal.h inc/MantidDataHandling/LoadDspacemap.h - inc/MantidDataHandling/LoadEmptyInstrument.h inc/MantidDataHandling/LoadEMU.h - inc/MantidDataHandling/LoadOff.h - inc/MantidDataHandling/LoadPLN.h + inc/MantidDataHandling/LoadEmptyInstrument.h inc/MantidDataHandling/LoadEventNexus.h inc/MantidDataHandling/LoadEventNexusIndexSetup.h inc/MantidDataHandling/LoadEventPreNexus2.h inc/MantidDataHandling/LoadFITS.h inc/MantidDataHandling/LoadFullprofResolution.h - inc/MantidDataHandling/LoadGeometry.h inc/MantidDataHandling/LoadGSASInstrumentFile.h inc/MantidDataHandling/LoadGSS.h + inc/MantidDataHandling/LoadGeometry.h + inc/MantidDataHandling/LoadHFIRSANS.h inc/MantidDataHandling/LoadHelper.h inc/MantidDataHandling/LoadIDFFromNexus.h inc/MantidDataHandling/LoadILLDiffraction.h @@ -290,29 +290,30 @@ set(INC_FILES inc/MantidDataHandling/LoadNexusMonitors.h inc/MantidDataHandling/LoadNexusMonitors2.h inc/MantidDataHandling/LoadNexusProcessed.h + inc/MantidDataHandling/LoadOff.h inc/MantidDataHandling/LoadPDFgetNFile.h + inc/MantidDataHandling/LoadPLN.h + inc/MantidDataHandling/LoadPSIMuonBin.h inc/MantidDataHandling/LoadParameterFile.h inc/MantidDataHandling/LoadPreNexus.h inc/MantidDataHandling/LoadPreNexusMonitors.h - inc/MantidDataHandling/LoadPSIMuonBin.h inc/MantidDataHandling/LoadQKK.h inc/MantidDataHandling/LoadRKH.h inc/MantidDataHandling/LoadRaw3.h inc/MantidDataHandling/LoadRawBin0.h inc/MantidDataHandling/LoadRawHelper.h inc/MantidDataHandling/LoadRawSpectrum0.h - inc/MantidDataHandling/LoadSampleShape.h - inc/MantidDataHandling/LoadSampleEnvironment.h inc/MantidDataHandling/LoadSESANS.h inc/MantidDataHandling/LoadSINQFocus.h inc/MantidDataHandling/LoadSNSspec.h inc/MantidDataHandling/LoadSPE.h inc/MantidDataHandling/LoadSampleDetailsFromRaw.h + inc/MantidDataHandling/LoadSampleEnvironment.h + inc/MantidDataHandling/LoadSampleShape.h inc/MantidDataHandling/LoadSassena.h inc/MantidDataHandling/LoadShape.h inc/MantidDataHandling/LoadSpec.h inc/MantidDataHandling/LoadSpice2D.h - inc/MantidDataHandling/LoadHFIRSANS.h inc/MantidDataHandling/LoadSpiceAscii.h inc/MantidDataHandling/LoadSpiceXML2DDet.h inc/MantidDataHandling/LoadStl.h @@ -366,6 +367,7 @@ set(INC_FILES inc/MantidDataHandling/SaveNXTomo.h inc/MantidDataHandling/SaveNXcanSAS.h inc/MantidDataHandling/SaveNexus.h + inc/MantidDataHandling/SaveNexusGeometry.h inc/MantidDataHandling/SaveNexusProcessed.h inc/MantidDataHandling/SaveOpenGenieAscii.h inc/MantidDataHandling/SavePAR.h @@ -373,12 +375,12 @@ set(INC_FILES inc/MantidDataHandling/SavePHX.h inc/MantidDataHandling/SaveParameterFile.h inc/MantidDataHandling/SaveRKH.h - inc/MantidDataHandling/SaveReflectometryAscii.h inc/MantidDataHandling/SaveReflCustomAscii.h inc/MantidDataHandling/SaveReflThreeColumnAscii.h - inc/MantidDataHandling/SaveSampleEnvironmentAndShape.h + inc/MantidDataHandling/SaveReflectometryAscii.h inc/MantidDataHandling/SaveSESANS.h inc/MantidDataHandling/SaveSPE.h + inc/MantidDataHandling/SaveSampleEnvironmentAndShape.h inc/MantidDataHandling/SaveStl.h inc/MantidDataHandling/SaveTBL.h inc/MantidDataHandling/SaveToSNSHistogramNexus.h @@ -427,8 +429,8 @@ set(TEST_FILES InstrumentRayTracerTest.h JoinISISPolarizationEfficienciesTest.h LoadAscii2Test.h - LoadAsciiTest.h LoadAsciiStlTest.h + LoadAsciiTest.h LoadBBYTest.h LoadBinaryStlTest.h LoadCalFileTest.h @@ -438,8 +440,8 @@ set(TEST_FILES LoadDetectorsGroupingFileTest.h LoadDiffCalTest.h LoadDspacemapTest.h - LoadEmptyInstrumentTest.h LoadEMUauTest.h + LoadEmptyInstrumentTest.h LoadEventNexusIndexSetupTest.h LoadEventNexusTest.h LoadEventPreNexus2Test.h @@ -447,6 +449,7 @@ set(TEST_FILES LoadFullprofResolutionTest.h LoadGSASInstrumentFileTest.h LoadGSSTest.h + LoadHFIRSANSTest.h LoadIDFFromNexusTest.h LoadILLDiffractionTest.h LoadILLIndirect2Test.h @@ -477,32 +480,31 @@ set(TEST_FILES LoadNexusProcessedTest.h LoadNexusTest.h LoadPDFgetNFileTest.h - LoadParameterFileTest.h LoadPLNTest.h + LoadPSIMuonBinTest.h + LoadParameterFileTest.h LoadPreNexusMonitorsTest.h LoadPreNexusTest.h - LoadPSIMuonBinTest.h LoadQKKTest.h LoadRKHTest.h LoadRaw3Test.h LoadRawBin0Test.h LoadRawSaveNxsLoadNxsTest.h LoadRawSpectrum0Test.h - LoadStlTest.h - LoadSampleShapeTest.h - LoadSampleEnvironmentTest.h LoadSESANSTest.h LoadSINQFocusTest.h LoadSNSspecTest.h LoadSPETest.h LoadSampleDetailsFromRawTest.h + LoadSampleEnvironmentTest.h + LoadSampleShapeTest.h LoadSassenaTest.h LoadSaveAsciiTest.h LoadSpecTest.h LoadSpice2dTest.h - LoadHFIRSANSTest.h LoadSpiceAsciiTest.h LoadSpiceXML2DDetTest.h + LoadStlTest.h LoadSwansTest.h LoadTBLTest.h LoadTOFRawNexusTest.h @@ -547,6 +549,7 @@ set(TEST_FILES SaveNXSPETest.h SaveNXTomoTest.h SaveNXcanSASTest.h + SaveNexusGeometryTest.h SaveNexusProcessedTest.h SaveNexusTest.h SaveOpenGenieAsciiTest.h @@ -555,12 +558,12 @@ set(TEST_FILES SavePHXTest.h SaveParameterFileTest.h SaveRKHTest.h - SaveReflectometryAsciiTest.h SaveReflCustomAsciiTest.h SaveReflThreeColumnAsciiTest.h - SaveSampleEnvironmentAndShapeTest.h + SaveReflectometryAsciiTest.h SaveSESANSTest.h SaveSPETest.h + SaveSampleEnvironmentAndShapeTest.h SaveStlTest.h SaveTBLTest.h SaveToSNSHistogramNexusTest.h diff --git a/Framework/DataHandling/inc/MantidDataHandling/SaveNexusGeometry.h b/Framework/DataHandling/inc/MantidDataHandling/SaveNexusGeometry.h new file mode 100644 index 0000000000000000000000000000000000000000..fff3604f30a91021c3b66368caaaa7052d8c569d --- /dev/null +++ b/Framework/DataHandling/inc/MantidDataHandling/SaveNexusGeometry.h @@ -0,0 +1,40 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + + +/* SaveNexusGeometry : A thin Algorithm wrapper over + * NexusGeometry::saveInstrument allowing user to save the geometry from + * instrument attached to a workspace. + * + * @author Takudzwa Makoni, RAL (UKRI), ISIS + * @date 16/08/2019 + */ +#ifndef MANTID_DATAHANDLING_SAVENEXUSGEOMETRY_H_ +#define MANTID_DATAHANDLING_SAVENEXUSGEOMETRY_H_ + +#include "MantidAPI/Algorithm.h" +#include "MantidDataHandling/DllConfig.h" + +namespace Mantid { + +namespace DataHandling { + +class MANTID_DATAHANDLING_DLL SaveNexusGeometry : public API::Algorithm { +public: + const std::string name() const override; + int version() const override; + const std::string category() const override; + const std::string summary() const override; + +private: + void init() override; + void exec() override; +}; + +} // namespace DataHandling +} // namespace Mantid + +#endif /* MANTID_DATAHANDLING_SAVENEXUSGEOMETRY_H_ */ \ No newline at end of file diff --git a/Framework/DataHandling/src/SaveNexusGeometry.cpp b/Framework/DataHandling/src/SaveNexusGeometry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..440c88b799855a5553b3a22a1bf60be8d417d544 --- /dev/null +++ b/Framework/DataHandling/src/SaveNexusGeometry.cpp @@ -0,0 +1,100 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + + +/* SaveNexusGeometry : A thin Algorithm wrapper over + * NexusGeometry::saveInstrument allowing user to save the geometry from + * instrument attached to a workspace. + * + * @author Takudzwa Makoni, RAL (UKRI), ISIS + * @date 16/08/2019 + */ +#include "MantidDataHandling/SaveNexusGeometry.h" +#include "MantidAPI/ExperimentInfo.h" +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/WorkspaceProperty.h" +#include "MantidGeometry/Instrument/ComponentInfo.h" +#include "MantidGeometry/Instrument/DetectorInfo.h" +#include "MantidGeometry/Instrument/InstrumentVisitor.h" +#include "MantidNexusGeometry/NexusGeometrySave.h" + +#include <memory> +#include <utility> + +namespace Mantid { +namespace DataHandling { +using Mantid::API::WorkspaceProperty; +using Mantid::Kernel::Direction; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(SaveNexusGeometry) + +//---------------------------------------------------------------------------------------------- + +/// Algorithms name for identification. @see Algorithm::name + +const std::string SaveNexusGeometry::name() const { + return "SaveNexusGeometry"; +} + +/// Algorithm's version for identification. @see Algorithm::version + +int SaveNexusGeometry::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category + +const std::string SaveNexusGeometry::category() const { + return "DataHandling\\Instrument"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary + +const std::string SaveNexusGeometry::summary() const { + return "Save the instrument from a workspace to a Nexus-format" + " HDF file. WARNING: shapes are NOT saved in the present version " + "(1.0)."; +} + +//---------------------------------------------------------------------------------------------- + +/** Initialize the algorithm's properties. + */ +void SaveNexusGeometry::init() { + + // TODO resolve linkererror for experimentinfo, replace MatrixWorkspace with + // base class ExperimentInfo. + declareProperty(std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>( + "InputWorkspace", "", Direction::Input), + "Workspace containing the Instrument."); + + declareProperty(std::make_unique<API::FileProperty>( + "Filename", "", API::FileProperty::OptionalSave), + "Full path to save destination file"); + + declareProperty("H5Path", "entry" /*default*/, + "(optional) Name of the H5 root group in which the " + "Instrument is to be saved. Default name: 'entry'."); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void SaveNexusGeometry::exec() { + API::MatrixWorkspace_const_sptr workspace = getProperty("InputWorkspace"); + std::string destinationFile = getPropertyValue("FileName"); + std::string rootFileName = getPropertyValue("H5Path"); + + auto ws = workspace.get(); + const auto &compInfo = ws->componentInfo(); + const auto &detInfo = ws->detectorInfo(); + + Mantid::NexusGeometry::NexusGeometrySave::saveInstrument( + compInfo, detInfo, destinationFile, rootFileName); +} + +} // namespace DataHandling +} // namespace Mantid diff --git a/Framework/DataHandling/test/CMakeLists.txt b/Framework/DataHandling/test/CMakeLists.txt index 036e8017ef87c69410f1355989c691b55dc189ec..6bfa6330a242b431357a7791bb5840a0562cf9fa 100644 --- a/Framework/DataHandling/test/CMakeLists.txt +++ b/Framework/DataHandling/test/CMakeLists.txt @@ -1,5 +1,6 @@ if(CXXTEST_FOUND) - include_directories(SYSTEM ${CXXTEST_INCLUDE_DIR}) + include_directories(SYSTEM + ${CXXTEST_INCLUDE_DIR}) include_directories(../../TestHelpers/inc) # This variable is used within the cxxtest_add_test macro to build this helper diff --git a/Framework/DataHandling/test/SaveNexusGeometryTest.h b/Framework/DataHandling/test/SaveNexusGeometryTest.h new file mode 100644 index 0000000000000000000000000000000000000000..ffe5edebda30d18103542ba98feb040f81268c23 --- /dev/null +++ b/Framework/DataHandling/test/SaveNexusGeometryTest.h @@ -0,0 +1,193 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source +// & Institut Laue - Langevin +// SPDX - License - Identifier: GPL - 3.0 + +#ifndef MANTID_DATAHANDLING_SAVENEXUSGEOMETRYTEST_H_ +#define MANTID_DATAHANDLING_SAVENEXUSGEOMETRYTEST_H_ + +#include "MantidAPI/IEventWorkspace.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/WorkspaceFactory.h" +#include "MantidAPI/WorkspaceProperty.h" +#include "MantidDataHandling/LoadEmptyInstrument.h" +#include "MantidDataHandling/SaveNexusGeometry.h" +#include "MantidKernel/ProgressBase.h" +#include "MantidTestHelpers/FileResource.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + +#include <H5Cpp.h> +#include <boost/filesystem.hpp> +#include <cxxtest/TestSuite.h> + +using Mantid::DataHandling::SaveNexusGeometry; + +class SaveNexusGeometryTest : 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 SaveNexusGeometryTest *createSuite() { + return new SaveNexusGeometryTest(); + } + static void destroySuite(SaveNexusGeometryTest *suite) { delete suite; } + + void test_Init() { + SaveNexusGeometry alg; + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void test_exec() { + + ScopedFileHandle fileResource("algorithm_test_file.hdf5"); + auto destinationFile = fileResource.fullPath(); + // Create test input if necessary + Mantid::API::IEventWorkspace_sptr inputWS = + WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(1, 5); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS", + inputWS)); + SaveNexusGeometry alg; + + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()); + + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "testWS")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile)); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("H5Path", "algorithm_test_data")); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + TS_ASSERT(alg.isExecuted()); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().remove("testWS")); + } + + void + test_execution_succesful_when_no_h5_root_provided_and_default_root_is_used() { + + ScopedFileHandle fileResource("algorithm_no_h5_root_file.hdf5"); + auto destinationFile = fileResource.fullPath(); + // Create test input if necessary + Mantid::API::IEventWorkspace_sptr inputWS = + WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(1, 5); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS", + inputWS)); + SaveNexusGeometry alg; + + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()); + + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "testWS")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile)); + TS_ASSERT_THROWS_NOTHING(alg.execute()); + TS_ASSERT(alg.isExecuted()); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().remove("testWS")); + } + + void test_invalid_workspace_throws() { + + /* + test runtime error is thrown when a workspae without an Instrument is passed + into the Input workspace property. + */ + + ScopedFileHandle fileResource( + "algorithm_no_instrument_in_workspace_provided_test_file.hdf5"); + auto destinationFile = fileResource.fullPath(); + // Create test input if necessary + + WorkspaceCreationHelper::EPPTableRow row( + 1, 1, 1, WorkspaceCreationHelper::EPPTableRow::FitStatus::SUCCESS); + std::vector<WorkspaceCreationHelper::EPPTableRow> rows{row}; + Mantid::API::ITableWorkspace_sptr inputWS = + WorkspaceCreationHelper::createEPPTableWorkspace(rows); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS", + inputWS)); + SaveNexusGeometry alg; + // Don't put output in ADS by default + + alg.setChild(false); + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT(alg.isInitialized()); + + TS_ASSERT_THROWS(alg.setProperty("InputWorkspace", "testWS"), + std::invalid_argument &); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile)); + TS_ASSERT_THROWS(alg.execute(), std::runtime_error &); + TS_ASSERT(!alg.isExecuted()); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().remove("testWS")); + } + + void test_valid_fileName_with_invalid_extension_propagates_throw() { + /* + test saveInstrument propagates invalid_argument in executuion of algorithm + when invalid file extension is passed into fileName property. + */ + + ScopedFileHandle fileResource( + "algorithm_invalid_extension_provided_test_file.txt"); + auto destinationFile = fileResource.fullPath(); + // Create test workspace + Mantid::API::IEventWorkspace_sptr inputWS = + WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument2(5, 5); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().addOrReplace("testWS", + inputWS)); + SaveNexusGeometry alg; + // Don't put output in ADS by default + + alg.setChild(false); + alg.setRethrows(true); + TS_ASSERT_THROWS_NOTHING(alg.initialize()); + TS_ASSERT(alg.isInitialized()); + + TS_ASSERT_THROWS_NOTHING(alg.setProperty("InputWorkspace", "testWS")); + TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("FileName", destinationFile)); + TS_ASSERT_THROWS(alg.execute(), std::invalid_argument &); + TS_ASSERT(!alg.isExecuted()); + + TS_ASSERT_THROWS_NOTHING( + Mantid::API::AnalysisDataService::Instance().remove("testWS")); + } + + void test_characterise_eight_pack_bug() { + + // Bilby contains eight-packs, though other instrument features could still + // be problematic + Mantid::DataHandling::LoadEmptyInstrument alg; + alg.setChild(true); + alg.initialize(); + alg.setProperty("Filename", "BILBY_Definition.xml"); + alg.setPropertyValue("OutputWorkspace", "ws"); + alg.execute(); + Mantid::API::MatrixWorkspace_sptr ws = alg.getProperty("OutputWorkspace"); + + // problem actually in + // Mantid::NexusGeometry::NexusGeometrySave::saveInstrument / + // ComponentInfoBankHelpers::isSaveableBank but demonstrated here via save + // algorithm. + + Mantid::DataHandling::SaveNexusGeometry saver; + saver.setChild(true); + saver.setRethrows(true); + saver.initialize(); + saver.setProperty("Filename", "output.nxs"); + saver.setProperty("InputWorkspace", ws); + TS_ASSERT_THROWS(saver.execute(), H5::Exception &); + TS_ASSERT(!saver.isExecuted()); + } +}; + +#endif /* MANTID_DATAHANDLING_SAVENEXUSGEOMETRYTEST_H_ */ diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h index 15fefd005c235c0769389b66b7d49d69437ca8a2..7c17d7096289c58e58fe604c65a03e7d617726d2 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ComponentInfo.h @@ -116,6 +116,7 @@ public: Kernel::V3D samplePosition() const; bool hasSource() const; bool hasSample() const; + bool hasDetectors(const size_t componentIndex) const; size_t source() const; size_t sample() const; double l1() const; diff --git a/Framework/Geometry/src/Instrument/ComponentInfo.cpp b/Framework/Geometry/src/Instrument/ComponentInfo.cpp index 9fd94e440fca8323f1ccae35490c61fa9ec9f679..b33d2a9b449d29ebc9400d1d61bed12f4134eb03 100644 --- a/Framework/Geometry/src/Instrument/ComponentInfo.cpp +++ b/Framework/Geometry/src/Instrument/ComponentInfo.cpp @@ -223,6 +223,13 @@ bool ComponentInfo::hasSource() const { return m_componentInfo->hasSource(); } bool ComponentInfo::hasSample() const { return m_componentInfo->hasSample(); } +bool ComponentInfo::hasDetectors(const size_t componentIndex) const { + if (isDetector(componentIndex)) + return false; + const auto range = m_componentInfo->detectorRangeInSubtree(componentIndex); + return range.begin() < range.end(); +} + size_t ComponentInfo::source() const { return m_componentInfo->source(); } size_t ComponentInfo::sample() const { return m_componentInfo->sample(); } diff --git a/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp b/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp index 77028710fd2b75c06844d13b04435ccd97fca114..32f08be6f6db2c4269cf4811e8495e191ad6b568 100644 --- a/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp +++ b/Framework/Geometry/src/Instrument/ComponentInfoBankHelpers.cpp @@ -54,6 +54,8 @@ bool isSaveableBank(const ComponentInfo &compInfo, const size_t idx) { // needs to ignore if index is the source if (compInfo.source() == idx) return false; + if (!compInfo.hasDetectors(idx)) + return false; // a bank must have a parent, skip this block if the component does not. if (compInfo.hasParent(idx)) { size_t parent = compInfo.parent(idx); diff --git a/Framework/Geometry/test/ComponentInfoTest.h b/Framework/Geometry/test/ComponentInfoTest.h index 075706fffad0ac4d54c5aa96a926bd43c35d6680..3f0f5d89a1e020b437fa03099beb64b083bd414b 100644 --- a/Framework/Geometry/test/ComponentInfoTest.h +++ b/Framework/Geometry/test/ComponentInfoTest.h @@ -704,6 +704,19 @@ public: TS_ASSERT_EQUALS(panel.topLeft, 3); TS_ASSERT_EQUALS(panel.topRight, 15); } + + void test_has_detectors() { + auto instrument = ComponentCreationHelper::createTestInstrumentRectangular( + 1 /*1 bank*/, 4 /*4 by 4 pixels*/); + auto wrappers = InstrumentVisitor::makeWrappers(*instrument); + const auto &componentInfo = std::get<0>(wrappers); + + TS_ASSERT(componentInfo->hasDetectors(componentInfo->root())); + TS_ASSERT(!componentInfo->hasDetectors(0)); + TS_ASSERT(!componentInfo->hasDetectors(componentInfo->sample())); + TS_ASSERT(!componentInfo->hasDetectors(componentInfo->source())); + TS_ASSERT(componentInfo->hasDetectors(componentInfo->indexOfAny("bank1"))); + } }; #endif /* MANTID_GEOMETRY_COMPONENTINFOTEST_H_ */ diff --git a/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h b/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h index 90b1a6ffaef306bcbfcaeff82023d7d37745b8e7..cc0593b02d7498c274d059a4baebbec4dba30244 100644 --- a/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h +++ b/Framework/NexusGeometry/inc/MantidNexusGeometry/NexusGeometrySave.h @@ -39,6 +39,12 @@ class DetectorInfo; namespace NexusGeometry { namespace NexusGeometrySave { +MANTID_NEXUSGEOMETRY_DLL void +saveInstrument(const Geometry::ComponentInfo &compInfo, + const Geometry::DetectorInfo &detInfo, + const std::string &fullPath, const std::string &rootPath, + Kernel::ProgressBase *reporter = nullptr); + MANTID_NEXUSGEOMETRY_DLL void saveInstrument( const std::pair<std::unique_ptr<Geometry::ComponentInfo>, std::unique_ptr<Geometry::DetectorInfo>> &instrPair, diff --git a/Framework/NexusGeometry/src/NexusGeometrySave.cpp b/Framework/NexusGeometry/src/NexusGeometrySave.cpp index 2273cd92a1f167868c32ef52e3ed3c2c07753914..1e511ee20dc32eb23b51aebae8ea960d25801fd3 100644 --- a/Framework/NexusGeometry/src/NexusGeometrySave.cpp +++ b/Framework/NexusGeometry/src/NexusGeometrySave.cpp @@ -709,17 +709,15 @@ void saveNXDetector(const H5::Group &parentGroup, * Produces a Nexus format file containing the Instrument geometry and metadata. * * @param compInfo : componentInfo object. + * @param detInfo : detectorInfo object. * @param fullPath : save destination as full path. + * @param rootPath : name of root entry * @param reporter : (optional) report to progressBase. */ -void saveInstrument( - const std::pair<std::unique_ptr<Geometry::ComponentInfo>, - std::unique_ptr<Geometry::DetectorInfo>> &instrPair, - const std::string &fullPath, const std::string &rootPath, - Kernel::ProgressBase *reporter) { - - const Geometry::ComponentInfo &compInfo = (*instrPair.first); - const Geometry::DetectorInfo &detInfo = (*instrPair.second); +void saveInstrument(const Geometry::ComponentInfo &compInfo, + const Geometry::DetectorInfo &detInfo, + const std::string &fullPath, const std::string &rootPath, + Kernel::ProgressBase *reporter) { // Exception handling. boost::filesystem::path tmp(fullPath); @@ -808,6 +806,29 @@ void saveInstrument( file.close(); // close file } // saveInstrument + +/* + * Function: saveInstrument (overload) + * calls the save methods to write components to file after exception checking. + * Produces a Nexus format file containing the Instrument geometry and metadata. + * + * @param instrPair : instrument 2.0 object. + * @param fullPath : save destination as full path. + * @param rootPath : name of root entry + * @param reporter : (optional) report to progressBase. + */ +void saveInstrument( + const std::pair<std::unique_ptr<Geometry::ComponentInfo>, + std::unique_ptr<Geometry::DetectorInfo>> &instrPair, + const std::string &fullPath, const std::string &rootPath, + Kernel::ProgressBase *reporter) { + + const Geometry::ComponentInfo &compInfo = (*instrPair.first); + const Geometry::DetectorInfo &detInfo = (*instrPair.second); + + return saveInstrument(compInfo, detInfo, fullPath, rootPath, reporter); +} // saveInstrument + } // namespace NexusGeometrySave } // namespace NexusGeometry } // namespace Mantid diff --git a/Framework/NexusGeometry/test/NexusGeometrySaveTest.h b/Framework/NexusGeometry/test/NexusGeometrySaveTest.h index 39ebed2a11cb7f9eca84c7c52a7f7fa2fcd156c3..d0722e652fdd11290a319d9f2b486c8c6ae39963 100644 --- a/Framework/NexusGeometry/test/NexusGeometrySaveTest.h +++ b/Framework/NexusGeometry/test/NexusGeometrySaveTest.h @@ -7,7 +7,6 @@ #ifndef MANTID_NEXUSGEOMETRY_NEXUSGEOMETRYSAVETEST_H_ #define MANTID_NEXUSGEOMETRY_NEXUSGEOMETRYSAVETEST_H_ -#include "FileResource.h" #include "MantidGeometry/Instrument/ComponentInfo.h" #include "MantidGeometry/Instrument/ComponentInfoBankHelpers.h" #include "MantidGeometry/Instrument/DetectorInfo.h" @@ -18,7 +17,8 @@ #include "MantidNexusGeometry/NexusGeometryDefinitions.h" #include "MantidNexusGeometry/NexusGeometrySave.h" #include "MantidTestHelpers/ComponentCreationHelper.h" -#include "NexusFileReader.h" +#include "MantidTestHelpers/FileResource.h" +#include "MantidTestHelpers/NexusFileReader.h" #include <cxxtest/TestSuite.h> #include <gmock/gmock.h> @@ -340,7 +340,8 @@ used. V3D(0, 0, 10) /*bank position*/); auto instr = Mantid::Geometry::InstrumentVisitor::makeWrappers(*instrument); - auto const &compInfo = (*instr.first); + // instrument cache + auto &compInfo = (*instr.first); NexusGeometrySave::saveInstrument(instr, destinationFile, DEFAULT_ROOT_PATH); @@ -994,8 +995,8 @@ Instrument cache. non-zero translation in source. Expected behaviour is: (dataset) 'depends_on' has value "/absoulute/path/to/orientation", (dataset) 'orientation' has dAttribute (AKA attribute of dataset) 'depends_on' with - value "/absoulute/path/to/location", and (dataset) 'location' has - dAttribute 'depends_on' with value "." + value "/absoulute/path/to/location", and (dataset) 'location' has + dAttribute 'depends_on' with value "." */ // Geometry for test instrument @@ -1109,7 +1110,7 @@ Instrument cache. // assert the group NXtransformations doesnt exist in file TS_ASSERT_THROWS(tester.openfullH5Path(transformationsPath), - H5::GroupIException &) + H5::GroupIException &); } }; diff --git a/Framework/NexusGeometry/test/FileResource.h b/Framework/TestHelpers/inc/MantidTestHelpers/FileResource.h similarity index 89% rename from Framework/NexusGeometry/test/FileResource.h rename to Framework/TestHelpers/inc/MantidTestHelpers/FileResource.h index 51594cf291a9516d336bd13ef98698c78d44a77f..c5b0bb68f8007623127c379376cc04fc9ebff95e 100644 --- a/Framework/NexusGeometry/test/FileResource.h +++ b/Framework/TestHelpers/inc/MantidTestHelpers/FileResource.h @@ -5,20 +5,20 @@ // & Institut Laue - Langevin // SPDX - License - Identifier: GPL - 3.0 + +/* + * RAII: Gives a clean file destination and removes the file when + * handle is out of scope. Must be stack allocated. + * + * @author Takudzwa Makoni, RAL (UKRI), ISIS + * @date 06/08/2019 + */ + #ifndef MANTID_NEXUSGEOMETRY_FILERESOURCE_H_ #define MANTID_NEXUSGEOMETRY_FILERESOURCE_H_ #include <boost/filesystem.hpp> #include <string> -/* - RAII: Gives a clean file destination and removes the file when - handle is out of scope. Must be stack allocated. - - TODO: DOCUMENTATION - *@author Takudzwa Makoni, RAL (UKRI), ISIS - *@date 06/08/2019 -*/ class ScopedFileHandle { public: diff --git a/Framework/NexusGeometry/test/NexusFileReader.h b/Framework/TestHelpers/inc/MantidTestHelpers/NexusFileReader.h similarity index 79% rename from Framework/NexusGeometry/test/NexusFileReader.h rename to Framework/TestHelpers/inc/MantidTestHelpers/NexusFileReader.h index 5f3300aead3ab95c4be58f7d5e99984099c25b8f..08e198e05f197b23ffc16a0616ad8239581bb7f6 100644 --- a/Framework/NexusGeometry/test/NexusFileReader.h +++ b/Framework/TestHelpers/inc/MantidTestHelpers/NexusFileReader.h @@ -10,17 +10,19 @@ #include "MantidNexusGeometry/NexusGeometryDefinitions.h" +#include <Eigen/Dense> #include <H5Cpp.h> #include <boost/filesystem.hpp> #include <string> #include <vector> /* - TODO: DOCUMENTATION - - *@author Takudzwa Makoni, RAL (UKRI), ISIS - *@date 06/08/2019 -*/ + * NexusFileReader: Test utility for unit testing in + * NexusGeometrySave::saveInstrument. + * + * @author Takudzwa Makoni, RAL (UKRI), ISIS + * @date 06/08/2019 + */ namespace Mantid { namespace NexusGeometry { @@ -34,6 +36,40 @@ std::string toNXPathString(FullNXPath &path) { return pathString; } +// ported from NexusGeometryParser, for validating storage type of dataset +// before reading its contents into a container +template <typename ExpectedT> +void validateStorageType(const H5::DataSet &data) { + + const auto typeClass = data.getTypeClass(); + const size_t sizeOfType = data.getDataType().getSize(); + // Early check to prevent reinterpretation of underlying data. + if (std::is_floating_point<ExpectedT>::value) { + if (H5T_FLOAT != typeClass) { + throw std::runtime_error("Storage type mismatch. Expecting to extract a " + "floating point number"); + } + if (sizeOfType != sizeof(ExpectedT)) { + throw std::runtime_error( + "Storage type mismatch for floats. This operation " + "is dangerous. Nexus stored has byte size:" + + std::to_string(sizeOfType)); + } + } else if (std::is_integral<ExpectedT>::value) { + if (H5T_INTEGER != typeClass) { + throw std::runtime_error( + "Storage type mismatch. Expecting to extract a integer"); + } + if (sizeOfType > sizeof(ExpectedT)) { + // endianness not checked + throw std::runtime_error( + "Storage type mismatch for integer. Result " + "would result in truncation. Nexus stored has byte size:" + + std::to_string(sizeOfType)); + } + } +} + // test utility used for validation of the structure of a nexus file as needed // for unit tests in Nexus Geometry. class NexusFileReader { @@ -49,6 +85,25 @@ public: } } + // read a multidimensional dataset and returns vector containing the data + template <typename T> + std::vector<T> readDataSetMultidimensional(FullNXPath &pathToGroup, + std::string dataSetName) { + + std::vector<T> dataInFile; + + // open dataset and read. + H5::Group parentGroup = openfullH5Path(pathToGroup); + H5::DataSet dataset = parentGroup.openDataSet(dataSetName); + + validateStorageType<T>(dataset); + auto space = dataset.getSpace(); + + dataInFile.resize(space.getSelectNpoints()); + dataset.read(dataInFile.data(), dataset.getDataType(), space); + return dataInFile; + } + /* safely open a HDF5 group path with additional helpful debug information to output where open fails) */ H5::Group openfullH5Path(const FullNXPath &pathList) const { @@ -75,7 +130,7 @@ public: // file structure only. (dont take extra step to look for parent group) if (parentNX_CLASS_TYPE == NX_ENTRY) { - for (hsize_t i = 0; i < rootGroup.getNumObjs(); ++i) { + for (size_t i = 0; i < rootGroup.getNumObjs(); ++i) { if (rootGroup.getObjTypeByIdx(i) == GROUP_TYPE) { std::string childPath = rootGroup.getObjnameByIdx(i); // Open the sub group @@ -92,7 +147,7 @@ public: } // Iterate over children of root group, and determine if a group - for (hsize_t i = 0; i < rootGroup.getNumObjs(); ++i) { + for (size_t i = 0; i < rootGroup.getNumObjs(); ++i) { if (rootGroup.getObjTypeByIdx(i) == GROUP_TYPE) { std::string childPath = rootGroup.getObjnameByIdx(i); // Open the sub group @@ -103,7 +158,7 @@ public: std::string parentAttrVal; parentAttribute.read(parentAttribute.getDataType(), parentAttrVal); if (parentAttrVal == parentNX_CLASS_TYPE) { - for (hsize_t i = 0; i < childGroup.getNumObjs(); ++i) { + for (size_t i = 0; i < childGroup.getNumObjs(); ++i) { if (childGroup.getObjTypeByIdx(i) == GROUP_TYPE) { std::string grandchildPath = childGroup.getObjnameByIdx(i); // Open the sub group @@ -130,10 +185,10 @@ public: const FullNXPath &pathToGroup) { double value; int rank = 1; - hsize_t dims[(hsize_t)1]; - dims[0] = (hsize_t)1; + hsize_t dims[static_cast<hsize_t>(1)]; + dims[0] = static_cast<hsize_t>(1); - H5::DataSpace space = H5Screate_simple(rank, dims, NULL); + H5::DataSpace space = H5Screate_simple(rank, dims, nullptr); // open dataset and read. H5::Group parentGroup = openfullH5Path(pathToGroup); @@ -171,7 +226,7 @@ public: H5::Group parentGroup = m_file.openGroup(pathToGroup); auto numOfChildren = parentGroup.getNumObjs(); - for (hsize_t i = 0; i < numOfChildren; i++) { + for (size_t i = 0; i < numOfChildren; i++) { if (parentGroup.getObjTypeByIdx(i) == DATASET_TYPE) { std::string dSetName = parentGroup.getObjnameByIdx(i); H5::DataSet dSet = parentGroup.openDataSet(dSetName); @@ -194,7 +249,7 @@ public: H5::Group parentGroup = m_file.openGroup(pathToGroup); auto numOfChildren = parentGroup.getNumObjs(); - for (hsize_t i = 0; i < numOfChildren; i++) { + for (size_t i = 0; i < numOfChildren; i++) { if (parentGroup.getObjTypeByIdx(i) == DATASET_TYPE) { std::string dSetName = parentGroup.getObjnameByIdx(i); H5::DataSet dSet = parentGroup.openDataSet(dSetName); @@ -215,7 +270,7 @@ public: H5::Group parentGroup = openfullH5Path(pathToGroup); auto numOfChildren = parentGroup.getNumObjs(); - for (hsize_t i = 0; i < numOfChildren; i++) { + for (size_t i = 0; i < numOfChildren; i++) { if (parentGroup.getObjTypeByIdx(i) == DATASET_TYPE) { std::string dataSetName = parentGroup.getObjnameByIdx(i); if (dsetName == dataSetName) { diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h index b321c592bbaafcdc4b0ac8977f474ac42a8e8923..071c5d03cdef3d37af897cc4072c810dcc8843a3 100644 --- a/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h +++ b/Framework/TestHelpers/inc/MantidTestHelpers/WorkspaceCreationHelper.h @@ -273,6 +273,12 @@ Mantid::DataObjects::EventWorkspace_sptr createEventWorkspaceWithFullInstrument(int numBanks, int numPixels, bool clearEvents = true); +/** Create an Eventworkspace with instrument 2.0 that contains + * RectangularDetector's */ +Mantid::DataObjects::EventWorkspace_sptr +createEventWorkspaceWithFullInstrument2(int numBanks, int numPixels, + bool clearEvents = true); + /** * Creates an event workspace with instrument which consists of cylindrical *detectors. diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index 8a43fd33b205a2f6be22b42cf6645467aa72b692..d204f31e7fb5984254b42adb0d7ffefa6f602255 100644 --- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -497,6 +497,47 @@ createEventWorkspaceWithFullInstrument(int numBanks, int numPixels, return ws; } +/** Create an Eventworkspace with instrument 2.0 that contains + *RectangularDetector's. + * X axis = 100 histogrammed bins from 0.0 in steps of 1.0. + * 200 events per pixel. + * + * @param numBanks :: number of rectangular banks + * @param numPixels :: each bank will be numPixels*numPixels + * @param clearEvents :: if true, erase the events from list + * @return The EventWorkspace + */ +Mantid::DataObjects::EventWorkspace_sptr +createEventWorkspaceWithFullInstrument2(int numBanks, int numPixels, + bool clearEvents) { + Instrument_sptr inst = + ComponentCreationHelper::createTestInstrumentRectangular2(numBanks, + numPixels); + EventWorkspace_sptr ws = + createEventWorkspace2(numBanks * numPixels * numPixels, 100); + ws->setInstrument(inst); + + // Set the X axes + const auto &xVals = ws->x(0); + const size_t xSize = xVals.size(); + auto ax0 = std::make_unique<NumericAxis>(xSize); + ax0->setUnit("dSpacing"); + for (size_t i = 0; i < xSize; i++) { + ax0->setValue(i, xVals[i]); + } + ws->replaceAxis(0, std::move(ax0)); + + // re-assign detector IDs to the rectangular detector + const auto detIds = inst->getDetectorIDs(); + for (int wi = 0; wi < static_cast<int>(ws->getNumberHistograms()); ++wi) { + ws->getSpectrum(wi).clearDetectorIDs(); + if (clearEvents) + ws->getSpectrum(wi).clear(true); + ws->getSpectrum(wi).setDetectorID(detIds[wi]); + } + return ws; +} + Mantid::DataObjects::EventWorkspace_sptr createEventWorkspaceWithNonUniformInstrument(int numBanks, bool clearEvents) { // Number of detectors in a bank as created by createTestInstrumentCylindrical diff --git a/docs/source/algorithms/SaveNexusGeometry-v1.rst b/docs/source/algorithms/SaveNexusGeometry-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..5f30cbb4e4a9798d7508aa413a4185d5d48fa878 --- /dev/null +++ b/docs/source/algorithms/SaveNexusGeometry-v1.rst @@ -0,0 +1,104 @@ + +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +Saves the Instrument geometry from the workspace to a Nexus file. Saves detector positions and rotations. +Current version (1.0) does NOT save instrument shapes of instrument components. file is compliant to Nexus standards. +For more information on the Nexus format, see https://www.nexusformat.org/ + +the Instrument will be extracted from the specified workspace, and written to the specified location. + +The (optional) H5 root group name is the parent group in which the Instrument and sample data are stored. +If no name is given, the root group will have a default nme of 'entry' + + +Usage +----- + +**Example - basic example using SaveNexusGeometry, with default H5 root group** + +.. testcode:: SaveNexusGeometryExampleDefault + + import os + + ws = CreateSampleWorkspace() + compInfo = ws.componentInfo() + detInfo = ws.detectorInfo() + file_name = "example_save_Nexus_geometry_1.nxs" + path = os.path.join(os.path.expanduser("~"), file_name) + + SaveNexusGeometry(ws, path) + print(os.path.isfile(path)) + + + +Output: + +.. testoutput:: SaveNexusGeometryExampleDefault + + True + +.. testcleanup:: SaveNexusGeometryExampleDefault + + import os + def removeFiles(files): + for ws in files: + try: + path = os.path.join(os.path.expanduser("~"), ws) + os.remove(path) + except: + pass + + removeFiles([file_name]) + + +**Example - basic example using SaveNexusGeometry, with specific H5 root group** + +.. testcode:: SaveNexusGeometryExampleOption + + import os + + ws = CreateSampleWorkspace() + compInfo = ws.componentInfo() + detInfo = ws.detectorInfo() + file_name = "example_save_Nexus_geometry_2.hdf5" + path = os.path.join(os.path.expanduser("~"), file_name) + + SaveNexusGeometry(ws, path) + print(os.path.isfile(path)) + + + +Output: + +.. testoutput:: SaveNexusGeometryExampleOption + + True + +.. testcleanup:: SaveNexusGeometryExampleOption + + import os + def removeFiles(files): + for ws in files: + try: + path = os.path.join(os.path.expanduser("~"), ws) + os.remove(path) + except: + pass + + removeFiles([file_name]) + + + +.. categories:: + +.. sourcelink:: + diff --git a/instrument/unit_testing/nicos_00000489_agg_with_monitor.nxs.md5 b/instrument/unit_testing/nicos_00000489_agg_with_monitor.nxs.md5 new file mode 100644 index 0000000000000000000000000000000000000000..b73b11fc526a2f0d83ea93fc5c4fe5e6f0b0fa2a --- /dev/null +++ b/instrument/unit_testing/nicos_00000489_agg_with_monitor.nxs.md5 @@ -0,0 +1 @@ +5ec36a1dbff0d68ca200b072232953cd