Skip to content

Commit aea8754

Browse files
MialLewisdarshdinger
authored andcommitted
Add a new revision to LoadMuonNexus to reenable alg selection
This is a squashed version of #38845 into `ornl-next` add LoadMuonNexus3 add unit tests for LoadMuonNexus3 wrapper resolve spurious cppcheck warning small code improvements remove redundant const return fix compiler warnings and add doc change variable order ammend release note change Load to LoadMuonNexus in examples remove datahandling dependency from muon package remove unneeded imports and code add guard if alg not registered fix non-windows compiler warnings
1 parent 4925113 commit aea8754

File tree

6 files changed

+399
-2
lines changed

6 files changed

+399
-2
lines changed

Framework/Muon/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(SRC_FILES
1313
src/LoadMuonNexus.cpp
1414
src/LoadMuonNexus1.cpp
1515
src/LoadMuonNexus2.cpp
16+
src/LoadMuonNexus3.cpp
1617
src/MuonAlgorithmHelper.cpp
1718
src/MuonAsymmetryHelper.cpp
1819
src/MuonGroupDetectors.cpp
@@ -41,6 +42,7 @@ set(INC_FILES
4142
inc/MantidMuon/LoadMuonNexus.h
4243
inc/MantidMuon/LoadMuonNexus1.h
4344
inc/MantidMuon/LoadMuonNexus2.h
45+
inc/MantidMuon/LoadMuonNexus3.h
4446
inc/MantidMuon/EstimateMuonAsymmetryFromCounts.h
4547
inc/MantidMuon/MuonAlgorithmHelper.h
4648
inc/MantidMuon/MuonAsymmetryHelper.h
@@ -69,6 +71,7 @@ set(TEST_FILES
6971
LoadAndApplyMuonDetectorGroupingTest.h
7072
LoadMuonNexus1Test.h
7173
LoadMuonNexus2Test.h
74+
LoadMuonNexus3Test.h
7275
MuonAlgorithmHelperTest.h
7376
EstimateMuonAsymmetryFromCountsTest.h
7477
MuonGroupDetectorsTest.h
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Mantid Repository : https://github.com/mantidproject/mantid
2+
//
3+
// Copyright © 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
// NScD Oak Ridge National Laboratory, European Spallation Source,
5+
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6+
// SPDX - License - Identifier: GPL - 3.0 +
7+
#pragma once
8+
9+
//----------------------------------------------------------------------
10+
// Includes
11+
//----------------------------------------------------------------------
12+
#include "MantidMuon/DllConfig.h"
13+
#include "MantidMuon/LoadMuonNexus.h"
14+
15+
#include <vector>
16+
17+
namespace Mantid::Algorithms {
18+
19+
using ConfFuncPtr = int (*)(const std::string &, const std::shared_ptr<Mantid::API::Algorithm> &);
20+
21+
struct AlgDetail {
22+
AlgDetail(const std::string &name, const int version, const ConfFuncPtr &loader,
23+
const Mantid::API::Algorithm_sptr &alg)
24+
: m_name(name), m_version(version), m_confFunc(loader), m_alg(alg) {}
25+
26+
const std::string m_name;
27+
const int m_version;
28+
const ConfFuncPtr m_confFunc;
29+
const Mantid::API::Algorithm_sptr m_alg;
30+
};
31+
32+
/**
33+
Loads an file in NeXus Muon format version 1 and 2 and stores it in a 2D
34+
workspace
35+
(Workspace2D class). LoadMuonNexus is an algorithm and as such inherits
36+
from the Algorithm class, via DataHandlingCommand, and overrides
37+
the init() & exec() methods.
38+
39+
Required Properties:
40+
<UL>
41+
<LI> Filename - The name of and path to the input NeXus file </LI>
42+
<LI> OutputWorkspace - The name of the workspace in which to store the imported
43+
data
44+
(a multiperiod file will store higher periods in workspaces called
45+
OutputWorkspace_PeriodNo)
46+
[ not yet implemented for NeXus ]</LI>
47+
</UL>
48+
49+
Optional Properties: (note that these options are not available if reading a
50+
multiperiod file)
51+
<UL>
52+
<LI> spectrum_min - The spectrum to start loading from</LI>
53+
<LI> spectrum_max - The spectrum to load to</LI>
54+
<LI> spectrum_list - An ArrayProperty of spectra to load</LI>
55+
<LI> auto_group - Determines whether the spectra are automatically grouped
56+
together based on the groupings in the NeXus file. </LI>
57+
</UL>
58+
*/
59+
class MANTID_MUON_DLL LoadMuonNexus3 : public LoadMuonNexus {
60+
public:
61+
LoadMuonNexus3();
62+
63+
const std::string summary() const override {
64+
return "The LoadMuonNexus algorithm will read the given NeXus Muon data "
65+
"file Version 1 or 2 and use the results to populate the named "
66+
"workspace. LoadMuonNexus may be invoked by LoadNexus if it is "
67+
"given a NeXus file of this type.";
68+
}
69+
70+
int version() const override { return 3; }
71+
const std::vector<std::string> seeAlso() const override { return {"LoadNexus", "LoadMuonNexusV2"}; }
72+
73+
// Returns 0, as this wrapper version of the algorithm is never to be selected via load.
74+
int confidence(Kernel::NexusDescriptor &) const override { return 0; };
75+
// Methods to enable testing.
76+
const std::string &getSelectedAlg() const { return m_loadAlgs[m_selectedIndex].m_name; }
77+
int getSelectedVersion() const { return m_loadAlgs[m_selectedIndex].m_version; }
78+
79+
private:
80+
std::vector<AlgDetail> m_loadAlgs;
81+
size_t m_selectedIndex;
82+
83+
void exec() override;
84+
void runSelectedAlg();
85+
void addAlgToVec(const std::string &name, const int version, const ConfFuncPtr &loader);
86+
};
87+
88+
} // namespace Mantid::Algorithms
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Mantid Repository : https://github.com/mantidproject/mantid
2+
//
3+
// Copyright &copy; 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
// NScD Oak Ridge National Laboratory, European Spallation Source,
5+
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6+
// SPDX - License - Identifier: GPL - 3.0 +
7+
#include "MantidMuon/LoadMuonNexus3.h"
8+
9+
#include "MantidAPI/AlgorithmFactory.h"
10+
#include "MantidAPI/NexusFileLoader.h"
11+
#include "MantidAPI/Progress.h"
12+
#include "MantidAPI/RegisterFileLoader.h"
13+
#include "MantidKernel/Logger.h"
14+
#include "MantidNexus/NexusClasses.h"
15+
#include <H5Cpp.h>
16+
#include <string>
17+
18+
namespace {
19+
const int CONFIDENCE_THRESHOLD{80};
20+
21+
int calculateConfidenceHDF5(const std::string &filePath, const std::shared_ptr<Mantid::API::Algorithm> &alg) {
22+
const auto nexusLoader = std::dynamic_pointer_cast<Mantid::API::NexusFileLoader>(alg);
23+
int confidence{0};
24+
if (H5::H5File::isHdf5(filePath)) {
25+
try {
26+
Mantid::Kernel::NexusHDF5Descriptor descriptorHDF5(filePath);
27+
confidence = nexusLoader->confidence(descriptorHDF5);
28+
} catch (std::exception const &e) {
29+
Mantid::Kernel::Logger("LoadMuonNexus3").debug()
30+
<< "Error in calculating confidence for: " << nexusLoader->name() << " " << e.what() << '\n';
31+
}
32+
}
33+
return (confidence >= CONFIDENCE_THRESHOLD) ? confidence : 0;
34+
}
35+
36+
int calculateConfidence(const std::string &filePath, const std::shared_ptr<Mantid::API::Algorithm> &alg) {
37+
const auto fileLoader = std::dynamic_pointer_cast<Mantid::API::IFileLoader<Mantid::Kernel::NexusDescriptor>>(alg);
38+
Mantid::Kernel::NexusDescriptor descriptor(filePath);
39+
const int confidence = fileLoader->confidence(descriptor);
40+
return (confidence >= CONFIDENCE_THRESHOLD) ? confidence : 0;
41+
}
42+
} // namespace
43+
44+
namespace Mantid::Algorithms {
45+
// Register the algorithm into the algorithm factory
46+
DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadMuonNexus3)
47+
48+
/** Executes the right version of the Muon nexus loader
49+
* @throw Exception::FileError If the Nexus file cannot be found/opened
50+
* @throw std::invalid_argument If the optional properties are set to invalid
51+
*values
52+
*/
53+
LoadMuonNexus3::LoadMuonNexus3() : LoadMuonNexus() {
54+
addAlgToVec("LoadMuonNexusV2", 1, &calculateConfidenceHDF5);
55+
addAlgToVec("LoadMuonNexus", 1, &calculateConfidence);
56+
addAlgToVec("LoadMuonNexus", 2, &calculateConfidence);
57+
}
58+
59+
void LoadMuonNexus3::exec() {
60+
const std::string filePath = getPropertyValue("Filename");
61+
62+
int maxConfidenceRes{0};
63+
for (size_t i = 0; i < m_loadAlgs.size(); i++) {
64+
const int confidenceRes = m_loadAlgs[i].m_confFunc(filePath, m_loadAlgs[i].m_alg);
65+
if (confidenceRes > maxConfidenceRes) {
66+
maxConfidenceRes = confidenceRes;
67+
m_selectedIndex = i;
68+
}
69+
}
70+
71+
if (!maxConfidenceRes) {
72+
throw Kernel::Exception::FileError("Cannot open the file ", filePath);
73+
}
74+
75+
runSelectedAlg();
76+
}
77+
78+
void LoadMuonNexus3::runSelectedAlg() {
79+
const auto &alg = m_loadAlgs[m_selectedIndex].m_alg;
80+
this->setupAsChildAlgorithm(alg, 0, 1, true);
81+
alg->copyPropertiesFrom(*this);
82+
alg->executeAsChildAlg();
83+
this->copyPropertiesFrom(*alg);
84+
}
85+
86+
void LoadMuonNexus3::addAlgToVec(const std::string &name, const int version, const ConfFuncPtr &loader) {
87+
auto &factory = API::AlgorithmFactory::Instance();
88+
if (factory.exists(name, version)) {
89+
const auto alg = factory.create(name, version);
90+
m_loadAlgs.push_back(AlgDetail(name, version, loader, alg));
91+
} else {
92+
Mantid::Kernel::Logger("LoadMuonNexus3").debug()
93+
<< "Cannot add algorithm: " << name << " v" << version << ". The algorithm is not registered." << '\n';
94+
}
95+
}
96+
} // namespace Mantid::Algorithms
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Mantid Repository : https://github.com/mantidproject/mantid
2+
//
3+
// Copyright &copy; 2025 ISIS Rutherford Appleton Laboratory UKRI,
4+
// NScD Oak Ridge National Laboratory, European Spallation Source,
5+
// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6+
// SPDX - License - Identifier: GPL - 3.0 +
7+
#pragma once
8+
9+
#include <cxxtest/TestSuite.h>
10+
11+
#include "MantidAPI/AnalysisDataService.h"
12+
#include "MantidAPI/NexusFileLoader.h"
13+
#include "MantidAPI/WorkspaceGroup.h"
14+
#include "MantidDataObjects/Workspace2D.h"
15+
#include "MantidMuon/LoadMuonNexus1.h"
16+
#include "MantidMuon/LoadMuonNexus2.h"
17+
#include "MantidMuon/LoadMuonNexus3.h"
18+
19+
using namespace Mantid::API;
20+
using namespace Mantid::Kernel;
21+
using namespace Mantid::Algorithms;
22+
using namespace Mantid::DataObjects;
23+
24+
namespace {
25+
// Mock class for LoadMuonNexusV2 which is in the DataHandling Library
26+
class LoadMuonNexusV2 : public NexusFileLoader {
27+
const std::string name() const override { return "LoadMuonNexusV2"; }
28+
int version() const override { return 1; }
29+
int confidence(NexusHDF5Descriptor &) const override { return 100; }
30+
void execLoader() override {}
31+
const std::string summary() const override { return "mock class"; }
32+
void init() override {}
33+
};
34+
} // namespace
35+
36+
class LoadMuonNexus3Test : public CxxTest::TestSuite {
37+
public:
38+
void check_spectra_and_detectors(const MatrixWorkspace_sptr &output) {
39+
40+
//----------------------------------------------------------------------
41+
// Tests to check that spectra-detector mapping is done correctly
42+
//----------------------------------------------------------------------
43+
// Check the total number of elements in the map for HET
44+
TS_ASSERT_EQUALS(output->getNumberHistograms(), 192);
45+
46+
// Test one to one mapping, for example spectra 6 has only 1 pixel
47+
TS_ASSERT_EQUALS(output->getSpectrum(6).getDetectorIDs().size(), 1);
48+
49+
auto detectorgroup = output->getSpectrum(99).getDetectorIDs();
50+
TS_ASSERT_EQUALS(detectorgroup.size(), 1);
51+
TS_ASSERT_EQUALS(*detectorgroup.begin(), 100);
52+
}
53+
54+
void testExecLoadMuonNexus2() {
55+
LoadMuonNexus3 nxLoad;
56+
nxLoad.initialize();
57+
58+
// Now set required filename and output workspace name
59+
std::string inputFile = "argus0026287.nxs";
60+
nxLoad.setPropertyValue("FileName", inputFile);
61+
62+
std::string outputSpace = "outer";
63+
nxLoad.setPropertyValue("OutputWorkspace", outputSpace);
64+
65+
// Test execute to read file and populate workspace
66+
TS_ASSERT_THROWS_NOTHING(nxLoad.execute());
67+
TS_ASSERT(nxLoad.isExecuted());
68+
69+
// Check output workspace
70+
MatrixWorkspace_sptr output;
71+
output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outputSpace);
72+
Workspace2D_sptr output2D = std::dynamic_pointer_cast<Workspace2D>(output);
73+
74+
// Perform limited tests on the outwork workspace as this is essentially just a wrapper algorithm.
75+
// subset of tests performed in LoadMuonNexus2Test
76+
check_spectra_and_detectors(output);
77+
78+
TS_ASSERT(nxLoad.getSelectedAlg() == "LoadMuonNexus");
79+
TS_ASSERT(nxLoad.getSelectedVersion() == 2);
80+
}
81+
82+
void testExecLoadMuonNexus1() {
83+
LoadMuonNexus3 nxLoad;
84+
nxLoad.initialize();
85+
86+
// Now set required filename and output workspace name
87+
std::string inputFile = "emu00006475.nxs";
88+
nxLoad.setPropertyValue("FileName", inputFile);
89+
90+
std::string outputSpace = "outer";
91+
nxLoad.setPropertyValue("OutputWorkspace", outputSpace);
92+
93+
// Test execute to read file and populate workspace
94+
TS_ASSERT_THROWS_NOTHING(nxLoad.execute());
95+
TS_ASSERT(nxLoad.isExecuted());
96+
97+
// Check output workspace group
98+
Mantid::API::WorkspaceGroup_sptr output = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputSpace);
99+
TS_ASSERT(output->size() == 4);
100+
101+
TS_ASSERT(nxLoad.getSelectedAlg() == "LoadMuonNexus");
102+
TS_ASSERT(nxLoad.getSelectedVersion() == 1);
103+
}
104+
105+
void testExecLoadMuonNexusV2() {
106+
LoadMuonNexus3 nxLoad;
107+
nxLoad.initialize();
108+
109+
// Now set required filename and output workspace name
110+
std::string inputFile = "ARGUS00073601.nxs";
111+
nxLoad.setPropertyValue("FileName", inputFile);
112+
113+
std::string outputSpace = "outer";
114+
nxLoad.setPropertyValue("OutputWorkspace", outputSpace);
115+
116+
// Test execute to read file and populate workspace
117+
TS_ASSERT_THROWS_NOTHING(nxLoad.execute());
118+
TS_ASSERT(nxLoad.isExecuted());
119+
120+
TS_ASSERT(nxLoad.getSelectedAlg() == "LoadMuonNexusV2");
121+
TS_ASSERT(nxLoad.getSelectedVersion() == 1);
122+
}
123+
};

0 commit comments

Comments
 (0)