##// END OF EJS Templates
Merge branch 'feature/MockSpectrogram' into develop
Alexandre Leroux -
r898:c7e7c81a51b1 merge
parent child
Show More
@@ -1,211 +1,274
1 1 #include "CosinusProvider.h"
2 2 #include "MockDefs.h"
3 3
4 4 #include <Data/DataProviderParameters.h>
5 5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 7 #include <Data/VectorSeries.h>
7 8
8 9 #include <cmath>
9 10
10 11 #include <QFuture>
11 12 #include <QThread>
12 13 #include <QtConcurrent/QtConcurrent>
13 14
14 15 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
15 16
16 17 namespace {
17 18
19 /// Number of bands generated for a spectrogram
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21
18 22 /// Abstract cosinus type
19 23 struct ICosinusType {
20 24 virtual ~ICosinusType() = default;
21 25 /// @return the number of components generated for the type
22 26 virtual int componentCount() const = 0;
23 27 /// @return the data series created for the type
24 28 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
25 29 std::vector<double> valuesData,
26 30 Unit xAxisUnit,
27 31 Unit valuesUnit) const = 0;
32 /// Generates values (one value per component)
33 /// @param x the x-axis data used to generate values
34 /// @param values the vector in which to insert the generated values
35 /// @param dataIndex the index of insertion of the generated values
36 ///
37 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
28 38 };
29 39
30 40 struct ScalarCosinus : public ICosinusType {
31 41 int componentCount() const override { return 1; }
32 42
33 43 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
34 44 std::vector<double> valuesData, Unit xAxisUnit,
35 45 Unit valuesUnit) const override
36 46 {
37 47 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
38 48 xAxisUnit, valuesUnit);
39 49 }
50
51 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
52 {
53 values[dataIndex] = std::cos(x);
54 }
40 55 };
56
57 struct SpectrogramCosinus : public ICosinusType {
58 /// Ctor with y-axis
59 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit)
60 : m_YAxisData{std::move(yAxisData)}, m_YAxisUnit{std::move(yAxisUnit)}
61 {
62 }
63
64 int componentCount() const override { return m_YAxisData.size(); }
65
66 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
67 std::vector<double> valuesData, Unit xAxisUnit,
68 Unit valuesUnit) const override
69 {
70 return std::make_shared<SpectrogramSeries>(std::move(xAxisData), m_YAxisData,
71 std::move(valuesData), xAxisUnit, m_YAxisUnit,
72 valuesUnit);
73 }
74
75 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
76 {
77 auto componentCount = this->componentCount();
78 for (int i = 0; i < componentCount; ++i) {
79 auto y = m_YAxisData[i];
80 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
81 auto value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
82
83 values[componentCount * dataIndex + i] = value;
84 }
85 }
86
87 std::vector<double> m_YAxisData;
88 Unit m_YAxisUnit;
89 };
90
41 91 struct VectorCosinus : public ICosinusType {
42 92 int componentCount() const override { return 3; }
43 93
44 94 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
45 95 std::vector<double> valuesData, Unit xAxisUnit,
46 96 Unit valuesUnit) const override
47 97 {
48 98 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
49 99 xAxisUnit, valuesUnit);
50 100 }
101
102 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
103 {
104 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
105 auto xValue = std::cos(x);
106 auto componentCount = this->componentCount();
107 for (auto i = 0; i < componentCount; ++i) {
108 values[componentCount * dataIndex + i] = xValue / (i + 1);
109 }
110 }
51 111 };
52 112
53 113 /// Converts string to cosinus type
54 114 /// @return the cosinus type if the string could be converted, nullptr otherwise
55 115 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
56 116 {
57 117 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
58 118 return std::make_unique<ScalarCosinus>();
59 119 }
120 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
121 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
122 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
123 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
124
125 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"});
126 }
60 127 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
61 128 return std::make_unique<VectorCosinus>();
62 129 }
63 130 else {
64 131 return nullptr;
65 132 }
66 133 }
67 134
68 135 } // namespace
69 136
70 137 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
71 138 {
72 139 // No copy is made in clone
73 140 return std::make_shared<CosinusProvider>();
74 141 }
75 142
76 143 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
77 144 const SqpRange &dataRangeRequested,
78 145 const QVariantHash &data)
79 146 {
80 147 // TODO: Add Mutex
81 148 auto dataIndex = 0;
82 149
83 150 // Retrieves cosinus type
84 151 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
85 152 if (!typeVariant.canConvert<QString>()) {
86 153 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
87 154 return nullptr;
88 155 }
89 156
90 157 auto type = cosinusType(typeVariant.toString());
91 158 if (!type) {
92 159 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
93 160 return nullptr;
94 161 }
95 162
96 163 // Retrieves frequency
97 164 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
98 165 if (!freqVariant.canConvert<double>()) {
99 166 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
100 167 return nullptr;
101 168 }
102 169
103 170 // Gets the timerange from the parameters
104 171 double freq = freqVariant.toDouble();
105 172 double start = std::ceil(dataRangeRequested.m_TStart * freq);
106 173 double end = std::floor(dataRangeRequested.m_TEnd * freq);
107 174
108 175 // We assure that timerange is valid
109 176 if (end < start) {
110 177 std::swap(start, end);
111 178 }
112 179
113 180 // Generates scalar series containing cosinus values (one value per second, end value is
114 181 // included)
115 182 auto dataCount = end - start + 1;
116 183
117 184 // Number of components (depending on the cosinus type)
118 185 auto componentCount = type->componentCount();
119 186
120 187 auto xAxisData = std::vector<double>{};
121 188 xAxisData.resize(dataCount);
122 189
123 190 auto valuesData = std::vector<double>{};
124 191 valuesData.resize(dataCount * componentCount);
125 192
126 193 int progress = 0;
127 194 auto progressEnd = dataCount;
128 195 for (auto time = start; time <= end; ++time, ++dataIndex) {
129 196 auto it = m_VariableToEnableProvider.find(acqIdentifier);
130 197 if (it != m_VariableToEnableProvider.end() && it.value()) {
131 const auto timeOnFreq = time / freq;
198 const auto x = time / freq;
132 199
133 xAxisData[dataIndex] = timeOnFreq;
200 xAxisData[dataIndex] = x;
134 201
135 // Generates all components' values
136 // Example: for a vector, values will be : cos(x), cos(x)/2, cos(x)/3
137 auto value = std::cos(timeOnFreq);
138 for (auto i = 0; i < componentCount; ++i) {
139 valuesData[componentCount * dataIndex + i] = value / (i + 1);
140 }
202 // Generates values (depending on the type)
203 type->generateValues(x, valuesData, dataIndex);
141 204
142 205 // progression
143 206 int currentProgress = (time - start) * 100.0 / progressEnd;
144 207 if (currentProgress != progress) {
145 208 progress = currentProgress;
146 209
147 210 emit dataProvidedProgress(acqIdentifier, progress);
148 211 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
149 212 << QThread::currentThread()->objectName()
150 213 << progress;
151 214 // NOTE: Try to use multithread if possible
152 215 }
153 216 }
154 217 else {
155 218 if (!it.value()) {
156 219 qCDebug(LOG_CosinusProvider())
157 220 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
158 221 << end - time;
159 222 }
160 223 }
161 224 }
162 225 if (progress != 100) {
163 226 // We can close progression beacause all data has been retrieved
164 227 emit dataProvidedProgress(acqIdentifier, 100);
165 228 }
166 229 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
167 230 Unit{QStringLiteral("t"), true}, Unit{});
168 231 }
169 232
170 233 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
171 234 const DataProviderParameters &parameters)
172 235 {
173 236 // TODO: Add Mutex
174 237 m_VariableToEnableProvider[acqIdentifier] = true;
175 238 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
176 239 << QThread::currentThread()->objectName();
177 240 // NOTE: Try to use multithread if possible
178 241 const auto times = parameters.m_Times;
179 242
180 243 for (const auto &dateTime : qAsConst(times)) {
181 244 if (m_VariableToEnableProvider[acqIdentifier]) {
182 245 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
183 246 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
184 247 }
185 248 }
186 249 }
187 250
188 251 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
189 252 {
190 253 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
191 254 << QThread::currentThread()->objectName();
192 255 auto it = m_VariableToEnableProvider.find(acqIdentifier);
193 256 if (it != m_VariableToEnableProvider.end()) {
194 257 it.value() = false;
195 258 }
196 259 else {
197 260 qCDebug(LOG_CosinusProvider())
198 261 << tr("Aborting progression of inexistant identifier detected !!!");
199 262 }
200 263 }
201 264
202 265 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
203 266 const QVariantHash &data)
204 267 {
205 268 auto uid = QUuid::createUuid();
206 269 m_VariableToEnableProvider[uid] = true;
207 270 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
208 271
209 272 m_VariableToEnableProvider.remove(uid);
210 273 return dataSeries;
211 274 }
@@ -1,109 +1,114
1 1 #include "MockPlugin.h"
2 2 #include "CosinusProvider.h"
3 3 #include "MockDefs.h"
4 4
5 5 #include <DataSource/DataSourceController.h>
6 6 #include <DataSource/DataSourceItem.h>
7 7 #include <DataSource/DataSourceItemAction.h>
8 8
9 9 #include <SqpApplication.h>
10 10
11 11 Q_LOGGING_CATEGORY(LOG_MockPlugin, "MockPlugin")
12 12
13 13 namespace {
14 14
15 15 /// Name of the data source
16 16 const auto DATA_SOURCE_NAME = QStringLiteral("MMS");
17 17
18 18 /// Creates the data provider relative to the plugin
19 19 std::unique_ptr<IDataProvider> createDataProvider() noexcept
20 20 {
21 21 return std::make_unique<CosinusProvider>();
22 22 }
23 23
24 24 std::unique_ptr<DataSourceItem> createProductItem(const QVariantHash &data,
25 25 const QUuid &dataSourceUid)
26 26 {
27 27 auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT, data);
28 28 auto productName = data.value(DataSourceItem::NAME_DATA_KEY).toString();
29 29
30 30 // Add action to load product from DataSourceController
31 31 result->addAction(std::make_unique<DataSourceItemAction>(
32 32 QObject::tr("Load %1 product").arg(productName),
33 33 [productName, dataSourceUid](DataSourceItem &item) {
34 34 if (auto app = sqpApp) {
35 35 app->dataSourceController().loadProductItem(dataSourceUid, item);
36 36 }
37 37 }));
38 38
39 39 return result;
40 40 }
41 41
42 42 /// Creates the data source item relative to the plugin
43 43 std::unique_ptr<DataSourceItem> createDataSourceItem(const QUuid &dataSourceUid) noexcept
44 44 {
45 45 // Magnetic field products
46 46 auto magneticFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
47 47 QStringLiteral("Magnetic field"));
48 48 magneticFieldFolder->appendChild(
49 49 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 10 Hz")},
50 50 {COSINUS_TYPE_KEY, "scalar"},
51 51 {COSINUS_FREQUENCY_KEY, 10.}},
52 52 dataSourceUid));
53 53 magneticFieldFolder->appendChild(
54 54 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 60 Hz")},
55 55 {COSINUS_TYPE_KEY, "scalar"},
56 56 {COSINUS_FREQUENCY_KEY, 60.}},
57 57 dataSourceUid));
58 58 magneticFieldFolder->appendChild(
59 59 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Scalar 100 Hz")},
60 60 {COSINUS_TYPE_KEY, "scalar"},
61 61 {COSINUS_FREQUENCY_KEY, 100.}},
62 62 dataSourceUid));
63 63 magneticFieldFolder->appendChild(
64 64 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 10 Hz")},
65 65 {COSINUS_TYPE_KEY, "vector"},
66 66 {COSINUS_FREQUENCY_KEY, 10.}},
67 67 dataSourceUid));
68 68 magneticFieldFolder->appendChild(
69 69 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 60 Hz")},
70 70 {COSINUS_TYPE_KEY, "vector"},
71 71 {COSINUS_FREQUENCY_KEY, 60.}},
72 72 dataSourceUid));
73 73 magneticFieldFolder->appendChild(
74 74 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Vector 100 Hz")},
75 75 {COSINUS_TYPE_KEY, "vector"},
76 76 {COSINUS_FREQUENCY_KEY, 100.}},
77 77 dataSourceUid));
78 magneticFieldFolder->appendChild(
79 createProductItem({{DataSourceItem::NAME_DATA_KEY, QStringLiteral("Spectrogram 1 Hz")},
80 {COSINUS_TYPE_KEY, "spectrogram"},
81 {COSINUS_FREQUENCY_KEY, 1.}},
82 dataSourceUid));
78 83
79 84 // Electric field products
80 85 auto electricFieldFolder = std::make_unique<DataSourceItem>(DataSourceItemType::NODE,
81 86 QStringLiteral("Electric field"));
82 87
83 88 // Root
84 89 auto root = std::make_unique<DataSourceItem>(DataSourceItemType::NODE, DATA_SOURCE_NAME);
85 90 root->appendChild(std::move(magneticFieldFolder));
86 91 root->appendChild(std::move(electricFieldFolder));
87 92
88 93 return root;
89 94 }
90 95
91 96 } // namespace
92 97
93 98 void MockPlugin::initialize()
94 99 {
95 100 if (auto app = sqpApp) {
96 101 // Registers to the data source controller
97 102 auto &dataSourceController = app->dataSourceController();
98 103 auto dataSourceUid = dataSourceController.registerDataSource(DATA_SOURCE_NAME);
99 104
100 105 // Sets data source tree
101 106 dataSourceController.setDataSourceItem(dataSourceUid, createDataSourceItem(dataSourceUid));
102 107
103 108 // Sets data provider
104 109 dataSourceController.setDataProvider(dataSourceUid, createDataProvider());
105 110 }
106 111 else {
107 112 qCWarning(LOG_MockPlugin()) << tr("Can't access to SciQlop application");
108 113 }
109 114 }
General Comments 0
You need to be logged in to leave comments. Login now