Newer
Older
// ************************************************************************************************
// BornAgain: simulate and fit reflection and scattering
//! @brief Implement class InstrumentItem and all its children
//! @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 "Base/Const/Units.h"
#include "Core/Simulation/DepthProbeSimulation.h"
#include "Device/Detector/RectangularDetector.h"
#include "Device/Detector/SphericalDetector.h"
#include "Device/Instrument/CoordSystem2D.h"
#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"
#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"
Pospelov, Gennady
committed
const QString background_group_label = "Type";
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->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);
// ************************************************************************************************
// 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
{
Gennady Pospelov
committed
return item<BeamItem>(P_BEAM);
BackgroundItem* InstrumentItem::backgroundItem() const
{
return &groupItem<BackgroundItem>(P_BACKGROUND);
}
GroupItem* InstrumentItem::backgroundGroup()
{
Gennady Pospelov
committed
return item<GroupItem>(P_BACKGROUND);
bool InstrumentItem::alignedWith(const RealDataItem* item) const
{
return shape() == item->shape();
}
std::unique_ptr<Instrument> InstrumentItem::createInstrument() const
{
std::unique_ptr<Instrument> result(new Instrument);
result->setBeam(*beamItem()->createBeam());
return result;
}
InstrumentItem::InstrumentItem(const QString& modelType) : SessionItem(modelType)
{
setItemName(modelType);
addProperty(P_IDENTIFIER, GUIHelpers::createUuid())->setVisible(false);
void InstrumentItem::initBackgroundGroup()
{

Wuttke, Joachim
committed
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")
{
initBackgroundGroup();
beam<SpecularBeamItem>()->updateFileName(
Gennady Pospelov
committed
ItemFileNameUtils::instrumentDataFileName(*this));
SpecularBeamItem* SpecularInstrumentItem::beamItem() const
{
SpecularInstrumentItem::~SpecularInstrumentItem() = default;
std::vector<int> SpecularInstrumentItem::shape() const
{
const auto axis_item = beamItem()->currentInclinationAxisItem();
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();

Wuttke, Joachim
committed
if (native_units == "nbins") {
return beamItem()->currentInclinationAxisItem()->modelType() == BasicAxisItem::M_TYPE
&& shape() == item->shape();
} else {
auto axis_item = dynamic_cast<PointwiseAxisItem*>(beamItem()->currentInclinationAxisItem());
if (!axis_item)
return false;
if (axis_item->getUnitsLabel() != native_units)
return false;
if (!instrument_axis)
return false;
if (!item->hasNativeData())
return false;
const auto& native_axis = item->nativeOutputData()->axis(0);
return *instrument_axis == native_axis;
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;
Axes::Coords native_units = JobItemUtils::coordsFromName(pointwise_axis->getUnitsLabel());
return new AngularReflectometryCoordinates(instrument->beam().wavelength(),
*pointwise_axis->axis(), native_units);
return new AngularReflectometryCoordinates(instrument->beam().wavelength(),
*axis_item->createAxis(1.0), Axes::Coords::DEGREES);
QString SpecularInstrumentItem::defaultName() const
{
return "Specular";
}
// ************************************************************************************************
// class Instrument2DItem
// ************************************************************************************************
Pospelov, Gennady
committed
const QString Instrument2DItem::P_DETECTOR = "Detector";
Instrument2DItem::Instrument2DItem(const QString& modelType) : InstrumentItem(modelType)
{

Wuttke, Joachim
committed
addGroupProperty(P_DETECTOR, "Detector group");
initBackgroundGroup();
setDefaultTag(P_DETECTOR);
Pospelov, Gennady
committed
Instrument2DItem::~Instrument2DItem() = default;
DetectorItem* Instrument2DItem::detectorItem() const
{
return &groupItem<DetectorItem>(P_DETECTOR);
Pospelov, Gennady
committed
}
GroupItem* Instrument2DItem::detectorGroup()
{
Gennady Pospelov
committed
return item<GroupItem>(P_DETECTOR);
Pospelov, Gennady
committed
}
void Instrument2DItem::setDetectorGroup(const QString& modelType)
{
setGroupProperty(P_DETECTOR, modelType);
void Instrument2DItem::clearMasks()
{
detectorItem()->clearMasks();
void Instrument2DItem::importMasks(const MaskContainerItem* maskContainer)
{
detectorItem()->importMasks(maskContainer);
Van Herck, Walter
committed
std::unique_ptr<Instrument> Instrument2DItem::createInstrument() const
{
auto result = InstrumentItem::createInstrument();
result->setDetector(*detectorItem()->createDetector());
return result;
}
// ************************************************************************************************
// class GISASInstrumentItem
// ************************************************************************************************

Wuttke, Joachim
committed
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();

Wuttke, Joachim
committed
return instrument->createScatteringCoords();
// ************************************************************************************************
// 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)
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");
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->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>();
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
}
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());
return simulation;
}
ICoordSystem* DepthProbeInstrumentItem::createCoordSystem() const
return createSimulation()->createCoordSystem();