21#include <boost/algorithm/string/predicate.hpp>
22#include <boost/scoped_ptr.hpp>
24#include <nexus/NeXusFile.hpp>
25#include <nexus/NeXusException.hpp>
35using namespace Kernel;
49 "The name of the workspace in which to store the imported instrument");
51 std::vector<std::string>{
".raw",
".nxs",
".dat",
".s*"}),
52 "The filename of the input file.\n"
53 "Currently supports RAW, ISIS NeXus, DAT & multi-column (at "
54 "least 2) ascii files");
56 "If true the positions of any detectors marked as monitors "
57 "in the IDF will be moved also");
60 "If the file is a simple text file, then this property is used to"
61 "define the values in each column of the file. For example: "
62 "spectrum,theta,t0,-,R"
63 "Keywords=spectrum,ID,R,theta,phi. A dash means skip column. Keywords "
65 "as identifying components to move to new positions. Any other names in "
67 "are added as instrument parameters.");
69 "If the file is ASCII, then skip this "
70 "number of lines at the start of the "
85 throw std::runtime_error(
"Input workspace has no defined instrument");
89 const bool moveMonitors =
getProperty(
"MoveMonitors");
105 auto &nxFile = descriptor->data();
106 const auto &rootEntry = descriptor->firstEntryNameType();
107 nxFile.openGroup(rootEntry.first, rootEntry.second);
117 (boost::iends_with(filename,
".dat") || boost::iends_with(filename,
".sca"))) {
118 this->
setPropertyValue(
"AsciiHeader",
"ID,-,R,-,theta,phi,-,-,-,-,-,-,-,-,-,-,-,-,-");
126 auto descriptor = std::make_unique<Kernel::FileDescriptor>(filename);
130 throw std::invalid_argument(
"File \"" + filename +
"\" is not a valid input file.");
141 g_log.
error(
"Unable to open file " + filename);
145 const int32_t numDetector = iraw.
i_det;
146 std::vector<int32_t> detID(iraw.
udet, iraw.
udet + numDetector);
147 std::vector<float>
l2(iraw.
len2, iraw.
len2 + numDetector);
148 std::vector<float> theta(iraw.
tthe, iraw.
tthe + numDetector);
151 bool phiPresent = iraw.
i_use > 0 && iraw.
ut[0] != 1.0 && iraw.
ut[0] != 2.0;
152 std::vector<float> phi(0);
154 phi = std::vector<float>(iraw.
ut, iraw.
ut + numDetector);
156 phi = std::vector<float>(numDetector, 0.0);
168 nxFile.openGroup(
"isis_vms_compat",
"IXvms");
169 }
catch (::NeXus::Exception &) {
170 throw std::runtime_error(
"Unknown NeXus flavour. Cannot update instrument "
171 "positions using this type of file");
174 std::vector<int32_t> detID;
175 nxFile.openData(
"UDET");
176 nxFile.getData(detID);
179 std::vector<float>
l2, theta, phi;
180 nxFile.openData(
"LEN2");
183 nxFile.openData(
"TTHE");
184 nxFile.getData(theta);
186 nxFile.openData(
"UT01");
205 std::ifstream datfile(filename.c_str(), std::ios_base::in);
206 const int skipNLines =
getProperty(
"SkipFirstNLines");
209 while (lineCount < skipNLines) {
210 std::getline(datfile, line);
215 auto &detectorInfo =
m_workspace->mutableDetectorInfo();
216 const auto &spectrumInfo =
m_workspace->spectrumInfo();
218 std::vector<double> colValues(header.colCount - 1, 0.0);
219 while (std::getline(datfile, line)) {
221 std::istringstream is(line);
223 int32_t detOrSpec(-1000);
227 g_log.
debug() <<
"Skipping \"" << line <<
"\". Cannot interpret as list of numbers.\n";
232 auto index =
static_cast<size_t>(-1);
235 auto it = specToIndex.find(detOrSpec);
236 if (it != specToIndex.end()) {
238 if (spectrumInfo.hasDetectors(
index)) {
239 det = &spectrumInfo.detector(
index);
244 g_log.
debug() <<
"Skipping \"" << line <<
"\". Spectrum is not in workspace.\n";
249 index = detectorInfo.indexOf(detOrSpec);
250 det = &detectorInfo.detector(
index);
251 }
catch (std::out_of_range &) {
255 if (skip ||
index ==
static_cast<size_t>(-1)) {
256 g_log.
debug() <<
"Skipping \"" << line <<
"\". Spectrum in workspace but cannot find associated detector.\n";
260 std::vector<size_t> indices;
263 const auto detIDs = group->getDetectorIDs();
264 std::transform(detIDs.cbegin(), detIDs.cend(), std::back_inserter(indices),
265 [detectorInfo](
const auto detID) { return detectorInfo.indexOf(detID); });
267 indices.emplace_back(detectorInfo.indexOf(det->getID()));
270 indices.emplace_back(
index);
275 double R(0.0), theta(0.0), phi(0.0);
276 for (
size_t i = 1; i < header.colCount; ++i) {
279 if (i < header.colCount - 1 && is.eof()) {
282 throw std::runtime_error(
"UpdateInstrumentFromFile::updateFromAscii - "
283 "File contains fewer than expected number of "
284 "columns, check AsciiHeader property.");
287 if (i == header.rColIdx)
289 else if (i == header.thetaColIdx)
291 else if (i == header.phiColIdx)
293 else if (header.detParCols.count(i) == 1) {
294 for (
const auto detIndex : indices) {
295 auto id = detectorInfo.detector(detIndex).getComponentID();
296 pmap.addDouble(
id, header.colToName[i],
value);
304 throw std::runtime_error(
"UpdateInstrumentFromFile::updateFromAscii - "
305 "File contains more than expected number of "
306 "columns, check AsciiHeader property.");
312 spectrumInfo.position(
index).getSpherical(r, t, p);
314 detectorInfo.position(
index).getSpherical(r, t, p);
315 if (header.rColIdx == 0)
317 if (header.thetaColIdx == 0)
322 for (
const auto detIndex : indices)
323 setDetectorPosition(detectorInfo, detIndex,
static_cast<float>(R),
static_cast<float>(theta),
324 static_cast<float>(phi));
336 const std::string header =
getProperty(
"AsciiHeader");
337 if (header.empty()) {
338 throw std::invalid_argument(
"Ascii file provided but the AsciiHeader "
339 "property is empty, cannot interpret columns");
344 auto it = splitter.
begin();
345 const std::string &col0 = *it;
346 bool isSpectrum(
false);
347 if (boost::iequals(
"spectrum", col0))
349 if (!isSpectrum && !boost::iequals(
"id", col0)) {
350 throw std::invalid_argument(
"Invalid AsciiHeader, first column name must "
351 "be either 'spectrum' or 'id'");
356 for (; it != splitter.
end(); ++it) {
357 const std::string &colName = *it;
358 if (boost::iequals(
"R", colName))
360 else if (boost::iequals(
"theta", colName))
362 else if (boost::iequals(
"phi", colName))
364 else if (boost::iequals(
"-", colName))
370 headerInfo.
colToName.emplace(counter, colName);
386 const std::vector<float> &theta,
const std::vector<float> &phi) {
387 const auto numDetector =
static_cast<int>(detID.size());
388 g_log.
information() <<
"Setting new positions for " << numDetector <<
" detectors\n";
390 auto &detectorInfo =
m_workspace->mutableDetectorInfo();
391 for (
int i = 0; i < numDetector; ++i) {
393 auto index = detectorInfo.indexOf(detID[i]);
397 detectorInfo.position(
index).getSpherical(r, t, p);
400 }
catch (std::out_of_range &) {
404 progress(
static_cast<double>(i) / numDetector,
"Updating Detector Positions from File");
417 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(Kernel::NexusHDF5Descriptor &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(Kernel::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.
void updateFromNeXus(::NeXus::File &nxFile)
Assumes the file is an ISIS NeXus file.
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 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.
Defines a wrapper around a file whose internal structure can be accessed using the NeXus API.
static bool isReadable(const std::string &filename, const Version version=AnyVersion)
Returns true if the file is considered to store data in a hierarchy.
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.
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.