Mantid
Loading...
Searching...
No Matches
LoadILLSALSA.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2021 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 +
8
15#include "MantidHistogramData/Points.h"
17#include "MantidNexus/H5Util.h"
18#include "MantidNexus/NexusFile.h"
19
20#include <iterator>
21#include <sstream>
22
23namespace Mantid::DataHandling {
24
26
29
38 if ((descriptor.isEntry("/entry0/data_scan") || descriptor.isEntry("/entry0/data")) &&
39 descriptor.isEntry("/entry0/instrument/Tx") && descriptor.isEntry("/entry0/instrument/Ty") &&
40 descriptor.isEntry("/entry0/instrument/Tz"))
41 return 80;
42 else
43 return 0;
44}
45
50 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load, ".nxs"),
51 "File path of the Data file to load");
52 declareProperty(std::make_unique<API::WorkspaceProperty<>>("OutputWorkspace", "", Kernel::Direction::Output),
53 "The name to use for the output workspace");
54 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<double>>();
55 mustBePositive->setLower(0.0);
56 declareProperty("DetectorDistance", 1.0, mustBePositive, "Distance between the sample and the detector (meters)");
57 declareProperty("ThetaOffset", 0.0, "Offset for the 2theta value (degrees)");
58}
59
64 const std::string filename = getPropertyValue("Filename");
65 H5::H5File h5file(filename, H5F_ACC_RDONLY, Nexus::H5Util::defaultFileAcc());
66
67 enum FileType { NONE, V1, V2 };
68
69 FileType fileType = NONE;
70 // guess type of file
71 if (!h5file.nameExists("entry0"))
72 throw std::runtime_error(
73 "The Nexus file your are trying to open is incorrectly formatted, 'entry0' group does not exist");
74 H5::Group entryGroup = h5file.openGroup("entry0");
75 if (entryGroup.nameExists("data"))
76 fileType = V1;
77 else if (entryGroup.nameExists("data_scan"))
78 fileType = V2;
79 entryGroup.close();
80
81 switch (fileType) {
82 case NONE:
83 throw std::runtime_error("The Nexus file your are trying to open is not supported by the SALSA loader.");
84 break;
85 case V1:
86 loadNexusV1(h5file);
87
88 break;
89 case V2:
90 loadNexusV2(h5file);
91 break;
92 }
93
94 // set the instrument
95 double sampleToDetectorDistance = getProperty("DetectorDistance");
96 H5::DataSet thetaDataset = h5file.openDataSet("entry0/instrument/2theta/value");
97 float theta;
98 thetaDataset.read(&theta, thetaDataset.getDataType());
99 double twoThetaAngle = theta + static_cast<double>(getProperty("ThetaOffset"));
100 setInstrument(sampleToDetectorDistance, twoThetaAngle);
101 thetaDataset.close();
102
103 h5file.close();
104
105 fillWorkspaceMetadata(filename);
106}
107
113void LoadILLSALSA::setInstrument(double distance, double angle) {
114 // load instrument
116
117 // rotation due to the IDF (channels are created along Y)
118 auto rotateInst = createChildAlgorithm("RotateInstrumentComponent");
119 rotateInst->setProperty<API::MatrixWorkspace_sptr>("Workspace", m_outputWorkspace);
120 rotateInst->setPropertyValue("ComponentName", "detector");
121 rotateInst->setPropertyValue("Z", "1");
122 rotateInst->setProperty<double>("Angle", 90);
123 rotateInst->execute();
124
125 // translation
126 double angleRad = angle * M_PI / 180.0;
127 double dx = -distance * sin(angleRad);
128 double dz = distance * cos(angleRad);
129 auto moveInst = createChildAlgorithm("MoveInstrumentComponent");
130 moveInst->setProperty<API::MatrixWorkspace_sptr>("Workspace", m_outputWorkspace);
131 moveInst->setPropertyValue("ComponentName", "detector");
132 moveInst->setProperty<double>("X", dx);
133 moveInst->setProperty<double>("Y", 0.);
134 moveInst->setProperty<double>("Z", dz);
135 moveInst->setProperty<bool>("RelativePosition", false);
136 moveInst->execute();
137
138 // rotation
139 rotateInst = createChildAlgorithm("RotateInstrumentComponent");
140 rotateInst->setProperty<API::MatrixWorkspace_sptr>("Workspace", m_outputWorkspace);
141 rotateInst->setPropertyValue("ComponentName", "detector");
142 rotateInst->setPropertyValue("X", "1"); // Y->X with the first rotation
143 rotateInst->setProperty<double>("Angle", -angle);
144 rotateInst->execute();
145}
146
151void LoadILLSALSA::loadNexusV1(const H5::H5File &h5file) {
152 H5::DataSet detectorDataset = h5file.openDataSet("entry0/data/Multi_data");
153 H5::DataSet monitorDataset = h5file.openDataSet("entry0/monitor/data");
154
155 m_outputWorkspace = DataObjects::create<DataObjects::Workspace2D>(
156 VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + 1, HistogramData::Points(1));
157 setProperty("OutputWorkspace", m_outputWorkspace);
158
159 std::vector<int> dataInt(VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + 1);
160 detectorDataset.read(dataInt.data(), detectorDataset.getDataType());
161 monitorDataset.read(dataInt.data() + VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS, monitorDataset.getDataType());
162
163 for (size_t i = 0; i < dataInt.size(); i++) {
164 double count = dataInt[i];
165 double error = sqrt(count);
166 m_outputWorkspace->mutableY(i)[0] = count;
167 m_outputWorkspace->mutableE(i)[0] = error;
168 }
169
170 detectorDataset.close();
171 monitorDataset.close();
172}
173
179void LoadILLSALSA::loadNexusV2(const H5::H5File &h5file) {
180 H5::DataSet detectorDataset = h5file.openDataSet("entry0/data_scan/detector_data/data");
181 H5::DataSpace detectorDataspace = detectorDataset.getSpace();
182
183 int nDims = detectorDataspace.getSimpleExtentNdims();
184 std::vector<hsize_t> dimsSize(nDims);
185 detectorDataspace.getSimpleExtentDims(dimsSize.data(), NULL);
186
187 size_t numberOfScans = dimsSize[0];
188
189 if ((dimsSize[1] != VERTICAL_NUMBER_PIXELS) || (dimsSize[2] != HORIZONTAL_NUMBER_PIXELS)) {
190 std::ostringstream oss;
191 oss << "Unexpected data shape, got " << dimsSize[1] << "x" << dimsSize[2] << "pixels ";
192 oss << "instead of " << VERTICAL_NUMBER_PIXELS << "x" << HORIZONTAL_NUMBER_PIXELS;
193 throw std::runtime_error(oss.str());
194 }
195
196 m_outputWorkspace = DataObjects::create<DataObjects::Workspace2D>(
197 VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + 1, HistogramData::Points(numberOfScans));
198 setProperty("OutputWorkspace", m_outputWorkspace);
199
200 std::vector<int> dataInt(numberOfScans * VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS);
201 detectorDataset.read(dataInt.data(), detectorDataset.getDataType());
202
203 detectorDataset.close();
204
205 // get scanned variable names
206 H5::DataSet scanVarNames = h5file.openDataSet("entry0/data_scan/scanned_variables/variables_names/name");
207 H5::DataSpace scanVarNamesSpace = scanVarNames.getSpace();
208
209 nDims = scanVarNamesSpace.getSimpleExtentNdims();
210 dimsSize.resize(nDims);
211 scanVarNamesSpace.getSimpleExtentDims(dimsSize.data(), nullptr);
212
213 std::vector<char *> rdata(dimsSize[0]);
214 scanVarNames.read(rdata.data(), scanVarNames.getDataType());
215 size_t monitorIndex = 0;
216 while (monitorIndex < rdata.size()) {
217 if (std::string(rdata[monitorIndex]) == "Monitor1")
218 break;
219 monitorIndex++;
220 }
221 if (monitorIndex == rdata.size())
222 throw std::runtime_error("Monitor count not found. Please check your nexus file.");
223 scanVarNames.vlenReclaim(rdata.data(), scanVarNames.getDataType(), scanVarNamesSpace);
224
225 scanVarNames.close();
226
227 // get scanned variable values and extract monitor count
228 H5::DataSet scanVar = h5file.openDataSet("entry0/data_scan/scanned_variables/data");
229 H5::DataSpace scanVarSpace = scanVar.getSpace();
230
231 nDims = scanVarSpace.getSimpleExtentNdims();
232 std::vector<double> monitorData;
233 dimsSize.resize(nDims);
234 if (dimsSize.size() < 2) {
235 throw std::runtime_error("Scanned variables are not formatted properly. Check you nexus file.");
236 } else {
237 scanVarSpace.getSimpleExtentDims(dimsSize.data(), nullptr);
238
239 if (dimsSize[1] != numberOfScans)
240 throw std::runtime_error("Scanned variables are not formatted properly. Check you nexus file.");
241
242 std::vector<double> scanVarData(dimsSize[0] * dimsSize[1]);
243 scanVar.read(scanVarData.data(), scanVar.getDataType());
244 monitorData.resize(dimsSize[1]);
245 for (size_t i = 0; i < monitorData.size(); i++)
246 monitorData[i] = scanVarData[monitorIndex * dimsSize[1] + i];
247 }
248 scanVar.close();
249
250 // fill the workspace
251 for (size_t j = 0; j < numberOfScans; j++) {
252 for (size_t i = 0; i < VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS; i++) {
253 double count = dataInt[j * VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + i];
254 double error = sqrt(count);
255 m_outputWorkspace->mutableY(i)[j] = count;
256 m_outputWorkspace->mutableE(i)[j] = error;
257 }
259 }
260}
261
262void LoadILLSALSA::fillWorkspaceMetadata(const std::string &filename) {
263 API::Run &runDetails = m_outputWorkspace->mutableRun();
264
265 Nexus::File nxHandle(filename, NXaccess::READ);
266 LoadHelper::addNexusFieldsToWsRun(nxHandle, runDetails);
267}
268} // namespace Mantid::DataHandling
double error
int count
counter
Definition Matrix.cpp:37
#define DECLARE_NEXUS_FILELOADER_ALGORITHM(classname)
DECLARE_NEXUS_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro wh...
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.
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.
@ Load
allowed here which will be passed to the algorithm
This class stores information regarding an experimental run as a series of log entries.
Definition Run.h:35
A property class for workspaces.
int confidence(Nexus::NexusDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
void exec() override
Executes the algorithm.
void init() override
Initialises the algorithm.
void loadNexusV2(const H5::H5File &h5file)
Load V2 Nexus file.
void fillWorkspaceMetadata(const std::string &filename)
std::shared_ptr< DataObjects::Workspace2D > m_outputWorkspace
static const size_t HORIZONTAL_NUMBER_PIXELS
void loadNexusV1(const H5::H5File &h5file)
Load V1 Nexus file.
void setInstrument(double distance, double angle)
Load the instrument and set its position.
static const size_t VERTICAL_NUMBER_PIXELS
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
bool isEntry(const std::string &entryName, const std::string &groupClass) const noexcept
Checks if a full-address entry exists for a particular groupClass in a Nexus dataset.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void addNexusFieldsToWsRun(Nexus::File &filehandle, API::Run &runDetails, const std::string &entryName="", bool useFullAddress=false)
Add properties from a nexus file to the workspace run.
void loadEmptyInstrument(const API::MatrixWorkspace_sptr &ws, const std::string &instrumentName, const std::string &instrumentAddress="")
Loads empty instrument of chosen name into a provided workspace.
FileType
Allowed file types.
MANTID_NEXUS_DLL H5::FileAccPropList defaultFileAcc()
Default file access is H5F_CLOSE_STRONG.
Definition H5Util.cpp:119
@ Output
An output workspace.
Definition Property.h:54