22#include "MantidNexus/NexusFile.h"
23#include "MantidTypes/SpectrumDefinition.h"
27#include <boost/algorithm/string/predicate.hpp>
28#include <boost/algorithm/string/trim.hpp>
29#include <boost/scoped_ptr.hpp>
37using namespace Kernel;
51 "The name of the workspace in which to store the imported instrument");
53 std::vector<std::string>{
".raw",
".nxs",
".dat",
".s*"}),
54 "The filename of the input file.\n"
55 "Currently supports RAW, ISIS NeXus, DAT & multi-column (at "
56 "least 2) ascii files");
58 "If true the positions of any detectors marked as monitors "
59 "in the IDF will be moved also");
62 "If the file is a simple text file, then this property is used to"
63 "define the values in each column of the file. For example: "
64 "spectrum,theta,t0,-,R"
65 "Keywords=spectrum,ID,R,theta,phi. A dash means skip column. Keywords "
67 "as identifying components to move to new positions. Any other names in "
69 "are added as instrument parameters.");
71 "If the file is ASCII, then skip this "
72 "number of lines at the start of the "
87 throw std::runtime_error(
"Input workspace has no defined instrument");
91 const bool moveMonitors =
getProperty(
"MoveMonitors");
95 if (H5::H5File::isHdf5(filename)) {
102 if (isisNexus.
confidence(*descriptorNexusLazy) > 0 || eventNexus.
confidence(*descriptorNexusLazy) > 0) {
103 const auto &rootEntry = descriptorNexusLazy->firstEntryNameType();
104 Nexus::File nxFile(filename);
105 nxFile.openGroup(rootEntry.first, rootEntry.second);
115 (boost::iends_with(filename,
".dat") || boost::iends_with(filename,
".sca"))) {
116 this->
setPropertyValue(
"AsciiHeader",
"ID,-,R,-,theta,phi,-,-,-,-,-,-,-,-,-,-,-,-,-");
124 auto descriptor = std::make_unique<Kernel::FileDescriptor>(filename);
128 throw std::invalid_argument(
"File \"" + filename +
"\" is not a valid input file.");
139 g_log.
error(
"Unable to open file " + filename);
143 const int32_t numDetector = iraw.
i_det;
144 std::vector<int32_t> detID(iraw.
udet, iraw.
udet + numDetector);
145 std::vector<float>
l2(iraw.
len2, iraw.
len2 + numDetector);
146 std::vector<float> theta(iraw.
tthe, iraw.
tthe + numDetector);
149 bool phiPresent = iraw.
i_use > 0 && iraw.
ut[0] != 1.0 && iraw.
ut[0] != 2.0;
150 std::vector<float> phi(0);
152 phi = std::vector<float>(iraw.
ut, iraw.
ut + numDetector);
154 phi = std::vector<float>(numDetector, 0.0);
166 nxFile.openGroup(
"isis_vms_compat",
"IXvms");
168 throw std::runtime_error(
"Unknown NeXus flavour. Cannot update instrument "
169 "positions using this type of file");
172 std::vector<int32_t> detID;
173 nxFile.openData(
"UDET");
174 nxFile.getData(detID);
177 std::vector<float>
l2, theta, phi;
178 nxFile.openData(
"LEN2");
181 nxFile.openData(
"TTHE");
182 nxFile.getData(theta);
184 nxFile.openData(
"UT01");
203 std::ifstream datfile(filename.c_str(), std::ios_base::in);
204 const int skipNLines =
getProperty(
"SkipFirstNLines");
207 while (lineCount < skipNLines) {
208 std::getline(datfile, line);
212 auto &detectorInfo =
m_workspace->mutableDetectorInfo();
213 auto &componentInfo =
m_workspace->mutableComponentInfo();
214 const auto &spectrumInfo =
m_workspace->spectrumInfo();
216 std::vector<double> colValues(header.colCount - 1, 0.0);
217 while (std::getline(datfile, line)) {
219 std::istringstream is(line);
221 int32_t detOrSpec(-1000);
225 g_log.
debug() <<
"Skipping \"" << line <<
"\". Cannot interpret as list of numbers.\n";
230 auto index =
static_cast<size_t>(-1);
232 auto it = specToIndex.find(detOrSpec);
233 if (it != specToIndex.end()) {
235 if (!spectrumInfo.hasDetectors(
index)) {
239 g_log.
debug() <<
"Skipping \"" << line <<
"\". Spectrum is not in workspace.\n";
244 index = detectorInfo.indexOf(detOrSpec);
245 }
catch (std::out_of_range &) {
249 if (skip ||
index ==
static_cast<size_t>(-1)) {
250 g_log.
debug() <<
"Skipping \"" << line <<
"\". Spectrum in workspace but cannot find associated detector.\n";
254 std::vector<size_t> indices;
257 std::set<size_t> detIndices;
258 for (
const auto &specDefItem : spectrumInfo.spectrumDefinition(
index))
259 detIndices.insert(specDefItem.first);
260 indices.assign(detIndices.cbegin(), detIndices.cend());
262 indices.emplace_back(
index);
267 double R(0.0), theta(0.0), phi(0.0);
268 for (
size_t i = 1; i < header.colCount; ++i) {
271 if (i < header.colCount - 1 && is.eof()) {
274 throw std::runtime_error(
"UpdateInstrumentFromFile::updateFromAscii - "
275 "File contains fewer than expected number of "
276 "columns, check AsciiHeader property.");
279 if (i == header.rColIdx)
281 else if (i == header.thetaColIdx)
283 else if (i == header.phiColIdx)
285 else if (header.detParCols.count(i) == 1) {
286 for (
const auto detIndex : indices) {
287 componentInfo.addDouble(detIndex, header.colToName[i],
value);
295 throw std::runtime_error(
"UpdateInstrumentFromFile::updateFromAscii - "
296 "File contains more than expected number of "
297 "columns, check AsciiHeader property.");
303 spectrumInfo.position(
index).getSpherical(r, t, p);
305 detectorInfo.position(
index).getSpherical(r, t, p);
306 if (header.rColIdx == 0)
308 if (header.thetaColIdx == 0)
313 for (
const auto detIndex : indices)
314 setDetectorPosition(detectorInfo, detIndex,
static_cast<float>(R),
static_cast<float>(theta),
315 static_cast<float>(phi));
327 const std::string header =
getProperty(
"AsciiHeader");
328 if (header.empty()) {
329 throw std::invalid_argument(
"Ascii file provided but the AsciiHeader "
330 "property is empty, cannot interpret columns");
335 auto it = splitter.
begin();
336 const std::string &col0 = *it;
337 bool isSpectrum(
false);
338 if (boost::iequals(
"spectrum", col0))
340 if (!isSpectrum && !boost::iequals(
"id", col0)) {
341 throw std::invalid_argument(
"Invalid AsciiHeader, first column name must "
342 "be either 'spectrum' or 'id'");
347 for (; it != splitter.
end(); ++it) {
348 const std::string &colName = *it;
349 if (boost::iequals(
"R", colName))
351 else if (boost::iequals(
"theta", colName))
353 else if (boost::iequals(
"phi", colName))
355 else if (boost::iequals(
"-", colName))
361 headerInfo.
colToName.emplace(counter, colName);
377 const std::vector<float> &theta,
const std::vector<float> &phi) {
378 const auto numDetector =
static_cast<int>(detID.size());
379 g_log.
information() <<
"Setting new positions for " << numDetector <<
" detectors\n";
381 auto &detectorInfo =
m_workspace->mutableDetectorInfo();
382 for (
int i = 0; i < numDetector; ++i) {
384 auto index = detectorInfo.indexOf(detID[i]);
388 detectorInfo.position(
index).getSpherical(r, t, p);
391 }
catch (std::out_of_range &) {
395 progress(
static_cast<double>(i) / numDetector,
"Updating Detector Positions from File");
408 const float l2,
const float theta,
const float phi) {
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
float * ut
nuse UT* user tables (total size NUSE*NDET) ut01=phi
int i_use
number of user defined UTn tables NUSE
int i_det
number of detectors NDET
int readFromFile(const char *filename, bool read_data=true)
stuff
int * udet
user detector number for each detector (size NDET)
float * tthe
2theta scattering angle (size NDET)
float * len2
L2 table (size NDET)
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.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
@ Load
allowed here which will be passed to the algorithm
A property class for workspaces.
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Return the confidence with with this algorithm can load the file.
Loads a file in a NeXus format and stores it in a 2D workspace.
int confidence(Nexus::NexusDescriptorLazy &descriptor) const override
Returns a confidence value that this algorithm can load a file.
Helper class for LoadRaw algorithms.
int confidence(Kernel::FileDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
void setDetectorPositions(const std::vector< int32_t > &detID, const std::vector< float > &l2, const std::vector< float > &theta, const std::vector< float > &phi)
Set the new detector positions.
void updateFromRaw(const std::string &filename)
Assumes the file is a raw file.
bool m_ignorePhi
Cached ignore phi.
void updateFromAscii(const std::string &filename)
Updates from a more generic ascii file.
void setDetectorPosition(Geometry::DetectorInfo &detectorInfo, const size_t index, const float l2, const float theta, const float phi)
Set the new detector position for a single det ID.
UpdateInstrumentFromFile()
Default constructor.
API::MatrixWorkspace_sptr m_workspace
The input workspace to modify.
bool m_ignoreMonitors
Cached ignore Monitors.
bool parseAsciiHeader(AsciiFileHeader &headerInfo)
Parse the header and fill the headerInfo struct.
void init() override
Overwrites Algorithm method. Does nothing at present.
void updateFromNeXus(Nexus::File &nxFile)
Assumes the file is an ISIS NeXus file.
void exec() override
Overwrites Algorithm method.
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.
bool isMonitor(const size_t index) const
Returns true if the detector is a monitor.
Records the filename and the description of failure.
bool isAscii() const
Returns true if the descriptor is looking at an ascii file.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
void error(const std::string &msg)
Logs at error level.
void information(const std::string &msg)
Logs at information level.
Iterator begin()
Iterator referring to first element in the container.
@ TOK_TRIM
remove leading and trailing whitespace from tokens
Iterator end()
Iterator referring to the past-the-end element in the container.
std::size_t count() const
Get the total number of tokens.
void spherical(const double R, const double theta, const double phi) noexcept
Sets the vector position based on spherical coordinates.
Class that provides for a standard Nexus exception.
std::shared_ptr< Instrument > Instrument_sptr
Shared pointer to an instrument object.
std::shared_ptr< Mantid::Geometry::IDetector > IDetector_sptr
Shared pointer to IDetector.
std::unordered_map< specnum_t, size_t > spec2index_map
Map with key = spectrum number, value = workspace index.
Simple structure to store information about the ASCII file header.
std::set< size_t > detParCols
std::map< size_t, std::string > colToName
@ InOut
Both an input & output workspace.