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