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