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 case V1:
85 loadNexusV1(h5file);
86
87 break;
88 case V2:
89 loadNexusV2(h5file);
90 break;
91 }
92
93 // set the instrument
94 double sampleToDetectorDistance = getProperty("DetectorDistance");
95 H5::DataSet thetaDataset = h5file.openDataSet("entry0/instrument/2theta/value");
96 float theta;
97 thetaDataset.read(&theta, thetaDataset.getDataType());
98 double twoThetaAngle = theta + static_cast<double>(getProperty("ThetaOffset"));
99 setInstrument(sampleToDetectorDistance, twoThetaAngle);
100 thetaDataset.close();
101
102 h5file.close();
103
104 fillWorkspaceMetadata(filename);
105}
106
112void LoadILLSALSA::setInstrument(double distance, double angle) {
113 // load instrument
115
116 // rotation due to the IDF (channels are created along Y)
117 auto rotateInst = createChildAlgorithm("RotateInstrumentComponent");
118 rotateInst->setProperty<API::MatrixWorkspace_sptr>("Workspace", m_outputWorkspace);
119 rotateInst->setPropertyValue("ComponentName", "detector");
120 rotateInst->setPropertyValue("Z", "1");
121 rotateInst->setProperty<double>("Angle", 90);
122 rotateInst->execute();
123
124 // translation
125 double angleRad = angle * M_PI / 180.0;
126 double dx = -distance * sin(angleRad);
127 double dz = distance * cos(angleRad);
128 auto moveInst = createChildAlgorithm("MoveInstrumentComponent");
129 moveInst->setProperty<API::MatrixWorkspace_sptr>("Workspace", m_outputWorkspace);
130 moveInst->setPropertyValue("ComponentName", "detector");
131 moveInst->setProperty<double>("X", dx);
132 moveInst->setProperty<double>("Y", 0.);
133 moveInst->setProperty<double>("Z", dz);
134 moveInst->setProperty<bool>("RelativePosition", false);
135 moveInst->execute();
136
137 // rotation
138 rotateInst = createChildAlgorithm("RotateInstrumentComponent");
139 rotateInst->setProperty<API::MatrixWorkspace_sptr>("Workspace", m_outputWorkspace);
140 rotateInst->setPropertyValue("ComponentName", "detector");
141 rotateInst->setPropertyValue("X", "1"); // Y->X with the first rotation
142 rotateInst->setProperty<double>("Angle", -angle);
143 rotateInst->execute();
144}
145
150void LoadILLSALSA::loadNexusV1(const H5::H5File &h5file) {
151 H5::DataSet detectorDataset = h5file.openDataSet("entry0/data/Multi_data");
152 H5::DataSet monitorDataset = h5file.openDataSet("entry0/monitor/data");
153
154 m_outputWorkspace = DataObjects::create<DataObjects::Workspace2D>(
155 VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + 1, HistogramData::Points(1));
156 setProperty("OutputWorkspace", m_outputWorkspace);
157
158 std::vector<int> dataInt(VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + 1);
159 detectorDataset.read(dataInt.data(), detectorDataset.getDataType());
160 monitorDataset.read(dataInt.data() + VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS, monitorDataset.getDataType());
161
162 for (size_t i = 0; i < dataInt.size(); i++) {
163 double count = dataInt[i];
164 double error = sqrt(count);
165 m_outputWorkspace->mutableY(i)[0] = count;
166 m_outputWorkspace->mutableE(i)[0] = error;
167 }
168
169 detectorDataset.close();
170 monitorDataset.close();
171}
172
178void LoadILLSALSA::loadNexusV2(const H5::H5File &h5file) {
179 H5::DataSet detectorDataset = h5file.openDataSet("entry0/data_scan/detector_data/data");
180 H5::DataSpace detectorDataspace = detectorDataset.getSpace();
181
182 int nDims = detectorDataspace.getSimpleExtentNdims();
183 std::vector<hsize_t> dimsSize(nDims);
184 detectorDataspace.getSimpleExtentDims(dimsSize.data(), NULL);
185
186 size_t numberOfScans = dimsSize[0];
187
188 if ((dimsSize[1] != VERTICAL_NUMBER_PIXELS) || (dimsSize[2] != HORIZONTAL_NUMBER_PIXELS)) {
189 std::ostringstream oss;
190 oss << "Unexpected data shape, got " << dimsSize[1] << "x" << dimsSize[2] << "pixels ";
191 oss << "instead of " << VERTICAL_NUMBER_PIXELS << "x" << HORIZONTAL_NUMBER_PIXELS;
192 throw std::runtime_error(oss.str());
193 }
194
195 m_outputWorkspace = DataObjects::create<DataObjects::Workspace2D>(
196 VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + 1, HistogramData::Points(numberOfScans));
197 setProperty("OutputWorkspace", m_outputWorkspace);
198
199 std::vector<int> dataInt(numberOfScans * VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS);
200 detectorDataset.read(dataInt.data(), detectorDataset.getDataType());
201
202 detectorDataset.close();
203
204 // get scanned variable names
205 H5::DataSet scanVarNames = h5file.openDataSet("entry0/data_scan/scanned_variables/variables_names/name");
206 H5::DataSpace scanVarNamesSpace = scanVarNames.getSpace();
207
208 nDims = scanVarNamesSpace.getSimpleExtentNdims();
209 dimsSize.resize(nDims);
210 scanVarNamesSpace.getSimpleExtentDims(dimsSize.data(), nullptr);
211
212 std::vector<char *> rdata(dimsSize[0]);
213 scanVarNames.read(rdata.data(), scanVarNames.getDataType());
214 size_t monitorIndex = 0;
215 while (monitorIndex < rdata.size()) {
216 if (std::string(rdata[monitorIndex]) == "Monitor1")
217 break;
218 monitorIndex++;
219 }
220 if (monitorIndex == rdata.size())
221 throw std::runtime_error("Monitor count not found. Please check your nexus file.");
222 scanVarNames.vlenReclaim(rdata.data(), scanVarNames.getDataType(), scanVarNamesSpace);
223
224 scanVarNames.close();
225
226 // get scanned variable values and extract monitor count
227 H5::DataSet scanVar = h5file.openDataSet("entry0/data_scan/scanned_variables/data");
228 H5::DataSpace scanVarSpace = scanVar.getSpace();
229
230 nDims = scanVarSpace.getSimpleExtentNdims();
231 std::vector<double> monitorData;
232 dimsSize.resize(nDims);
233 if (dimsSize.size() < 2) {
234 throw std::runtime_error("Scanned variables are not formatted properly. Check you nexus file.");
235 } else {
236 scanVarSpace.getSimpleExtentDims(dimsSize.data(), nullptr);
237
238 if (dimsSize[1] != numberOfScans)
239 throw std::runtime_error("Scanned variables are not formatted properly. Check you nexus file.");
240
241 std::vector<double> scanVarData(dimsSize[0] * dimsSize[1]);
242 scanVar.read(scanVarData.data(), scanVar.getDataType());
243 monitorData.resize(dimsSize[1]);
244 for (size_t i = 0; i < monitorData.size(); i++)
245 monitorData[i] = scanVarData[monitorIndex * dimsSize[1] + i];
246 }
247 scanVar.close();
248
249 // fill the workspace
250 for (size_t j = 0; j < numberOfScans; j++) {
251 for (size_t i = 0; i < VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS; i++) {
252 double count = dataInt[j * VERTICAL_NUMBER_PIXELS * HORIZONTAL_NUMBER_PIXELS + i];
253 double error = sqrt(count);
254 m_outputWorkspace->mutableY(i)[j] = count;
255 m_outputWorkspace->mutableE(i)[j] = error;
256 }
258 }
259}
260
261void LoadILLSALSA::fillWorkspaceMetadata(const std::string &filename) {
262 API::Run &runDetails = m_outputWorkspace->mutableRun();
263
264 Nexus::File nxHandle(filename, NXaccess::READ);
265 LoadHelper::addNexusFieldsToWsRun(nxHandle, runDetails);
266}
267} // 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.
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.
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Returns a confidence value that this algorithm can load a file.
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(std::string const &entryName, std::string const &groupClass) const
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