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 "MantidKernel/System.h"
25#include <Poco/File.h>
26
27using file_holder_type = std::unique_ptr<::NeXus::File>;
28
29using namespace Mantid::Kernel;
30using namespace Mantid::API;
31using namespace Mantid::DataObjects;
32using namespace Mantid::Geometry;
33
34namespace Mantid::MDAlgorithms {
35
36// Register the algorithm into the AlgorithmFactory
37DECLARE_ALGORITHM(SaveMD2)
38
39//----------------------------------------------------------------------------------------------
42void SaveMD2::init() {
43 declareProperty(std::make_unique<WorkspaceProperty<IMDWorkspace>>("InputWorkspace", "", Direction::Input),
44 "An input MDEventWorkspace or MDHistoWorkspace.");
45
46 declareProperty(std::make_unique<FileProperty>("Filename", "", FileProperty::OptionalSave, ".nxs"),
47 "The name of the Nexus file to write, as a full or relative path.\n"
48 "Optional if UpdateFileBackEnd is checked.");
49 // Filename is NOT used if UpdateFileBackEnd
50 setPropertySettings("Filename", std::make_unique<EnabledWhenProperty>("UpdateFileBackEnd", IS_EQUAL_TO, "0"));
51
52 declareProperty("UpdateFileBackEnd", false,
53 "Only for MDEventWorkspaces with a file back end: check this to update "
54 "the NXS file on disk\n"
55 "to reflect the current data structure. Filename parameter is ignored.");
56 setPropertySettings("UpdateFileBackEnd", std::make_unique<EnabledWhenProperty>("MakeFileBacked", IS_EQUAL_TO, "0"));
57
58 declareProperty("MakeFileBacked", false,
59 "For an MDEventWorkspace that was created in memory:\n"
60 "This saves it to a file AND makes the workspace into a "
61 "file-backed one.");
62 setPropertySettings("MakeFileBacked", std::make_unique<EnabledWhenProperty>("UpdateFileBackEnd", IS_EQUAL_TO, "0"));
63 declareProperty("SaveHistory", true, "Option to not save the Mantid history in the file. Only for MDHisto");
64 declareProperty("SaveInstrument", true, "Option to not save the instrument in the file. Only for MDHisto");
65 declareProperty("SaveSample", true, "Option to not save the sample in the file. Only for MDHisto");
66 declareProperty("SaveLogs", true, "Option to not save the logs in the file. Only for MDHisto");
67}
68
69//----------------------------------------------------------------------------------------------
75 std::string filename = getPropertyValue("Filename");
76
77 // Erase the file if it exists
78 Poco::File oldFile(filename);
79 if (oldFile.exists())
80 oldFile.remove();
81
82 // Create a new file in HDF5 mode.
83 auto file = std::make_unique<::NeXus::File>(filename, NXACC_CREATE5);
84
85 // The base entry. Named so as to distinguish from other workspace types.
86 file->makeGroup("MDHistoWorkspace", "NXentry", true);
87 file->putAttr("SaveMDVersion", 2);
88
89 // Write out the coordinate system
90 if (getProperty("SaveSample"))
91 file->writeData("coordinate_system", static_cast<uint32_t>(ws->getSpecialCoordinateSystem()));
92
93 // Write out the Qconvention
94 // ki-kf for Inelastic convention; kf-ki for Crystallography convention
95 std::string m_QConvention = Kernel::ConfigService::Instance().getString("Q.convention");
96 file->putAttr("QConvention", m_QConvention);
97
98 // Write out the visual normalization
99 if (getProperty("SaveSample"))
100 file->writeData("visual_normalization", static_cast<uint32_t>(ws->displayNormalization()));
101
102 // Save the algorithm history under "process"
103 if (getProperty("SaveHistory"))
104 ws->getHistory().saveNexus(file.get());
105
106 // Save all the ExperimentInfos
107 if (getProperty("SaveInstrument") || (getProperty("SaveSample")) || getProperty("SaveLogs")) {
108 for (uint16_t i = 0; i < ws->getNumExperimentInfo(); i++) {
109 ExperimentInfo_sptr ei = ws->getExperimentInfo(i);
110 std::string groupName = "experiment" + Strings::toString(i);
111 if (ei) {
112 // Can't overwrite entries. Just add the new ones
113 file->makeGroup(groupName, "NXgroup", true);
114 file->putAttr("version", 1);
115 ei->saveExperimentInfoNexus(file.get(), getProperty("SaveInstrument"), getProperty("SaveSample"),
116 getProperty("SaveLogs"));
117 file->closeGroup();
118 }
119 }
120 }
121
122 // Write out the affine matrices
123 if (getProperty("SaveSample"))
124 MDBoxFlatTree::saveAffineTransformMatricies(file.get(), std::dynamic_pointer_cast<const IMDWorkspace>(ws));
125
126 file->makeGroup("data", "NXdata", true);
127
128 // Save each axis dimension as an array
129 size_t numDims = ws->getNumDims();
130 std::string axes_label;
131 for (size_t d = 0; d < numDims; d++) {
132 std::vector<double> axis;
133 IMDDimension_const_sptr dim = ws->getDimension(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(dim->getDimensionId(), ::NeXus::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, dim->getDimensionId());
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 std::vector<int> 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] = int(dim->getNBins());
156 }
157
158 std::vector<int> 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", ::NeXus::FLOAT64, size, ::NeXus::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", ::NeXus::FLOAT64, size, ::NeXus::LZW, chunks, true);
169 file->putData(ws->getErrorSquaredArray());
170 file->closeData();
171
172 file->makeCompData("num_events", ::NeXus::FLOAT64, size, ::NeXus::LZW, chunks, true);
173 file->putData(ws->getNumEventsArray());
174 file->closeData();
175
176 file->makeCompData("mask", ::NeXus::INT8, size, ::NeXus::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:576
std::unique_ptr<::NeXus::File > file_holder_type
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
@ OptionalSave
to specify a file to write to but an empty string is
Definition: FileProperty.h:50
A property class for workspaces.
static void saveAffineTransformMatricies(::NeXus::File *const file, const API::IMDWorkspace_const_sptr &ws)
Save the affine matrices to both directional conversions to the data.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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:74
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.
Definition: IMDWorkspace.h:146
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.
Definition: IMDDimension.h:101
std::string toString(const T &value)
Convert a number to a string.
Definition: Strings.cpp:703
@ Input
An input workspace.
Definition: Property.h:53