21#include "MantidNexus/NexusFile.h"
25#include <boost/algorithm/string/predicate.hpp>
26#include <boost/algorithm/string/trim.hpp>
27#include <boost/scoped_ptr.hpp>
34using namespace Kernel;
48 "The name of the workspace in which to store the imported instrument");
50 std::vector<std::string>{
".raw",
".nxs",
".dat",
".s*"}),
51 "The filename of the input file.\n"
52 "Currently supports RAW, ISIS NeXus, DAT & multi-column (at "
53 "least 2) ascii files");
55 "If true the positions of any detectors marked as monitors "
56 "in the IDF will be moved also");
59 "If the file is a simple text file, then this property is used to"
60 "define the values in each column of the file. For example: "
61 "spectrum,theta,t0,-,R"
62 "Keywords=spectrum,ID,R,theta,phi. A dash means skip column. Keywords "
64 "as identifying components to move to new positions. Any other names in "
66 "are added as instrument parameters.");
68 "If the file is ASCII, then skip this "
69 "number of lines at the start of the "
84 throw std::runtime_error(
"Input workspace has no defined instrument");
88 const bool moveMonitors =
getProperty(
"MoveMonitors");
92 if (H5::H5File::isHdf5(filename)) {
99 if (isisNexus.
confidence(*descriptorNexusHDF5) > 0 || eventNexus.
confidence(*descriptorNexusHDF5) > 0) {
100 const auto &rootEntry = descriptorNexusHDF5->firstEntryNameType();
101 Nexus::File nxFile(filename);
102 nxFile.openGroup(rootEntry.first, rootEntry.second);
112 (boost::iends_with(filename,
".dat") || boost::iends_with(filename,
".sca"))) {
113 this->
setPropertyValue(
"AsciiHeader",
"ID,-,R,-,theta,phi,-,-,-,-,-,-,-,-,-,-,-,-,-");
121 auto descriptor = std::make_unique<Kernel::FileDescriptor>(filename);
125 throw std::invalid_argument(
"File \"" + filename +
"\" is not a valid input file.");
136 g_log.
error(
"Unable to open file " + filename);
140 const int32_t numDetector = iraw.
i_det;
141 std::vector<int32_t> detID(iraw.
udet, iraw.
udet + numDetector);
142 std::vector<float>
l2(iraw.
len2, iraw.
len2 + numDetector);
143 std::vector<float> theta(iraw.
tthe, iraw.
tthe + numDetector);
146 bool phiPresent = iraw.
i_use > 0 && iraw.
ut[0] != 1.0 && iraw.
ut[0] != 2.0;
147 std::vector<float> phi(0);
149 phi = std::vector<float>(iraw.
ut, iraw.
ut + numDetector);
151 phi = std::vector<float>(numDetector, 0.0);
163 nxFile.openGroup(
"isis_vms_compat",
"IXvms");
165 throw std::runtime_error(
"Unknown NeXus flavour. Cannot update instrument "
166 "positions using this type of file");
169 std::vector<int32_t> detID;
170 nxFile.openData(
"UDET");
171 nxFile.getData(detID);
174 std::vector<float>
l2, theta, phi;
175 nxFile.openData(
"LEN2");
178 nxFile.openData(
"TTHE");
179 nxFile.getData(theta);
181 nxFile.openData(
"UT01");
200 std::ifstream datfile(filename.c_str(), std::ios_base::in);
201 const int skipNLines =
getProperty(
"SkipFirstNLines");
204 while (lineCount < skipNLines) {
205 std::getline(datfile, line);
210 auto &detectorInfo =
m_workspace->mutableDetectorInfo();
211 const auto &spectrumInfo =
m_workspace->spectrumInfo();
213 std::vector<double> colValues(header.colCount - 1, 0.0);
214 while (std::getline(datfile, line)) {
216 std::istringstream is(line);
218 int32_t detOrSpec(-1000);
222 g_log.
debug() <<
"Skipping \"" << line <<
"\". Cannot interpret as list of numbers.\n";
227 auto index =
static_cast<size_t>(-1);
230 auto it = specToIndex.find(detOrSpec);
231 if (it != specToIndex.end()) {
233 if (spectrumInfo.hasDetectors(
index)) {
234 det = &spectrumInfo.detector(
index);
239 g_log.
debug() <<
"Skipping \"" << line <<
"\". Spectrum is not in workspace.\n";
244 index = detectorInfo.indexOf(detOrSpec);
245 det = &detectorInfo.detector(
index);
246 }
catch (std::out_of_range &) {
250 if (skip ||
index ==
static_cast<size_t>(-1)) {
251 g_log.
debug() <<
"Skipping \"" << line <<
"\". Spectrum in workspace but cannot find associated detector.\n";
255 std::vector<size_t> indices;
258 const auto detIDs =
group->getDetectorIDs();
259 std::transform(detIDs.cbegin(), detIDs.cend(), std::back_inserter(indices),
260 [detectorInfo](
const auto detID) { return detectorInfo.indexOf(detID); });
262 indices.emplace_back(detectorInfo.indexOf(det->getID()));
265 indices.emplace_back(
index);
270 double R(0.0), theta(0.0), phi(0.0);
271 for (
size_t i = 1; i < header.colCount; ++i) {
274 if (i < header.colCount - 1 && is.eof()) {
277 throw std::runtime_error(
"UpdateInstrumentFromFile::updateFromAscii - "
278 "File contains fewer than expected number of "
279 "columns, check AsciiHeader property.");
282 if (i == header.rColIdx)
284 else if (i == header.thetaColIdx)
286 else if (i == header.phiColIdx)
288 else if (header.detParCols.count(i) == 1) {
289 for (
const auto detIndex : indices) {
290 auto id = detectorInfo.detector(detIndex).getComponentID();
291 pmap.addDouble(
id, header.colToName[i],
value);
299 throw std::runtime_error(
"UpdateInstrumentFromFile::updateFromAscii - "
300 "File contains more than expected number of "
301 "columns, check AsciiHeader property.");
307 spectrumInfo.position(
index).getSpherical(r, t, p);
309 detectorInfo.position(
index).getSpherical(r, t, p);
310 if (header.rColIdx == 0)
312 if (header.thetaColIdx == 0)
317 for (
const auto detIndex : indices)
318 setDetectorPosition(detectorInfo, detIndex,
static_cast<float>(R),
static_cast<float>(theta),
319 static_cast<float>(phi));
331 const std::string header =
getProperty(
"AsciiHeader");
332 if (header.empty()) {
333 throw std::invalid_argument(
"Ascii file provided but the AsciiHeader "
334 "property is empty, cannot interpret columns");
339 auto it = splitter.
begin();
340 const std::string &col0 = *it;
341 bool isSpectrum(
false);
342 if (boost::iequals(
"spectrum", col0))
344 if (!isSpectrum && !boost::iequals(
"id", col0)) {
345 throw std::invalid_argument(
"Invalid AsciiHeader, first column name must "
346 "be either 'spectrum' or 'id'");
351 for (; it != splitter.
end(); ++it) {
352 const std::string &colName = *it;
353 if (boost::iequals(
"R", colName))
355 else if (boost::iequals(
"theta", colName))
357 else if (boost::iequals(
"phi", colName))
359 else if (boost::iequals(
"-", colName))
365 headerInfo.
colToName.emplace(counter, colName);
381 const std::vector<float> &theta,
const std::vector<float> &phi) {
382 const auto numDetector =
static_cast<int>(detID.size());
383 g_log.
information() <<
"Setting new positions for " << numDetector <<
" detectors\n";
385 auto &detectorInfo =
m_workspace->mutableDetectorInfo();
386 for (
int i = 0; i < numDetector; ++i) {
388 auto index = detectorInfo.indexOf(detID[i]);
392 detectorInfo.position(
index).getSpherical(r, t, p);
395 }
catch (std::out_of_range &) {
399 progress(
static_cast<double>(i) / numDetector,
"Updating Detector Positions from File");
412 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::NexusDescriptor &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::NexusDescriptor &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.
Holds a collection of detectors.
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.
Interface class for detector objects.
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.
Generate a tableworkspace to store the calibration results.
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.