Skip to content

Commit 994e3de

Browse files
Add SavePolarizationNXcanSAS Algorithm (#39118)
* Change spin state validator to input std::string and accept an optional extra spin paramter * Refactor constructor for spin state validator where necessary * add save pol algorithm * Add cansas and nexus definitions for polarization * Add polarization to SaveNXcanSAS base * Refactor NXcanSASHelper file to save polarized metadata and data * Add missing spin combinations * Add helper struct for handling spin vectors and add error signal to file * Add default suffix for sas entry * Add a struct to handle spin vectors more gracefully, and reorganied code better * Add some validation for input spin strings and reorganized redundant code * Save docs file with basic info * typo in definitions * Remove private class methods and inherit from nxcansasfiletest class to access those methods * Add helper test class for SaveNXcanSASTest and SavePolarizedNXcanSASTest * Add release notes * Clean SavePolarized class * ammend release note typo * Add nxcansas polarization states to polarization correction helpers * Add SavePolarized test suite * Refactor NXcanSAS test helpers to accomodate polarized data * Update definitions * Refactor, reorganized and clean NXcanSAS helper library * - Refactor, reorganized and clean base algorithm - Improve validation for polarized data - Add definitions for standard properties - Improve polarized component map creation * Modify signature of prepareFilename after refactor of helper file * Modify signature of prepareFilename after refactor of helper file in SavePol algorithm * Refactor Load and Save NXcanSAS test after changing the structure of transmission parameters in helper test file * Refactor, reorganized and clean helper test class Add more private methods for testing polarized data * Flesh out docs * Add instrument file to unit_testing folder in instruments with a polarized sans instrument * Fix some cppcheck warnings * Changes after rebase * Fix doxygen typo and include error * Try to fix docs typo * Refactor return of extra pairs * Reword error message and use output stream to simplify conditional error message * - Bring spin state validator from kernel - Remove dependencies with Mantid::algorithms - Homogeneize all const to west const * Remove link to mantid algorithms from data handling * Add better error message in spin state validator * Add separator parameter to split string into vector * Update file date * Move SaveNXcanSAS and SavePolarizedNXcanSAS property names to nxcansasdefinitions * - Add helper class for storing data dimensions information - Split save polarized fucntion into smaller functions * - Remove property names from cansasbase - Split validator of polarized properties into smaller validator functions * Use initilization list for points and histogram variables * Add consts where appropriate in NXcanSASFileTest * Fix grammar typo in release notes * - Rename parameter separator to separators - Specify the role of separators splitting multiple characters - Add test for multiple character separators * - Add consts where appropriate - Rename Pin, Pout to pIn, pOut - Prefix getters in DataDimensions struct with get - Fix various docstring typos * - Improve error handling in areAxisNumeric function - Fix various typos in docstrings - Add consts were appropriate * Use std iterator function to check non numeric axis and avoid cppcheck warning
1 parent 1e17ac8 commit 994e3de

27 files changed

+3330
-1191
lines changed

Framework/Algorithms/src/PolarizationCorrectionFredrikze.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ void PolarizationCorrectionFredrikze::init() {
297297
"An output workspace.");
298298

299299
const auto spinStateValidator =
300-
std::make_shared<SpinStateValidator>(std::unordered_set<int>{2, 4}, true, 'p', 'a', true);
300+
std::make_shared<SpinStateValidator>(std::unordered_set<int>{2, 4}, true, "p", "a", true);
301301

302302
declareProperty(Prop::INPUT_SPIN_STATES, "", spinStateValidator,
303303
"The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or "

Framework/Algorithms/src/PolarizationCorrectionWildes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ void PolarizationCorrectionWildes::init() {
336336
FlipperConfigurations::ON_OFF + ", " + FlipperConfigurations::ON_ON,
337337
flipperConfigValidator, "Flipper configurations of the input workspaces.");
338338
const auto spinStateValidator =
339-
std::make_shared<Kernel::SpinStateValidator>(std::unordered_set<int>{0, 2, 4}, false, '+', '-', true);
339+
std::make_shared<Kernel::SpinStateValidator>(std::unordered_set<int>{0, 2, 4}, false, "+", "-", true);
340340
declareProperty(Prop::SPIN_STATES, "", spinStateValidator, "The order of the spin states in the output workspace.");
341341
declareProperty(
342342
std::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>(Prop::EFFICIENCIES, "", Kernel::Direction::Input),

Framework/Algorithms/src/PolarizationEfficiencyCor.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,12 @@ void PolarizationEfficiencyCor::init() {
9797
"Ap, Rho and Alpha for Fredrikze.");
9898

9999
const auto wildesFlipperValidator =
100-
std::make_shared<SpinStateValidator>(std::unordered_set<int>{1, 2, 3, 4}, true, '0', '1', true);
100+
std::make_shared<SpinStateValidator>(std::unordered_set<int>{1, 2, 3, 4}, true, "0", "1", true);
101101
declareProperty(Prop::FLIPPERS, "", wildesFlipperValidator,
102102
"Flipper configurations of the input workspaces (Wildes method only)");
103103

104104
const auto spinStateValidator =
105-
std::make_shared<SpinStateValidator>(std::unordered_set<int>{0, 2, 4}, true, '+', '-', true);
105+
std::make_shared<SpinStateValidator>(std::unordered_set<int>{0, 2, 4}, true, "+", "-", true);
106106
declareProperty(Prop::OUTPUT_WILDES_SPIN_STATES, "", spinStateValidator,
107107
"The order of the spin states in the output workspace. (Wildes method only).");
108108

@@ -114,7 +114,7 @@ void PolarizationEfficiencyCor::init() {
114114
"(Fredrikze method only)");
115115

116116
const auto fredrikzeSpinStateValidator =
117-
std::make_shared<SpinStateValidator>(std::unordered_set<int>{2, 4}, true, 'p', 'a', true);
117+
std::make_shared<SpinStateValidator>(std::unordered_set<int>{2, 4}, true, "p", "a", true);
118118

119119
declareProperty(Prop::INPUT_FRED_SPIN_STATES, "", fredrikzeSpinStateValidator,
120120
"The order of spin states in the input workspace group. The possible values are 'pp,pa,ap,aa' or "

Framework/DataHandling/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ set(SRC_FILES
189189
src/SavePDFGui.cpp
190190
src/SavePHX.cpp
191191
src/SaveParameterFile.cpp
192+
src/SavePolarizedNXcanSAS.cpp
192193
src/SaveRKH.cpp
193194
src/SaveRMCProfile.cpp
194195
src/SaveReflectometryAscii.cpp
@@ -401,6 +402,7 @@ set(INC_FILES
401402
inc/MantidDataHandling/SavePDFGui.h
402403
inc/MantidDataHandling/SavePHX.h
403404
inc/MantidDataHandling/SaveParameterFile.h
405+
inc/MantidDataHandling/SavePolarizedNXcanSAS.h
404406
inc/MantidDataHandling/SaveRKH.h
405407
inc/MantidDataHandling/SaveRMCProfile.h
406408
inc/MantidDataHandling/SaveReflectometryAscii.h
@@ -598,6 +600,7 @@ set(TEST_FILES
598600
SavePDFGuiTest.h
599601
SavePHXTest.h
600602
SaveParameterFileTest.h
603+
SavePolarizedNXcanSASTest.h
601604
SaveRKHTest.h
602605
SaveRMCProfileTest.h
603606
SaveReflectometryAsciiTest.h

Framework/DataHandling/inc/MantidDataHandling/NXcanSASDefinitions.h

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,49 @@ namespace Mantid {
1212
namespace DataHandling {
1313

1414
namespace NXcanSAS {
15+
16+
/// Property names for save algorithms.
17+
namespace StandardProperties {
18+
static const std::string INPUT_WORKSPACE = "InputWorkspace";
19+
static const std::string FILENAME = "Filename";
20+
static const std::string RADIATION_SOURCE = "RadiationSource";
21+
static const std::string DETECTOR_NAMES = "DetectorNames";
22+
static const std::string TRANSMISSION = "Transmission";
23+
static const std::string TRANSMISSION_CAN = "TransmissionCan";
24+
static const std::string SAMPLE_TRANS_RUN_NUMBER = "SampleTransmissionRunNumber";
25+
static const std::string SAMPLE_DIRECT_RUN_NUMBER = "SampleDirectRunNumber";
26+
static const std::string CAN_SCATTER_RUN_NUMBER = "CanScatterRunNumber";
27+
static const std::string CAN_DIRECT_RUN_NUMBER = "CanDirectRunNumber";
28+
static const std::string BKG_SUB_WORKSPACE = "BackgroundSubtractionWorkspace";
29+
static const std::string BKG_SUB_SCALE = "BackgroundSubtractionScaleFactor";
30+
static const std::string GEOMETRY = "Geometry";
31+
static const std::string SAMPLE_HEIGHT = "SampleHeight";
32+
static const std::string SAMPLE_WIDTH = "SampleWidth";
33+
static const std::string SAMPLE_THICKNESS = "SampleThickness";
34+
} // namespace StandardProperties
35+
36+
namespace PolProperties {
37+
static const std::string INPUT_SPIN_STATES = "InputSpinStates";
38+
static const std::string POLARIZER_COMP_NAME = "PolarizerComponentName";
39+
static const std::string ANALYZER_COMP_NAME = "AnalyzerComponentName";
40+
static const std::string FLIPPER_COMP_NAMES = "FlipperComponentNames";
41+
static const std::string MAG_FIELD_STRENGTH_LOGNAME = "MagneticFieldStrengthLogName";
42+
static const std::string MAG_FIELD_DIR = "MagneticFieldDirection";
43+
inline std::map<std::string, std::string> POL_COMPONENTS = {
44+
{"polarizer", POLARIZER_COMP_NAME}, {"analyzer", ANALYZER_COMP_NAME}, {"flipper", FLIPPER_COMP_NAMES}};
45+
} // namespace PolProperties
46+
47+
namespace SpinStateNXcanSAS {
48+
static const std::string SPIN_PARA = "+1";
49+
static const std::string SPIN_ANTIPARA = "-1";
50+
static const std::string SPIN_ZERO = "0";
51+
} // namespace SpinStateNXcanSAS
52+
1553
// General
16-
enum class WorkspaceDimensionality { oneD, twoD, other };
54+
enum class WorkspaceDimensionality { other, oneD, twoD };
55+
56+
// NXcanSAS file extension
57+
const std::string NX_CANSAS_EXTENSION = ".h5";
1758

1859
// NXcanSAS Tag Definitions
1960
const std::string sasUnitAttr = "units";
@@ -46,6 +87,7 @@ const std::string sasEntryDefinitionFormat = "NXcanSAS";
4687
const std::string sasEntryTitle = "title";
4788
const std::string sasEntryRun = "run";
4889
const std::string sasEntryRunInLogs = "run_number";
90+
const std::string sasEntryDefaultSuffix = "01";
4991

5092
// SASdata
5193
const std::string sasDataClassAttr = "SASdata";
@@ -112,6 +154,42 @@ const std::string sasBeamAndSampleSizeUnitAttrValue = "mm";
112154

113155
const std::string sasInstrumentIDF = "idf";
114156

157+
// SASpolarization
158+
// WIP: Initial proposal: https://wiki.cansas.org/index.php?title=NXcanSAS_v1.1
159+
const std::string sasDataPout = "Pout";
160+
const std::string sasDataPin = "Pin";
161+
const std::string sasDataPoutIndicesAttr = "Pout_indices";
162+
const std::string sasDataPinIndicesAttr = "Pin_indices";
163+
constexpr int sasDataPoutIndicesValue = 1;
164+
constexpr int sasDataPinIndicesValue = 0;
165+
const std::string sasDataPolarizationUnitAttr = "none";
166+
167+
struct InstrumentPolarizer {
168+
explicit InstrumentPolarizer(const std::string &type, const std::string &name) : m_type(type), m_name(name) {};
169+
std::string sasPolarizerClassAttr() const { return "SAS" + m_type; }
170+
std::string sasPolarizerGroupAttr() const { return "sas" + m_type; }
171+
std::string nxPolarizerClassAttr() const { return (m_type == "flipper") ? "NX" + m_type : "NXpolarizer"; }
172+
static std::string sasPolarizerName() { return "name"; }
173+
static std::string sasPolarizerDeviceType() { return "type"; }
174+
static std::string sasPolarizerIDFDeviceType() { return "device-type"; }
175+
static std::string sasPolarizerDistance() { return "distance"; }
176+
static std::string sasPolarizerDistanceUnitAttr() { return "m"; }
177+
const std::string &getComponentName() const { return m_name; }
178+
const std::string &getComponentType() const { return m_type; }
179+
180+
private:
181+
std::string m_type;
182+
std::string m_name;
183+
};
184+
185+
const std::string sasSampleMagneticField = "magnetic_field";
186+
const std::string sasSampleEMFieldDirectionAttr = "direction";
187+
const std::string sasSampleEMFieldDirectionSphericalAttr = "direction_spherical";
188+
const std::string sasSampleEMFieldDirectionPolar = "polar_angle";
189+
const std::string sasSampleEMFieldDirectionAzimuthal = "azimuthal_angle";
190+
const std::string sasSampleEMFieldDirectionRotation = "rotation_angle";
191+
const std::string sasSampleEMFieldDirectionUnitsAttr = "degrees";
192+
115193
// SASprocess
116194
const std::string sasProcessClassAttr = "SASprocess";
117195
const std::string nxProcessClassAttr = "NXprocess";

Framework/DataHandling/inc/MantidDataHandling/NXcanSASHelper.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,24 @@
66
// SPDX - License - Identifier: GPL - 3.0 +
77
#pragma once
88

9-
#include "MantidAPI/Algorithm.h"
109
#include "MantidAPI/MatrixWorkspace_fwd.h"
10+
#include "MantidAPI/WorkspaceGroup_fwd.h"
1111
#include "MantidDataHandling/DllConfig.h"
1212
#include <H5Cpp.h>
1313
#include <filesystem>
14+
#include <vector>
1415

1516
namespace Mantid {
1617
namespace DataHandling {
1718
namespace NXcanSAS {
1819
// Helper functions for algorithms saving in NXcanSAS format.
1920
enum class WorkspaceDimensionality;
2021

21-
std::string MANTID_DATAHANDLING_DLL makeCanSASRelaxedName(const std::string &input);
22-
std::filesystem::path MANTID_DATAHANDLING_DLL prepareFilename(const std::string &baseFilename, int index,
23-
bool isGroup = false);
22+
// DATA
23+
void MANTID_DATAHANDLING_DLL addData1D(H5::Group &data, const Mantid::API::MatrixWorkspace_sptr &workspace);
24+
void MANTID_DATAHANDLING_DLL addData2D(H5::Group &data, const Mantid::API::MatrixWorkspace_sptr &workspace);
25+
26+
// STANDARD METADATA
2427
void MANTID_DATAHANDLING_DLL addDetectors(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace,
2528
const std::vector<std::string> &detectorNames);
2629
void MANTID_DATAHANDLING_DLL addInstrument(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace,
@@ -36,12 +39,27 @@ void MANTID_DATAHANDLING_DLL addProcessEntry(H5::Group &group, const std::string
3639
void MANTID_DATAHANDLING_DLL addTransmission(H5::Group &group, const Mantid::API::MatrixWorkspace_const_sptr &workspace,
3740
const std::string &transmissionName);
3841

39-
void MANTID_DATAHANDLING_DLL addData1D(H5::Group &data, const Mantid::API::MatrixWorkspace_sptr &workspace);
40-
void MANTID_DATAHANDLING_DLL addData2D(H5::Group &data, const Mantid::API::MatrixWorkspace_sptr &workspace);
42+
// POLARIZED DATA
43+
void MANTID_DATAHANDLING_DLL addPolarizedData(H5::Group &data, const Mantid::API::WorkspaceGroup_sptr &wsGroup,
44+
const std::string &inputSpinStates);
45+
void MANTID_DATAHANDLING_DLL addPolarizer(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace,
46+
const std::string &componentName, const std::string &componentType,
47+
const std::string &groupSuffix);
48+
49+
// POLARIZED METADATA
50+
void MANTID_DATAHANDLING_DLL addSampleEMFields(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace,
51+
const std::string &emFieldStrengthLog, const std::string &emFieldDir);
52+
void MANTID_DATAHANDLING_DLL addEMFieldDirection(H5::Group &group, const std::string &emFieldDir);
53+
54+
// UTILITY
55+
std::string MANTID_DATAHANDLING_DLL makeCanSASRelaxedName(const std::string &input);
56+
H5::H5File MANTID_DATAHANDLING_DLL prepareFile(const std::filesystem::path &path);
57+
std::filesystem::path MANTID_DATAHANDLING_DLL prepareFilename(const std::string &baseFilename,
58+
bool addDigitSuffix = false, size_t index = 0);
4159

60+
std::string MANTID_DATAHANDLING_DLL addDigit(size_t index);
4261
WorkspaceDimensionality MANTID_DATAHANDLING_DLL
4362
getWorkspaceDimensionality(const Mantid::API::MatrixWorkspace_sptr &workspace);
44-
std::vector<std::string> MANTID_DATAHANDLING_DLL splitDetectorNames(std::string detectorNames);
4563

4664
} // namespace NXcanSAS
4765
} // namespace DataHandling

Framework/DataHandling/inc/MantidDataHandling/SaveNXcanSASBase.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,43 @@
88

99
#include "MantidAPI/Algorithm.h"
1010
#include "MantidAPI/MatrixWorkspace_fwd.h"
11+
#include "MantidAPI/WorkspaceGroup_fwd.h"
1112
#include "MantidDataHandling/DllConfig.h"
13+
1214
#include <H5Cpp.h>
1315
#include <filesystem>
1416

1517
namespace Mantid {
1618
namespace DataHandling {
1719

18-
/** SaveNXcanSASBase : Base class to save a reduced workspace in the NXcanSAS format. Currently
19-
* only MatrixWorkspaces resulting from
20-
* 1D and 2D reductions are supported.
20+
/** SaveNXcanSASBase : Base class to save a reduced workspace in the NXcanSAS format.
21+
* Depending on the derived algorithm, it contains a member that stores standard SANS reduced data
22+
* in 1D or 2D from group or matrix workspaces,or polarized SANS reduced data in 1D or 2D from group workspaces.
2123
*/
2224
class MANTID_DATAHANDLING_DLL SaveNXcanSASBase : public API::Algorithm {
2325
protected:
24-
void saveSingleWorkspaceFile(const API::MatrixWorkspace_sptr &workspace, const std::filesystem::path &path);
25-
void addStandardMetadata(const Mantid::API::MatrixWorkspace_sptr &workspace, H5::Group &sasEntry);
26-
void addData(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace);
26+
void addStandardMetadata(const Mantid::API::MatrixWorkspace_sptr &workspace, H5::Group &sasEntry) const;
27+
void addPolarizedMetadata(const Mantid::API::MatrixWorkspace_sptr &workspace, H5::Group &sasEntry) const;
28+
void addData(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace) const;
29+
void addPolarizedData(H5::Group &group, const Mantid::API::WorkspaceGroup_sptr &wsGroup) const;
2730
H5::Group addSasEntry(H5::H5File &file, const Mantid::API::MatrixWorkspace_sptr &workspace,
28-
const std::string &suffix);
31+
const std::string &suffix) const;
32+
2933
void initStandardProperties();
30-
std::map<std::string, std::string> validateStandardInputs();
34+
void initPolarizedProperties();
35+
std::map<std::string, std::string> validateStandardInputs() const;
36+
// Polarized data and metadata
37+
std::map<std::string, std::string> validatePolarizedInputWorkspace(const std::vector<std::string> &spinVec) const;
38+
std::map<std::string, std::string> validateSpinStateStrings(const std::vector<std::string> &spinVec) const;
39+
std::map<std::string, std::string> validatePolarizedMetadata() const;
40+
41+
void saveSingleWorkspaceFile(const API::MatrixWorkspace_sptr &workspace, const std::filesystem::path &path) const;
42+
void savePolarizedGroup(const API::WorkspaceGroup_sptr &wsGroup, const std::filesystem::path &path) const;
3143

3244
std::unique_ptr<API::Progress> m_progress = nullptr;
45+
46+
private:
47+
std::map<std::string, std::vector<std::string>> createPolarizedComponentMap() const;
3348
};
3449

3550
} // namespace DataHandling
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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 "MantidDataHandling/DllConfig.h"
10+
#include "MantidDataHandling/SaveNXcanSASBase.h"
11+
12+
namespace Mantid {
13+
namespace DataHandling {
14+
15+
/** SavePolarizedNXcanSAS : Extends SaveNXcanSAS adding metadata for polarized SANS measurements.
16+
*/
17+
class MANTID_DATAHANDLING_DLL SavePolarizedNXcanSAS final : public SaveNXcanSASBase {
18+
public:
19+
/// Constructor
20+
SavePolarizedNXcanSAS();
21+
/// Virtual dtor
22+
~SavePolarizedNXcanSAS() override = default;
23+
const std::string name() const override { return "SavePolarizedNXcanSAS"; }
24+
const std::string summary() const override {
25+
return "Save a Group Workspace with reduced SANS polarized data in NXcanSAS Format.";
26+
}
27+
28+
/// InputWorkspace property only accepts workspace groups so we don't want the base algorithm class to process
29+
/// them as it will done in exec.
30+
bool checkGroups() override { return false; }
31+
32+
/// Algorithm's version
33+
int version() const override { return (1); }
34+
const std::vector<std::string> seeAlso() const override { return {"SaveNXcanSAS", "LoadNXcanSAS"}; }
35+
/// Algorithm's category for identification
36+
const std::string category() const override { return "DataHandling\\Nexus"; }
37+
38+
std::map<std::string, std::string> validateInputs() override;
39+
40+
private:
41+
/// Initialisation code
42+
void init() override;
43+
/// Execution code
44+
void exec() override;
45+
};
46+
47+
} // namespace DataHandling
48+
} // namespace Mantid

0 commit comments

Comments
 (0)