##// END OF EJS Templates
Updates method for reading results according to the value type (vector or scalar)
Alexandre Leroux -
r564:c797ff6ef110
parent child
Show More
@@ -1,167 +1,194
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 /// @return the number of lines to be read depending on the type of value passed in parameter
49 int nbValues(AmdaResultParser::ValueType valueType) noexcept
50 {
51 switch (valueType) {
52 case AmdaResultParser::ValueType::SCALAR:
53 return 1;
54 case AmdaResultParser::ValueType::VECTOR:
55 return 3;
56 case AmdaResultParser::ValueType::UNKNOWN:
57 // Invalid case
58 break;
59 }
60
61 // Invalid cases
62 qCCritical(LOG_AmdaResultParser())
63 << QObject::tr("Can't get the number of values to read: unsupported type");
64 return 0;
65 }
66
48 67 /**
49 68 * Reads stream to retrieve x-axis unit
50 69 * @param stream the stream to read
51 70 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
52 71 * error occured during reading
53 72 */
54 73 Unit readXAxisUnit(QTextStream &stream)
55 74 {
56 75 QString line{};
57 76
58 77 // Searches unit in the comment lines
59 78 while (stream.readLineInto(&line) && isCommentLine(line)) {
60 79 auto match = UNIT_REGEX.match(line);
61 80 if (match.hasMatch()) {
62 81 return Unit{match.captured(1), true};
63 82 }
64 83 }
65 84
66 85 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
67 86
68 87 // Error cases
69 88 return Unit{{}, true};
70 89 }
71 90
72 91 /**
73 92 * Reads stream to retrieve results
74 93 * @param stream the stream to read
75 94 * @return the pair of vectors x-axis data/values data that has been read in the stream
76 95 */
77 QPair<QVector<double>, QVector<double> > readResults(QTextStream &stream)
96 QPair<QVector<double>, QVector<QVector<double> > >
97 readResults(QTextStream &stream, AmdaResultParser::ValueType valueType)
78 98 {
99 auto expectedNbValues = nbValues(valueType);
100
79 101 auto xData = QVector<double>{};
80 auto valuesData = QVector<double>{};
102 auto valuesData = QVector<QVector<double> >(expectedNbValues);
81 103
82 104 QString line{};
83 105
84 106 while (stream.readLineInto(&line)) {
85 107 // Ignore comment lines
86 108 if (!isCommentLine(line)) {
87 109 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
88 if (lineData.size() == 2) {
110 if (lineData.size() == expectedNbValues + 1) {
89 111 // X : the data is converted from date to double (in secs)
90 112 auto x = doubleDate(lineData.at(0));
91 113
92 // Value
93 bool valueOk;
94 auto value = lineData.at(1).toDouble(&valueOk);
95
96 114 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
97 115 if (!std::isnan(x)) {
98 116 xData.push_back(x);
99 117
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();
118 // Values
119 for (auto valueIndex = 0; valueIndex < expectedNbValues; ++valueIndex) {
120 auto column = valueIndex + 1;
121
122 bool valueOk;
123 auto value = lineData.at(column).toDouble(&valueOk);
124
125 if (!valueOk) {
126 qCWarning(LOG_AmdaResultParser())
127 << QObject::tr(
128 "Value from (line %1, column %2) is invalid and will be "
129 "converted to NaN")
130 .arg(line, column);
131 value = std::numeric_limits<double>::quiet_NaN();
132 }
133 valuesData[valueIndex].append(value);
106 134 }
107
108 valuesData.push_back(value);
109 135 }
110 136 else {
111 137 qCWarning(LOG_AmdaResultParser())
112 138 << QObject::tr("Can't retrieve results from line %1: x is invalid")
113 139 .arg(line);
114 140 }
115 141 }
116 142 else {
117 143 qCWarning(LOG_AmdaResultParser())
118 144 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
119 145 }
120 146 }
121 147 }
122 148
123 149 return qMakePair(std::move(xData), std::move(valuesData));
124 150 }
125 151
126 152 } // namespace
127 153
128 154 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
129 155 ValueType valueType) noexcept
130 156 {
131 157 if (valueType == ValueType::UNKNOWN) {
132 158 qCCritical(LOG_AmdaResultParser())
133 159 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
134 160 return nullptr;
135 161 }
136 162
137 163 QFile file{filePath};
138 164
139 165 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
140 166 qCCritical(LOG_AmdaResultParser())
141 167 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
142 168 .arg(filePath, file.errorString());
143 169 return nullptr;
144 170 }
145 171
146 172 QTextStream stream{&file};
147 173
148 174 // Checks if the file was found on the server
149 175 auto firstLine = stream.readLine();
150 176 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
151 177 qCCritical(LOG_AmdaResultParser())
152 178 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
153 179 .arg(filePath);
154 180 return nullptr;
155 181 }
156 182
157 183 // Reads x-axis unit
158 184 stream.seek(0); // returns to the beginning of the file
159 185 auto xAxisUnit = readXAxisUnit(stream);
160 186
161 187 // Reads results
162 188 stream.seek(0); // returns to the beginning of the file
163 auto results = readResults(stream);
189 auto results = readResults(stream, valueType);
190
164 191
165 192 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
166 193 xAxisUnit, Unit{});
167 194 }
General Comments 0
You need to be logged in to leave comments. Login now