Mantid
Loading...
Searching...
No Matches
LoadPreNexus.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 +
11#include "MantidAPI/Run.h"
17#include "MantidKernel/System.h"
19#include <Poco/DOM/AutoPtr.h>
20#include <Poco/DOM/DOMParser.h>
21#include <Poco/DOM/Document.h>
22#include <Poco/DOM/Element.h>
23#include <Poco/DOM/NodeFilter.h>
24#include <Poco/DOM/NodeIterator.h>
25#include <Poco/DOM/NodeList.h>
26#include <Poco/File.h>
27#include <Poco/Path.h>
28#include <Poco/SAX/InputSource.h>
29#include <exception>
30#include <fstream>
31
32using namespace Mantid::Kernel;
33using namespace Mantid::API;
34using std::size_t;
35using std::string;
36using std::vector;
37
38namespace Mantid::DataHandling {
39
41
42static const string RUNINFO_PARAM("Filename");
43static const string MAP_PARAM("MappingFilename");
44
46const std::string LoadPreNexus::name() const { return "LoadPreNexus"; }
47
49int LoadPreNexus::version() const { return 1; }
50
52const std::string LoadPreNexus::category() const { return "DataHandling\\PreNexus;Workflow\\DataHandling"; }
53
61 const std::string &filename = descriptor.filename();
62 if (filename.size() > 12 ? (filename.compare(filename.size() - 12, 12, "_runinfo.xml") == 0) : false)
63 return 80;
64 else
65 return 0;
66}
67
70 // runfile to read in
71 declareProperty(std::make_unique<FileProperty>(RUNINFO_PARAM, "", FileProperty::Load, "_runinfo.xml"),
72 "The name of the runinfo file to read, including its full or relative "
73 "path.");
74
75 // copied (by hand) from LoadEventPreNexus2
76 declareProperty(std::make_unique<FileProperty>(MAP_PARAM, "", FileProperty::OptionalLoad, ".dat"),
77 "File containing the pixel mapping (DAS pixels to pixel IDs) file "
78 "(typically INSTRUMENT_TS_YYYY_MM_DD.dat). The filename will be found "
79 "automatically if not specified.");
80 auto mustBePositive = std::make_shared<BoundedValidator<int>>();
81 mustBePositive->setLower(1);
82 declareProperty("ChunkNumber", EMPTY_INT(), mustBePositive,
83 "If loading the file by sections ('chunks'), this is the "
84 "section number of this execution of the algorithm.");
85 declareProperty("TotalChunks", EMPTY_INT(), mustBePositive,
86 "If loading the file by sections ('chunks'), this is the "
87 "total number of sections.");
88 // TotalChunks is only meaningful if ChunkNumber is set
89 // Would be nice to be able to restrict ChunkNumber to be <= TotalChunks at
90 // validation
91 setPropertySettings("TotalChunks", std::make_unique<VisibleWhenProperty>("ChunkNumber", IS_NOT_DEFAULT));
92 std::vector<std::string> propOptions{"Auto", "Serial", "Parallel"};
93 declareProperty("UseParallelProcessing", "Auto", std::make_shared<StringListValidator>(propOptions),
94 "Use multiple cores for loading the data?\n"
95 " Auto: Use serial loading for small data sets, parallel "
96 "for large data sets.\n"
97 " Serial: Use a single core.\n"
98 " Parallel: Use all available cores.");
99
100 declareProperty(std::make_unique<PropertyWithValue<bool>>("LoadMonitors", true, Direction::Input),
101 "Load the monitors from the file.");
102
103 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
104 "An output workspace.");
105}
106
107//----------------------------------------------------------------------------------------------
110 string runinfo = this->getPropertyValue(RUNINFO_PARAM);
111 string mapfile = this->getPropertyValue(MAP_PARAM);
112 int chunkTotal = this->getProperty("TotalChunks");
113 int chunkNumber = this->getProperty("ChunkNumber");
114 if (isEmpty(chunkTotal) || isEmpty(chunkNumber)) {
115 chunkNumber = EMPTY_INT();
116 chunkTotal = EMPTY_INT();
117 } else {
118 if (chunkNumber > chunkTotal)
119 throw std::out_of_range("ChunkNumber cannot be larger than TotalChunks");
120 }
121 string useParallel = this->getProperty("UseParallelProcessing");
122 string wsname = this->getProperty("OutputWorkspace");
123 bool loadmonitors = this->getProperty("LoadMonitors");
124
125 // determine the event file names
126 Progress prog(this, 0., .1, 1);
127 vector<string> eventFilenames;
128 string dataDir;
129 this->parseRuninfo(runinfo, dataDir, eventFilenames);
130 prog.doReport("parsed runinfo file");
131
132 // do math for the progress bar
133 size_t numFiles = eventFilenames.size() + 1; // extra 1 is nexus logs
134 if (loadmonitors)
135 numFiles++;
136 double prog_start = .1;
137 double prog_delta = (1. - prog_start) / static_cast<double>(numFiles);
138
139 // load event files
140 string temp_wsname;
141
142 for (size_t i = 0; i < eventFilenames.size(); i++) {
143 if (i == 0)
144 temp_wsname = wsname;
145 else
146 temp_wsname = "__" + wsname + "_temp__";
147
148 auto alg = createChildAlgorithm("LoadEventPreNexus", prog_start, prog_start + prog_delta);
149 alg->setProperty("EventFilename", dataDir + eventFilenames[i]);
150 alg->setProperty("MappingFilename", mapfile);
151 alg->setProperty("ChunkNumber", chunkNumber);
152 alg->setProperty("TotalChunks", chunkTotal);
153 alg->setProperty("UseParallelProcessing", useParallel);
154 alg->setPropertyValue("OutputWorkspace", temp_wsname);
155 alg->executeAsChildAlg();
156 prog_start += prog_delta;
157
158 if (i == 0) {
159 m_outputWorkspace = alg->getProperty("OutputWorkspace");
160 } else {
161 IEventWorkspace_sptr tempws = alg->getProperty("OutputWorkspace");
162 // clean up properties before adding data
163 Run &run = tempws->mutableRun();
164 if (run.hasProperty("gd_prtn_chrg"))
165 run.removeProperty("gd_prtn_chrg");
166 if (run.hasProperty("proton_charge"))
167 run.removeProperty("proton_charge");
168
169 m_outputWorkspace += tempws;
170 }
171 }
172
173 // load the logs
174 this->runLoadNexusLogs(runinfo, dataDir, prog_start, prog_start + prog_delta);
175 prog_start += prog_delta;
176
177 // publish output workspace
178 this->setProperty("OutputWorkspace", m_outputWorkspace);
179
180 // load the monitor
181 if (loadmonitors) {
182 this->runLoadMonitors(prog_start, 1.);
183 }
184}
185
194void LoadPreNexus::parseRuninfo(const string &runinfo, string &dataDir, vector<string> &eventFilenames) {
195 eventFilenames.clear();
196
197 // Create a Poco Path object for runinfo filename
198 Poco::Path runinfoPath(runinfo, Poco::Path::PATH_GUESS);
199 // Now lets get the directory
200 Poco::Path dirPath(runinfoPath.parent());
201 dataDir = dirPath.absolute().toString();
202 g_log.debug() << "Data directory \"" << dataDir << "\"\n";
203
204 std::ifstream in(runinfo.c_str());
205 Poco::XML::InputSource src(in);
206
207 Poco::XML::DOMParser parser;
208 Poco::AutoPtr<Poco::XML::Document> pDoc = parser.parse(&src);
209
210 Poco::XML::NodeIterator it(pDoc, Poco::XML::NodeFilter::SHOW_ELEMENT);
211 Poco::XML::Node *pNode = it.nextNode(); // root node
212 while (pNode) {
213 if (pNode->nodeName() == "RunInfo") // standard name for this type
214 {
215 pNode = pNode->firstChild();
216 while (pNode) {
217 if (pNode->nodeName() == "FileList") {
218 pNode = pNode->firstChild();
219 while (pNode) {
220 if (pNode->nodeName() == "DataList") {
221 pNode = pNode->firstChild();
222 while (pNode) {
223 if (pNode->nodeName() == "scattering") {
224 auto *element = static_cast<Poco::XML::Element *>(pNode);
225 eventFilenames.emplace_back(element->getAttribute("name"));
226 }
227 pNode = pNode->nextSibling();
228 }
229 } else // search for DataList
230 pNode = pNode->nextSibling();
231 }
232 } else // search for FileList
233 pNode = pNode->nextSibling();
234 }
235 } else // search for RunInfo
236 pNode = pNode->nextSibling();
237 }
238
239 // report the results to the log
240 if (eventFilenames.size() == 1) {
241 g_log.debug() << "Found 1 event file: \"" << eventFilenames[0] << "\"\n";
242 } else {
243 g_log.debug() << "Found " << eventFilenames.size() << " event files:";
244 for (auto &eventFilename : eventFilenames) {
245 g_log.debug() << "\"" << eventFilename << "\" ";
246 }
247 g_log.debug() << "\n";
248 }
249}
250
259void LoadPreNexus::runLoadNexusLogs(const string &runinfo, const string &dataDir, const double prog_start,
260 const double prog_stop) {
261 // determine the name of the file "inst_run"
262 string shortName = runinfo.substr(runinfo.find_last_of("/\\") + 1);
263 shortName = shortName.substr(0, shortName.find("_runinfo.xml"));
264 g_log.debug() << "SHORTNAME = \"" << shortName << "\"\n";
265
266 // put together a list of possible locations
267 vector<string> possibilities;
268 possibilities.emplace_back(dataDir + shortName + "_event.nxs"); // next to runinfo
269 possibilities.emplace_back(dataDir + shortName + "_histo.nxs");
270 possibilities.emplace_back(dataDir + shortName + ".nxs");
271 possibilities.emplace_back(dataDir + "../NeXus/" + shortName + "_event.nxs"); // in NeXus directory
272 possibilities.emplace_back(dataDir + "../NeXus/" + shortName + "_histo.nxs");
273 possibilities.emplace_back(dataDir + "../NeXus/" + shortName + ".nxs");
274
275 // run the algorithm
276 bool loadedLogs = false;
277 for (auto &possibility : possibilities) {
278 if (Poco::File(possibility).exists()) {
279 g_log.information() << "Loading logs from \"" << possibility << "\"\n";
280 auto alg = createChildAlgorithm("LoadNexusLogs", prog_start, prog_stop);
281 alg->setProperty("Workspace", m_outputWorkspace);
282 alg->setProperty("Filename", possibility);
283 alg->setProperty("OverwriteLogs", false);
284 alg->executeAsChildAlg();
285 loadedLogs = true;
286 // Reload instrument so SNAP can use log values
287 std::string entry_name = LoadTOFRawNexus::getEntryName(possibility);
288 LoadEventNexus::runLoadInstrument(possibility, m_outputWorkspace, entry_name, this);
289 break;
290 }
291 }
292
293 if (!loadedLogs)
294 g_log.notice() << "Did not find a nexus file to load logs from\n";
295}
296
303void LoadPreNexus::runLoadMonitors(const double prog_start, const double prog_stop) {
304 std::string mon_wsname = this->getProperty("OutputWorkspace");
305 mon_wsname.append("_monitors");
306
307 try {
308 auto alg = createChildAlgorithm("LoadPreNexusMonitors", prog_start, prog_stop);
309 alg->setPropertyValue("RunInfoFilename", this->getProperty(RUNINFO_PARAM));
310 alg->setPropertyValue("OutputWorkspace", mon_wsname);
311 alg->executeAsChildAlg();
312 MatrixWorkspace_sptr mons = alg->getProperty("OutputWorkspace");
313 this->declareProperty(std::make_unique<WorkspaceProperty<>>("MonitorWorkspace", mon_wsname, Direction::Output),
314 "Monitors from the Event NeXus file");
315 this->setProperty("MonitorWorkspace", mons);
316 // Add an internal pointer to monitor workspace in the 'main' workspace
317 m_outputWorkspace->setMonitorWorkspace(mons);
318 } catch (std::exception &e) {
319 g_log.warning() << "Failed to load monitors: " << e.what() << "\n";
320 }
321}
322
323} // namespace Mantid::DataHandling
#define DECLARE_FILELOADER_ALGORITHM(classname)
DECLARE_FILELOADER_ALGORITHM should be used in place of the standard DECLARE_ALGORITHM macro when wri...
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ OptionalLoad
to specify a file to read but the file doesn't have to exist
Definition: FileProperty.h:53
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
bool hasProperty(const std::string &name) const
Does the property exist on the object.
Definition: LogManager.cpp:265
void removeProperty(const std::string &name, bool delProperty=true)
Remove a named property.
Definition: LogManager.cpp:275
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
void doReport(const std::string &msg="") override
Actually do the reporting, without changing the loop counter.
Definition: Progress.cpp:70
This class stores information regarding an experimental run as a series of log entries.
Definition: Run.h:38
A property class for workspaces.
static bool runLoadInstrument(const std::string &nexusfilename, T localWorkspace, const std::string &top_entry_name, Algorithm *alg, const Kernel::NexusHDF5Descriptor *descriptor=nullptr)
Load instrument from IDF file specified by Nexus file.
LoadPreNexus : Workflow algorithm to load a collection of preNeXus files.
Definition: LoadPreNexus.h:23
void init() override
Virtual method - must be overridden by concrete algorithm.
API::IEventWorkspace_sptr m_outputWorkspace
Definition: LoadPreNexus.h:45
int version() const override
function to return a version of the algorithm, must be overridden in all algorithms
const std::string category() const override
function to return a category of the algorithm.
int confidence(Kernel::FileDescriptor &descriptor) const override
Returns a confidence value that this algorithm can load a file.
void parseRuninfo(const std::string &runinfo, std::string &dataDir, std::vector< std::string > &eventFilenames)
Parse the runinfo file to find the names of the neutron event files.
void exec() override
Virtual method - must be overridden by concrete algorithm.
void runLoadMonitors(const double prog_start, const double prog_stop)
Load the monitor files.
void runLoadNexusLogs(const std::string &runinfo, const std::string &dataDir, const double prog_start, const double prog_stop)
Load logs from a nexus file onto the workspace.
static std::string getEntryName(const std::string &filename)
Defines a wrapper around an open file.
const std::string & filename() const
Access the filename.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
The concrete, templated class for properties.
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IEventWorkspace > IEventWorkspace_sptr
shared pointer to Mantid::API::IEventWorkspace
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
bool exists(::NeXus::File &file, const std::string &name)
Based on the current group in the file, does the named sub-entry exist?
static const string MAP_PARAM("MappingFilename")
static const string RUNINFO_PARAM("Filename")
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
Definition: EmptyValues.h:25
STL namespace.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54