##// END OF EJS Templates
Updates AMDA result parser to accept NaN values...
Alexandre Leroux -
r496:10850ea661a6
parent child
Show More
@@ -1,152 +1,160
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Common/DateUtils.h>
4 4 #include <Data/ScalarSeries.h>
5 5
6 6 #include <QDateTime>
7 7 #include <QFile>
8 8 #include <QRegularExpression>
9 9
10 10 #include <cmath>
11 11
12 12 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
13 13
14 14 namespace {
15 15
16 16 /// Message in result file when the file was not found on server
17 17 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
18 18
19 19 /// Format for dates in result files
20 20 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
21 21
22 22 /// Separator between values in a result line
23 23 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
24 24
25 25 /// Regex to find unit in a line. Examples of valid lines:
26 26 /// ... - Units : nT - ...
27 27 /// ... -Units:nT- ...
28 28 /// ... -Units: mΒ²- ...
29 29 /// ... - Units : m/s - ...
30 30 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
31 31
32 32 /// Converts a string date to a double date
33 33 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
34 34 double doubleDate(const QString &stringDate) noexcept
35 35 {
36 36 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
37 37 dateTime.setTimeSpec(Qt::UTC);
38 38 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
39 39 : std::numeric_limits<double>::quiet_NaN();
40 40 }
41 41
42 42 /// Checks if a line is a comment line
43 43 bool isCommentLine(const QString &line)
44 44 {
45 45 return line.startsWith("#");
46 46 }
47 47
48 48 /**
49 49 * Reads stream to retrieve x-axis unit
50 50 * @param stream the stream to read
51 51 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
52 52 * error occured during reading
53 53 */
54 54 Unit readXAxisUnit(QTextStream &stream)
55 55 {
56 56 QString line{};
57 57
58 58 // Searches unit in the comment lines
59 59 while (stream.readLineInto(&line) && isCommentLine(line)) {
60 60 auto match = UNIT_REGEX.match(line);
61 61 if (match.hasMatch()) {
62 62 return Unit{match.captured(1), true};
63 63 }
64 64 }
65 65
66 66 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
67 67
68 68 // Error cases
69 69 return Unit{{}, true};
70 70 }
71 71
72 72 /**
73 73 * Reads stream to retrieve results
74 74 * @param stream the stream to read
75 75 * @return the pair of vectors x-axis data/values data that has been read in the stream
76 76 */
77 77 QPair<QVector<double>, QVector<double> > readResults(QTextStream &stream)
78 78 {
79 79 auto xData = QVector<double>{};
80 80 auto valuesData = QVector<double>{};
81 81
82 82 QString line{};
83 83
84 84 while (stream.readLineInto(&line)) {
85 85 // Ignore comment lines
86 86 if (!isCommentLine(line)) {
87 87 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
88 88 if (lineData.size() == 2) {
89 89 // X : the data is converted from date to double (in secs)
90 90 auto x = doubleDate(lineData.at(0));
91 91
92 92 // Value
93 93 bool valueOk;
94 94 auto value = lineData.at(1).toDouble(&valueOk);
95 95
96 // Adds result only if x and value are valid
97 if (!std::isnan(x) && !std::isnan(value) && valueOk) {
96 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
97 if (!std::isnan(x)) {
98 98 xData.push_back(x);
99
100 if (!valueOk) {
101 qCWarning(LOG_AmdaResultParser())
102 << QObject::tr(
103 "Value from line %1 is invalid and will be converted to NaN")
104 .arg(line);
105 value = std::numeric_limits<double>::quiet_NaN();
106 }
107
99 108 valuesData.push_back(value);
100 109 }
101 110 else {
102 111 qCWarning(LOG_AmdaResultParser())
103 << QObject::tr(
104 "Can't retrieve results from line %1: x and/or value are invalid")
112 << QObject::tr("Can't retrieve results from line %1: x is invalid")
105 113 .arg(line);
106 114 }
107 115 }
108 116 else {
109 117 qCWarning(LOG_AmdaResultParser())
110 118 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
111 119 }
112 120 }
113 121 }
114 122
115 123 return qMakePair(std::move(xData), std::move(valuesData));
116 124 }
117 125
118 126 } // namespace
119 127
120 128 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath) noexcept
121 129 {
122 130 QFile file{filePath};
123 131
124 132 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
125 133 qCCritical(LOG_AmdaResultParser())
126 134 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
127 135 .arg(filePath, file.errorString());
128 136 return nullptr;
129 137 }
130 138
131 139 QTextStream stream{&file};
132 140
133 141 // Checks if the file was found on the server
134 142 auto firstLine = stream.readLine();
135 143 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
136 144 qCCritical(LOG_AmdaResultParser())
137 145 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
138 146 .arg(filePath);
139 147 return nullptr;
140 148 }
141 149
142 150 // Reads x-axis unit
143 151 stream.seek(0); // returns to the beginning of the file
144 152 auto xAxisUnit = readXAxisUnit(stream);
145 153
146 154 // Reads results
147 155 stream.seek(0); // returns to the beginning of the file
148 156 auto results = readResults(stream);
149 157
150 158 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
151 159 xAxisUnit, Unit{});
152 160 }
General Comments 0
You need to be logged in to leave comments. Login now