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