35 if (ws->axes() == 0) {
38 const auto unit = ws->getAxis(0)->unit();
39 return (unit && unit->unitID() == unitToCompareWith);
43 if (numberOfDims == 0) {
44 throw std::invalid_argument(
"Workspace can only have 1 or 2 dimensions");
46 std::vector<int> indices(numberOfDims);
47 std::generate(indices.begin(), indices.end(), [i = 0]()
mutable { return i++; });
48 const auto itIndex = std::find_if(indices.cbegin(), indices.cend(), [&
workspace](
const auto &
index) {
49 return !workspace->getAxis(index)->isNumeric();
51 if (itIndex != indices.cend()) {
52 throw std::invalid_argument(
"Invalid workspace: Axis " +
std::to_string(*itIndex) +
" is not numeric");
57 const auto &ws_input = std::dynamic_pointer_cast<MatrixWorkspace>(ws);
58 return (ws_input && hasUnit(
"MomentumTransfer", ws_input) && ws_input->isCommonBins());
63 return "Workspace has to be a valid workspace";
67 const auto &groupItems = std::dynamic_pointer_cast<WorkspaceGroup>(ws)->getAllItems();
68 if (std::any_of(groupItems.cbegin(), groupItems.cend(),
69 [](
const auto &childWs) { return !checkValidMatrixWorkspace(childWs); })) {
70 return "Workspace must have common bins and Momentum transfer units";
75 if (!checkValidMatrixWorkspace(ws)) {
76 return "Workspace must have common bins and Momentum transfer units";
87 auto groupValidator = std::make_shared<Kernel::LambdaValidator<Workspace_sptr>>(validateGroupWithProperties);
90 "The input workspace, which must be in units of Q. Can be a 1D or a 2D workspace.");
92 "The name of the .h5 file to save");
94 std::vector<std::string> radiationSourceOptions{
"Spallation Neutron Source",
95 "Pulsed Reactor Neutron Source",
96 "Reactor Neutron Source",
97 "Synchrotron X-ray Source",
99 "Rotating Anode X-ray",
106 std::make_shared<Kernel::StringListValidator>(radiationSourceOptions),
"The type of radiation used.");
108 "Specify in a comma separated list, which detectors to store "
109 "information about; \nwhere each name must match a name "
110 "given for a detector in the [[IDF|instrument definition "
111 "file (IDF)]]. \nIDFs are located in the instrument "
112 "sub-directory of the Mantid install directory.");
115 std::make_shared<API::WorkspaceUnitValidator>(
"Wavelength")),
116 "The transmission workspace. Optional. If given, will be saved at "
117 "TransmissionSpectrum");
121 std::make_shared<API::WorkspaceUnitValidator>(
"Wavelength")),
122 "The transmission workspace of the Can. Optional. If given, will be "
123 "saved at TransmissionSpectrum");
126 "The run number for the sample transmission workspace. Optional.");
128 "The run number for the sample direct workspace. Optional.");
130 "The run number for the can scatter workspace. Optional.");
132 "The run number for the can direct workspace. Optional.");
136 "The name of the workspace used in the scaled background subtraction, to be included in the metadata. Optional.");
139 "The scale factor used in the scaled background subtraction, to be included in the metadata. Optional.");
141 std::vector<std::string>
const geometryOptions{
"Cylinder",
"FlatPlate",
"Flat plate",
"Disc",
"Unknown"};
143 std::make_shared<Kernel::StringListValidator>(geometryOptions),
144 "The geometry type of the collimation.");
146 "The height of the collimation element in mm. If specified as 0 it will not be recorded.");
148 "The width of the collimation element in mm. If specified as 0 it will not be recorded.");
150 "The thickness of the sample in mm. If specified as 0 it will not be recorded.");
154 const auto spinStateValidator = std::make_shared<Kernel::SpinStateValidator>(
159 "The order of the spin states in the input group workspace: +1 Polarization parallel to polarizer, "
160 "-1 antiparallel and 0 no polarization");
162 "The name of the Polarizer Component as defined in the IDF. i.e. 'short-polarizer'");
164 "The name of the Analyzer Component as defined in the IDF. i.e. 'helium-analyzer'");
166 "Comma separated list of flipper components as defined in the IDF i.e. 'RF-flipper");
168 "The name of sample logs in which the magnetic field strength is stored");
170 "Direction of the magnetic field on the sample: comma separated vector"
171 "with three values: Polar, Azimuthal and Rotation angles");
175 std::map<std::string, std::string> result;
181 return ws && std::dynamic_pointer_cast<const Mantid::DataObjects::Workspace2D>(ws);
184 const auto &groupItems = std::dynamic_pointer_cast<WorkspaceGroup>(
workspace)->getAllItems();
185 if (std::any_of(groupItems.cbegin(), groupItems.cend(),
186 [&](
const auto &childWs) { return !valid2DWorkspace(childWs); })) {
187 result.emplace(
"InputWorkspace",
188 "All input workspaces in the input group must be a Workspace2D with numeric axis.");
192 result.emplace(
"InputWorkspace",
"The InputWorkspace must be a Workspace2D with numeric axis.");
200 auto checkTransmission = [&result](
const MatrixWorkspace_sptr &trans,
const std::string &propertyName) {
201 if (trans->getNumberHistograms() != 1) {
202 result.emplace(propertyName,
"The input workspaces for transmissions have to be 1D.");
209 if (transmissionCan) {
216std::map<std::string, std::string>
218 std::map<std::string, std::string> result;
223 "Input Workspaces for polarized data can only be workspace groups.");
226 const auto wsGroup = std::dynamic_pointer_cast<WorkspaceGroup>(
workspace);
227 const auto &entries = wsGroup->getNumberOfEntries();
228 if (entries != 2 && entries != 4) {
230 "Input Group Workspace can only contain 2 or 4 workspace members.");
233 if (entries !=
static_cast<int>(spinVec.size())) {
235 " member workspaces on the InputWorkspace group");
238 const auto wsVec = wsGroup->getAllItems();
241 if (std::any_of(wsVec.cbegin(), wsVec.cend(), [&dim0](
const Workspace_sptr &ws) {
242 return dim0 != getWorkspaceDimensionality(std::dynamic_pointer_cast<MatrixWorkspace>(ws));
249std::map<std::string, std::string>
251 std::map<std::string, std::string> result;
254 if (spinVec.size() == 4 && std::any_of(spinVec.cbegin(), spinVec.cend(), [](
const std::string &spinPair) {
255 return (spinPair.find(SpinStateNXcanSAS::SPIN_ZERO) != std::string::npos);
260 if (spinVec.size() == 2) {
261 if (std::any_of(spinVec.cbegin(), spinVec.cend(),
262 [](
const std::string &state) { return state.find(
'1') == std::string::npos; })) {
269 if (noPin == noPout) {
271 "The 0 polarized state can only be either Pin or Pout for 2 spin configurations");
278 std::map<std::string, std::string> result;
280 if (!magneticFieldDirection.empty()) {
283 std::for_each(direction.cbegin(), direction.cend(), [](
const std::string &val) { (void)std::stod(val); });
284 }
catch (
const std::invalid_argument &) {
287 if (direction.size() != 3) {
289 "Magnetic Field Direction should contain 3 comma separated values to represent a 3D vector");
339 if (transmissionCan) {
343 if (transmissionSample) {
348 if (!scaledBgSubWorkspace.empty()) {
356 if (transmissionSample) {
361 if (transmissionCan) {
378 for (
size_t i = 0; i < compVec.size(); i++) {
379 const auto suffix = compVec.size() > 1 ?
addDigit(i + 1) :
"";
394 std::map<std::string, std::vector<std::string>> componentMap;
396 std::string
const &componentName =
getProperty(compName);
397 if (!componentName.empty()) {
399 componentMap.emplace(std::make_pair(compType, componentVec));
413 const std::string &suffix)
const {
424 const auto workspaceTitle =
workspace->getTitle();
428 auto runNumber =
workspace->getRunNumber();
443 areAxesNumeric(
workspace,
static_cast<int>(dim));
445 case (WorkspaceDimensionality::oneD):
448 case (WorkspaceDimensionality::twoD):
452 throw std::runtime_error(
"SaveNXcanSAS: The provided workspace "
453 "dimensionality is not 1D or 2D.");
475 auto workspace = std::dynamic_pointer_cast<MatrixWorkspace>(wsGroup->getItem(0));
482 m_progress->report(
"Adding standard metadata");
485 m_progress->report(
"Adding polarized metadata");
501 const std::filesystem::path &path)
const {
508 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 MANTID_KERNEL_DLL 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.