Skip to content
Snippets Groups Projects
InstrumentItems.cpp 15.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • //  ************************************************************************************************
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    //
    
    //  BornAgain: simulate and fit reflection and scattering
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    //
    
    t.knopff's avatar
    t.knopff committed
    //! @file      GUI/Models/InstrumentItems.cpp
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    //! @brief     Implement class InstrumentItem and all its children
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    //!
    
    //! @homepage  http://www.bornagainproject.org
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    //! @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)
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    //
    
    //  ************************************************************************************************
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    
    
    t.knopff's avatar
    t.knopff committed
    #include "GUI/Models/InstrumentItems.h"
    
    #include "Base/Pixel/RectangularPixel.h"
    
    #include "Core/Simulation/DepthProbeSimulation.h"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "Device/Coord/CoordSystem1D.h"
    
    #include "Device/Detector/RectangularDetector.h"
    #include "Device/Detector/SphericalDetector.h"
    
    #include "Device/Instrument/CoordSystem2D.h"
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    #include "Device/Instrument/Instrument.h"
    
    t.knopff's avatar
    t.knopff committed
    #include "GUI/Models/BackgroundItems.h"
    #include "GUI/Models/BeamWavelengthItem.h"
    #include "GUI/Models/DataItem.h"
    #include "GUI/Models/DetectorItems.h"
    
    #include "GUI/Models/Error.h"
    
    t.knopff's avatar
    t.knopff committed
    #include "GUI/Models/GroupItem.h"
    #include "GUI/Models/ItemFileNameUtils.h"
    #include "GUI/Models/JobItemUtils.h"
    #include "GUI/Models/MaskItems.h"
    #include "GUI/Models/PointwiseAxisItem.h"
    #include "GUI/Models/RealDataItem.h"
    #include "GUI/Models/SessionModel.h"
    #include "GUI/Models/SpecularBeamInclinationItem.h"
    #include "GUI/Models/TransformToDomain.h"
    #include "GUI/utils/GUIHelpers.h"
    
    namespace {
    
    const QString background_group_label = "Type";
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
    const QStringList instrument_names{"GISASInstrument", "OffSpecularInstrument",
                                       "SpecularInstrument"};
    
    BasicAxisItem* addAxisGroupProperty(SessionItem* parent, const QString& tag)
    
        BasicAxisItem* axisItem = parent->addProperty<BasicAxisItem>(tag);
    
        axisItem->setToolTip("Incoming alpha range [deg]");
    
        axisItem->titleItem()->setVisible(false);
    
        axisItem->binsItem()->setToolTip("Number of points in scan");
    
        axisItem->lowerBoundItem()->setToolTip("Starting value [deg]");
        axisItem->upperBoundItem()->setToolTip("Ending value [deg]");
    
    
        axisItem->setTitle("alpha_i");
        axisItem->setLowerBound(0.0);
        axisItem->setUpperBound(10.0);
    
    
        return axisItem;
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
    } // namespace
    
    
    //  ************************************************************************************************
    //  class InstrumentItem
    //  ************************************************************************************************
    
    
    const QString InstrumentItem::P_IDENTIFIER = "Identifier";
    
    const QString InstrumentItem::P_BEAM = "Beam";
    const QString InstrumentItem::P_BACKGROUND = "Background";
    
    
    QString InstrumentItem::id() const
    {
        return getItemValue(P_IDENTIFIER).toString();
    }
    
    void InstrumentItem::setId(const QString& id)
    {
        setItemValue(P_IDENTIFIER, id);
    }
    
    
    void InstrumentItem::setName(const QString& instrumentName)
    {
        setItemName(instrumentName);
    }
    
    QString InstrumentItem::name() const
    {
        return itemName();
    }
    
    
    BeamItem* InstrumentItem::beamItem() const
    {
    
    BackgroundItem* InstrumentItem::backgroundItem() const
    {
    
        return &groupItem<BackgroundItem>(P_BACKGROUND);
    }
    
    
    GroupItem* InstrumentItem::backgroundGroup()
    {
    
    bool InstrumentItem::alignedWith(const RealDataItem* item) const
    {
    
    std::unique_ptr<Instrument> InstrumentItem::createInstrument() const
    {
    
        std::unique_ptr<Instrument> result(new Instrument);
    
        result->setBeam(*beamItem()->createBeam());
    
    InstrumentItem::InstrumentItem(const QString& modelType) : SessionItem(modelType)
    {
    
        setItemName(modelType);
        addProperty(P_IDENTIFIER, GUIHelpers::createUuid())->setVisible(false);
    
    void InstrumentItem::initBackgroundGroup()
    {
    
        auto item = addGroupProperty(P_BACKGROUND, "Background group");
    
        item->setDisplayName(background_group_label);
        item->setToolTip("Background type");
    }
    
    
    template <typename T> void InstrumentItem::addBeam()
    {
        addProperty<T>(P_BEAM);
    }
    
    template <typename T> T* InstrumentItem::beam() const
    {
        return item<T>(P_BEAM);    
    }
    
    
    //  ************************************************************************************************
    //  class SpecularInstrumentItem
    //  ************************************************************************************************
    
    
    SpecularInstrumentItem::SpecularInstrumentItem() : InstrumentItem("SpecularInstrument")
    {
    
        addBeam<SpecularBeamItem>();
    
        beam<SpecularBeamItem>()->updateFileName(
    
            ItemFileNameUtils::instrumentDataFileName(*this));
    
    SpecularBeamItem* SpecularInstrumentItem::beamItem() const
    {
    
        return beam<SpecularBeamItem>();
    
    SpecularInstrumentItem::~SpecularInstrumentItem() = default;
    
    
    std::vector<int> SpecularInstrumentItem::shape() const
    {
    
        const auto axis_item = beamItem()->currentInclinationAxisItem();
    
        return {axis_item->binCount()};
    
    void SpecularInstrumentItem::updateToRealData(const RealDataItem* item)
    {
    
        if (shape().size() != item->shape().size())
    
            throw Error("Error in SpecularInstrumentItem::updateToRealData: The type "
                        "of instrument is incompatible with passed data shape.");
    
        const auto& data = item->nativeOutputData()->axis(0);
    
        beamItem()->updateToData(data, item->nativeDataUnits());
    
    bool SpecularInstrumentItem::alignedWith(const RealDataItem* item) const
    {
    
        const QString native_units = item->nativeDataUnits();
    
            return beamItem()->currentInclinationAxisItem()->modelType() == BasicAxisItem::M_TYPE
    
                   && shape() == item->shape();
        } else {
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
            auto axis_item = dynamic_cast<PointwiseAxisItem*>(beamItem()->currentInclinationAxisItem());
    
            if (!axis_item)
                return false;
            if (axis_item->getUnitsLabel() != native_units)
                return false;
    
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            auto instrument_axis = axis_item->axis();
    
            const auto& native_axis = item->nativeOutputData()->axis(0);
    
            return *instrument_axis == native_axis;
    
    Pospelov, Gennady's avatar
    Pospelov, Gennady committed
        }
    
    ICoordSystem* SpecularInstrumentItem::createCoordSystem() const
    
        const auto instrument = createInstrument();
        auto axis_item = beamItem()->currentInclinationAxisItem();
    
        if (auto pointwise_axis = dynamic_cast<PointwiseAxisItem*>(axis_item)) {
    
            if (!pointwise_axis->containsNonXMLData()) // workaround for loading project
                return nullptr;
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            Axes::Coords native_units = JobItemUtils::coordsFromName(pointwise_axis->getUnitsLabel());
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
            return new AngularReflectometryCoordinates(instrument->beam().wavelength(),
                                                       *pointwise_axis->axis(), native_units);
    
    Wuttke, Joachim's avatar
    Wuttke, Joachim committed
        return new AngularReflectometryCoordinates(instrument->beam().wavelength(),
                                                   *axis_item->createAxis(1.0), Axes::Coords::DEGREES);
    
    QString SpecularInstrumentItem::defaultName() const
    {
        return "Specular";
    }
    
    
    
    //  ************************************************************************************************
    //  class Instrument2DItem
    //  ************************************************************************************************
    
    
    const QString Instrument2DItem::P_DETECTOR = "Detector";
    
    Instrument2DItem::Instrument2DItem(const QString& modelType) : InstrumentItem(modelType)
    {
    
        addBeam<GISASBeamItem>();
    
        addGroupProperty(P_DETECTOR, "Detector group");
    
    Instrument2DItem::~Instrument2DItem() = default;
    
    
    DetectorItem* Instrument2DItem::detectorItem() const
    {
    
        return &groupItem<DetectorItem>(P_DETECTOR);
    
    GroupItem* Instrument2DItem::detectorGroup()
    {
    
    void Instrument2DItem::setDetectorGroup(const QString& modelType)
    {
    
        setGroupProperty(P_DETECTOR, modelType);
    
    void Instrument2DItem::clearMasks()
    {
    
        detectorItem()->clearMasks();
    
    void Instrument2DItem::importMasks(const MaskContainerItem* maskContainer)
    {
    
        detectorItem()->importMasks(maskContainer);
    
    std::unique_ptr<Instrument> Instrument2DItem::createInstrument() const
    {
    
        auto result = InstrumentItem::createInstrument();
    
        result->setDetector(*detectorItem()->createDetector());
    
    
    //  ************************************************************************************************
    //  class GISASInstrumentItem
    //  ************************************************************************************************
    
    
    GISASInstrumentItem::GISASInstrumentItem() : Instrument2DItem("GISASInstrument") {}
    
    std::vector<int> GISASInstrumentItem::shape() const
    {
    
        auto detector_item = detectorItem();
        return {detector_item->xSize(), detector_item->ySize()};
    }
    
    
    void GISASInstrumentItem::updateToRealData(const RealDataItem* item)
    {
    
        if (!item)
            return;
    
        const auto data_shape = item->shape();
    
        if (shape().size() != data_shape.size())
    
            throw Error("Error in GISASInstrumentItem::updateToRealData: The type of "
                        "instrument is incompatible with passed data shape.");
    
        detectorItem()->setXSize(data_shape[0]);
        detectorItem()->setYSize(data_shape[1]);
    }
    
    
    QString GISASInstrumentItem::defaultName() const
    {
        return "GISAS";
    }
    
    
    ICoordSystem* GISASInstrumentItem::createCoordSystem() const
    
    {
        const auto instrument = createInstrument();
        instrument->initDetector();
    
    
    //  ************************************************************************************************
    //  class OffSpecularInstrumentItem
    //  ************************************************************************************************
    
    
    const QString OffSpecularInstrumentItem::P_ALPHA_AXIS = "Alpha axis";
    
    OffSpecularInstrumentItem::OffSpecularInstrumentItem() : Instrument2DItem("OffSpecularInstrument")
    {
    
        BasicAxisItem* axis_item = addAxisGroupProperty(this, P_ALPHA_AXIS);
        auto inclination_item = axis_item->lowerBoundItem();
    
        auto beam_item = beamItem();
        beam_item->setInclinationAngle(inclination_item->value().toDouble());
    
        beam_item->inclinationAngleItem()->setEnabled(false);
    
        inclination_item->mapper()->setOnValueChange([beam_item, inclination_item]() {
            beam_item->setInclinationAngle(inclination_item->value().toDouble());
        });
    
    std::vector<int> OffSpecularInstrumentItem::shape() const
    {
    
        const int x_size = item<BasicAxisItem>(P_ALPHA_AXIS)->binCount();
    
        auto detector_item = detectorItem();
        return {x_size, detector_item->ySize()};
    }
    
    
    void OffSpecularInstrumentItem::updateToRealData(const RealDataItem* dataItem)
    
        if (!dataItem)
    
        const auto data_shape = dataItem->shape();
    
        if (shape().size() != data_shape.size())
    
            throw Error("Error in OffSpecularInstrumentItem::updateToRealData: The type of "
                        "instrument is incompatible with passed data shape.");
    
    
        item<BasicAxisItem>(P_ALPHA_AXIS)->setBinCount(data_shape[0]);
    
        detectorItem()->setYSize(data_shape[1]);
    }
    
    
    QString OffSpecularInstrumentItem::defaultName() const
    {
        return "OffSpecular";
    }
    
    ICoordSystem* OffSpecularInstrumentItem::createCoordSystem() const
    
    {
        const auto instrument = createInstrument();
        instrument->initDetector();
    
        const auto axis_item = item<BasicAxisItem>(OffSpecularInstrumentItem::P_ALPHA_AXIS);
    
        const auto detector2d = dynamic_cast<const IDetector2D*>(instrument->getDetector());
    
        const auto axes = detector2d->axesClippedToRegionOfInterest();
        ASSERT(axes.size() == 2);
        const IAxis& yAxis = *axes[1];
        const Beam& beam = instrument->beam();
        const auto alphaAxis = axis_item->createAxis(Units::deg);
    
        if (const auto* rectDetector = dynamic_cast<const RectangularDetector*>(detector2d)) {
            std::unique_ptr<RectangularPixel> detectorPixel(rectDetector->regionOfInterestPixel());
            return OffSpecularCoordinates::createForRectangularDetector(beam, *alphaAxis,
                                                                        *detectorPixel, yAxis);
        } else if (dynamic_cast<const SphericalDetector*>(detector2d))
            return OffSpecularCoordinates::createForSphericalDetector(beam, *alphaAxis, yAxis);
    
        ASSERT(0);
        return nullptr;
    
    
    //  ************************************************************************************************
    //  class DepthProbeInstrumentItem
    //  ************************************************************************************************
    
    
    const QString DepthProbeInstrumentItem::P_Z_AXIS = "Z axis";
    
    DepthProbeInstrumentItem::DepthProbeInstrumentItem() : InstrumentItem("DepthProbeInstrument")
    {
        setItemName("DepthProbeInstrument");
    
    
        addBeam<SpecularBeamItem>();
    
    
        auto axisItem = beamItem()->currentInclinationAxisItem();
        axisItem->setLowerBound(0.0);
        axisItem->setUpperBound(1.0);
        axisItem->setBinCount(500);
    
        auto axis = addProperty<BasicAxisItem>(P_Z_AXIS);
        axis->setLowerBound(-100.0);
        axis->setUpperBound(100.0);
    
        axis->titleItem()->setVisible(false);
    
        axis->binsItem()->setToolTip("Number of points in scan across sample bulk");
    
        axis->lowerBoundItem()->setToolTip("Starting value below sample horizont in nm");
        axis->upperBoundItem()->setToolTip("Ending value above sample horizont in nm");
    
    }
    
    SpecularBeamItem* DepthProbeInstrumentItem::beamItem() const
    {
    
        return beam<SpecularBeamItem>();
    
    }
    
    std::unique_ptr<Instrument> DepthProbeInstrumentItem::createInstrument() const
    {
        throw std::runtime_error("DepthProbeInstrumentItem::createInstrument()");
    }
    
    std::vector<int> DepthProbeInstrumentItem::shape() const
    {
        return std::vector<int>(); // no certain shape to avoid linking to real data
    }
    
    void DepthProbeInstrumentItem::updateToRealData(const RealDataItem*)
    {
        throw std::runtime_error("DepthProbeInstrumentItem::updateToRealData()");
    }
    
    QString DepthProbeInstrumentItem::defaultName() const
    {
        return "DepthProbe";
    }
    
    std::unique_ptr<DepthProbeSimulation> DepthProbeInstrumentItem::createSimulation() const
    {
        std::unique_ptr<DepthProbeSimulation> simulation = std::make_unique<DepthProbeSimulation>();
    
        const auto axis_item = beamItem()->currentInclinationAxisItem();
    
        auto axis = axis_item->createAxis(Units::deg);
    
        simulation->setBeamParameters(beamItem()->wavelength(), static_cast<int>(axis->size()),
                                      axis->lowerBound(), axis->upperBound());
    
        auto depthAxisItem = dynamic_cast<BasicAxisItem*>(getItem(P_Z_AXIS));
        auto depthAxis = depthAxisItem->createAxis(1.0);
        simulation->setZSpan(depthAxis->size(), depthAxis->lowerBound(), depthAxis->upperBound());
    
    
        TransformToDomain::setBeamDistribution(ParameterDistribution::BeamWavelength,
                                               *beamItem()->wavelengthItem(), *simulation.get());
    
        TransformToDomain::setBeamDistribution(ParameterDistribution::BeamInclinationAngle,
                                               *beamItem()->inclinationAngleItem(), *simulation.get());
    
    ICoordSystem* DepthProbeInstrumentItem::createCoordSystem() const
    
        return createSimulation()->createCoordSystem();