34 if (ws->axes() == 0) {
37 const auto unit = ws->getAxis(0)->unit();
38 return (unit && unit->unitID() == unitToCompareWith);
42 if (numberOfDims == 0) {
43 throw std::invalid_argument(
"Workspace can only have 1 or 2 dimensions");
45 std::vector<int> indices(numberOfDims);
46 std::generate(indices.begin(), indices.end(), [i = 0]()
mutable { return i++; });
47 const auto itIndex = std::find_if(indices.cbegin(), indices.cend(), [&
workspace](
const auto &
index) {
48 return !workspace->getAxis(index)->isNumeric();
50 if (itIndex != indices.cend()) {
51 throw std::invalid_argument(
"Invalid workspace: Axis " +
std::to_string(*itIndex) +
" is not numeric");
56 const auto &ws_input = std::dynamic_pointer_cast<MatrixWorkspace>(ws);
57 return (ws_input && hasUnit(
"MomentumTransfer", ws_input) && ws_input->isCommonBins());
62 return "Workspace has to be a valid workspace";
66 const auto &groupItems = std::dynamic_pointer_cast<WorkspaceGroup>(ws)->getAllItems();
67 if (std::any_of(groupItems.cbegin(), groupItems.cend(),
68 [](
const auto &childWs) { return !checkValidMatrixWorkspace(childWs); })) {
69 return "Workspace must have common bins and Momentum transfer units";
74 if (!checkValidMatrixWorkspace(ws)) {
75 return "Workspace must have common bins and Momentum transfer units";
86 auto groupValidator = std::make_shared<Kernel::LambdaValidator<Workspace_sptr>>(validateGroupWithProperties);
89 "The input workspace, which must be in units of Q. Can be a 1D or a 2D workspace.");
91 "The name of the .h5 file to save");
93 std::vector<std::string> radiationSourceOptions{
"Spallation Neutron Source",
94 "Pulsed Reactor Neutron Source",
95 "Reactor Neutron Source",
96 "Synchrotron X-ray Source",
98 "Rotating Anode X-ray",
105 std::make_shared<Kernel::StringListValidator>(radiationSourceOptions),
"The type of radiation used.");
107 "Specify in a comma separated list, which detectors to store "
108 "information about; \nwhere each name must match a name "
109 "given for a detector in the [[IDF|instrument definition "
110 "file (IDF)]]. \nIDFs are located in the instrument "
111 "sub-directory of the Mantid install directory.");
114 std::make_shared<API::WorkspaceUnitValidator>(
"Wavelength")),
115 "The transmission workspace. Optional. If given, will be saved at "
116 "TransmissionSpectrum");
120 std::make_shared<API::WorkspaceUnitValidator>(
"Wavelength")),
121 "The transmission workspace of the Can. Optional. If given, will be "
122 "saved at TransmissionSpectrum");
125 "The run number for the sample transmission workspace. Optional.");
127 "The run number for the sample direct workspace. Optional.");
129 "The run number for the can scatter workspace. Optional.");
131 "The run number for the can direct workspace. Optional.");
135 "The name of the workspace used in the scaled background subtraction, to be included in the metadata. Optional.");
138 "The scale factor used in the scaled background subtraction, to be included in the metadata. Optional.");
140 std::vector<std::string>
const geometryOptions{
"Cylinder",
"FlatPlate",
"Flat plate",
"Disc",
"Unknown"};
142 std::make_shared<Kernel::StringListValidator>(geometryOptions),
143 "The geometry type of the collimation.");
145 "The height of the collimation element in mm. If specified as 0 it will not be recorded.");
147 "The width of the collimation element in mm. If specified as 0 it will not be recorded.");
149 "The thickness of the sample in mm. If specified as 0 it will not be recorded.");
153 const auto spinStateValidator = std::make_shared<Kernel::SpinStateValidator>(
158 "The order of the spin states in the input group workspace: +1 Polarization parallel to polarizer, "
159 "-1 antiparallel and 0 no polarization");
161 "The name of the Polarizer Component as defined in the IDF. i.e. 'short-polarizer'");
163 "The name of the Analyzer Component as defined in the IDF. i.e. 'helium-analyzer'");
165 "Comma separated list of flipper components as defined in the IDF i.e. 'RF-flipper");
167 "The name of sample logs in which the magnetic field strength is stored");
169 "Direction of the magnetic field on the sample: comma separated vector"
170 "with three values: Polar, Azimuthal and Rotation angles");
174 std::map<std::string, std::string> result;
180 return ws && std::dynamic_pointer_cast<const Mantid::DataObjects::Workspace2D>(ws);
183 const auto &groupItems = std::dynamic_pointer_cast<WorkspaceGroup>(
workspace)->getAllItems();
184 if (std::any_of(groupItems.cbegin(), groupItems.cend(),
185 [&](
const auto &childWs) { return !valid2DWorkspace(childWs); })) {
186 result.emplace(
"InputWorkspace",
187 "All input workspaces in the input group must be a Workspace2D with numeric axis.");
191 result.emplace(
"InputWorkspace",
"The InputWorkspace must be a Workspace2D with numeric axis.");
199 auto checkTransmission = [&result](
const MatrixWorkspace_sptr &trans,
const std::string &propertyName) {
200 if (trans->getNumberHistograms() != 1) {
201 result.emplace(propertyName,
"The input workspaces for transmissions have to be 1D.");
208 if (transmissionCan) {
215std::map<std::string, std::string>
217 std::map<std::string, std::string> result;
222 "Input Workspaces for polarized data can only be workspace groups.");
225 const auto wsGroup = std::dynamic_pointer_cast<WorkspaceGroup>(
workspace);
226 const auto &entries = wsGroup->getNumberOfEntries();
227 if (entries != 2 && entries != 4) {
229 "Input Group Workspace can only contain 2 or 4 workspace members.");
232 if (entries !=
static_cast<int>(spinVec.size())) {
234 " member workspaces on the InputWorkspace group");
237 const auto wsVec = wsGroup->getAllItems();
240 if (std::any_of(wsVec.cbegin(), wsVec.cend(), [&dim0](
const Workspace_sptr &ws) {
241 return dim0 != getWorkspaceDimensionality(std::dynamic_pointer_cast<MatrixWorkspace>(ws));
248std::map<std::string, std::string>
250 std::map<std::string, std::string> result;
253 if (spinVec.size() == 4 && std::any_of(spinVec.cbegin(), spinVec.cend(), [](
const std::string &spinPair) {
254 return (spinPair.find(SpinStateNXcanSAS::SPIN_ZERO) != std::string::npos);
259 if (spinVec.size() == 2) {
260 if (std::any_of(spinVec.cbegin(), spinVec.cend(),
261 [](
const std::string &state) { return state.find(
'1') == std::string::npos; })) {
268 if (noPin == noPout) {
270 "The 0 polarized state can only be either Pin or Pout for 2 spin configurations");
277 std::map<std::string, std::string> result;
279 if (!magneticFieldDirection.empty()) {
282 std::for_each(direction.cbegin(), direction.cend(), [](
const std::string &val) { (void)std::stod(val); });
283 }
catch (
const std::invalid_argument &) {
286 if (direction.size() != 3) {
288 "Magnetic Field Direction should contain 3 comma separated values to represent a 3D vector");
338 if (transmissionCan) {
342 if (transmissionSample) {
347 if (!scaledBgSubWorkspace.empty()) {
355 if (transmissionSample) {
360 if (transmissionCan) {
377 for (
size_t i = 0; i < compVec.size(); i++) {
378 const auto suffix = compVec.size() > 1 ?
addDigit(i + 1) :
"";
393 std::map<std::string, std::vector<std::string>> componentMap;
395 std::string
const &componentName =
getProperty(compName);
396 if (!componentName.empty()) {
398 componentMap.emplace(std::make_pair(compType, componentVec));
412 const std::string &suffix)
const {
423 const auto workspaceTitle =
workspace->getTitle();
427 auto runNumber =
workspace->getRunNumber();
442 areAxesNumeric(
workspace,
static_cast<int>(dim));
444 case (WorkspaceDimensionality::oneD):
447 case (WorkspaceDimensionality::twoD):
451 throw std::runtime_error(
"SaveNXcanSAS: The provided workspace "
452 "dimensionality is not 1D or 2D.");
474 auto workspace = std::dynamic_pointer_cast<MatrixWorkspace>(wsGroup->getItem(0));
481 m_progress->report(
"Adding standard metadata");
484 m_progress->report(
"Adding polarized metadata");
500 const std::filesystem::path &path)
const {
507 m_progress->report(
"Adding standard metadata");
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
@ Save
to specify a file to write to, the file may or may not exist
A property class for workspaces.
std::map< std::string, std::vector< std::string > > createPolarizedComponentMap() const
Creates a component map to access the polarizer component names defined in input properties on the co...
std::map< std::string, std::string > validatePolarizedMetadata() const
std::map< std::string, std::string > validateStandardInputs() const
H5::Group addSasEntry(H5::H5File &file, const Mantid::API::MatrixWorkspace_sptr &workspace, const std::string &suffix) const
Add the sasEntry to the sasroot.
void addPolarizedData(H5::Group &group, const Mantid::API::WorkspaceGroup_sptr &wsGroup) const
Calls out polarized data function from helper library.
void initStandardProperties()
std::unique_ptr< API::Progress > m_progress
void addPolarizedMetadata(const Mantid::API::MatrixWorkspace_sptr &workspace, H5::Group &sasEntry) const
Adds polarized metadata to a NXcanSAS file format.
void addStandardMetadata(const Mantid::API::MatrixWorkspace_sptr &workspace, H5::Group &sasEntry) const
Adds standard metadata to a NXcanSAS file format.
void addData(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace) const
Sorts out dimensionality of the data (1D, 2D) and calls helper function to insert data in workspace t...
void savePolarizedGroup(const API::WorkspaceGroup_sptr &wsGroup, const std::filesystem::path &path) const
Saves NXcanSAS data for a group workspace.
void saveSingleWorkspaceFile(const API::MatrixWorkspace_sptr &workspace, const std::filesystem::path &path) const
Saves NXcanSAS data for a matrix workspace.
std::map< std::string, std::string > validateSpinStateStrings(const std::vector< std::string > &spinVec) const
void initPolarizedProperties()
std::map< std::string, std::string > validatePolarizedInputWorkspace(const std::vector< std::string > &spinVec) const
std::shared_ptr< WorkspaceGroup > WorkspaceGroup_sptr
shared pointer to Mantid::API::WorkspaceGroup
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
static const std::string ANALYZER_COMP_NAME
static const std::string MAG_FIELD_STRENGTH_LOGNAME
static const std::string POLARIZER_COMP_NAME
static const std::string MAG_FIELD_DIR
static const std::string FLIPPER_COMP_NAMES
std::map< std::string, std::string > POL_COMPONENTS
static const std::string INPUT_SPIN_STATES
static const std::string SPIN_ANTIPARA
static const std::string SPIN_PARA
static const std::string SPIN_ZERO
static const std::string SAMPLE_TRANS_RUN_NUMBER
static const std::string SAMPLE_DIRECT_RUN_NUMBER
static const std::string TRANSMISSION_CAN
static const std::string BKG_SUB_SCALE
static const std::string CAN_DIRECT_RUN_NUMBER
static const std::string FILENAME
static const std::string SAMPLE_WIDTH
static const std::string SAMPLE_THICKNESS
static const std::string GEOMETRY
static const std::string CAN_SCATTER_RUN_NUMBER
static const std::string DETECTOR_NAMES
static const std::string TRANSMISSION
static const std::string SAMPLE_HEIGHT
static const std::string INPUT_WORKSPACE
static const std::string BKG_SUB_WORKSPACE
static const std::string RADIATION_SOURCE
void MANTID_DATAHANDLING_DLL addInstrument(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace, const std::string &radiationSource, const std::string &geometry, double beamHeight, double beamWidth, const std::vector< std::string > &detectorNames)
Add the instrument group to the NXcanSAS file.
const std::string sasProcessTermScaledBgSubScaleFactor
const std::string sasProcessGroupName
const std::string sasEntryRun
void MANTID_DATAHANDLING_DLL addData2D(H5::Group &data, const Mantid::API::MatrixWorkspace_sptr &workspace)
Stores the 2D signal and Q data in the HDF5 file.
const std::string sasTransmissionSpectrumNameCanAttrValue
const std::string nxEntryClassAttr
void MANTID_DATAHANDLING_DLL addSampleEMFields(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace, const std::string &emFieldStrengthLog, const std::string &emFieldDir)
Adds the direction and strength of either magnetic or electric field on the sample.
const std::string sasEntryVersionAttr
const std::string sasDataGroupName
void MANTID_DATAHANDLING_DLL addData1D(H5::Group &data, const Mantid::API::MatrixWorkspace_sptr &workspace)
Adds signal and Q data to the data group from 1D reduced SANS data.
const std::string sasProcessTermCanDirect
void MANTID_DATAHANDLING_DLL addProcess(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace)
const std::string sasEntryClassAttr
const std::string sasSampleMagneticField
const std::string sasProcessTermSampleDirect
const std::string sasDataClassAttr
std::string MANTID_DATAHANDLING_DLL addDigit(size_t index)
const std::string sasEntryDefinition
const std::string sasProcessTermCanScatter
void MANTID_DATAHANDLING_DLL addPolarizer(H5::Group &group, const Mantid::API::MatrixWorkspace_sptr &workspace, const std::string &componentName, const std::string &componentType, const std::string &groupSuffix)
Add the polarizer component information to the instrument cansas group.
const std::string nxDataClassAttr
const std::string sasTransmissionSpectrumNameSampleAttrValue
WorkspaceDimensionality getWorkspaceDimensionality(const Mantid::API::MatrixWorkspace_sptr &workspace)
Retrieves workspace dimensionality enum value: oneD , twoD, other (error)
void MANTID_DATAHANDLING_DLL addPolarizedData(H5::Group &data, const Mantid::API::WorkspaceGroup_sptr &wsGroup, const std::string &inputSpinStates)
Adds signal, Q and spin data to the data group from 1D or 2D reduced polarized SANS data.
const std::string sasEntryVersionAttrValue
const std::string sasEntryDefinitionFormat
void MANTID_DATAHANDLING_DLL addSample(H5::Group &group, const double &sampleThickness)
Adds sample thickness information to the sas sample group.
H5::H5File MANTID_DATAHANDLING_DLL prepareFile(const std::filesystem::path &path)
Creates and opens a H5 File in the given path.
const std::string sasProcessTermScaledBgSubWorkspace
const std::string sasEntryGroupName
const std::string sasEntryDefaultSuffix
const std::string sasEntryTitle
void MANTID_DATAHANDLING_DLL addTransmission(H5::Group &group, const Mantid::API::MatrixWorkspace_const_sptr &workspace, const std::string &transmissionName)
Add a transmission group to the cansas file, including metadata extracted from the transmission works...
const std::string sasProcessTermSampleTrans
template DLLExport std::vector< std::string > splitStringIntoVector< std::string >(std::string listString, const std::string &separator)
MANTID_NEXUS_DLL void writeStrAttribute(const H5::H5Object &object, const std::string &name, const std::string &value)
MANTID_NEXUS_DLL H5::Group createGroupCanSAS(H5::Group &group, const std::string &name, const std::string &nxtype, const std::string &cstype)
MANTID_NEXUS_DLL void write(H5::Group &group, const std::string &name, const std::string &value)
void writeScalarDataSetWithStrAttributes(H5::Group &group, const std::string &name, const T &value, const std::map< std::string, std::string > &attributes)
Header for a base Nexus::Exception.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.