##// END OF EJS Templates
Updates data series creation according to the value type (vector or scalar)
Alexandre Leroux -
r532:522bb785789b
parent child
Show More
@@ -1,194 +1,216
1 1 #include "AmdaResultParser.h"
2 2
3 3 #include <Common/DateUtils.h>
4 4 #include <Data/ScalarSeries.h>
5 #include <Data/VectorSeries.h>
5 6
6 7 #include <QDateTime>
7 8 #include <QFile>
8 9 #include <QRegularExpression>
9 10
10 11 #include <cmath>
11 12
12 13 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
13 14
14 15 namespace {
15 16
16 17 /// Message in result file when the file was not found on server
17 18 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
18 19
19 20 /// Format for dates in result files
20 21 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
21 22
22 23 /// Separator between values in a result line
23 24 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
24 25
25 26 /// Regex to find unit in a line. Examples of valid lines:
26 27 /// ... - Units : nT - ...
27 28 /// ... -Units:nT- ...
28 29 /// ... -Units: mΒ²- ...
29 30 /// ... - Units : m/s - ...
30 31 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
31 32
32 33 /// Converts a string date to a double date
33 34 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
34 35 double doubleDate(const QString &stringDate) noexcept
35 36 {
36 37 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
37 38 dateTime.setTimeSpec(Qt::UTC);
38 39 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
39 40 : std::numeric_limits<double>::quiet_NaN();
40 41 }
41 42
42 43 /// Checks if a line is a comment line
43 44 bool isCommentLine(const QString &line)
44 45 {
45 46 return line.startsWith("#");
46 47 }
47 48
48 49 /// @return the number of lines to be read depending on the type of value passed in parameter
49 50 int nbValues(AmdaResultParser::ValueType valueType) noexcept
50 51 {
51 52 switch (valueType) {
52 53 case AmdaResultParser::ValueType::SCALAR:
53 54 return 1;
54 55 case AmdaResultParser::ValueType::VECTOR:
55 56 return 3;
56 57 case AmdaResultParser::ValueType::UNKNOWN:
57 58 // Invalid case
58 59 break;
59 60 }
60 61
61 62 // Invalid cases
62 63 qCCritical(LOG_AmdaResultParser())
63 64 << QObject::tr("Can't get the number of values to read: unsupported type");
64 65 return 0;
65 66 }
66 67
67 68 /**
68 69 * Reads stream to retrieve x-axis unit
69 70 * @param stream the stream to read
70 71 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
71 72 * error occured during reading
72 73 */
73 74 Unit readXAxisUnit(QTextStream &stream)
74 75 {
75 76 QString line{};
76 77
77 78 // Searches unit in the comment lines
78 79 while (stream.readLineInto(&line) && isCommentLine(line)) {
79 80 auto match = UNIT_REGEX.match(line);
80 81 if (match.hasMatch()) {
81 82 return Unit{match.captured(1), true};
82 83 }
83 84 }
84 85
85 86 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
86 87
87 88 // Error cases
88 89 return Unit{{}, true};
89 90 }
90 91
91 92 /**
92 93 * Reads stream to retrieve results
93 94 * @param stream the stream to read
94 95 * @return the pair of vectors x-axis data/values data that has been read in the stream
95 96 */
96 97 QPair<QVector<double>, QVector<QVector<double> > >
97 98 readResults(QTextStream &stream, AmdaResultParser::ValueType valueType)
98 99 {
99 100 auto expectedNbValues = nbValues(valueType);
100 101
101 102 auto xData = QVector<double>{};
102 103 auto valuesData = QVector<QVector<double> >(expectedNbValues);
103 104
104 105 QString line{};
105 106
106 107 while (stream.readLineInto(&line)) {
107 108 // Ignore comment lines
108 109 if (!isCommentLine(line)) {
109 110 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
110 111 if (lineData.size() == expectedNbValues + 1) {
111 112 // X : the data is converted from date to double (in secs)
112 113 auto x = doubleDate(lineData.at(0));
113 114
114 115 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
115 116 if (!std::isnan(x)) {
116 117 xData.push_back(x);
117 118
118 119 // Values
119 120 for (auto valueIndex = 0; valueIndex < expectedNbValues; ++valueIndex) {
120 121 auto column = valueIndex + 1;
121 122
122 123 bool valueOk;
123 124 auto value = lineData.at(column).toDouble(&valueOk);
124 125
125 126 if (!valueOk) {
126 127 qCWarning(LOG_AmdaResultParser())
127 128 << QObject::tr(
128 129 "Value from (line %1, column %2) is invalid and will be "
129 130 "converted to NaN")
130 131 .arg(line, column);
131 132 value = std::numeric_limits<double>::quiet_NaN();
132 133 }
133 134 valuesData[valueIndex].append(value);
134 135 }
135 136 }
136 137 else {
137 138 qCWarning(LOG_AmdaResultParser())
138 139 << QObject::tr("Can't retrieve results from line %1: x is invalid")
139 140 .arg(line);
140 141 }
141 142 }
142 143 else {
143 144 qCWarning(LOG_AmdaResultParser())
144 145 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
145 146 }
146 147 }
147 148 }
148 149
149 150 return qMakePair(std::move(xData), std::move(valuesData));
150 151 }
151 152
152 153 } // namespace
153 154
154 155 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
155 156 ValueType valueType) noexcept
156 157 {
157 158 if (valueType == ValueType::UNKNOWN) {
158 159 qCCritical(LOG_AmdaResultParser())
159 160 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
160 161 return nullptr;
161 162 }
162 163
163 164 QFile file{filePath};
164 165
165 166 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
166 167 qCCritical(LOG_AmdaResultParser())
167 168 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
168 169 .arg(filePath, file.errorString());
169 170 return nullptr;
170 171 }
171 172
172 173 QTextStream stream{&file};
173 174
174 175 // Checks if the file was found on the server
175 176 auto firstLine = stream.readLine();
176 177 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
177 178 qCCritical(LOG_AmdaResultParser())
178 179 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
179 180 .arg(filePath);
180 181 return nullptr;
181 182 }
182 183
183 184 // Reads x-axis unit
184 185 stream.seek(0); // returns to the beginning of the file
185 186 auto xAxisUnit = readXAxisUnit(stream);
186 187
187 188 // Reads results
188 189 stream.seek(0); // returns to the beginning of the file
189 190 auto results = readResults(stream, valueType);
190 191
192 // Creates data series
193 switch (valueType) {
194 case ValueType::SCALAR:
195 Q_ASSERT(results.second.size() == 1);
196 return std::make_shared<ScalarSeries>(
197 std::move(results.first), std::move(results.second.takeFirst()), xAxisUnit, Unit{});
198 case ValueType::VECTOR: {
199 Q_ASSERT(results.second.size() == 3);
200 auto xValues = results.second.takeFirst();
201 auto yValues = results.second.takeFirst();
202 auto zValues = results.second.takeFirst();
203 return std::make_shared<VectorSeries>(std::move(results.first), std::move(xValues),
204 std::move(yValues), std::move(zValues), xAxisUnit,
205 Unit{});
206 }
207 case ValueType::UNKNOWN:
208 // Invalid case
209 break;
210 }
191 211
192 return std::make_shared<ScalarSeries>(std::move(results.first), std::move(results.second),
193 xAxisUnit, Unit{});
212 // Invalid cases
213 qCCritical(LOG_AmdaResultParser())
214 << QObject::tr("Can't create data series: unsupported value type");
215 return nullptr;
194 216 }
General Comments 0
You need to be logged in to leave comments. Login now