diff --git a/GUI/coregui/Models/SpecularDataItem.cpp b/GUI/coregui/Models/SpecularDataItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc13a2a943cb511898dfaf82215aefe2b958739f --- /dev/null +++ b/GUI/coregui/Models/SpecularDataItem.cpp @@ -0,0 +1,295 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file GUI/coregui/Models/SpecularDataItem.cpp +//! @brief Implements class SpecularDataItem +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************** // + +#include "SpecularDataItem.h" +#include "AxesItems.h" +#include "BornAgainNamespace.h" +#include "ComboProperty.h" +#include "GUIHelpers.h" +#include "BornAgainNamespace.h" + +const QString SpecularDataItem::P_AXES_UNITS = "Axes Units"; +const QString SpecularDataItem::P_TITLE = "Title"; +const QString SpecularDataItem::P_XAXIS = "x-axis"; +const QString SpecularDataItem::P_YAXIS = "y-axis"; +const QString SpecularDataItem::P_FILE_NAME = "FileName"; + +SpecularDataItem::SpecularDataItem() : SessionItem(Constants::SpecularDataType) +{ + ComboProperty units = ComboProperty() << Constants::UnitsNbins; + addProperty(P_AXES_UNITS, units.variant()); + + addProperty(P_TITLE, QString())->setVisible(false); + + SessionItem* item = addGroupProperty(P_XAXIS, Constants::BasicAxisType); + item->getItem(BasicAxisItem::P_NBINS)->setVisible(false); + + item = addGroupProperty(P_YAXIS, Constants::AmplitudeAxisType); + item->getItem(BasicAxisItem::P_NBINS)->setVisible(false); + item->getItem(BasicAxisItem::P_TITLE)->setVisible(true); + + item = item->getItem(AmplitudeAxisItem::P_IS_VISIBLE); + item->setValue(true); + item->setVisible(false); + + setXaxisTitle("X [nbins]"); + setYaxisTitle("Signal [a.u.]"); + + // name of the file used to serialize given SpecularDataItem + addProperty(P_FILE_NAME, QStringLiteral("undefined"))->setVisible(false); + + mapper()->setOnPropertyChange([this](const QString& name) + { + if(name == P_FILE_NAME) + setLastModified(QDateTime::currentDateTime()); + }); + + mapper()->setOnValueChange([this]() + { + // OutputData was modified + setLastModified(QDateTime::currentDateTime()); + }); +} + +void SpecularDataItem::setOutputData(OutputData<double>* data) +{ + Q_ASSERT(data); + m_data.reset(data); + + updateAxesZoomLevel(); + updateAxesLabels(); + computeDataRange(); + + emitDataChanged(); +} + +//! Sets the raw data vector from external source + +void SpecularDataItem::setRawDataVector(const OutputData<double>* data) +{ + if (!m_data->hasSameDimensions(*data)) { + throw GUIHelpers::Error("SpecularDataItem::setRawDataVector() -> Error. " + "Different dimensions of data."); + } + m_data->setRawDataVector(data->getRawDataVector()); + emitDataChanged(); +} + +int SpecularDataItem::getNbins() const +{ + return xAxisItem()->getItemValue(BasicAxisItem::P_NBINS).toInt(); +} + +double SpecularDataItem::getLowerX() const +{ + return getItem(P_XAXIS)->getItemValue(BasicAxisItem::P_MIN).toDouble(); +} + +double SpecularDataItem::getUpperX() const +{ + return getItem(P_XAXIS)->getItemValue(BasicAxisItem::P_MAX).toDouble(); +} + +double SpecularDataItem::getXmin() const +{ + const double defaultXmin(0.0); + return m_data ? m_data->getAxis(BornAgain::X_AXIS_INDEX).getMin() : defaultXmin; +} + +double SpecularDataItem::getXmax() const +{ + const double defaultXmax(1.0); + return m_data ? m_data->getAxis(BornAgain::X_AXIS_INDEX).getMax() : defaultXmax; +} + +double SpecularDataItem::getLowerY() const +{ + return getItem(P_YAXIS)->getItemValue(BasicAxisItem::P_MIN).toDouble(); +} + +double SpecularDataItem::getUpperY() const +{ + return getItem(P_YAXIS)->getItemValue(BasicAxisItem::P_MAX).toDouble(); +} + +double SpecularDataItem::getYmin() const +{ + const double defaultYmin(0.0); + auto limits = dataRange(); + return m_data ? limits.first : defaultYmin; +} + +double SpecularDataItem::getYmax() const +{ + const double defaultYmax(1.0); + auto limits = dataRange(); + return m_data ? limits.second : defaultYmax; +} + +bool SpecularDataItem::isLog() const +{ + return getItem(P_YAXIS)->getItemValue(AmplitudeAxisItem::P_IS_LOGSCALE).toBool(); +} + +QString SpecularDataItem::getXaxisTitle() const +{ + return getItem(P_XAXIS)->getItemValue(BasicAxisItem::P_TITLE).toString(); +} + +QString SpecularDataItem::getYaxisTitle() const +{ + return getItem(P_YAXIS)->getItemValue(BasicAxisItem::P_TITLE).toString(); +} + +QString SpecularDataItem::selectedAxesUnits() const +{ + ComboProperty combo = getItemValue(SpecularDataItem::P_AXES_UNITS).value<ComboProperty>(); + return combo.getValue(); +} + +QString SpecularDataItem::fileName(const QString& projectDir) const +{ + QString filename = getItemValue(SpecularDataItem::P_FILE_NAME).toString(); + return projectDir.isEmpty() ? filename : projectDir + QStringLiteral("/") + filename; +} + +void SpecularDataItem::setLowerX(double xmin) +{ + getItem(P_XAXIS)->setItemValue(BasicAxisItem::P_MIN, xmin); +} + +void SpecularDataItem::setUpperX(double xmax) +{ + getItem(P_XAXIS)->setItemValue(BasicAxisItem::P_MAX, xmax); +} + +void SpecularDataItem::setLowerY(double ymin) +{ + getItem(P_YAXIS)->setItemValue(AmplitudeAxisItem::P_MIN, ymin); +} + +void SpecularDataItem::setUpperY(double ymax) +{ + getItem(P_YAXIS)->setItemValue(AmplitudeAxisItem::P_MAX, ymax); +} + +void SpecularDataItem::setLog(bool log_flag) +{ + getItem(P_YAXIS)->setItemValue(AmplitudeAxisItem::P_IS_LOGSCALE, log_flag); +} + +void SpecularDataItem::setXaxisTitle(QString xtitle) +{ + getItem(P_XAXIS)->setItemValue(BasicAxisItem::P_TITLE, xtitle); +} + +void SpecularDataItem::setYaxisTitle(QString ytitle) +{ + getItem(P_YAXIS)->setItemValue(AmplitudeAxisItem::P_TITLE, ytitle); +} + +//! set zoom range of x,y axes to axes of input data +void SpecularDataItem::setAxesRangeToData() +{ + setLowerX(getXmin()); + setUpperX(getXmax()); + setLowerY(getYmin()); + setUpperY(getYmax()); +} + +//! Sets zoom range of X,Y axes, if it was not yet defined. + +void SpecularDataItem::updateAxesZoomLevel() +{ + // set zoom range of x-axis to min, max values if it was not set already + if (getUpperX() < getLowerX()) { + setLowerX(getXmin()); + setUpperX(getXmax()); + } + + // set zoom range of y-axis to min, max values if it was not set already + if (getUpperY() < getLowerY()) { + setLowerY(getYmin()); + setUpperY(getYmax()); + } + + const int nx = static_cast<int>(m_data->getAxis(BornAgain::X_AXIS_INDEX).size()); + xAxisItem()->setItemValue(BasicAxisItem::P_NBINS, nx); +} + +//! Init axes labels, if it was not done already. + +void SpecularDataItem::updateAxesLabels() +{ + if (getXaxisTitle().isEmpty()) + setXaxisTitle(QString::fromStdString(m_data->getAxis(BornAgain::X_AXIS_INDEX).getName())); +} + +void SpecularDataItem::computeDataRange() +{ + QPair<double, double> minmax = dataRange(); + setLowerY(minmax.first); + setUpperY(minmax.second); +} + +//! Init ymin, ymax to match the intensity values range. +QPair<double, double> SpecularDataItem::dataRange() const +{ + const OutputData<double>* data = getOutputData(); + double min(*std::min_element(data->begin(), data->end())); + double max(*std::max_element(data->begin(), data->end())); + if (isLog()) { + min /= 2.0; + max *= 2.0; + } else { + max = max * 1.1; + } + + return QPair<double, double>(min, max); +} + +const BasicAxisItem* SpecularDataItem::xAxisItem() const +{ + return dynamic_cast<const BasicAxisItem*>(getItem(P_XAXIS)); +} + +BasicAxisItem* SpecularDataItem::xAxisItem() +{ + return const_cast<BasicAxisItem*>(static_cast<const SpecularDataItem*>(this)->xAxisItem()); +} + +const AmplitudeAxisItem* SpecularDataItem::yAxisItem() const +{ + auto result = dynamic_cast<const AmplitudeAxisItem*>(getItem(P_YAXIS)); + Q_ASSERT(result); + return result; +} + +//! Set axes viewport to original data. + +void SpecularDataItem::resetView() +{ + setAxesRangeToData(); + computeDataRange(); +} + +QDateTime SpecularDataItem::lastModified() const +{ + return m_last_modified; +} + +void SpecularDataItem::setLastModified(const QDateTime &dtime) +{ + m_last_modified = dtime; +} diff --git a/GUI/coregui/Models/SpecularDataItem.h b/GUI/coregui/Models/SpecularDataItem.h new file mode 100644 index 0000000000000000000000000000000000000000..2912ac3012e0a72e35373f660d93181cdcc9571c --- /dev/null +++ b/GUI/coregui/Models/SpecularDataItem.h @@ -0,0 +1,101 @@ +// ************************************************************************** // +// +// BornAgain: simulate and fit scattering at grazing incidence +// +//! @file GUI/coregui/Models/SpecularDataItem.h +//! @brief Defines class SpecularDataItem +//! +//! @homepage http://www.bornagainproject.org +//! @license GNU General Public License v3 or higher (see COPYING) +//! @copyright Forschungszentrum Jülich GmbH 2018 +//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS) +// +// ************************************************************************** // + +#ifndef SPECULARDATAITEM_H +#define SPECULARDATAITEM_H + +#include "SessionItem.h" +#include "OutputData.h" +#include <QDateTime> + +class AmplitudeAxisItem; +class BasicAxisItem; +class MaskContainerItem; +class ProjectionContainerItem; + +class BA_CORE_API_ SpecularDataItem : public SessionItem +{ +public: + static const QString P_TITLE; + static const QString P_AXES_UNITS; + static const QString P_XAXIS; + static const QString P_YAXIS; + static const QString P_FILE_NAME; + + SpecularDataItem(); + + OutputData<double>* getOutputData() { return m_data.get(); } + const OutputData<double>* getOutputData() const { return m_data.get(); } + void setOutputData(OutputData<double>* data); + void setRawDataVector(const OutputData<double>* data); + + //! Number of bins in data + int getNbins() const; + + //! returns lower and upper zoom ranges of x-axis + double getLowerX() const; + double getUpperX() const; + + //! returns min and max range of x-axis as given by IntensityData + double getXmin() const; + double getXmax() const; + + //! returns lower and upper zoom ranges of y-axis + double getLowerY() const; + double getUpperY() const; + + //! returns min and max range of y-axis as given by IntensityData + double getYmin() const; + double getYmax() const; + + bool isLog() const; + QString getXaxisTitle() const; + QString getYaxisTitle() const; + + QString selectedAxesUnits() const; + + QString fileName(const QString& projectDir = QString()) const; + + void updateDataRange(); + void computeDataRange(); + QPair<double, double> dataRange() const; + + const BasicAxisItem* xAxisItem() const; + BasicAxisItem* xAxisItem(); + const AmplitudeAxisItem* yAxisItem() const; + + void resetView(); + + QDateTime lastModified() const; + void setLastModified(const QDateTime& dtime); + +public slots: + void setLowerX(double xmin); + void setUpperX(double xmax); + void setLowerY(double ymin); + void setUpperY(double ymax); + void setLog(bool log_flag); + void setXaxisTitle(QString xtitle); + void setYaxisTitle(QString ytitle); + void setAxesRangeToData(); + +private: + void updateAxesZoomLevel(); + void updateAxesLabels(); + + std::unique_ptr<OutputData<double>> m_data; //!< simulation results + QDateTime m_last_modified; +}; + +#endif // SPECULARDATAITEM_H diff --git a/GUI/coregui/Models/item_constants.h b/GUI/coregui/Models/item_constants.h index 6fc68656a053b1c99df102eebcd922a126bf3f5d..6fae1f0802f3b29a0b9b47a8a0609f44c5e5d473 100644 --- a/GUI/coregui/Models/item_constants.h +++ b/GUI/coregui/Models/item_constants.h @@ -135,6 +135,7 @@ const ModelType FitSuiteType = "FitSuite"; const ModelType JobItemType = "JobItem"; const ModelType IntensityDataType = "IntensityData"; +const ModelType SpecularDataType = "SpecularData"; const ModelType BasicAxisType = "BasicAxis"; const ModelType AmplitudeAxisType = "AmplitudeAxis";