28 #include "qcustomplot.h"
29 #include "ui_QREDataLoaderProperties.h"
32 #include <QTextStream>
39 AutoEmit(std::function<
void()> fn) : m_fn(fn) {}
40 ~AutoEmit() { m_fn(); }
43 std::function<void()> m_fn;
46 QVector<QPair<int, int>> expandLineNumberPattern(
const QString& pattern,
bool* ok =
nullptr)
48 QVector<QPair<int, int>> result;
51 for (
const auto& token : pattern.split(
",")) {
52 const auto parts = token.split(
"-");
58 const auto conv0 = parts[0].toInt(&ok2);
60 const auto conv1 = parts.size() > 1 ? parts[1].toInt(&ok2) : conv0;
62 result.push_back({conv0, conv1});
85 return "CSV file (Reflectometry - Q/R/sigma_R)";
90 return "QREDataLoader";
98 QHBoxLayout* l =
new QHBoxLayout(parent);
99 l->setContentsMargins(0, 0, 0, 0);
100 parent->setLayout(l);
158 QDataStream s(&a, QIODevice::WriteOnly);
159 s.setVersion(QDataStream::Qt_5_12);
184 s.setVersion(QDataStream::Qt_5_12);
209 if (s.status() != QDataStream::Ok)
232 const auto invalidateItemData = [
this]() {
237 const bool parsingSettingsChanged =
241 const bool calculationSettingsChanged =
243 const bool calculationIsNecessary = (parsingSettingsChanged || calculationSettingsChanged);
244 const bool creationOfOutputDataIsNecessary = calculationIsNecessary;
246 if (parsingSettingsChanged)
250 if (calculationIsNecessary)
260 invalidateItemData();
264 if (creationOfOutputDataIsNecessary) {
270 invalidateItemData();
308 const auto isFirstNumberChar = [](
const QChar& c) {
309 return c.isNumber() || c ==
'.' || c ==
'+' || c ==
'-';
312 const auto belongsToNumber = [](
const QChar& c) {
313 return c.isNumber() || c ==
'.' || c ==
'e' || c ==
'E' || c ==
'+' || c ==
'-';
318 const int maxLinesToExamine = 100;
319 while (!in.atEnd() && lineNr < maxLinesToExamine) {
321 QString line = in.readLine().trimmed();
324 if (!isFirstNumberChar(line[0]))
329 while (startOfGap < line.size() && belongsToNumber(line[startOfGap]))
332 if (startOfGap == line.size())
335 int endOfGap = startOfGap;
336 while (endOfGap < line.size() && !belongsToNumber(line[endOfGap])) {
340 QStringRef gapContent(&line, startOfGap, endOfGap - startOfGap);
341 if (gapContent.isEmpty())
344 if (gapContent.contains(
"\t")) {
349 gapContent = gapContent.trimmed();
350 if (gapContent.isEmpty()) {
355 if (gapContent.contains(
";")) {
360 if (gapContent.contains(
",")) {
380 const auto lineIsHeader = [headerPrefixes](
const QString& line) {
381 for (
const auto& prefix : headerPrefixes) {
382 if (line.startsWith(prefix.trimmed()))
390 const auto lineShouldBeSkipped = [skippedLines](
int lineNr) {
391 for (
const auto pair : skippedLines) {
392 if (lineNr >= pair.first && lineNr <= pair.second)
402 QString::SplitBehavior splitBehavior =
405 while (!in.atEnd()) {
408 QString line = in.readLine();
411 lineIsHeader(line) || lineShouldBeSkipped(lineNr) || line.trimmed().isEmpty();
424 const QStringList lineEntries =
430 QVector<double> rowEntriesAsDouble;
432 for (
int col = 0; col < lineEntries.count(); col++) {
434 double val = lineEntries[col].toDouble(&ok);
436 val = std::numeric_limits<double>::quiet_NaN();
438 rowEntriesAsDouble << val;
454 const bool errorColumnIsEnabled = c[
DataType::dR].enabled;
456 const double qFactor = c[
DataType::Q].factor * unitFac;
464 QSet<double> foundQValues;
465 double lastFoundQ = std::numeric_limits<double>::quiet_NaN();
474 const bool qColIsValid = qCol >= 0 && qCol < rawValues.size();
475 const bool rColIsValid = rCol >= 0 && rCol < rawValues.size();
476 const bool eColIsValid = eCol >= 0 && eCol < rawValues.size();
479 qColIsValid ? rawValues[qCol] * qFactor : std::numeric_limits<double>::quiet_NaN();
481 rColIsValid ? rawValues[rCol] * rFactor : std::numeric_limits<double>::quiet_NaN();
483 eColIsValid ? rawValues[eCol] * eFactor : std::numeric_limits<double>::quiet_NaN();
497 if (std::isnan(e) && errorColumnIsEnabled) {
503 if (foundQValues.contains(q)) {
508 if (!std::isnan(lastFoundQ) && q <= lastFoundQ) {
535 std::vector<double> qVec;
536 std::vector<double> rVec;
541 if (skipLine || lineHasError)
565 const auto xAxisTitle = QString::fromStdString(label_map[Axes::Units::QSPACE]);
566 const auto yAxisTitle =
"Signal [a.u.]";
641 calculationErrors.clear();
642 validCalculatedLines = 0;
669 QDataStream s(&a, QIODevice::WriteOnly);
670 s.setVersion(QDataStream::Qt_5_12);
677 s << (quint8)columnDefinitions.count();
678 for (
const auto dataType : columnDefinitions.keys()) {
679 s << (quint8)dataType;
680 s << columnDefinitions[dataType].enabled;
681 s << columnDefinitions[dataType].column;
682 s << (quint8)columnDefinitions[dataType].unit;
683 s << columnDefinitions[dataType].factor;
691 columnDefinitions.clear();
694 s.setVersion(QDataStream::Qt_5_12);
706 for (
int i = 0; i < nDefs; i++) {
709 auto& colDef = columnDefinitions[(
DataType)dataType];
720 if (s.status() != QDataStream::Ok)
727 && factor == other.
factor;
736 case columnDoesNotContainValidNumber:
737 return QString(
"Raw column %1 does not contain a valid number - line is discarded")
738 .arg(std::get<int>(data));
741 return QString(
"The value %1 for Q is duplicate - line is discarded")
742 .arg(std::get<double>(data));
745 return QString(
"Q coordinates must be sorted in ascending order - line is discarded");
748 return QString(
"The value %1 for R is greater than 1.0 - line is discarded")
749 .arg(std::get<double>(data));
752 return QString(
"The value %1 for R is less than 0 - line is discarded")
753 .arg(std::get<double>(data));
756 return "Unspecified error";
761 stream << (quint8)s.
type;
762 if (std::holds_alternative<int>(s.
data)) {
764 stream << quint32(std::get<int>(s.
data));
767 stream << qreal(std::get<double>(s.
data));
#define ASSERT(condition)
Defines namespace AxisNames.
Defines class DeserializationException.
Defines ImportDataInfo helper struct.
Defines class IntensityDataIOFactory.
Defines class JobItemUtils.
Defines class PointwiseAxis.
Defines class QREDataLoaderResultModel.
QDataStream & operator>>(QDataStream &stream, QREDataLoader::ImportSettings &s)
Defines class QREDataLoader.
Defines class RealDataItem.
Defines class SpecularDataItem.
Base class for result tables of data loaders.
Base class for all data loaders (classes which can import real data)
void contentsProcessed()
Emitted whenever contents have been processed.
void importSettingsChanged()
Emitted whenever an import setting changed.
std::ostream & operator<<(std::ostream &os, const BasicVector3D< T > &a)
Output to stream.
Custom property to define list of string values with multiple selections.
QVariant variant() const
Constructs variant enclosing given ComboProperty.
static const QString P_AXES_UNITS
static DeserializationException streamError()
static DeserializationException tooOld()
static DeserializationException tooNew()
void addAxis(const IAxis &new_axis)
void setRawDataVector(const std::vector< T > &data_vector)
Sets new values to raw data vector.
OutputData * clone() const
Axis containing arbitrary (non-equidistant) coordinate values.
Properties widget for the QREDataLoader.
virtual QByteArray fileContent() const override
Returns the original file content.
virtual QString persistentClassName() const override
A name which can be used for save/load purposes (which will not change ever more)
friend QDataStream & operator<<(QDataStream &stream, const QREDataLoader::ImportSettings &s)
virtual void guessSettings() override
Guess appropriate settings (for example the separator in a CSV file).
virtual int numLineRelatedErrors() const override
Number of errors related to a specific line.
virtual int numErrors() const override
Number of errors found while processing the content.
virtual void initWithDefaultImportSettings() override
Set import settings to defaults.
virtual void setFileContents(const QByteArray &fileContent) override
Sets the file contents to be imported.
virtual QByteArray serialize() const override
Returns every internal setting so it can be restored completely.
void calculateFromParseResult() const
virtual void deserialize(const QByteArray &data) override
Initialize from serialization data.
virtual void applyImportSettings() override
Read all values from the properties UI into the internal variables.
virtual AbstractDataLoader * clone() const override
Create a complete clone, including all internal states.
virtual AbstractDataLoaderResultModel * createResultModel() const override
Create a table model which contains the import information like original file content,...
virtual void populateImportSettingsWidget(QWidget *parent) override
Fills the widget on the import dialog pane.
virtual QStringList lineUnrelatedErrors() const override
Errors not related to a particular line.
virtual QString name() const override
The name shown in the format selection combo.
QPointer< QREDataLoaderProperties > m_propertiesWidget
struct QREDataLoader::ImportSettings m_importSettings
ImportResult m_importResult
void createOutputDataFromParsingResult(RealDataItem *item) const
void parseFileContent() const
virtual void processContents() override
Process the file contents.
friend class QREDataLoaderResultModel
friend QDataStream & operator>>(QDataStream &stream, QREDataLoader::ImportSettings &s)
The RealDataItem class represents intensity data imported from file and intended for fitting.
bool isSpecularData() const
void setNativeOutputData(OutputData< double > *data)
takes ownership of data
void setNativeDataUnits(const QString &units)
SpecularDataItem * specularDataItem()
void setVisible(bool enabled)
Flags accessors.
void setItemValue(const QString &tag, const QVariant &variant)
Directly set value of item under given tag.
SessionItem * getItem(const QString &tag="", int row=0) const
Returns item in given row of given tag.
void setYaxisTitle(const QString &title) override
void setXaxisTitle(const QString &title) override
void setOutputData(OutputData< double > *data) override
The given pointer becomes owned by this class!!
void setAxesRangeToData() override
set zoom range of x,y axes to axes of input data
std::map< Axes::Units, std::string > InitSpecAxis()
QString nameFromAxesUnits(Axes::Units units)
returns axes units names from their domain counterpart
bool operator==(const ColumnDefinition &other) const
Contains a line related error (stored in the import result).
std::variant< int, double > data
Additional data; meaning depends on the error type (see implementation of toString() for more informa...
@ columnDoesNotContainValidNumber
ErrorDefinition(Type t=none, int d=0)
QString toString() const
Human readable error text.
QVector< double > rValues
index is 0-based line number
int maxColumnCount
max found columns in raw data
QString error
error unrelated to lines
void addError(int line, ErrorDefinition::Type type, int data=0)
void clearCalculatedValues()
int validCalculatedLines
number of valid resulting data rows
QVector< QVector< double > > rawValues
index is 0-based line number
QMap< int, ErrorDefinition > calculationErrors
calculation error per line; line is 0-based
QVector< double > eValues
index is 0-based line number
QString errorText(int line) const
ImportSettings importSettings
Settings used for the import.
QVector< double > qValues
index is 0-based line number
QVector< QPair< bool, QString > > lines
bool describes whether line is skipped index is 0-based line number
Settings for importing the file.
QString separator
column separator
QByteArray serialize() const
void deserialize(const QByteArray &data)
QMap< DataType, ColumnDefinition > columnDefinitions
QString headerPrefix
prefix denoting header line
bool operator!=(const ImportSettings &other) const
QString linesToSkip
pattern denoting line to skip (i.e. '1,10-12,42')