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 <Poco/File.h>
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 Poco::File oldFile(filename);
78 if (oldFile.exists())
79 oldFile.remove();
80
81 // Create a new file in HDF5 mode.
82 auto file = std::make_unique<Nexus::File>(filename, NXaccess::CREATE5);
83
84 // The base entry. Named so as to distinguish from other workspace types.
85 file->makeGroup("MDHistoWorkspace", "NXentry", true);
86 file->putAttr("SaveMDVersion", 2);
87
88 // Write out the coordinate system
89 if (getProperty("SaveSample"))
90 file->writeData("coordinate_system", static_cast<uint32_t>(ws->getSpecialCoordinateSystem()));
91
92 // Write out the Qconvention
93 // ki-kf for Inelastic convention; kf-ki for Crystallography convention
94 std::string m_QConvention = Kernel::ConfigService::Instance().getString("Q.convention");
95 file->putAttr("QConvention", m_QConvention);
96
97 // Write out the visual normalization
98 if (getProperty("SaveSample"))
99 file->writeData("visual_normalization", static_cast<uint32_t>(ws->displayNormalization()));
100
101 // Save the algorithm history under "process"
102 if (getProperty("SaveHistory"))
103 ws->getHistory().saveNexus(file.get());
104
105 // Save all the ExperimentInfos
106 if (getProperty("SaveInstrument") || (getProperty("SaveSample")) || getProperty("SaveLogs")) {
107 for (uint16_t i = 0; i < ws->getNumExperimentInfo(); i++) {
108 ExperimentInfo_sptr ei = ws->getExperimentInfo(i);
109 std::string groupName = "experiment" + Strings::toString(i);
110 if (ei) {
111 // Can't overwrite entries. Just add the new ones
112 file->makeGroup(groupName, "NXgroup", true);
113 file->putAttr("version", 1);
114 ei->saveExperimentInfoNexus(file.get(), getProperty("SaveInstrument"), getProperty("SaveSample"),
115 getProperty("SaveLogs"));
116 file->closeGroup();
117 }
118 }
119 }
120
121 // Write out the affine matrices
122 if (getProperty("SaveSample"))
123 MDBoxFlatTree::saveAffineTransformMatricies(file.get(), std::dynamic_pointer_cast<const IMDWorkspace>(ws));
124
125 file->makeGroup("data", "NXdata", true);
126
127 // Save each axis dimension as an array
128 size_t numDims = ws->getNumDims();
129 std::string axes_label;
130 for (size_t d = 0; d < numDims; d++) {
131 std::vector<double> axis;
132 IMDDimension_const_sptr dim = ws->getDimension(d);
133 // NeXus field names must be alphanumeric only
134 std::string axis_title("D" + std::to_string(d));
135 auto nbounds = dim->getNBoundaries();
136 for (size_t n = 0; n < nbounds; n++)
137 axis.emplace_back(dim->getX(n));
138 file->makeData(axis_title, NXnumtype::FLOAT64, static_cast<int>(dim->getNBoundaries()), true);
139 file->putData(&axis[0]);
140 file->putAttr("units", std::string(dim->getUnits()));
141 file->putAttr("long_name", std::string(dim->getName()));
142 file->putAttr("frame", dim->getMDFrame().name());
143 file->closeData();
144 if (d != 0)
145 axes_label.insert(0, ":");
146 axes_label.insert(0, axis_title);
147 }
148
149 // Number of data points
150 // Size in each dimension (in the "C" style order, so z,y,x
151 // That is, data[z][y][x] = etc.
152 Nexus::DimVector size(numDims);
153 for (size_t d = 0; d < numDims; d++) {
154 IMDDimension_const_sptr dim = ws->getDimension(d);
155 // Size in each dimension (reverse order for RANK)
156 size[numDims - 1 - d] = dim->getNBins();
157 }
158
159 Nexus::DimVector chunks = size;
160 chunks[0] = 1; // Drop the largest stride for chunking, I don't know
161 // if this is the best but appears to work
162
163 file->makeCompData("signal", NXnumtype::FLOAT64, size, NXcompression::LZW, chunks, true);
164 file->putData(ws->getSignalArray());
165 file->putAttr("signal", 1);
166 file->putAttr("axes", axes_label);
167 file->closeData();
168
169 file->makeCompData("errors_squared", NXnumtype::FLOAT64, size, NXcompression::LZW, chunks, true);
170 file->putData(ws->getErrorSquaredArray());
171 file->closeData();
172
173 file->makeCompData("num_events", NXnumtype::FLOAT64, size, NXcompression::LZW, chunks, true);
174 file->putData(ws->getNumEventsArray());
175 file->closeData();
176
177 file->makeCompData("mask", NXnumtype::INT8, size, NXcompression::LZW, chunks, true);
178 file->putData(ws->getMaskArray());
179 file->closeData();
180
181 file->closeGroup();
182
183 // TODO: Links to original workspace???
184
185 file->closeGroup();
186 file->close();
187}
188
189//----------------------------------------------------------------------------------------------
193 IMDWorkspace_sptr ws = getProperty("InputWorkspace");
194 IMDEventWorkspace_sptr eventWS = std::dynamic_pointer_cast<IMDEventWorkspace>(ws);
195 MDHistoWorkspace_sptr histoWS = std::dynamic_pointer_cast<MDHistoWorkspace>(ws);
196
197 if (eventWS) {
198 // If event workspace use SaveMD version 1.
199 auto saveMDv1 = createChildAlgorithm("SaveMD", -1, -1, true, 1);
200 saveMDv1->setProperty<IMDWorkspace_sptr>("InputWorkspace", ws);
201 saveMDv1->setProperty<std::string>("Filename", getProperty("Filename"));
202 saveMDv1->setProperty<bool>("UpdateFileBackEnd", getProperty("UpdateFileBackEnd"));
203 saveMDv1->setProperty<bool>("MakeFileBacked", getProperty("MakeFileBacked"));
204 saveMDv1->execute();
205 } else if (histoWS) {
206 this->doSaveHisto(histoWS);
207 } else
208 throw std::runtime_error("SaveMD can only save MDEventWorkspaces and "
209 "MDHistoWorkspaces.\nPlease use SaveNexus or "
210 "another algorithm appropriate for this workspace "
211 "type.");
212}
213
214} // 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:192
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