##// END OF EJS Templates
Updated to fixed TS lib, added spectrogram min/max sampling hints when available...
jeandet -
r85:1e3f92d40b0e
parent child
Show More
@@ -1,1 +1,1
1 Subproject commit 22e3e4553178230053aac40131b4fdb36c163075
1 Subproject commit 1c245f84d0728d99b6f5deab7793fb238105a54d
@@ -1,35 +1,41
1 1 #ifndef SCIQLOP_SPECTROGRAMTIMESERIE_H
2 2 #define SCIQLOP_SPECTROGRAMTIMESERIE_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <TimeSeries.h>
7 #include <cmath>
7 8
8 9 class SCIQLOP_CORE_EXPORT SpectrogramTimeSerie
9 10 : public TimeSeries::TimeSerie<double, SpectrogramTimeSerie, 2>
10 11 {
11 12 public:
13 double min_sampling = std::nan("");
14 double max_sampling = std::nan("");
12 15 using item_t =
13 16 decltype(std::declval<
14 17 TimeSeries::TimeSerie<double, SpectrogramTimeSerie, 2>>()[0]);
15 18
16 19 using iterator_t = decltype(
17 20 std::declval<TimeSeries::TimeSerie<double, SpectrogramTimeSerie, 2>>()
18 21 .begin());
19 22
20 23 SpectrogramTimeSerie() {}
21 24 SpectrogramTimeSerie(SpectrogramTimeSerie::axis_t&& t,
22 25 SpectrogramTimeSerie::axis_t&& y,
23 26 SpectrogramTimeSerie::container_type<
24 27 SpectrogramTimeSerie::raw_value_type>&& values,
25 std::vector<std::size_t>& shape)
26 : TimeSeries::TimeSerie<double, SpectrogramTimeSerie, 2>(t, values, shape)
28 std::vector<std::size_t>& shape, double min_sampling,
29 double max_sampling)
30 : TimeSeries::TimeSerie<double, SpectrogramTimeSerie, 2>(t, values,
31 shape),
32 min_sampling{min_sampling}, max_sampling{max_sampling}
27 33 {
28 34 _axes[1] = y;
29 35 }
30 36
31 37 ~SpectrogramTimeSerie() = default;
32 38 using TimeSerie::TimeSerie;
33 39 };
34 40
35 41 #endif // SCIQLOP_SPECTROGRAMTIMESERIE_H
@@ -1,83 +1,93
1 1 #ifndef TIMESERIESUTILS_H
2 2 #define TIMESERIESUTILS_H
3 3 #include "MultiComponentTimeSerie.h"
4 4 #include "ScalarTimeSerie.h"
5 5 #include "SpectrogramTimeSerie.h"
6 6 #include "VectorTimeSerie.h"
7 7
8 8 #include <TimeSeries.h>
9 9 #include <cmath>
10 10 #include <memory>
11 11
12 12 namespace TimeSeriesUtils
13 13 {
14 14 template<typename T> TimeSeries::ITimeSerie* copy(T input_ts)
15 15 {
16 16 if constexpr(std::is_base_of_v<TimeSeries::ITimeSerie, T>)
17 17 {
18 18 if(auto ts = dynamic_cast<VectorTimeSerie*>(input_ts))
19 19 { return new VectorTimeSerie(*ts); }
20 20 if(auto ts = dynamic_cast<ScalarTimeSerie*>(input_ts))
21 21 { return new ScalarTimeSerie(*ts); }
22 22 if(auto ts = dynamic_cast<MultiComponentTimeSerie*>(input_ts))
23 23 { return new MultiComponentTimeSerie(*ts); }
24 24 if(auto ts = dynamic_cast<SpectrogramTimeSerie*>(input_ts))
25 25 { return new SpectrogramTimeSerie(*ts); }
26 26 }
27 27 else
28 28 {
29 29 if(auto ts = std::dynamic_pointer_cast<VectorTimeSerie>(input_ts))
30 30 { return new VectorTimeSerie(*ts); }
31 31 if(auto ts = std::dynamic_pointer_cast<ScalarTimeSerie>(input_ts))
32 32 { return new ScalarTimeSerie(*ts); }
33 33 if(auto ts = std::dynamic_pointer_cast<SpectrogramTimeSerie>(input_ts))
34 34 { return new SpectrogramTimeSerie(*ts); }
35 35 if(auto ts = std::dynamic_pointer_cast<MultiComponentTimeSerie>(input_ts))
36 36 { return new MultiComponentTimeSerie(*ts); }
37 37 }
38 38 return nullptr;
39 39 }
40 40
41 41 struct axis_properties
42 42 {
43 43 double range;
44 44 double max_resolution;
45 45 bool is_log;
46 double min;
47 double max;
46 48 };
47 49
48 50 constexpr auto IsLog = true;
49 51 constexpr auto IsLinear = false;
50 52
51 53 constexpr auto CheckMedian = true;
52 54 constexpr auto DontCheckMedian = false;
53 55
54 56 template<bool is_log, bool check_median>
55 57 axis_properties axis_analysis(
56 58 typename std::conditional<is_log, std::vector<double>&,
57 const std::vector<double>&>::type axis)
59 const std::vector<double>&>::type axis,
60 double given_max_resolution = std::nan(""))
58 61 {
59 62 std::vector<double> axis_diff(axis.size());
60 63 if constexpr(is_log)
61 64 {
62 65 std::transform(std::cbegin(axis), std::cend(axis), std::begin(axis),
63 66 [](const auto v) { return std::log10(v); });
64 67 }
65 auto range = *(std::cend(axis) - 1) - *(std::begin(axis));
66 std::adjacent_difference(std::cbegin(axis), std::cend(axis),
67 std::begin(axis_diff));
68 auto min_diff =
69 (*std::min_element(std::cbegin(axis_diff) + 1, std::cend(axis_diff)));
70 if constexpr(check_median)
68 auto min = *std::begin(axis);
69 auto max = *(std::cend(axis) - 1);
70 auto range = max - min;
71 auto min_diff = given_max_resolution;
72 if(std::isnan(min_diff))
71 73 {
72 std::nth_element(std::begin(axis_diff) + 1,
73 std::begin(axis_diff) + axis_diff.size() / 2,
74 std::end(axis_diff));
75 auto median_diff = *(std::begin(axis_diff) + axis_diff.size() / 2);
76 if(median_diff > (4 * min_diff)) min_diff = median_diff;
74 std::adjacent_difference(std::cbegin(axis), std::cend(axis),
75 std::begin(axis_diff));
76 min_diff =
77 (*std::min_element(std::cbegin(axis_diff) + 1, std::cend(axis_diff)));
78 if constexpr(check_median)
79 {
80 std::nth_element(std::begin(axis_diff) + 1,
81 std::begin(axis_diff) + axis_diff.size() / 2,
82 std::end(axis_diff));
83 auto median_diff = *(std::begin(axis_diff) + axis_diff.size() / 2);
84 if(median_diff > (4 * min_diff)) min_diff = median_diff;
85 }
77 86 }
78 return {range, min_diff, is_log};
87
88 return {range, min_diff, is_log, min, max};
79 89 }
80 90
81 91 } // namespace TimeSeriesUtils
82 92
83 93 #endif
@@ -1,148 +1,148
1 1 #include "Variable/VariableSynchronizationGroup2.h"
2 2
3 3 #include <Common/containers.h>
4 4 #include <Common/debug.h>
5 5 #include <Data/DataProviderParameters.h>
6 6 #include <Data/DateTimeRange.h>
7 7 #include <Data/DateTimeRangeHelper.h>
8 8 #include <Data/IDataProvider.h>
9 9 #include <QObject>
10 10 #include <QReadWriteLock>
11 11 #include <QRunnable>
12 12 #include <QThreadPool>
13 13 #include <TimeSeries.h>
14 14 #include <Variable/Variable2.h>
15 15
16 16 struct VCTransaction
17 17 {
18 18 VCTransaction(QUuid refVar, DateTimeRange range, int varCount)
19 19 : refVar{refVar}, range{range}, _remainingVars{varCount}
20 20 {}
21 21
22 22 QUuid refVar;
23 23 DateTimeRange range;
24 24 bool ready()
25 25 {
26 26 QReadLocker lock{&_lock};
27 27 return _remainingVars == 0;
28 28 }
29 29
30 30 bool done()
31 31 {
32 32 QWriteLocker lock{&_lock};
33 33 _remainingVars -= 1;
34 34 return _remainingVars == 0;
35 35 }
36 36
37 37 private:
38 38 QReadWriteLock _lock;
39 39 int _remainingVars;
40 40 };
41 41
42 42 class TransactionExe : public QObject, public QRunnable
43 43 {
44 44 Q_OBJECT
45 45 std::shared_ptr<Variable2> _variable;
46 46 std::shared_ptr<IDataProvider> _provider;
47 47 std::vector<DateTimeRange> _ranges;
48 48 DateTimeRange _range;
49 49 bool _overwrite;
50 50
51 51 public:
52 52 TransactionExe(const std::shared_ptr<Variable2>& variable,
53 53 const std::shared_ptr<IDataProvider>& provider,
54 54 const std::vector<DateTimeRange>& ranges, DateTimeRange range,
55 55 bool overwrite = true)
56 56 : _variable{variable}, _provider{provider}, _ranges{ranges},
57 57 _range{range}, _overwrite{overwrite}
58 58 {
59 59 setAutoDelete(true);
60 60 }
61 61 void run() override
62 62 {
63 63 std::vector<TimeSeries::ITimeSerie*> data;
64 64 for(auto range : _ranges)
65 65 {
66 66 auto ds = _provider->getData(
67 67 DataProviderParameters{{range}, _variable->metadata()});
68 if(ds) data.push_back(ds);
68 if(ds and ds->size()) data.push_back(ds); // skip empty dataSeries
69 69 }
70 70 if(_overwrite)
71 71 _variable->setData(data, _range, true);
72 72 else
73 73 {
74 74 data.push_back(_variable->data().get());
75 75 _variable->setData(data, _range, true);
76 76 }
77 77 std::for_each(std::begin(data), std::end(data),
78 78 [](TimeSeries::ITimeSerie* ts) { delete ts; });
79 79 emit transactionComplete();
80 80 }
81 81 signals:
82 82 void transactionComplete();
83 83 };
84 84
85 85 class VCTransactionsQueues
86 86 {
87 87 QReadWriteLock _mutex{QReadWriteLock::Recursive};
88 88 std::map<QUuid, std::optional<std::shared_ptr<VCTransaction>>>
89 89 _nextTransactions;
90 90 std::map<QUuid, std::optional<std::shared_ptr<VCTransaction>>>
91 91 _pendingTransactions;
92 92
93 93 public:
94 94 void addEntry(QUuid id)
95 95 {
96 96 QWriteLocker lock{&_mutex};
97 97 _nextTransactions[id] = std::nullopt;
98 98 _pendingTransactions[id] = std::nullopt;
99 99 }
100 100
101 101 void removeEntry(QUuid id)
102 102 {
103 103 QWriteLocker lock{&_mutex};
104 104 _nextTransactions.erase(id);
105 105 _pendingTransactions.erase(id);
106 106 }
107 107
108 108 std::map<QUuid, std::optional<std::shared_ptr<VCTransaction>>>
109 109 pendingTransactions()
110 110 {
111 111 QReadLocker lock{&_mutex};
112 112 return _pendingTransactions;
113 113 }
114 114
115 115 std::map<QUuid, std::optional<std::shared_ptr<VCTransaction>>>
116 116 nextTransactions()
117 117 {
118 118 QReadLocker lock{&_mutex};
119 119 return _nextTransactions;
120 120 }
121 121
122 122 std::optional<std::shared_ptr<VCTransaction>> start(QUuid id)
123 123 {
124 124 QWriteLocker lock{&_mutex};
125 125 _pendingTransactions[id] = _nextTransactions[id];
126 126 _nextTransactions[id] = std::nullopt;
127 127 return _pendingTransactions[id];
128 128 }
129 129
130 130 void enqueue(QUuid id, std::shared_ptr<VCTransaction> transaction)
131 131 {
132 132 QWriteLocker lock{&_mutex};
133 133 _nextTransactions[id] = transaction;
134 134 }
135 135
136 136 void complete(QUuid id)
137 137 {
138 138 QWriteLocker lock{&_mutex};
139 139 _pendingTransactions[id] = std::nullopt;
140 140 }
141 141
142 142 bool active(QUuid id)
143 143 {
144 144 QReadLocker lock{&_mutex};
145 145 return _nextTransactions[id].has_value() ||
146 146 _pendingTransactions[id].has_value();
147 147 }
148 148 };
@@ -1,236 +1,248
1 1 #include "Variable/Variable2.h"
2 2
3 3 #define PROPERTY_(property, getter, setter, type) \
4 4 type getter() noexcept \
5 5 { \
6 6 QReadLocker lock{&m_Lock}; \
7 7 return property; \
8 8 } \
9 9 void setter(const type& getter) noexcept \
10 10 { \
11 11 QWriteLocker lock{&m_Lock}; \
12 12 property = getter; \
13 13 } \
14 14 type property;
15 15
16 16 #define V_FW_GETTER_SETTER(getter, setter, type) \
17 17 type Variable2::getter() \
18 18 { \
19 19 QReadLocker lock{&this->m_lock}; \
20 20 return impl->getter(); \
21 21 } \
22 22 void Variable2::setter(const type& value) \
23 23 { \
24 24 { \
25 25 QWriteLocker lock{&this->m_lock}; \
26 26 impl->setter(value); \
27 27 } \
28 28 emit updated(this->ID()); \
29 29 }
30 30
31 31 static DataSeriesType findDataSeriesType(const QVariantHash& metadata)
32 32 {
33 33 auto dataSeriesType = DataSeriesType::NONE;
34 34
35 35 // Go through the metadata and stop at the first value that could be converted
36 36 // to DataSeriesType
37 37 for(auto it = metadata.cbegin(), end = metadata.cend();
38 38 it != end && dataSeriesType == DataSeriesType::NONE; ++it)
39 39 {
40 40 dataSeriesType = DataSeriesTypeUtils::fromString(it.value().toString());
41 41 }
42 42
43 43 return dataSeriesType;
44 44 }
45 45
46 46 std::shared_ptr<TimeSeries::ITimeSerie>
47 47 clone_ts(const std::shared_ptr<TimeSeries::ITimeSerie>& ts)
48 48 {
49 49 if(auto scal_ts = std::dynamic_pointer_cast<ScalarTimeSerie>(ts))
50 50 return std::make_shared<ScalarTimeSerie>(*scal_ts);
51 51 if(auto scal_ts = std::dynamic_pointer_cast<VectorTimeSerie>(ts))
52 52 return std::make_shared<VectorTimeSerie>(*scal_ts);
53 53 if(auto scal_ts = std::dynamic_pointer_cast<SpectrogramTimeSerie>(ts))
54 54 return std::make_shared<SpectrogramTimeSerie>(*scal_ts);
55 55 return nullptr;
56 56 }
57 57
58 58 struct Variable2::VariablePrivate
59 59 {
60 60 VariablePrivate(const QString& name, const QVariantHash& metadata)
61 61 : m_Name{name}, m_Range{INVALID_RANGE}, m_Metadata{metadata}, m_TimeSerie{
62 62 nullptr}
63 63 {
64 64 switch(findDataSeriesType(metadata))
65 65 {
66 66 case DataSeriesType::SCALAR:
67 67 m_TimeSerie = std::make_shared<ScalarTimeSerie>(ScalarTimeSerie{});
68 68 break;
69 69 case DataSeriesType::VECTOR:
70 70 m_TimeSerie = std::make_shared<VectorTimeSerie>(VectorTimeSerie{});
71 71 break;
72 72 case DataSeriesType::SPECTROGRAM:
73 73 m_TimeSerie =
74 74 std::make_shared<SpectrogramTimeSerie>(SpectrogramTimeSerie{});
75 75 break;
76 76 case DataSeriesType::MULTICOMPONENT:
77 77 {
78 78 std::size_t count = metadata.value(QString("size"), 0).toInt();
79 79 m_TimeSerie = std::make_shared<MultiComponentTimeSerie>(
80 80 MultiComponentTimeSerie{{0, count}});
81 81 }
82 82 break;
83 83 default: break;
84 84 }
85 85 }
86 86
87 87 VariablePrivate(const VariablePrivate& other)
88 88 : m_Name{other.m_Name}, m_Range{other.m_Range},
89 89 m_Metadata{other.m_Metadata}, m_RealRange{other.m_RealRange}
90 90 {
91 91 m_TimeSerie = clone_ts(other.m_TimeSerie);
92 92 }
93 93
94 94 std::size_t nbPoints()
95 95 {
96 96 if(m_TimeSerie) return m_TimeSerie->size();
97 97 return 0;
98 98 }
99 99 DataSeriesType type() const
100 100 {
101 101 return DataSeriesTypeUtils::type(m_TimeSerie.get());
102 102 }
103 103
104 104 PROPERTY_(m_Name, name, setName, QString)
105 105 PROPERTY_(m_Range, range, setRange, DateTimeRange)
106 106 PROPERTY_(m_Metadata, metadata, setMetadata, QVariantHash)
107 107 PROPERTY_(m_RealRange, realRange, setRealRange, std::optional<DateTimeRange>)
108 108 std::shared_ptr<TimeSeries::ITimeSerie> dataSeries() { return m_TimeSerie; }
109 109 void setDataSeries(std::shared_ptr<TimeSeries::ITimeSerie>&& timeSerie)
110 110 {
111 111 QWriteLocker lock{&m_Lock};
112 112 m_TimeSerie = timeSerie;
113 113 if(m_TimeSerie) { setRealRange(DateTimeRange(m_TimeSerie->axis_range(0))); }
114 114 else
115 115 {
116 116 setRealRange(std::nullopt);
117 117 }
118 118 }
119 119 std::shared_ptr<TimeSeries::ITimeSerie> m_TimeSerie;
120 120 QReadWriteLock m_Lock{QReadWriteLock::Recursive};
121 121 };
122 122
123 123 Variable2::Variable2(const QString& name, const QVariantHash& metadata)
124 124 : impl{spimpl::make_unique_impl<VariablePrivate>(name, metadata)},
125 125 _uuid{QUuid::createUuid()}
126 126 {}
127 127
128 128 Variable2::Variable2(const Variable2& other)
129 129 : impl{spimpl::make_unique_impl<VariablePrivate>(*other.impl)},
130 130 _uuid{QUuid::createUuid()} // is a clone but must have a != uuid
131 131 {}
132 132
133 133 std::shared_ptr<Variable2> Variable2::clone() const
134 134 {
135 135 return std::make_shared<Variable2>(*this);
136 136 }
137 137
138 138 V_FW_GETTER_SETTER(name, setName, QString)
139 139
140 140 DateTimeRange Variable2::range() { return impl->range(); }
141 141
142 142 void Variable2::setRange(const DateTimeRange& range)
143 143 {
144 144 QWriteLocker lock{&m_lock};
145 145 impl->setRange(range);
146 146 }
147 147
148 148 std::optional<DateTimeRange> Variable2::realRange()
149 149 {
150 150 QReadLocker lock{&m_lock};
151 151 return impl->realRange();
152 152 }
153 153
154 154 std::size_t Variable2::nbPoints() { return impl->nbPoints(); }
155 155
156 156 std::shared_ptr<TimeSeries::ITimeSerie> Variable2::data()
157 157 {
158 158 return impl->dataSeries();
159 159 }
160 160
161 161 DataSeriesType Variable2::type()
162 162 {
163 163 QReadLocker lock{&m_lock};
164 164 return impl->type();
165 165 }
166 166
167 167 QVariantHash Variable2::metadata() const noexcept { return impl->metadata(); }
168 168
169 169 template<typename T>
170 170 std::shared_ptr<TimeSeries::ITimeSerie>
171 171 _merge(std::vector<TimeSeries::ITimeSerie*> source, const DateTimeRange& range)
172 172 {
173 173 std::sort(std::begin(source), std::end(source),
174 174 [](TimeSeries::ITimeSerie* a, TimeSeries::ITimeSerie* b) {
175 175 if(a->size() && b->size()) return a->t(0) < b->t(0);
176 176 return false;
177 177 });
178 178 std::shared_ptr<TimeSeries::ITimeSerie> dest = std::make_shared<T>();
179 179 std::for_each(
180 180 std::begin(source), std::end(source),
181 181 [&dest, &range](TimeSeries::ITimeSerie* serie) {
182 182 auto& ts = *static_cast<T*>(serie);
183 183 auto last_t = range.m_TStart;
184 184 if(dest->size()) last_t = dest->axis(0).back();
185 185 if(ts.size())
186 186 {
187 187 std::copy(std::upper_bound(
188 188 std::begin(ts), std::end(ts), last_t,
189 189 [](const auto& a, const auto& b) { return a < b.t(); }),
190 190 std::lower_bound(
191 191 std::begin(ts), std::end(ts), range.m_TEnd,
192 192 [](const auto& a, const auto& b) { return a.t() < b; }),
193 193 std::back_inserter(*std::dynamic_pointer_cast<T>(dest)));
194 194 }
195 195 });
196 196 if(source.size())
197 197 {
198 198 const auto& first = *source.begin();
199 199 for(std::size_t ax_index = 1; ax_index < first->shape().size(); ax_index++)
200 200 {
201 201 const auto& ax = first->axis(ax_index);
202 202 std::copy(std::cbegin(ax), std::cend(ax),
203 203 std::back_inserter(dest->axis(ax_index)));
204 204 }
205 205 }
206 if constexpr(std::is_same_v<T, SpectrogramTimeSerie>)
207 {
208 auto d = std::dynamic_pointer_cast<SpectrogramTimeSerie>(dest);
209 if(std::isnan(d->max_sampling))
210 {
211 std::for_each(std::begin(source), std::end(source), [&d](auto src) {
212 auto s = dynamic_cast<SpectrogramTimeSerie*>(src);
213 if(!std::isnan(s->max_sampling)) { d->max_sampling = s->max_sampling; }
214 if(!std::isnan(s->min_sampling)) { d->min_sampling = s->min_sampling; }
215 });
216 }
217 }
206 218 return dest;
207 219 }
208 220
209 221 std::shared_ptr<TimeSeries::ITimeSerie>
210 222 merge(const std::vector<TimeSeries::ITimeSerie*>& dataSeries,
211 223 const DateTimeRange& range)
212 224 {
213 225 if(dynamic_cast<ScalarTimeSerie*>(dataSeries.front()))
214 226 return _merge<ScalarTimeSerie>(dataSeries, range);
215 227 if(dynamic_cast<VectorTimeSerie*>(dataSeries.front()))
216 228 return _merge<VectorTimeSerie>(dataSeries, range);
217 229 if(dynamic_cast<MultiComponentTimeSerie*>(dataSeries.front()))
218 230 return _merge<MultiComponentTimeSerie>(dataSeries, range);
219 231 if(dynamic_cast<SpectrogramTimeSerie*>(dataSeries.front()))
220 232 return _merge<SpectrogramTimeSerie>(dataSeries, range);
221 233 return std::shared_ptr<TimeSeries::ITimeSerie>{};
222 234 }
223 235
224 236 void Variable2::setData(const std::vector<TimeSeries::ITimeSerie*>& dataSeries,
225 237 const DateTimeRange& range, bool notify)
226 238 {
227 239 if(dataSeries.size())
228 240 {
229 241 {
230 242 QWriteLocker lock{&m_lock};
231 243 impl->setDataSeries(merge(dataSeries, range));
232 244 impl->setRange(range);
233 245 }
234 246 if(notify) emit this->updated(this->ID());
235 247 }
236 248 }
@@ -1,447 +1,448
1 1 #include "Variable/VariableController2.h"
2 2
3 3 #include "Variable/VariableSynchronizationGroup2.h"
4 4
5 5 #include <Common/containers.h>
6 6 #include <Common/debug.h>
7 7 #include <Data/DataProviderParameters.h>
8 8 #include <Data/DateTimeRange.h>
9 9 #include <Data/DateTimeRangeHelper.h>
10 10 #include <QCoreApplication>
11 11 #include <QDataStream>
12 12 #include <QObject>
13 13 #include <QQueue>
14 14 #include <QRunnable>
15 15 #include <QThreadPool>
16 16 #include <Variable/private/VCTransaction.h>
17 17
18 18 class VariableController2::VariableController2Private
19 19 {
20 20 struct threadSafeVaraiblesMaps
21 21 {
22 22 inline void
23 23 addVariable(const std::shared_ptr<Variable2>& variable,
24 24 const std::shared_ptr<IDataProvider>& provider,
25 25 const std::shared_ptr<VariableSynchronizationGroup2>&
26 26 synchronizationGroup)
27 27 {
28 28 QWriteLocker lock{&_lock};
29 29 _variables[*variable] = variable;
30 30 _providers[*variable] = provider;
31 31 _synchronizationGroups[*variable] = synchronizationGroup;
32 32 }
33 33
34 34 inline void removeVariable(const std::shared_ptr<Variable2>& variable)
35 35 {
36 36 QWriteLocker lock{&_lock};
37 37 _variables.erase(*variable);
38 38 _providers.remove(*variable);
39 39 _synchronizationGroups.remove(*variable);
40 40 }
41 41
42 42 inline void
43 43 synchronize(const std::shared_ptr<Variable2>& variable,
44 44 const std::optional<std::shared_ptr<Variable2>>& with)
45 45 {
46 46 QWriteLocker lock{&_lock};
47 47 if(with.has_value())
48 48 {
49 49 auto newGroup = _synchronizationGroups[*with.value()];
50 50 newGroup->addVariable(*variable);
51 51 _synchronizationGroups[*variable] = newGroup;
52 52 }
53 53 else
54 54 {
55 55 _synchronizationGroups[*variable] =
56 56 std::make_shared<VariableSynchronizationGroup2>(*variable);
57 57 }
58 58 }
59 59
60 60 inline std::shared_ptr<Variable2> variable(QUuid variable)
61 61 {
62 62 QReadLocker lock{&_lock};
63 63 auto it = _variables.find(variable);
64 64 #if __cplusplus > 201703L
65 65 [[unlikely]]
66 66 #endif
67 67 if(it == _variables.end())
68 68 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable");
69 69 return (*it).second;
70 70 }
71 71
72 72 inline std::shared_ptr<Variable2> variable(int index)
73 73 {
74 74 QReadLocker lock{&_lock};
75 75 #if __cplusplus > 201703L
76 76 [[unlikely]]
77 77 #endif
78 78 if(!_variables.size() > index)
79 79 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Index is out of bounds");
80 80 auto it = _variables.cbegin();
81 81 while(index != 0)
82 82 {
83 83 index -= 1;
84 84 it++;
85 85 }
86 86 return (*(it)).second;
87 87 }
88 88
89 89 inline const std::vector<std::shared_ptr<Variable2>> variables()
90 90 {
91 91 std::vector<std::shared_ptr<Variable2>> vars;
92 92 QReadLocker lock{&_lock};
93 93 for(const auto& [id, var] : _variables)
94 94 {
95 95 vars.push_back(var);
96 96 }
97 97 return vars;
98 98 }
99 99
100 100 inline std::shared_ptr<IDataProvider> provider(QUuid variable)
101 101 {
102 102 QReadLocker lock{&_lock};
103 103 #if __cplusplus > 201703L
104 104 [[unlikely]]
105 105 #endif
106 106 if(!_providers.contains(variable))
107 107 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable");
108 108 return _providers[variable];
109 109 }
110 110
111 111 inline std::shared_ptr<VariableSynchronizationGroup2> group(QUuid variable)
112 112 {
113 113 QReadLocker lock{&_lock};
114 114 #if __cplusplus > 201703L
115 115 [[unlikely]]
116 116 #endif
117 117 if(!_synchronizationGroups.contains(variable))
118 118 SCIQLOP_ERROR(threadSafeVaraiblesMaps, "Unknown Variable");
119 119 return _synchronizationGroups[variable];
120 120 }
121 121
122 122 inline bool has(const std::shared_ptr<Variable2>& variable)
123 123 {
124 124 QReadLocker lock{&_lock};
125 125 return _variables.find(*variable) == _variables.end();
126 126 }
127 127
128 128 private:
129 129 std::map<QUuid, std::shared_ptr<Variable2>> _variables;
130 130 QMap<QUuid, std::shared_ptr<IDataProvider>> _providers;
131 131 QMap<QUuid, std::shared_ptr<VariableSynchronizationGroup2>>
132 132 _synchronizationGroups;
133 133 QReadWriteLock _lock{QReadWriteLock::Recursive};
134 134 } _maps;
135 135 std::vector<QUuid> _variablesToRemove;
136 136 QThreadPool* _ThreadPool;
137 137 VCTransactionsQueues _transactions;
138 138
139 139 void _transactionComplete(QUuid group,
140 140 std::shared_ptr<VCTransaction> transaction)
141 141 {
142 142 if(transaction->done()) { _transactions.complete(group); }
143 143 this->_processTransactions();
144 144 }
145 145
146 146 void _cleanupVariables()
147 147 {
148 148 for(auto id : _variablesToRemove)
149 149 {
150 150 auto v = this->variable(id);
151 151 if(!hasPendingTransactions(v))
152 152 {
153 153 _variablesToRemove.erase(std::remove(_variablesToRemove.begin(),
154 154 _variablesToRemove.end(), id),
155 155 _variablesToRemove.end());
156 156 this->deleteVariable(v);
157 157 }
158 158 }
159 159 }
160 160
161 161 void _processTransactions(bool fragmented = false)
162 162 {
163 163 auto nextTransactions = _transactions.nextTransactions();
164 164 auto pendingTransactions = _transactions.pendingTransactions();
165 165 for(auto [groupID, newTransaction] : nextTransactions)
166 166 {
167 167 if(newTransaction.has_value() &&
168 168 !pendingTransactions[groupID].has_value())
169 169 {
170 170 _transactions.start(groupID);
171 171 auto refVar = _maps.variable(newTransaction.value()->refVar);
172 172 auto ranges =
173 173 _computeAllRangesInGroup(refVar, newTransaction.value()->range);
174 174 for(auto const& [ID, range] : ranges)
175 175 {
176 176 auto provider = _maps.provider(ID);
177 177 auto variable = _maps.variable(ID);
178 178 if(fragmented)
179 179 {
180 180 auto missingRanges = _computeMissingRanges(variable, range);
181 181
182 182 auto exe =
183 183 new TransactionExe(variable, provider, missingRanges, range);
184 184 QObject::connect(
185 185 exe, &TransactionExe::transactionComplete,
186 186 [groupID = groupID, transaction = newTransaction.value(),
187 187 this]() { this->_transactionComplete(groupID, transaction); });
188 188 _ThreadPool->start(exe);
189 189 }
190 190 else
191 191 {
192 192 auto exe = new TransactionExe(variable, provider, {range}, range);
193 193 QObject::connect(
194 194 exe, &TransactionExe::transactionComplete,
195 195 [groupID = groupID, transaction = newTransaction.value(),
196 196 this]() { this->_transactionComplete(groupID, transaction); });
197 197 _ThreadPool->start(exe);
198 198 }
199 199 }
200 200 }
201 201 }
202 202 // after each transaction update we get a new distribution of idle and
203 203 // working variables so we can delete variables which are waiting to be
204 204 // deleted if they are now idle
205 205 _cleanupVariables();
206 206 }
207 207
208 208 std::map<QUuid, DateTimeRange>
209 209 _computeAllRangesInGroup(const std::shared_ptr<Variable2>& refVar,
210 210 DateTimeRange r)
211 211 {
212 212 std::map<QUuid, DateTimeRange> ranges;
213 213 if(!DateTimeRangeHelper::hasnan(r))
214 214 {
215 215 auto group = _maps.group(*refVar);
216 216 if(auto transformation =
217 217 DateTimeRangeHelper::computeTransformation(refVar->range(), r);
218 218 transformation.has_value())
219 219 {
220 220 for(auto varId : group->variables())
221 221 {
222 222 auto var = _maps.variable(varId);
223 223 auto newRange = var->range().transform(transformation.value());
224 224 ranges[varId] = newRange;
225 225 }
226 226 }
227 227 else // force new range to all variables -> may be weird if more than one
228 228 // var in the group
229 229 // @TODO ensure that there is no side effects
230 230 {
231 231 for(auto varId : group->variables())
232 232 {
233 233 auto var = _maps.variable(varId);
234 234 ranges[varId] = r;
235 235 }
236 236 }
237 237 }
238 238 else
239 239 {
240 240 SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN");
241 241 }
242 242 return ranges;
243 243 }
244 244
245 245 std::vector<DateTimeRange>
246 246 _computeMissingRanges(const std::shared_ptr<Variable2>& var, DateTimeRange r)
247 247 {
248 248 return r - var->range();
249 249 }
250 250
251 251 void _changeRange(QUuid id, DateTimeRange r)
252 252 {
253 253 _changeRange(_maps.variable(id), r);
254 254 }
255 255 void _changeRange(const std::shared_ptr<Variable2>& var, DateTimeRange r)
256 256 {
257 257 auto provider = _maps.provider(*var);
258 258 auto missingRanges = _computeMissingRanges(var, r);
259 259 std::vector<TimeSeries::ITimeSerie*> data;
260 260 for(auto range : missingRanges)
261 261 {
262 262 data.push_back(
263 263 provider->getData(DataProviderParameters{{range}, var->metadata()}));
264 264 }
265 265 data.push_back(var->data().get()); // might be smarter
266 266 var->setData(data, r, true);
267 std::for_each(std::begin(data), std::end(data), [](auto ts) { delete ts; });
267 268 }
268 269
269 270 public:
270 271 VariableController2Private(QObject* parent = Q_NULLPTR)
271 272 {
272 273 Q_UNUSED(parent);
273 274 this->_ThreadPool = new QThreadPool();
274 275 this->_ThreadPool->setMaxThreadCount(32);
275 276 }
276 277
277 278 /*
278 279 * This dtor has to like this even if this is ugly, because default dtor would
279 280 * rely on declaration order to destruct members and that would always lead to
280 281 * regressions when modifying class members
281 282 */
282 283 ~VariableController2Private() { delete this->_ThreadPool; }
283 284
284 285 std::shared_ptr<Variable2>
285 286 createVariable(const QString& name, const QVariantHash& metadata,
286 287 std::shared_ptr<IDataProvider> provider)
287 288 {
288 289 auto newVar = std::make_shared<Variable2>(name, metadata);
289 290 auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID());
290 291 _maps.addVariable(newVar, std::move(provider), group);
291 292 this->_transactions.addEntry(*group);
292 293 return newVar;
293 294 }
294 295
295 296 std::shared_ptr<Variable2> variable(QUuid ID) { return _maps.variable(ID); }
296 297
297 298 std::shared_ptr<Variable2> variable(int index)
298 299 {
299 300 return _maps.variable(index);
300 301 }
301 302
302 303 std::shared_ptr<Variable2>
303 304 cloneVariable(const std::shared_ptr<Variable2>& variable)
304 305 {
305 306 auto newVar = variable->clone();
306 307 _maps.synchronize(newVar, std::nullopt);
307 308 _maps.addVariable(newVar, _maps.provider(*variable), _maps.group(*newVar));
308 309 this->_transactions.addEntry(*_maps.group(*newVar));
309 310 return newVar;
310 311 }
311 312
312 313 bool hasPendingTransactions(const std::shared_ptr<Variable2>& variable)
313 314 {
314 315 return _transactions.active(*_maps.group(*variable));
315 316 }
316 317
317 318 bool hasPendingTransactions()
318 319 {
319 320 bool has = false;
320 321 for(const auto& var : _maps.variables())
321 322 {
322 323 has |= _transactions.active(*_maps.group(*var));
323 324 }
324 325 return has;
325 326 }
326 327
327 328 void deleteVariable(const std::shared_ptr<Variable2>& variable)
328 329 {
329 330 if(!hasPendingTransactions(variable))
330 331 _maps.removeVariable(variable);
331 332 else
332 333 _variablesToRemove.push_back(variable->ID());
333 334 }
334 335
335 336 void asyncChangeRange(const std::shared_ptr<Variable2>& variable,
336 337 const DateTimeRange& r)
337 338 {
338 339 if(!DateTimeRangeHelper::hasnan(r))
339 340 {
340 341 auto group = _maps.group(*variable);
341 342 // Just overwrite next transaction
342 343 {
343 344 _transactions.enqueue(*group,
344 345 std::make_shared<VCTransaction>(
345 346 variable->ID(), r,
346 347 static_cast<int>(group->variables().size())));
347 348 }
348 349 _processTransactions();
349 350 }
350 351 else
351 352 {
352 353 SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN");
353 354 }
354 355 }
355 356
356 357 void changeRange(const std::shared_ptr<Variable2>& variable, DateTimeRange r)
357 358 {
358 359 asyncChangeRange(variable, r);
359 360 while(hasPendingTransactions(variable))
360 361 {
361 362 QCoreApplication::processEvents();
362 363 }
363 364 }
364 365
365 366 inline void synchronize(const std::shared_ptr<Variable2>& var,
366 367 const std::shared_ptr<Variable2>& with)
367 368 {
368 369 _maps.synchronize(var, with);
369 370 }
370 371
371 372 inline const std::vector<std::shared_ptr<Variable2>> variables()
372 373 {
373 374 return _maps.variables();
374 375 }
375 376 };
376 377
377 378 VariableController2::VariableController2()
378 379 : impl{spimpl::make_unique_impl<VariableController2Private>()}
379 380 {}
380 381
381 382 std::shared_ptr<Variable2> VariableController2::createVariable(
382 383 const QString& name, const QVariantHash& metadata,
383 384 const std::shared_ptr<IDataProvider>& provider, const DateTimeRange& range)
384 385 {
385 386 auto var = impl->createVariable(name, metadata, provider);
386 387 var->setRange(range); // even with no data this is it's range
387 388 if(!DateTimeRangeHelper::hasnan(range))
388 389 impl->asyncChangeRange(var, range);
389 390 else
390 391 SCIQLOP_ERROR(VariableController2, "Creating a variable with default "
391 392 "constructed DateTimeRange is an error");
392 393 emit variableAdded(var);
393 394 return var;
394 395 }
395 396
396 397 std::shared_ptr<Variable2>
397 398 VariableController2::cloneVariable(const std::shared_ptr<Variable2>& variable)
398 399 {
399 400 return impl->cloneVariable(variable);
400 401 }
401 402
402 403 void VariableController2::deleteVariable(
403 404 const std::shared_ptr<Variable2>& variable)
404 405 {
405 406 impl->deleteVariable(variable);
406 407 emit variableDeleted(variable);
407 408 }
408 409
409 410 void VariableController2::changeRange(
410 411 const std::shared_ptr<Variable2>& variable, const DateTimeRange& r)
411 412 {
412 413 impl->changeRange(variable, r);
413 414 }
414 415
415 416 void VariableController2::asyncChangeRange(
416 417 const std::shared_ptr<Variable2>& variable, const DateTimeRange& r)
417 418 {
418 419 impl->asyncChangeRange(variable, r);
419 420 }
420 421
421 422 const std::vector<std::shared_ptr<Variable2>> VariableController2::variables()
422 423 {
423 424 return impl->variables();
424 425 }
425 426
426 427 bool VariableController2::isReady(const std::shared_ptr<Variable2>& variable)
427 428 {
428 429 return !impl->hasPendingTransactions(variable);
429 430 }
430 431
431 432 bool VariableController2::isReady() { return !impl->hasPendingTransactions(); }
432 433
433 434 void VariableController2::synchronize(const std::shared_ptr<Variable2>& var,
434 435 const std::shared_ptr<Variable2>& with)
435 436 {
436 437 impl->synchronize(var, with);
437 438 }
438 439
439 440 const std::vector<std::shared_ptr<Variable2>>
440 441 VariableController2::variables(const std::vector<QUuid>& ids)
441 442 {
442 443 std::vector<std::shared_ptr<Variable2>> variables;
443 444 std::transform(std::cbegin(ids), std::cend(ids),
444 445 std::back_inserter(variables),
445 446 [this](const auto& id) { return impl->variable(id); });
446 447 return variables;
447 448 }
@@ -1,299 +1,302
1 1 #include "CoreWrappers.h"
2 2
3 3 #include "pywrappers_common.h"
4 4
5 #include <Common/debug.h>
5 6 #include <Data/DataSeriesType.h>
6 7 #include <Data/IDataProvider.h>
7 8 #include <Network/Downloader.h>
8 9 #include <Time/TimeController.h>
9 10 #include <Variable/Variable2.h>
10 11 #include <Variable/VariableController2.h>
11 12 #include <pybind11/chrono.h>
12 13 #include <pybind11/embed.h>
13 14 #include <pybind11/functional.h>
14 15 #include <pybind11/numpy.h>
15 16 #include <pybind11/operators.h>
16 17 #include <pybind11/pybind11.h>
17 18 #include <pybind11/stl.h>
18 19 #include <pybind11/stl_bind.h>
19 20 #include <sstream>
20 21 #include <string>
21 22
22 23 namespace py = pybind11;
23 24 using namespace std::chrono;
24 25
25 26 template<typename T, typename U, bool row_major = true>
26 27 void copy_vector(py::array_t<double>& t, py::array_t<double>& values, T& dest_t,
27 28 U& dest_values)
28 29 {
29 30 auto t_view = t.unchecked<1>();
30 31 auto values_view = values.unchecked<2>();
31 32 for(std::size_t i = 0; i < t.size(); i++)
32 33 {
33 34 dest_t[i] = t_view[i];
34 35 dest_values[i] = {values_view(i, 0), values_view(i, 1), values_view(i, 2)};
35 36 }
36 37 }
37 38
38 39 template<typename T, typename U>
39 40 void copy_scalar(py::array_t<double>& t, py::array_t<double>& values, T& dest_t,
40 41 U& dest_values)
41 42 {
42 43 auto t_view = t.unchecked<1>();
43 44 if(values.ndim() == 1)
44 45 {
45 46 auto values_view = values.unchecked<1>();
46 47 for(std::size_t i = 0; i < t.size(); i++)
47 48 {
48 49 dest_t[i] = t_view[i];
49 50 dest_values[i] = values_view[i];
50 51 }
51 52 }
52 53 else if(values.ndim() == 2 && values.shape(1) == 1)
53 54 {
54 55 auto values_view = values.unchecked<2>();
55 56 for(std::size_t i = 0; i < t.size(); i++)
56 57 {
57 58 dest_t[i] = t_view[i];
58 59 dest_values[i] = values_view(i, 0);
59 60 }
60 61 }
61 62 }
62 63 template<typename T, typename U>
63 64 void copy_multicomp(py::array_t<double>& t, py::array_t<double>& values,
64 65 T& dest_t, U& dest_values)
65 66 {
66 67 auto t_view = t.unchecked<1>();
67 68 auto values_view = values.unchecked<2>();
68 69 const auto width = values.shape(1);
69 70 for(std::size_t i = 0; i < t.size(); i++)
70 71 {
71 72 dest_t[i] = t_view[i];
72 73 for(int j = 0; j < width; j++)
73 74 {
74 75 dest_values[i * width + j] = values_view(i, j);
75 76 }
76 77 }
77 78 }
78 79
79 80 template<typename T, typename U>
80 81 void copy_spectro(py::array_t<double>& t, py::array_t<double>& y,
81 82 py::array_t<double>& values, T& dest_t, T& dest_y,
82 83 U& dest_values)
83 84 {
84 85 auto t_view = t.unchecked<1>();
85 86 auto y_view = y.unchecked<1>();
86 87 auto values_view = values.unchecked<2>();
87 88 const auto width = values.shape(1);
88 89 for(std::size_t i = 0; i < y.size(); i++)
89 90 {
90 91 dest_y[i] = y_view[i];
91 92 }
92 93 for(std::size_t i = 0; i < t.size(); i++)
93 94 {
94 95 dest_t[i] = t_view[i];
95 96 for(int j = 0; j < width; j++)
96 97 {
97 98 dest_values[i * width + j] = values_view(i, j);
98 99 }
99 100 }
100 101 }
101 102
102 103 PYBIND11_MODULE(pysciqlopcore, m)
103 104 {
104 105 pybind11::bind_vector<std::vector<double>>(m, "VectorDouble");
105 106
106 107 py::enum_<DataSeriesType>(m, "DataSeriesType")
107 108 .value("SCALAR", DataSeriesType::SCALAR)
108 109 .value("SPECTROGRAM", DataSeriesType::SPECTROGRAM)
109 110 .value("VECTOR", DataSeriesType::VECTOR)
110 111 .value("MULTICOMPONENT", DataSeriesType::MULTICOMPONENT)
111 112 .value("NONE", DataSeriesType::NONE)
112 113 .export_values();
113 114
114 115 py::class_<Response>(m, "Response")
115 116 .def("status_code", &Response::status_code);
116 117
117 118 py::class_<Downloader>(m, "Downloader")
118 119 .def_static("get", Downloader::get)
119 120 .def_static("getAsync", Downloader::getAsync)
120 121 .def_static("downloadFinished", Downloader::downloadFinished);
121 122
122 123 py::class_<IDataProvider, std::shared_ptr<IDataProvider>>(m, "IDataProvider");
123 124
124 125 py::class_<TimeSeries::ITimeSerie, std::shared_ptr<TimeSeries::ITimeSerie>>(
125 126 m, "ITimeSerie")
126 127 .def_property_readonly(
127 128 "size", [](const TimeSeries::ITimeSerie& ts) { return ts.size(); })
128 129 .def("__len__",
129 130 [](const TimeSeries::ITimeSerie& ts) { return ts.size(); })
130 131 .def_property_readonly(
131 132 "shape", [](const TimeSeries::ITimeSerie& ts) { return ts.shape(); })
132 133 .def_property_readonly(
133 134 "t",
134 135 [](TimeSeries::ITimeSerie& ts) -> decltype(ts.axis(0))& {
135 136 return ts.axis(0);
136 137 },
137 138 py::return_value_policy::reference)
138 139 .def(
139 140 "axis",
140 141 [](TimeSeries::ITimeSerie& ts, unsigned int index)
141 142 -> decltype(ts.axis(0))& { return ts.axis(index); },
142 143 py::return_value_policy::reference);
143 144
144 145 py::class_<ScalarTimeSerie, TimeSeries::ITimeSerie,
145 146 std::shared_ptr<ScalarTimeSerie>>(m, "ScalarTimeSerie")
146 147 .def(py::init<>())
147 148 .def(py::init<std::size_t>())
148 149 .def(py::init([](py::array_t<double> t, py::array_t<double> values) {
149 150 assert(t.size() == values.size());
150 151 ScalarTimeSerie::axis_t _t(t.size());
151 152 ScalarTimeSerie::axis_t _values(t.size());
152 153 copy_scalar(t, values, _t, _values);
153 154 return ScalarTimeSerie(_t, _values);
154 155 }))
155 156 .def("__getitem__",
156 157 [](ScalarTimeSerie& ts, std::size_t key) { return ts[key]; })
157 158 .def("__setitem__", [](ScalarTimeSerie& ts, std::size_t key,
158 159 double value) { *(ts.begin() + key) = value; });
159 160
160 161 py::class_<VectorTimeSerie::raw_value_type>(m, "vector")
161 162 .def(py::init<>())
162 163 .def(py::init<double, double, double>())
163 164 .def("__repr__", __repr__<VectorTimeSerie::raw_value_type>)
164 165 .def_readwrite("x", &VectorTimeSerie::raw_value_type::x)
165 166 .def_readwrite("y", &VectorTimeSerie::raw_value_type::y)
166 167 .def_readwrite("z", &VectorTimeSerie::raw_value_type::z);
167 168
168 169 py::class_<VectorTimeSerie, TimeSeries::ITimeSerie,
169 170 std::shared_ptr<VectorTimeSerie>>(m, "VectorTimeSerie")
170 171 .def(py::init<>())
171 172 .def(py::init<std::size_t>())
172 173 .def(py::init([](py::array_t<double> t, py::array_t<double> values) {
173 174 assert(t.size() * 3 == values.size());
174 175 VectorTimeSerie::axis_t _t(t.size());
175 176 VectorTimeSerie::container_type<VectorTimeSerie::raw_value_type>
176 177 _values(t.size());
177 178 copy_vector(t, values, _t, _values);
178 179 return VectorTimeSerie(_t, _values);
179 180 }))
180 181 .def(
181 182 "__getitem__",
182 183 [](VectorTimeSerie& ts, std::size_t key)
183 184 -> VectorTimeSerie::raw_value_type& { return ts[key]; },
184 185 py::return_value_policy::reference)
185 186 .def("__setitem__", [](VectorTimeSerie& ts, std::size_t key,
186 187 VectorTimeSerie::raw_value_type value) {
187 188 *(ts.begin() + key) = value;
188 189 });
189 190
190 191 py::class_<MultiComponentTimeSerie::iterator_t>(m,
191 192 "MultiComponentTimeSerieItem")
192 193 .def("__getitem__", [](MultiComponentTimeSerie::iterator_t& self,
193 194 std::size_t key) { return (*self)[key]; })
194 195 .def("__setitem__",
195 196 [](MultiComponentTimeSerie::iterator_t& self, std::size_t key,
196 197 double value) { (*self)[key] = value; });
197 198
198 199 py::class_<MultiComponentTimeSerie, TimeSeries::ITimeSerie,
199 200 std::shared_ptr<MultiComponentTimeSerie>>(
200 201 m, "MultiComponentTimeSerie")
201 202 .def(py::init<>())
202 203 .def(py::init<const std::vector<std::size_t>>())
203 204 .def(py::init([](py::array_t<double> t, py::array_t<double> values) {
204 205 assert((t.size() < values.size()) |
205 206 (t.size() == 0)); // TODO check geometry
206 207 MultiComponentTimeSerie::axis_t _t(t.size());
207 208 MultiComponentTimeSerie::container_type<
208 209 MultiComponentTimeSerie::raw_value_type>
209 210 _values(values.size());
210 211 copy_multicomp(t, values, _t, _values);
211 212 std::vector<std::size_t> shape;
212 213 shape.push_back(values.shape(0));
213 214 shape.push_back(values.shape(1));
214 215 return MultiComponentTimeSerie(_t, _values, shape);
215 216 }))
216 217 .def("__getitem__",
217 218 [](MultiComponentTimeSerie& ts,
218 219 std::size_t key) -> MultiComponentTimeSerie::iterator_t {
219 220 return ts.begin() + key;
220 221 });
221 222
222 223 py::class_<SpectrogramTimeSerie::iterator_t>(m, "SpectrogramTimeSerieItem")
223 224 .def("__getitem__", [](SpectrogramTimeSerie::iterator_t& self,
224 225 std::size_t key) { return (*self)[key]; })
225 226 .def("__setitem__",
226 227 [](SpectrogramTimeSerie::iterator_t& self, std::size_t key,
227 228 double value) { (*self)[key] = value; });
228 229
229 230 py::class_<SpectrogramTimeSerie, TimeSeries::ITimeSerie,
230 231 std::shared_ptr<SpectrogramTimeSerie>>(m, "SpectrogramTimeSerie")
231 232 .def(py::init<>())
232 233 .def(py::init<const std::vector<std::size_t>>())
233 234 .def(py::init([](py::array_t<double> t, py::array_t<double> y,
234 py::array_t<double> values) {
235 auto t_s = t.size();
236 auto v_s = values.size();
237 assert(t.size() < values.size() or
238 t.size() == 0); // TODO check geometry
239 assert(y.size() == values.shape(1));
235 py::array_t<double> values, double min_sampling,
236 double max_sampling) {
237 if(t.size() >= values.size() and t.size() != 0)
238 SCIQLOP_ERROR(decltype(py::self), "Doesn't look like a Spectrogram");
239 if(y.size() != values.shape(1))
240 SCIQLOP_ERROR(decltype(py::self),
241 "Y axis size and data shape are incompatible");
240 242 SpectrogramTimeSerie::axis_t _t(t.size());
241 243 SpectrogramTimeSerie::axis_t _y(y.size());
242 244 SpectrogramTimeSerie::container_type<
243 245 SpectrogramTimeSerie::raw_value_type>
244 246 _values(values.size());
245 247 copy_spectro(t, y, values, _t, _y, _values);
246 248 std::vector<std::size_t> shape;
247 249 shape.push_back(values.shape(0));
248 250 shape.push_back(values.shape(1));
249 251 return SpectrogramTimeSerie(std::move(_t), std::move(_y),
250 std::move(_values), shape);
252 std::move(_values), shape, min_sampling,
253 max_sampling);
251 254 }))
252 255 .def("__getitem__",
253 256 [](SpectrogramTimeSerie& ts,
254 257 std::size_t key) -> SpectrogramTimeSerie::iterator_t {
255 258 return ts.begin() + key;
256 259 });
257 260
258 261 py::class_<Variable2, std::shared_ptr<Variable2>>(m, "Variable2")
259 262 .def(py::init<const QString&>())
260 263 .def_property("name", &Variable2::name, &Variable2::setName)
261 264 .def_property_readonly("range", &Variable2::range)
262 265 .def_property_readonly("nbPoints", &Variable2::nbPoints)
263 266 .def_property_readonly(
264 267 "data",
265 268 [](Variable2& var) -> std::shared_ptr<TimeSeries::ITimeSerie> {
266 269 return var.data();
267 270 })
268 271 .def("set_data",
269 272 [](Variable2& var, std::vector<TimeSeries::ITimeSerie*> ts_list,
270 273 const DateTimeRange& range) { var.setData(ts_list, range); })
271 274 .def("__len__", &Variable2::nbPoints)
272 275 .def("__repr__", __repr__<Variable2>);
273 276
274 277 py::class_<DateTimeRange>(m, "SqpRange")
275 278 //.def("fromDateTime", &DateTimeRange::fromDateTime,
276 279 // py::return_value_policy::move)
277 280 .def(py::init([](double start, double stop) {
278 281 return DateTimeRange{start, stop};
279 282 }))
280 283 .def(py::init(
281 284 [](system_clock::time_point start, system_clock::time_point stop) {
282 285 double start_ =
283 286 0.001 *
284 287 duration_cast<milliseconds>(start.time_since_epoch()).count();
285 288 double stop_ =
286 289 0.001 *
287 290 duration_cast<milliseconds>(stop.time_since_epoch()).count();
288 291 return DateTimeRange{start_, stop_};
289 292 }))
290 293 .def_property_readonly("start",
291 294 [](const DateTimeRange& range) {
292 295 return system_clock::from_time_t(range.m_TStart);
293 296 })
294 297 .def_property_readonly("stop",
295 298 [](const DateTimeRange& range) {
296 299 return system_clock::from_time_t(range.m_TEnd);
297 300 })
298 301 .def("__repr__", __repr__<DateTimeRange>);
299 302 }
General Comments 0
You need to be logged in to leave comments. Login now