-
Notifications
You must be signed in to change notification settings - Fork 128
Add a new revision to LoadMuonNexus to reenable alg selection #38845
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9cb6800
817205d
e4e283c
cbc967d
b37e32a
a2cdd96
d6f6677
c515c81
9370aed
b2c60d0
d2a21d2
f71a3ee
967d131
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
// 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 | ||
|
||
//---------------------------------------------------------------------- | ||
// Includes | ||
//---------------------------------------------------------------------- | ||
#include "MantidMuon/DllConfig.h" | ||
#include "MantidMuon/LoadMuonNexus.h" | ||
|
||
#include <vector> | ||
|
||
namespace Mantid::Algorithms { | ||
|
||
using ConfFuncPtr = int (*)(const std::string &, const std::shared_ptr<Mantid::API::Algorithm> &); | ||
|
||
struct AlgDetail { | ||
AlgDetail(const std::string &name, const int version, const ConfFuncPtr &loader, | ||
const Mantid::API::Algorithm_sptr &alg) | ||
: m_name(name), m_version(version), m_confFunc(loader), m_alg(alg) {} | ||
|
||
const std::string m_name; | ||
const int m_version; | ||
const ConfFuncPtr m_confFunc; | ||
const Mantid::API::Algorithm_sptr m_alg; | ||
}; | ||
|
||
/** | ||
Loads an file in NeXus Muon format version 1 and 2 and stores it in a 2D | ||
workspace | ||
(Workspace2D class). LoadMuonNexus is an algorithm and as such inherits | ||
from the Algorithm class, via DataHandlingCommand, and overrides | ||
the init() & exec() methods. | ||
|
||
Required Properties: | ||
<UL> | ||
<LI> Filename - The name of and path to the input NeXus file </LI> | ||
<LI> OutputWorkspace - The name of the workspace in which to store the imported | ||
data | ||
(a multiperiod file will store higher periods in workspaces called | ||
OutputWorkspace_PeriodNo) | ||
[ not yet implemented for NeXus ]</LI> | ||
</UL> | ||
|
||
Optional Properties: (note that these options are not available if reading a | ||
multiperiod file) | ||
<UL> | ||
<LI> spectrum_min - The spectrum to start loading from</LI> | ||
<LI> spectrum_max - The spectrum to load to</LI> | ||
<LI> spectrum_list - An ArrayProperty of spectra to load</LI> | ||
<LI> auto_group - Determines whether the spectra are automatically grouped | ||
together based on the groupings in the NeXus file. </LI> | ||
</UL> | ||
*/ | ||
class MANTID_MUON_DLL LoadMuonNexus3 : public LoadMuonNexus { | ||
public: | ||
LoadMuonNexus3(); | ||
|
||
const std::string summary() const override { | ||
return "The LoadMuonNexus algorithm will read the given NeXus Muon data " | ||
"file Version 1 or 2 and use the results to populate the named " | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does Version 1 or 2 reference a file format, or LoadMuonNexus versions? I find this description quite confusing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this references a file format, the naming of the algorithms has caused much confusion. I think the Muon scientists will all understand this, but I'll add in the word |
||
"workspace. LoadMuonNexus may be invoked by LoadNexus if it is " | ||
"given a NeXus file of this type."; | ||
} | ||
|
||
int version() const override { return 3; } | ||
const std::vector<std::string> seeAlso() const override { return {"LoadNexus", "LoadMuonNexusV2"}; } | ||
|
||
// Returns 0, as this wrapper version of the algorithm is never to be selected via load. | ||
int confidence(Kernel::NexusDescriptor &) const override { return 0; }; | ||
// Methods to enable testing. | ||
const std::string &getSelectedAlg() const { return m_loadAlgs[m_selectedIndex].m_name; } | ||
int getSelectedVersion() const { return m_loadAlgs[m_selectedIndex].m_version; } | ||
|
||
private: | ||
std::vector<AlgDetail> m_loadAlgs; | ||
size_t m_selectedIndex; | ||
|
||
void exec() override; | ||
void runSelectedAlg(); | ||
void addAlgToVec(const std::string &name, const int version, const ConfFuncPtr &loader); | ||
}; | ||
|
||
} // namespace Mantid::Algorithms |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// 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 "MantidMuon/LoadMuonNexus3.h" | ||
|
||
#include "MantidAPI/AlgorithmFactory.h" | ||
#include "MantidAPI/NexusFileLoader.h" | ||
#include "MantidAPI/Progress.h" | ||
#include "MantidAPI/RegisterFileLoader.h" | ||
#include "MantidKernel/Logger.h" | ||
#include "MantidNexus/NexusClasses.h" | ||
#include <H5Cpp.h> | ||
#include <string> | ||
|
||
namespace { | ||
const int CONFIDENCE_THRESHOLD{80}; | ||
|
||
int calculateConfidenceHDF5(const std::string &filePath, const std::shared_ptr<Mantid::API::Algorithm> &alg) { | ||
const auto nexusLoader = std::dynamic_pointer_cast<Mantid::API::NexusFileLoader>(alg); | ||
int confidence{0}; | ||
if (H5::H5File::isHdf5(filePath)) { | ||
try { | ||
Mantid::Kernel::NexusHDF5Descriptor descriptorHDF5(filePath); | ||
confidence = nexusLoader->confidence(descriptorHDF5); | ||
} catch (std::exception const &e) { | ||
Mantid::Kernel::Logger("LoadMuonNexus3").debug() | ||
<< "Error in calculating confidence for: " << nexusLoader->name() << " " << e.what() << '\n'; | ||
} | ||
} | ||
return (confidence >= CONFIDENCE_THRESHOLD) ? confidence : 0; | ||
} | ||
|
||
int calculateConfidence(const std::string &filePath, const std::shared_ptr<Mantid::API::Algorithm> &alg) { | ||
const auto fileLoader = std::dynamic_pointer_cast<Mantid::API::IFileLoader<Mantid::Kernel::NexusDescriptor>>(alg); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know we're pretty certain that (Same thing in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for this, I guess it's worth adding in a check in case anyone in the future extends this algorithm with a new alg and assigns the wrong confidence function. |
||
Mantid::Kernel::NexusDescriptor descriptor(filePath); | ||
const int confidence = fileLoader->confidence(descriptor); | ||
return (confidence >= CONFIDENCE_THRESHOLD) ? confidence : 0; | ||
} | ||
} // namespace | ||
|
||
namespace Mantid::Algorithms { | ||
// Register the algorithm into the algorithm factory | ||
DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadMuonNexus3) | ||
|
||
/** Executes the right version of the Muon nexus loader | ||
* @throw Exception::FileError If the Nexus file cannot be found/opened | ||
* @throw std::invalid_argument If the optional properties are set to invalid | ||
*values | ||
*/ | ||
LoadMuonNexus3::LoadMuonNexus3() : LoadMuonNexus() { | ||
addAlgToVec("LoadMuonNexusV2", 1, &calculateConfidenceHDF5); | ||
addAlgToVec("LoadMuonNexus", 1, &calculateConfidence); | ||
addAlgToVec("LoadMuonNexus", 2, &calculateConfidence); | ||
} | ||
|
||
void LoadMuonNexus3::exec() { | ||
const std::string filePath = getPropertyValue("Filename"); | ||
|
||
int maxConfidenceRes{0}; | ||
for (size_t i = 0; i < m_loadAlgs.size(); i++) { | ||
const int confidenceRes = m_loadAlgs[i].m_confFunc(filePath, m_loadAlgs[i].m_alg); | ||
if (confidenceRes > maxConfidenceRes) { | ||
maxConfidenceRes = confidenceRes; | ||
m_selectedIndex = i; | ||
} | ||
} | ||
|
||
if (!maxConfidenceRes) { | ||
throw Kernel::Exception::FileError("Cannot open the file ", filePath); | ||
} | ||
|
||
runSelectedAlg(); | ||
} | ||
|
||
void LoadMuonNexus3::runSelectedAlg() { | ||
const auto &alg = m_loadAlgs[m_selectedIndex].m_alg; | ||
this->setupAsChildAlgorithm(alg, 0, 1, true); | ||
alg->copyPropertiesFrom(*this); | ||
alg->executeAsChildAlg(); | ||
this->copyPropertiesFrom(*alg); | ||
} | ||
|
||
void LoadMuonNexus3::addAlgToVec(const std::string &name, const int version, const ConfFuncPtr &loader) { | ||
auto &factory = API::AlgorithmFactory::Instance(); | ||
if (factory.exists(name, version)) { | ||
const auto alg = factory.create(name, version); | ||
m_loadAlgs.push_back(AlgDetail(name, version, loader, alg)); | ||
} else { | ||
Mantid::Kernel::Logger("LoadMuonNexus3").debug() | ||
<< "Cannot add algorithm: " << name << " v" << version << ". The algorithm is not registered." << '\n'; | ||
} | ||
} | ||
} // namespace Mantid::Algorithms |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,123 @@ | ||||
// 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 <cxxtest/TestSuite.h> | ||||
|
||||
#include "MantidAPI/AnalysisDataService.h" | ||||
#include "MantidAPI/NexusFileLoader.h" | ||||
#include "MantidAPI/WorkspaceGroup.h" | ||||
#include "MantidDataObjects/Workspace2D.h" | ||||
#include "MantidMuon/LoadMuonNexus1.h" | ||||
#include "MantidMuon/LoadMuonNexus2.h" | ||||
#include "MantidMuon/LoadMuonNexus3.h" | ||||
|
||||
using namespace Mantid::API; | ||||
using namespace Mantid::Kernel; | ||||
using namespace Mantid::Algorithms; | ||||
using namespace Mantid::DataObjects; | ||||
|
||||
namespace { | ||||
// Mock class for LoadMuonNexusV2 which is in the DataHandling Library | ||||
class LoadMuonNexusV2 : public NexusFileLoader { | ||||
const std::string name() const override { return "LoadMuonNexusV2"; } | ||||
int version() const override { return 1; } | ||||
int confidence(NexusHDF5Descriptor &) const override { return 100; } | ||||
void execLoader() override {} | ||||
const std::string summary() const override { return "mock class"; } | ||||
void init() override {} | ||||
}; | ||||
} // namespace | ||||
|
||||
class LoadMuonNexus3Test : public CxxTest::TestSuite { | ||||
public: | ||||
void check_spectra_and_detectors(const MatrixWorkspace_sptr &output) { | ||||
|
||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
//---------------------------------------------------------------------- | ||||
// Tests to check that spectra-detector mapping is done correctly | ||||
//---------------------------------------------------------------------- | ||||
// Check the total number of elements in the map for HET | ||||
TS_ASSERT_EQUALS(output->getNumberHistograms(), 192); | ||||
|
||||
// Test one to one mapping, for example spectra 6 has only 1 pixel | ||||
TS_ASSERT_EQUALS(output->getSpectrum(6).getDetectorIDs().size(), 1); | ||||
|
||||
auto detectorgroup = output->getSpectrum(99).getDetectorIDs(); | ||||
TS_ASSERT_EQUALS(detectorgroup.size(), 1); | ||||
TS_ASSERT_EQUALS(*detectorgroup.begin(), 100); | ||||
} | ||||
|
||||
void testExecLoadMuonNexus2() { | ||||
LoadMuonNexus3 nxLoad; | ||||
nxLoad.initialize(); | ||||
|
||||
// Now set required filename and output workspace name | ||||
std::string inputFile = "argus0026287.nxs"; | ||||
nxLoad.setPropertyValue("FileName", inputFile); | ||||
|
||||
std::string outputSpace = "outer"; | ||||
nxLoad.setPropertyValue("OutputWorkspace", outputSpace); | ||||
|
||||
// Test execute to read file and populate workspace | ||||
TS_ASSERT_THROWS_NOTHING(nxLoad.execute()); | ||||
TS_ASSERT(nxLoad.isExecuted()); | ||||
|
||||
// Check output workspace | ||||
MatrixWorkspace_sptr output; | ||||
output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outputSpace); | ||||
Workspace2D_sptr output2D = std::dynamic_pointer_cast<Workspace2D>(output); | ||||
|
||||
// Perform limited tests on the outwork workspace as this is essentially just a wrapper algorithm. | ||||
// subset of tests performed in LoadMuonNexus2Test | ||||
check_spectra_and_detectors(output); | ||||
|
||||
TS_ASSERT(nxLoad.getSelectedAlg() == "LoadMuonNexus"); | ||||
TS_ASSERT(nxLoad.getSelectedVersion() == 2); | ||||
} | ||||
|
||||
void testExecLoadMuonNexus1() { | ||||
LoadMuonNexus3 nxLoad; | ||||
nxLoad.initialize(); | ||||
|
||||
// Now set required filename and output workspace name | ||||
std::string inputFile = "emu00006475.nxs"; | ||||
nxLoad.setPropertyValue("FileName", inputFile); | ||||
|
||||
std::string outputSpace = "outer"; | ||||
nxLoad.setPropertyValue("OutputWorkspace", outputSpace); | ||||
|
||||
// Test execute to read file and populate workspace | ||||
TS_ASSERT_THROWS_NOTHING(nxLoad.execute()); | ||||
TS_ASSERT(nxLoad.isExecuted()); | ||||
|
||||
// Check output workspace group | ||||
Mantid::API::WorkspaceGroup_sptr output = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputSpace); | ||||
TS_ASSERT(output->size() == 4); | ||||
|
||||
TS_ASSERT(nxLoad.getSelectedAlg() == "LoadMuonNexus"); | ||||
TS_ASSERT(nxLoad.getSelectedVersion() == 1); | ||||
} | ||||
|
||||
void testExecLoadMuonNexusV2() { | ||||
LoadMuonNexus3 nxLoad; | ||||
nxLoad.initialize(); | ||||
|
||||
// Now set required filename and output workspace name | ||||
std::string inputFile = "ARGUS00073601.nxs"; | ||||
nxLoad.setPropertyValue("FileName", inputFile); | ||||
|
||||
std::string outputSpace = "outer"; | ||||
nxLoad.setPropertyValue("OutputWorkspace", outputSpace); | ||||
|
||||
// Test execute to read file and populate workspace | ||||
TS_ASSERT_THROWS_NOTHING(nxLoad.execute()); | ||||
TS_ASSERT(nxLoad.isExecuted()); | ||||
|
||||
TS_ASSERT(nxLoad.getSelectedAlg() == "LoadMuonNexusV2"); | ||||
TS_ASSERT(nxLoad.getSelectedVersion() == 1); | ||||
} | ||||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now this I can't abide