Mantid
Loading...
Searching...
No Matches
LogParser.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 +
7//----------------------------------------------------------------------
8// Includes
9//----------------------------------------------------------------------
11#include "MantidKernel/Logger.h"
16
17#include <fstream>
18
19// constants for the new style icp event commands
20constexpr const char *START_COLLECTION = "START_COLLECTION";
21constexpr const char *STOP_COLLECTION = "STOP_COLLECTION";
22
23using std::size_t;
24
25namespace Mantid {
26
27using Types::Core::DateAndTime;
28namespace Kernel {
29namespace {
31Logger g_log("LogParser");
32} // namespace
33
39Kernel::Property *LogParser::createLogProperty(const std::string &logFName, const std::string &name) {
40 std::ifstream file(logFName.c_str());
41 if (!file) {
42 g_log.warning() << "Cannot open log file " << logFName << "\n";
43 return nullptr;
44 }
45
46 // Change times and new values read from file
47 std::multimap<std::string, std::string> change_times;
48
49 // Read in the data and determin if it is numeric
50 std::string str, old_data;
51 bool isNumeric(false);
52 std::string stime, sdata;
53 // MG 22/09/09: If the log file was written on a Windows machine and then read
54 // on a Linux machine, std::getline will
55 // leave CR at the end of the string and this causes problems when reading out
56 // the log values. Mantid::extractTOEOL
57 // extracts all EOL characters
58 while (Mantid::Kernel::Strings::extractToEOL(file, str)) {
59 if (str.empty() || str[0] == '#') {
60 continue;
61 }
62
64 // if the line doesn't start with a time treat it as a continuation of the
65 // previous data
66 if (change_times.empty() || isNumeric) { // if there are no previous data
67 std::string mess = std::string("Cannot parse log file ").append(logFName).append(". Line:").append(str);
68 g_log.error(mess);
69 throw std::logic_error(mess);
70 }
71 auto range = change_times.equal_range(stime);
72 if (range.first != range.second) {
73 auto last = range.first;
74 for (auto it = last; it != range.second; ++it) {
75 last = it;
76 }
77 last->second += std::string(" ") + str;
78 old_data = last->second;
79 continue;
80 }
81 }
82 stime = str.substr(0, 19);
83 sdata = str.substr(19);
84
85 if (sdata == old_data)
86 continue; // looking for a change in the data
87
88 // check if the data is numeric
89 std::istringstream istr(sdata);
90 double tmp;
91 istr >> tmp;
92 isNumeric = !istr.fail();
93 old_data = sdata;
94
95 change_times.emplace(stime, sdata);
96 }
97
98 if (change_times.empty())
99 return nullptr;
100
101 if (isNumeric) {
103 auto it = change_times.begin();
104 for (; it != change_times.end(); ++it) {
105 std::istringstream istr(it->second);
106 double d;
107 istr >> d;
108 logv->addValue(it->first, d);
109 }
110 return logv;
111 } else {
113 auto it = change_times.begin();
114 for (; it != change_times.end(); ++it) {
115 logv->addValue(it->first, it->second);
116 }
117 return logv;
118 }
119 return nullptr;
120}
121
129 CommandMap command_map;
130
131 if (newStyle) {
132 command_map["START_COLLECTION"] = commands::BEGIN;
133 command_map["STOP_COLLECTION"] = commands::END;
134 command_map["CHANGE"] = commands::CHANGE_PERIOD;
135 command_map["CHANGE_PERIOD"] = commands::CHANGE_PERIOD;
136 command_map["ABORT"] = commands::ABORT;
137 } else {
138 command_map["BEGIN"] = commands::BEGIN;
139 command_map["RESUME"] = commands::BEGIN;
140 command_map["END_SE_WAIT"] = commands::BEGIN;
141 command_map["PAUSE"] = commands::END;
142 command_map["END"] = commands::END;
143 command_map["ABORT"] = commands::ABORT;
144 command_map["UPDATE"] = commands::END;
145 command_map["START_SE_WAIT"] = commands::END;
146 command_map["CHANGE"] = commands::CHANGE_PERIOD;
147 command_map["CHANGE_PERIOD"] = commands::CHANGE_PERIOD;
148 }
149 return command_map;
150}
151
159void LogParser::tryParsePeriod(const std::string &scom, const DateAndTime &time, std::istringstream &idata,
160 Kernel::TimeSeriesProperty<int> *const periods) {
161 int ip = -1;
162 bool shouldAddPeriod = false;
163 // Handle the version where log flag is CHANGE PERIOD
164 if (scom == "CHANGE") {
165 std::string s;
166 idata >> s >> ip;
167 if (ip > 0 && s == "PERIOD") {
168 shouldAddPeriod = true;
169 }
170 }
171 // Handle the version where log flat is CHANGE_PERIOD
172 else if (scom == "CHANGE_PERIOD") {
173 idata >> ip;
174 if (ip > 0) {
175 shouldAddPeriod = true;
176 }
177 }
178 // Common for either variant of the log flag.
179 if (shouldAddPeriod) {
180 if (ip > m_nOfPeriods) {
181 m_nOfPeriods = ip;
182 }
183 periods->addValue(time, ip);
184 }
185}
186
190LogParser::LogParser(const Kernel::Property *log) : m_nOfPeriods(1) {
193
194 const auto *icpLog = dynamic_cast<const Kernel::TimeSeriesProperty<std::string> *>(log);
195 if (!icpLog || icpLog->size() == 0) {
196 m_periods->addValue(Types::Core::DateAndTime(), 1);
197 m_status->addValue(Types::Core::DateAndTime(), true);
198 g_log.information() << "Cannot process ICPevent log. Period 1 assumed for all data.\n";
199 return;
200 }
201
202 std::multimap<Types::Core::DateAndTime, std::string> logm = icpLog->valueAsMultiMap();
204
205 m_nOfPeriods = 1;
206
207 auto it = logm.begin();
208
209 for (; it != logm.end(); ++it) {
210 std::string scom;
211 std::istringstream idata(it->second);
212 idata >> scom;
213 commands com = command_map[scom];
214 if (com == commands::CHANGE_PERIOD) {
215 tryParsePeriod(scom, it->first, idata, m_periods.get());
216 } else if (com == commands::BEGIN) {
217 m_status->addValue(it->first, true);
218 } else if (com == commands::END) {
219 m_status->addValue(it->first, false);
220 } else if (com == commands::ABORT) {
221 // Set all previous values to false
222 const auto &times = m_status->timesAsVector();
223 const std::vector<bool> values(times.size(), false);
224 m_status->replaceValues(times, values);
225 // Add a new value at the present time
226 m_status->addValue(it->first, false);
227 }
228 };
229
230 if (m_periods->size() == 0)
231 m_periods->addValue(icpLog->firstTime(), 1);
232 if (m_status->size() == 0)
233 m_status->addValue(icpLog->firstTime(), true);
234}
235
242 auto const *periods = dynamic_cast<Kernel::TimeSeriesProperty<int> *>(m_periods.get());
243 if (!periods) {
244 throw std::logic_error("Failed to cast periods to TimeSeriesProperty");
245 }
247 std::map<Types::Core::DateAndTime, int> pMap = periods->valueAsMap();
248 auto it = pMap.begin();
249 if (it->second != period)
250 p->addValue(it->first, false);
251 for (; it != pMap.end(); ++it) {
252
253 p->addValue(it->first, (it->second == period));
254 }
255
256 return std::move(p);
257}
258
259const std::string LogParser::currentPeriodLogName(const int period) {
260 std::ostringstream ostr;
261 ostr << period;
262 return "period " + ostr.str();
263}
264
270 Kernel::PropertyWithValue<int> *currentPeriodProperty =
272 return currentPeriodProperty;
273}
274
277
280
281namespace {
283struct hasNewStyleCommands {
284 bool operator()(const std::pair<Mantid::Types::Core::DateAndTime, std::string> &p) {
285 return p.second.find(START_COLLECTION) != std::string::npos || p.second.find(STOP_COLLECTION) != std::string::npos;
286 }
287};
288} // namespace
289
296bool LogParser::isICPEventLogNewStyle(const std::multimap<Types::Core::DateAndTime, std::string> &logm) {
297 hasNewStyleCommands checker;
298
299 return std::find_if(logm.begin(), logm.end(), checker) != logm.end();
300}
301
314double timeMean(const Kernel::Property *p, const Kernel::TimeROI *roi) {
315 const auto *dp = dynamic_cast<const Kernel::TimeSeriesProperty<double> *>(p);
316 if (!dp) {
317 throw std::runtime_error("Property of a wrong type. Cannot be cast to a "
318 "TimeSeriesProperty<double>.");
319 }
320
321 return dp->timeAverageValue(roi);
322}
323
324} // namespace Kernel
325} // namespace Mantid
std::string name
Definition Run.cpp:60
gsl_vector * tmp
constexpr const char * STOP_COLLECTION
Definition LogParser.cpp:21
constexpr const char * START_COLLECTION
Definition LogParser.cpp:20
static Kernel::Property * createLogProperty(const std::string &logFName, const std::string &name)
Creates a TimeSeriesProperty of either double or string type depending on the log data Returns a poin...
Definition LogParser.cpp:39
std::shared_ptr< Kernel::TimeSeriesProperty< bool > > m_status
TimeSeriesProperty<bool> containing running status. Created by LogParser.
Definition LogParser.h:100
LogParser(const Kernel::Property *log)
Create given the icpevent log property.
static const std::string statusLogName()
Returns the name of the log created that defines the status during a run.
Definition LogParser.h:47
Kernel::Property * createAllPeriodsLog() const
Creates a TimeSeriesProperty<int> with all data periods.
static bool isICPEventLogNewStyle(const std::multimap< Types::Core::DateAndTime, std::string > &logm)
Check if the icp log commands are in the new style.
std::map< std::string, commands > CommandMap
Typedef for a map of string commands to an enum of strongly typed commands.
Definition LogParser.h:94
static const std::string currentPeriodLogName()
Returns the name of the log that contains the current period number.
Definition LogParser.h:45
Kernel::TimeSeriesProperty< bool > * createRunningLog() const
Creates a TimeSeriesProperty<bool> with running status.
commands
Available commands.
Definition LogParser.h:90
void tryParsePeriod(const std::string &scom, const Types::Core::DateAndTime &time, std::istringstream &idata, Kernel::TimeSeriesProperty< int > *const periods)
Try to parse period data.
std::shared_ptr< Kernel::TimeSeriesProperty< int > > m_periods
TimeSeriesProperty<int> containing data periods. Created by LogParser.
Definition LogParser.h:97
static const std::string periodsLogName()
Returns the name of the log that contains all of the periods.
Definition LogParser.h:51
Kernel::Property * createCurrentPeriodLog(const int &period) const
Creates a log value for the current period.
Kernel::TimeSeriesProperty< bool > * createPeriodLog(int period) const
Creates a TimeSeriesProperty<bool> showing times when a particular period was active.
CommandMap createCommandMap(bool newStyle) const
Creates a map of all available old-style commands.
int m_nOfPeriods
Number of periods.
Definition LogParser.h:103
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
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.
Base class for properties.
Definition Property.h:94
virtual Property * clone() const =0
'Virtual copy constructor'
TimeROI : Object that holds information about when the time measurement was active.
Definition TimeROI.h:18
A specialised Property class for holding a series of time-value pairs.
TimeSeriesProperty< TYPE > * clone() const override
"Virtual" copy constructor
void addValue(const Types::Core::DateAndTime &time, const TYPE &value)
Add a value to the map using a DateAndTime object.
MANTID_KERNEL_DLL std::istream & extractToEOL(std::istream &is, std::string &str)
Extract a line from input stream, discarding any EOL characters encountered.
Definition Strings.cpp:1167
MANTID_KERNEL_DLL double timeMean(const Kernel::Property *p, const TimeROI *roi=nullptr)
Returns the mean value if the property is TimeSeriesProperty<double>
Helper class which provides the Collimation Length for SANS instruments.