Mantid
Loading...
Searching...
No Matches
SaveMD2.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 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 +
11#include "MantidAPI/Progress.h"
22#include "MantidKernel/Matrix.h"
24#include <filesystem>
25
26using file_holder_type = std::unique_ptr<Mantid::Nexus::File>;
27
28using namespace Mantid::Kernel;
29using namespace Mantid::API;
30using namespace Mantid::DataObjects;
31using namespace Mantid::Geometry;
32
33namespace Mantid::MDAlgorithms {
34
35// Register the algorithm into the AlgorithmFactory
36DECLARE_ALGORITHM(SaveMD2)
37
38//----------------------------------------------------------------------------------------------
41void SaveMD2::init() {
42 declareProperty(std::make_unique<WorkspaceProperty<IMDWorkspace>>("InputWorkspace", "", Direction::Input),
43 "An input MDEventWorkspace or MDHistoWorkspace.");
44
45 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::OptionalSave, ".nxs"),
46 "The name of the Nexus file to write, as a full or relative path.\n"
47 "Optional if UpdateFileBackEnd is checked.");
48 // Filename is NOT used if UpdateFileBackEnd
49 setPropertySettings("Filename", std::make_unique<EnabledWhenProperty>("UpdateFileBackEnd", IS_EQUAL_TO, "0"));
50
51 declareProperty("UpdateFileBackEnd", false,
52 "Only for MDEventWorkspaces with a file back end: check this to update "
53 "the NXS file on disk\n"
54 "to reflect the current data structure. Filename parameter is ignored.");
55 setPropertySettings("UpdateFileBackEnd", std::make_unique<EnabledWhenProperty>("MakeFileBacked", IS_EQUAL_TO, "0"));
56
57 declareProperty("MakeFileBacked", false,
58 "For an MDEventWorkspace that was created in memory:\n"
59 "This saves it to a file AND makes the workspace into a "
60 "file-backed one.");
61 setPropertySettings("MakeFileBacked", std::make_unique<EnabledWhenProperty>("UpdateFileBackEnd", IS_EQUAL_TO, "0"));
62 declareProperty("SaveHistory", true, "Option to not save the Mantid history in the file. Only for MDHisto");
63 declareProperty("SaveInstrument", true, "Option to not save the instrument in the file. Only for MDHisto");
64 declareProperty("SaveSample", true, "Option to not save the sample in the file. Only for MDHisto");
65 declareProperty("SaveLogs", true, "Option to not save the logs in the file. Only for MDHisto");
66}
67
68//----------------------------------------------------------------------------------------------
74 std::string filename = getPropertyValue("Filename");
75
76 // Erase the file if it exists
77 if (std::filesystem::exists(filename))
78 std::filesystem::remove(filename);
79
80 // Create a new file in HDF5 mode.
81 auto file = std::make_unique<Nexus::File>(filename, NXaccess::CREATE5);
82
83 // The base entry. Named so as to distinguish from other workspace types.
84 file->makeGroup("MDHistoWorkspace", "NXentry", true);
85 file->putAttr("SaveMDVersion", 2);
86
87 // Write out the coordinate system
88 if (getProperty("SaveSample"))
89 file->writeData("coordinate_system", static_cast<uint32_t>(ws->getSpecialCoordinateSystem()));
90
91 // Write out the Qconvention
92 // ki-kf for Inelastic convention; kf-ki for Crystallography convention
93 std::string m_QConvention = Kernel::ConfigService::Instance().getString("Q.convention");
94 file->putAttr("QConvention", m_QConvention);
95
96 // Write out the visual normalization
97 if (getProperty("SaveSample"))
98 file->writeData("visual_normalization", static_cast<uint32_t>(ws->displayNormalization()));
99
100 // Save the algorithm history under "process"
101 if (getProperty("SaveHistory"))
102 ws->getHistory().saveNexus(file.get());
103
104 // Save all the ExperimentInfos
105 if (getProperty("SaveInstrument") || (getProperty("SaveSample")) || getProperty("SaveLogs")) {
106 for (uint16_t i = 0; i < ws->getNumExperimentInfo(); i++) {
107 ExperimentInfo_sptr ei = ws->getExperimentInfo(i);
108 std::string groupName = "experiment" + Strings::toString(i);
109 if (ei) {
110 // Can't overwrite entries. Just add the new ones
111 file->makeGroup(groupName, "NXgroup", true);
112 file->putAttr("version", 1);
113 ei->saveExperimentInfoNexus(file.get(), getProperty("SaveInstrument"), getProperty("SaveSample"),
114 getProperty("SaveLogs"));
115 file->closeGroup();
116 }
117 }
118 }
119
120 // Write out the affine matrices
121 if (getProperty("SaveSample"))
122 MDBoxFlatTree::saveAffineTransformMatricies(file.get(), std::dynamic_pointer_cast<const IMDWorkspace>(ws));
123
124 file->makeGroup("data", "NXdata", true);
125
126 // Save each axis dimension as an array
127 size_t numDims = ws->getNumDims();
128 std::string axes_label;
129 for (size_t d = 0; d < numDims; d++) {
130 std::vector<double> axis;
131 IMDDimension_const_sptr dim = ws->getDimension(d);
132 // NeXus field names must be alphanumeric only
133 std::string axis_title("D" + std::to_string(d));
134 auto nbounds = dim->getNBoundaries();
135 for (size_t n = 0; n < nbounds; n++)
136 axis.emplace_back(dim->getX(n));
137 file->makeData(axis_title, NXnumtype::FLOAT64, static_cast<int>(dim->getNBoundaries()), true);
138 file->putData(&axis[0]);
139 file->putAttr("units", std::string(dim->getUnits()));
140 file->putAttr("long_name", std::string(dim->getName()));
141 file->putAttr("frame", dim->getMDFrame().name());
142 file->closeData();
143 if (d != 0)
144 axes_label.insert(0, ":");
145 axes_label.insert(0, axis_title);
146 }
147
148 // Number of data points
149 // Size in each dimension (in the "C" style order, so z,y,x
150 // That is, data[z][y][x] = etc.
151 Nexus::DimVector size(numDims);
152 for (size_t d = 0; d < numDims; d++) {
153 IMDDimension_const_sptr dim = ws->getDimension(d);
154 // Size in each dimension (reverse order for RANK)
155 size[numDims - 1 - d] = dim->getNBins();
156 }
157
158 Nexus::DimVector chunks = size;
159 chunks[0] = 1; // Drop the largest stride for chunking, I don't know
160 // if this is the best but appears to work
161
162 file->makeCompData("signal", NXnumtype::FLOAT64, size, NXcompression::LZW, chunks, true);
163 file->putData(ws->getSignalArray());
164 file->putAttr("signal", 1);
165 file->putAttr("axes", axes_label);
166 file->closeData();
167
168 file->makeCompData("errors_squared", NXnumtype::FLOAT64, size, NXcompression::LZW, chunks, true);
169 file->putData(ws->getErrorSquaredArray());
170 file->closeData();
171
172 file->makeCompData("num_events", NXnumtype::FLOAT64, size, NXcompression::LZW, chunks, true);
173 file->putData(ws->getNumEventsArray());
174 file->closeData();
175
176 file->makeCompData("mask", NXnumtype::INT8, size, NXcompression::LZW, chunks, true);
177 file->putData(ws->getMaskArray());
178 file->closeData();
179
180 file->closeGroup();
181
182 // TODO: Links to original workspace???
183
184 file->closeGroup();
185 file->close();
186}
187
188//----------------------------------------------------------------------------------------------
192 IMDWorkspace_sptr ws = getProperty("InputWorkspace");
193 IMDEventWorkspace_sptr eventWS = std::dynamic_pointer_cast<IMDEventWorkspace>(ws);
194 MDHistoWorkspace_sptr histoWS = std::dynamic_pointer_cast<MDHistoWorkspace>(ws);
195
196 if (eventWS) {
197 // If event workspace use SaveMD version 1.
198 auto saveMDv1 = createChildAlgorithm("SaveMD", -1, -1, true, 1);
199 saveMDv1->setProperty<IMDWorkspace_sptr>("InputWorkspace", ws);
200 saveMDv1->setProperty<std::string>("Filename", getProperty("Filename"));
201 saveMDv1->setProperty<bool>("UpdateFileBackEnd", getProperty("UpdateFileBackEnd"));
202 saveMDv1->setProperty<bool>("MakeFileBacked", getProperty("MakeFileBacked"));
203 saveMDv1->execute();
204 } else if (histoWS) {
205 this->doSaveHisto(histoWS);
206 } else
207 throw std::runtime_error("SaveMD can only save MDEventWorkspaces and "
208 "MDHistoWorkspaces.\nPlease use SaveNexus or "
209 "another algorithm appropriate for this workspace "
210 "type.");
211}
212
213} // namespace Mantid::MDAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
std::unique_ptr< Mantid::Nexus::File > file_holder_type
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.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
@ OptionalSave
to specify a file to write to but an empty string is
A property class for workspaces.
static void saveAffineTransformMatricies(Mantid::Nexus::File *const file, const API::IMDWorkspace_const_sptr &ws)
Save the affine matrices to both directional conversions to the data.
Save a MDEventWorkspace to a .nxs file.
Definition SaveMD2.h:19
void exec() override
Run the algorithm.
Definition SaveMD2.cpp:191
void doSaveHisto(const Mantid::DataObjects::MDHistoWorkspace_sptr &ws)
Save the MDHistoWorkspace.
Definition SaveMD2.cpp:73
static unsigned short constexpr INT8
static unsigned short constexpr FLOAT64
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
std::shared_ptr< IMDWorkspace > IMDWorkspace_sptr
Shared pointer to the IMDWorkspace base class.
std::shared_ptr< MDHistoWorkspace > MDHistoWorkspace_sptr
A shared pointer to a MDHistoWorkspace.
std::shared_ptr< const IMDDimension > IMDDimension_const_sptr
Shared Pointer to const IMDDimension.
std::string toString(const T &value)
Convert a number to a string.
Definition Strings.cpp:734
std::vector< dimsize_t > DimVector
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
Definition Property.h:53