Mantid
Loading...
Searching...
No Matches
LoadDetectorInfo.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 +
8#include "LoadRaw/isisraw2.h"
14#include "MantidNexus/NexusFile.h"
15
16#include <boost/algorithm/string/compare.hpp>
17#include <boost/algorithm/string/predicate.hpp>
18
19#include <filesystem>
20#include <fstream>
21
22namespace Mantid::DataHandling {
23using namespace Kernel;
24using namespace API;
25using namespace Geometry;
26
27namespace {
28// Name of the offset parameter
29const char *DELAY_PARAM = "DelayTime";
30// Name of pressure parameter
31const char *PRESSURE_PARAM = "TubePressure";
32// Name of wall thickness parameter
33const char *THICKNESS_PARAM = "TubeThickness";
34} // namespace
35
36// Register the algorithm into the algorithm factory
37DECLARE_ALGORITHM(LoadDetectorInfo)
38
39
41 : Algorithm(), m_samplePos(), m_moveDets(false), m_workspace(), m_instDelta(-1.0), m_instPressure(-1.0),
42 m_instThickness(-1.0) {}
43
45
46 declareProperty(std::make_unique<WorkspaceProperty<>>("Workspace", "", Direction::InOut),
47 "The name of the workspace to that the detector information "
48 "will be loaded into.");
49
50 const std::vector<std::string> exts{".dat", ".raw", ".sca", ".nxs"};
51 declareProperty(std::make_unique<FileProperty>("DataFilename", "", FileProperty::Load, exts),
52 "A **raw, dat, nxs** or **sca** file that contains information about the "
53 "detectors in the "
54 "workspace. The description of **dat** and **nxs** file format is "
55 "provided below.");
56
57 declareProperty("RelocateDets", false,
58 "If true, the detectors are moved to "
59 "the positions specified in the file "
60 "defined by the field above.",
62}
63
66 std::string filename = getPropertyValue("DataFilename");
67 std::string ext = std::filesystem::path(filename).extension().string().substr(1); // remove the '.'
68 if (boost::iequals(ext, "dat") || boost::iequals(ext, "sca")) {
69 loadFromDAT(filename);
70 } else if (boost::iequals(ext, "raw")) {
71 loadFromRAW(filename);
72 } else if (boost::iequals(ext, "nxs")) {
73 loadFromIsisNXS(filename);
74 } else {
75 throw std::invalid_argument("Unknown file type with extension=." + ext);
76 }
77}
78
83 m_workspace = getProperty("Workspace");
84 m_moveDets = getProperty("RelocateDets");
85
86 const auto &componentInfo = m_workspace->componentInfo();
87 if (componentInfo.hasSample())
88 m_samplePos = componentInfo.samplePosition();
89
90 // cache values of instrument level parameters so we only change then if they
91 // are different
92 const size_t root = componentInfo.root();
93 // delay
94 auto values = componentInfo.getNumberParameter(root, DELAY_PARAM, false);
95 if (!values.empty())
96 m_instDelta = values.front();
97 // pressure
98 values = componentInfo.getNumberParameter(root, PRESSURE_PARAM, false);
99 if (!values.empty())
100 m_instPressure = values.front();
101 // thickness
102 values = componentInfo.getNumberParameter(root, THICKNESS_PARAM, false);
103 if (!values.empty())
104 m_instThickness = values.front();
105}
106
111void LoadDetectorInfo::loadFromDAT(const std::string &filename) {
112 std::ifstream datFile(filename.c_str());
113 if (!datFile) {
114 throw Exception::FileError("Unable to access dat file", filename);
115 }
116
117 std::string line;
118 // skip 3 lines of header info
119 for (int i = 0; i < 3; ++i)
120 getline(datFile, line);
121
122 // start loop over file
123 auto &componentInfo = m_workspace->mutableComponentInfo();
124 auto &wsDetInfo = m_workspace->mutableDetectorInfo();
125 while (getline(datFile, line)) {
126 if (line.empty() || line[0] == '#')
127 continue;
128
129 std::istringstream is(line);
130 detid_t detID(0);
131 int code(0);
132 float delta(0.0f), l2(0.0f), theta(0.0f), phi(0.0f);
133 is >> detID >> delta >> l2 >> code >> theta >> phi;
134 // offset value is be subtracted so store negative
135 delta *= -1.0f;
136
137 try {
138 size_t index = wsDetInfo.indexOf(detID);
139 if (wsDetInfo.isMonitor(index) || code == 1)
140 continue;
141
142 // drop 10 float columns
143 for (int i = 0; i < 10; ++i) {
144 float droppedFloat(0.0f);
145 is >> droppedFloat;
146 }
147
148 // pressure, wall thickness
149 float pressure(0.0), thickness(0.0);
150 is >> pressure >> thickness;
151
152 updateParameterMap(wsDetInfo, index, componentInfo, l2, theta, phi, delta, pressure, thickness);
153 } catch (std::out_of_range &) {
154 continue;
155 }
156 }
157}
158
162void LoadDetectorInfo::loadFromRAW(const std::string &filename) {
163 ISISRAW2 iraw;
164 if (iraw.readFromFile(filename.c_str(), false) != 0) {
165 throw Exception::FileError("Unable to access raw file:", filename);
166 }
167
168 const int numDets = iraw.i_det;
169 const int numUserTables = iraw.i_use;
170 int pressureTabNum(0), thicknessTabNum(0);
171 if (numUserTables == 10) {
172 pressureTabNum = 7;
173 thicknessTabNum = 8;
174 } else if (numUserTables == 14) {
175 pressureTabNum = 11;
176 thicknessTabNum = 12;
177 } else {
178 throw std::invalid_argument("RAW file contains unexpected number of user tables=" + std::to_string(numUserTables) +
179 ". Expected 10 or 14.");
180 }
181
182 // Is ut01 (=phi) present? Sometimes an array is present but has wrong values
183 // e.g.all 1.0 or all 2.0
184 bool phiPresent = (iraw.ut[0] != 1.0 && iraw.ut[0] != 2.0);
185
186 // Start loop over detectors
187 auto &componentInfo = m_workspace->mutableComponentInfo();
188 auto &wsDetInfo = m_workspace->mutableDetectorInfo();
189 for (int i = 0; i < numDets; ++i) {
190 auto detID = static_cast<detid_t>(iraw.udet[i]);
191 int code = iraw.code[i];
192 try {
193 size_t index = wsDetInfo.indexOf(detID);
194 if (wsDetInfo.isMonitor(index) || code == 1)
195 continue;
196
197 // Positions
198 float l2 = iraw.len2[i];
199 float theta = iraw.tthe[i];
200 float phi = (phiPresent ? iraw.ut[i] : 0.0f);
201
202 // Parameters
203 float delta = iraw.delt[i];
204 // offset value is be subtracted so store negative
205 delta *= -1.0f;
206 // pressure, wall thickness
207 float pressure = iraw.ut[i + pressureTabNum * numDets];
208 float thickness = iraw.ut[i + thicknessTabNum * numDets];
209
210 updateParameterMap(wsDetInfo, index, componentInfo, l2, theta, phi, delta, pressure, thickness);
211 } catch (std::out_of_range &) {
212 continue;
213 }
214 }
215}
216
221void LoadDetectorInfo::loadFromIsisNXS(const std::string &filename) {
222 Nexus::File nxsFile(filename,
223 NXaccess::READ); // will throw if file can't be opened
224
225 // two types of file:
226 // - new type entry per detector
227 // - old libisis with single pressure, thickness entry for whole file
228
229 // hold data read from file
230 DetectorInfo detInfo;
231
232 std::map<std::string, std::string> entries;
233 nxsFile.getEntries(entries);
234 if (entries.find("full_reference_detector") != entries.end()) {
235 nxsFile.openGroup("full_reference_detector", "NXIXTdetector");
236 readLibisisNxs(nxsFile, detInfo);
237 nxsFile.closeGroup();
238 } else if (entries.find("detectors.dat") != entries.end()) {
239 nxsFile.openGroup("detectors.dat", "NXEntry");
240 readNXSDotDat(nxsFile, detInfo);
241 nxsFile.closeGroup();
242 } else {
243 throw std::invalid_argument("Unknown NeXus file type");
244 }
245 nxsFile.close();
246
247 // Start loop over detectors
248 auto &componentInfo = m_workspace->mutableComponentInfo();
249 auto &wsDetInfo = m_workspace->mutableDetectorInfo();
250 auto numDets = static_cast<int>(detInfo.ids.size());
251 for (int i = 0; i < numDets; ++i) {
252 detid_t detID = detInfo.ids[i];
253 int code = detInfo.codes[i];
254 try {
255 size_t index = wsDetInfo.indexOf(detID);
256 if (wsDetInfo.isMonitor(index) || code == 1)
257 continue;
258
259 // Positions
260 double l2 = detInfo.l2[i];
261 double theta = detInfo.theta[i];
262 double phi = detInfo.phi[i];
263
264 // Parameters
265 double delta = detInfo.delays[i];
266 // offset value is be subtracted so store negative
267 delta *= -1.0;
268 // pressure, wall thickness
269 double pressure = detInfo.pressures[i];
270 double thickness = detInfo.thicknesses[i];
271
272 updateParameterMap(wsDetInfo, index, componentInfo, l2, theta, phi, delta, pressure, thickness);
273 } catch (std::out_of_range &) {
274 continue;
275 }
276 }
277}
278
286void LoadDetectorInfo::readLibisisNxs(Nexus::File &nxsFile, DetectorInfo &detInfo) const {
287 nxsFile.readData<int32_t>("det_no", detInfo.ids);
288 nxsFile.readData<int32_t>("det_type", detInfo.codes);
289 nxsFile.readData<double>("delay_time", detInfo.delays);
290 const size_t numDets = detInfo.ids.size();
291
292 if (m_moveDets) {
293 nxsFile.readData<double>("L2", detInfo.l2);
294 nxsFile.readData<double>("theta", detInfo.theta);
295 nxsFile.readData<double>("phi", detInfo.phi);
296 } else {
297 // these will get ignored
298 detInfo.l2.resize(numDets, -1.0);
299 detInfo.theta.resize(numDets, -1.0);
300 detInfo.phi.resize(numDets, -1.0);
301 }
302
303 // pressure & wall thickness are global here
304 double pressure = -1.0;
305 double thickness = -1.0;
306 nxsFile.openGroup("det_he3", "NXIXTdet_he3");
307 nxsFile.readData<double>("gas_pressure", pressure);
308 nxsFile.readData<double>("wall_thickness", thickness);
309 nxsFile.closeGroup();
310 if (pressure <= 0.0) {
311 g_log.warning("The data file does not contain correct He3 pressure, "
312 "default value of 10 bar is used instead");
313 pressure = 10.0;
314 }
315 if (thickness <= 0.0) {
316 g_log.warning("The data file does not contain correct detector's wall "
317 "thickness, default value of 0.8mm is used instead");
318 thickness = 0.0008;
319 }
320 detInfo.pressures.resize(numDets, pressure);
321 detInfo.thicknesses.resize(numDets, thickness);
322}
323
331void LoadDetectorInfo::readNXSDotDat(Nexus::File &nxsFile, DetectorInfo &detInfo) const {
332 std::vector<int32_t> fileIDs;
333 nxsFile.readData<int32_t>("detID", fileIDs); // containts both ids & codes
334 std::vector<float> fileOffsets;
335 nxsFile.readData<float>("timeOffsets", fileOffsets);
336 const size_t numDets = fileOffsets.size() / 2;
337
338 std::vector<float> detCoords;
339 if (m_moveDets) {
340 nxsFile.readData<float>("detSphericalCoord", detCoords);
341 } else {
342 detCoords.resize(3 * numDets, -1.0f);
343 }
344
345 // pressure & wall thickness
346 std::vector<float> pressureAndWall;
347 nxsFile.readData<float>("detPressureAndWall", pressureAndWall);
348
349 if (numDets != fileIDs.size() / 2 || numDets != detCoords.size() / 3 || numDets != pressureAndWall.size() / 2) {
350 std::ostringstream os;
351 os << "The sizes of NeXus data columns are inconsistent in detectors.dat.\n"
352 << "detIDs=" << fileIDs.size() << ", offsets=" << fileOffsets.size()
353 << ", pressure & thickness=" << pressureAndWall.size() << "\n";
354 throw std::runtime_error(os.str());
355 }
356
357 detInfo.ids.resize(numDets);
358 detInfo.codes.resize(numDets);
359 detInfo.delays.resize(numDets);
360 detInfo.l2.resize(numDets);
361 detInfo.theta.resize(numDets);
362 detInfo.phi.resize(numDets);
363 detInfo.pressures.resize(numDets);
364 detInfo.thicknesses.resize(numDets);
365
367 for (int i = 0; i < static_cast<int>(numDets); i++) {
368 detInfo.ids[i] = fileIDs[2 * i];
369 detInfo.codes[i] = fileIDs[2 * i + 1];
370 detInfo.delays[i] = fileOffsets[2 * i];
371
372 detInfo.l2[i] = detCoords[3 * i + 0]; // L2,
373 detInfo.theta[i] = detCoords[3 * i + 1]; // Theta
374 detInfo.phi[i] = detCoords[3 * i + 2]; // Phi
375
376 detInfo.pressures[i] = pressureAndWall[2 * i]; // pressure;
377 detInfo.thicknesses[i] = pressureAndWall[2 * i + 1]; // wallThickness;
378 }
379}
380
393void LoadDetectorInfo::updateParameterMap(Geometry::DetectorInfo &detectorInfo, const size_t detIndex,
394 Geometry::ComponentInfo &componentInfo, const double l2, const double theta,
395 const double phi, const double delay, const double pressure,
396 const double thickness) const {
397
398 // store detector params that are different to instrument level
399 if (fabs(delay - m_instDelta) > 1e-06)
400 componentInfo.addDouble(detIndex, DELAY_PARAM, delay);
401 if (fabs(pressure - m_instPressure) > 1e-06)
402 componentInfo.addDouble(detIndex, PRESSURE_PARAM, pressure);
403 if (fabs(thickness - m_instThickness) > 1e-06)
404 componentInfo.addDouble(detIndex, THICKNESS_PARAM, thickness);
405
406 // move
407 if (m_moveDets) {
408 V3D newPos;
409 newPos.spherical(l2, theta, phi);
410 // The sample position may not be at 0,0,0
411 newPos += m_samplePos;
412 detectorInfo.setPosition(detIndex, newPos);
413 }
414}
415} // namespace Mantid::DataHandling
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
std::map< DeltaEMode::Type, std::string > index
#define fabs(x)
Definition Matrix.cpp:22
#define PARALLEL_FOR_NO_WSP_CHECK()
isis raw file.
Definition isisraw2.h:13
float * ut
nuse UT* user tables (total size NUSE*NDET) ut01=phi
Definition isisraw.h:302
int i_use
number of user defined UTn tables NUSE
Definition isisraw.h:293
float * delt
hold off table (size NDET)
Definition isisraw.h:298
int i_det
number of detectors NDET
Definition isisraw.h:291
int * code
code for UTn tables (size NDET)
Definition isisraw.h:300
int readFromFile(const char *filename, bool read_data=true)
stuff
Definition isisraw.cpp:927
int * udet
user detector number for each detector (size NDET)
Definition isisraw.h:317
float * tthe
2theta scattering angle (size NDET)
Definition isisraw.h:301
float * len2
L2 table (size NDET)
Definition isisraw.h:299
Base class from which all concrete algorithm classes should be derived.
Definition Algorithm.h:76
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.
Kernel::Logger & g_log
Definition Algorithm.h:426
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
void readLibisisNxs(Nexus::File &nxsFile, DetectorInfo &detInfo) const
Read data from old-style libisis NeXus file.
double m_instThickness
Wall thickness value set on the instrument level.
double m_instDelta
Delta value that has been set on the instrument.
void loadFromRAW(const std::string &filename)
Use a .raw file as input.
void cacheInputs()
Cache the user input that will be frequently accessed.
bool m_moveDets
If set to true then update the detector positions base on the information in the given file.
void readNXSDotDat(Nexus::File &nxsFile, DetectorInfo &detInfo) const
Read data from old-style libisis NeXus file.
void exec() override
Virtual method - must be overridden by concrete algorithm.
Kernel::V3D m_samplePos
Cached sample position for this workspace.
API::MatrixWorkspace_sptr m_workspace
store a pointer to the user selected workspace
void loadFromIsisNXS(const std::string &filename)
Use a isis raw nexus or event file as input.
void init() override
Virtual method - must be overridden by concrete algorithm.
double m_instPressure
Pressure value set on the instrument level.
void updateParameterMap(Geometry::DetectorInfo &detectorInfo, const size_t detIndex, Geometry::ComponentInfo &componentInfo, const double l2, const double theta, const double phi, const double delay, const double pressure, const double thickness) const
Update the parameter map with the new values for the given detector.
void loadFromDAT(const std::string &filename)
Use a .dat or .sca file as input.
ComponentInfo : Provides a component centric view on to the instrument.
void addDouble(const size_t componentIndex, const std::string &name, double value, const std::string *const pDescription=nullptr, const std::string &pVisible="true")
Add or replace a named double parameter at a specific component index.
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
void setPosition(const size_t index, const Kernel::V3D &position)
Set the absolute position of the detector with given index. Not thread safe.
Records the filename and the description of failure.
Definition Exception.h:98
void warning(const std::string &msg)
Logs at warning level.
Definition Logger.cpp:117
Class for 3D vectors.
Definition V3D.h:35
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Definition V3D.cpp:56
int32_t detid_t
Typedef for a detector ID.
std::string to_string(const wide_integer< Bits, Signed > &n)
Simple data holder for passing the detector info around when dealing with the NeXus data.
@ InOut
Both an input & output workspace.
Definition Property.h:56
@ Input
An input workspace.
Definition Property.h:54