##// END OF EJS Templates
Adds "number of operations" and "number of variables" properties for the tests
Adds "number of operations" and "number of variables" properties for the tests

File last commit:

r922:e65d7f08d776
r1170:3da18e6983d5
Show More
CosinusProvider.cpp
291 lines | 10.7 KiB | text/x-c | CppLexer
#include "CosinusProvider.h"
#include "MockDefs.h"
#include <Data/DataProviderParameters.h>
#include <Data/ScalarSeries.h>
#include <Data/SpectrogramSeries.h>
#include <Data/VectorSeries.h>
#include <cmath>
#include <set>
#include <QFuture>
#include <QThread>
#include <QtConcurrent/QtConcurrent>
Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
namespace {
/// Number of bands generated for a spectrogram
const auto SPECTROGRAM_NUMBER_BANDS = 30;
/// Bands for which to generate NaN values for a spectrogram
const auto SPECTROGRAM_NAN_BANDS = std::set<int>{1, 3, 10, 20};
/// Bands for which to generate zeros for a spectrogram
const auto SPECTROGRAM_ZERO_BANDS = std::set<int>{2, 15, 19, 29};
/// Abstract cosinus type
struct ICosinusType {
virtual ~ICosinusType() = default;
/// @return the number of components generated for the type
virtual int componentCount() const = 0;
/// @return the data series created for the type
virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
std::vector<double> valuesData) const = 0;
/// Generates values (one value per component)
/// @param x the x-axis data used to generate values
/// @param values the vector in which to insert the generated values
/// @param dataIndex the index of insertion of the generated values
///
virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
};
struct ScalarCosinus : public ICosinusType {
int componentCount() const override { return 1; }
std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
std::vector<double> valuesData) const override
{
return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
Unit{QStringLiteral("t"), true}, Unit{});
}
void generateValues(double x, std::vector<double> &values, int dataIndex) const override
{
values[dataIndex] = std::cos(x);
}
};
struct SpectrogramCosinus : public ICosinusType {
/// Ctor with y-axis
explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit)
: m_YAxisData{std::move(yAxisData)},
m_YAxisUnit{std::move(yAxisUnit)},
m_ValuesUnit{std::move(valuesUnit)}
{
}
int componentCount() const override { return m_YAxisData.size(); }
std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
std::vector<double> valuesData) const override
{
return std::make_shared<SpectrogramSeries>(
std::move(xAxisData), m_YAxisData, std::move(valuesData),
Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit);
}
void generateValues(double x, std::vector<double> &values, int dataIndex) const override
{
auto componentCount = this->componentCount();
for (int i = 0; i < componentCount; ++i) {
auto y = m_YAxisData[i];
double value;
if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) {
value = 0.;
}
else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) {
value = std::numeric_limits<double>::quiet_NaN();
}
else {
// Generates value for non NaN/zero bands
auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
}
values[componentCount * dataIndex + i] = value;
}
}
std::vector<double> m_YAxisData;
Unit m_YAxisUnit;
Unit m_ValuesUnit;
};
struct VectorCosinus : public ICosinusType {
int componentCount() const override { return 3; }
std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
std::vector<double> valuesData) const override
{
return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
Unit{QStringLiteral("t"), true}, Unit{});
}
void generateValues(double x, std::vector<double> &values, int dataIndex) const override
{
// Generates value for each component: cos(x), cos(x)/2, cos(x)/3
auto xValue = std::cos(x);
auto componentCount = this->componentCount();
for (auto i = 0; i < componentCount; ++i) {
values[componentCount * dataIndex + i] = xValue / (i + 1);
}
}
};
/// Converts string to cosinus type
/// @return the cosinus type if the string could be converted, nullptr otherwise
std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
{
if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
return std::make_unique<ScalarCosinus>();
}
else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
// Generates default y-axis data for spectrogram [0., 1., 2., ...]
std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
std::iota(yAxisData.begin(), yAxisData.end(), 0.);
return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"},
Unit{"eV/(cm^2-s-sr-eV)"});
}
else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
return std::make_unique<VectorCosinus>();
}
else {
return nullptr;
}
}
} // namespace
std::shared_ptr<IDataProvider> CosinusProvider::clone() const
{
// No copy is made in clone
return std::make_shared<CosinusProvider>();
}
std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
const SqpRange &dataRangeRequested,
const QVariantHash &data)
{
// TODO: Add Mutex
auto dataIndex = 0;
// Retrieves cosinus type
auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
if (!typeVariant.canConvert<QString>()) {
qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
return nullptr;
}
auto type = cosinusType(typeVariant.toString());
if (!type) {
qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
return nullptr;
}
// Retrieves frequency
auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
if (!freqVariant.canConvert<double>()) {
qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
return nullptr;
}
// Gets the timerange from the parameters
double freq = freqVariant.toDouble();
double start = std::ceil(dataRangeRequested.m_TStart * freq);
double end = std::floor(dataRangeRequested.m_TEnd * freq);
// We assure that timerange is valid
if (end < start) {
std::swap(start, end);
}
// Generates scalar series containing cosinus values (one value per second, end value is
// included)
auto dataCount = end - start + 1;
// Number of components (depending on the cosinus type)
auto componentCount = type->componentCount();
auto xAxisData = std::vector<double>{};
xAxisData.resize(dataCount);
auto valuesData = std::vector<double>{};
valuesData.resize(dataCount * componentCount);
int progress = 0;
auto progressEnd = dataCount;
for (auto time = start; time <= end; ++time, ++dataIndex) {
auto it = m_VariableToEnableProvider.find(acqIdentifier);
if (it != m_VariableToEnableProvider.end() && it.value()) {
const auto x = time / freq;
xAxisData[dataIndex] = x;
// Generates values (depending on the type)
type->generateValues(x, valuesData, dataIndex);
// progression
int currentProgress = (time - start) * 100.0 / progressEnd;
if (currentProgress != progress) {
progress = currentProgress;
emit dataProvidedProgress(acqIdentifier, progress);
qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
<< QThread::currentThread()->objectName()
<< progress;
// NOTE: Try to use multithread if possible
}
}
else {
if (!it.value()) {
qCDebug(LOG_CosinusProvider())
<< "CosinusProvider::retrieveData: ARRET De l'acquisition detecté"
<< end - time;
}
}
}
if (progress != 100) {
// We can close progression beacause all data has been retrieved
emit dataProvidedProgress(acqIdentifier, 100);
}
return type->createDataSeries(std::move(xAxisData), std::move(valuesData));
}
void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
const DataProviderParameters &parameters)
{
// TODO: Add Mutex
m_VariableToEnableProvider[acqIdentifier] = true;
qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
<< QThread::currentThread()->objectName();
// NOTE: Try to use multithread if possible
const auto times = parameters.m_Times;
for (const auto &dateTime : qAsConst(times)) {
if (m_VariableToEnableProvider[acqIdentifier]) {
auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
emit dataProvided(acqIdentifier, scalarSeries, dateTime);
}
}
}
void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
{
qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
<< QThread::currentThread()->objectName();
auto it = m_VariableToEnableProvider.find(acqIdentifier);
if (it != m_VariableToEnableProvider.end()) {
it.value() = false;
}
else {
qCDebug(LOG_CosinusProvider())
<< tr("Aborting progression of inexistant identifier detected !!!");
}
}
std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
const QVariantHash &data)
{
auto uid = QUuid::createUuid();
m_VariableToEnableProvider[uid] = true;
auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
m_VariableToEnableProvider.remove(uid);
return dataSeries;
}