// ************************************************************************************************ // // BornAgain: simulate and fit reflection and scattering // //! @file GUI/Model/Beam/SourceItems.cpp //! @brief Implements BeamItem hierarchy //! //! @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 "GUI/Model/Beam/SourceItems.h" #include "Base/Axis/Scale.h" #include "Base/Const/Units.h" #include "Base/Util/Assert.h" #include "Device/Beam/Beam.h" #include "Device/Beam/FootprintGauss.h" #include "Device/Beam/FootprintSquare.h" #include "GUI/Model/Axis/PointwiseAxisItem.h" #include "GUI/Model/Beam/BeamAngleItems.h" #include "GUI/Model/Beam/BeamWavelengthItem.h" #include "GUI/Model/Beam/FootprintItems.h" #include "GUI/Model/Beam/GrazingScanItem.h" #include "Sim/Scan/AlphaScan.h" namespace { namespace Tag { const QString Intensity("Intensity"); const QString Wavelength("Wavelength"); const QString AzimuthalAngle("AzimuthalAngle"); const QString InclinationAngle("InclinationAngle"); const QString GrazingScan("GrazingScan"); const QString Footprint("Footprint"); const QString BaseData("BaseData"); const QString ExpandBeamParametersGroupbox("ExpandBeamParametersGroupbox"); const QString ExpandFootprintGroupbox("ExpandFootprintGroupbox"); } // namespace Tag } // namespace // ************************************************************************************************ // SourceItem // ************************************************************************************************ SourceItem::SourceItem() { m_intensity.init("Intensity", "Beam intensity in neutrons/photons per sec.", 1e8, Unit::unitless, 3 /* decimals */, RealLimits::limited(0.0, 1e32), "intensity"); m_azimuthalAngleItem.reset(new BeamAzimuthalAngleItem()); m_footprint.init("Type", "Footprint type"); } void SourceItem::writeTo(QXmlStreamWriter* w) const { ASSERT(m_wavelengthItem); XML::writeAttribute(w, XML::Attrib::version, uint(2)); // intensity w->writeStartElement(Tag::Intensity); m_intensity.writeTo(w); w->writeEndElement(); // wavelength w->writeStartElement(Tag::Wavelength); m_wavelengthItem->writeTo(w); w->writeEndElement(); // azimuthal angle w->writeStartElement(Tag::AzimuthalAngle); m_azimuthalAngleItem->writeTo(w); w->writeEndElement(); // beam parameters groupbox: is expanded? w->writeStartElement(Tag::ExpandBeamParametersGroupbox); XML::writeAttribute(w, XML::Attrib::value, m_expandBeamParameters); w->writeEndElement(); // footprint w->writeStartElement(Tag::Footprint); m_footprint.writeTo(w); w->writeEndElement(); // footprint groupbox: is expanded? w->writeStartElement(Tag::ExpandFootprintGroupbox); XML::writeAttribute(w, XML::Attrib::value, m_expandFootprint); w->writeEndElement(); } void SourceItem::readFrom(QXmlStreamReader* r) { ASSERT(m_wavelengthItem); const uint version = XML::readUIntAttribute(r, XML::Attrib::version); Q_UNUSED(version) while (r->readNextStartElement()) { QString tag = r->name().toString(); // intensity if (tag == Tag::Intensity) { m_intensity.readFrom(r); XML::gotoEndElementOfTag(r, tag); // wavelength } else if (tag == Tag::Wavelength) { m_wavelengthItem->readFrom(r); XML::gotoEndElementOfTag(r, tag); // azimuthal angle } else if (tag == Tag::AzimuthalAngle) { m_azimuthalAngleItem->readFrom(r); XML::gotoEndElementOfTag(r, tag); // beam parameters groupbox: is expanded? } else if (tag == Tag::ExpandBeamParametersGroupbox) { XML::readAttribute(r, XML::Attrib::value, &m_expandBeamParameters); XML::gotoEndElementOfTag(r, tag); // footprint } else if (tag == Tag::Footprint) { m_footprint.readFrom(r); XML::gotoEndElementOfTag(r, tag); // footprint groupbox: is expanded? } else if (tag == Tag::ExpandFootprintGroupbox) { XML::readAttribute(r, XML::Attrib::value, &m_expandFootprint); XML::gotoEndElementOfTag(r, tag); } else r->skipCurrentElement(); } } double SourceItem::wavelength() const { ASSERT(m_wavelengthItem); return m_wavelengthItem->wavelength(); } void SourceItem::setWavelength(double value) { ASSERT(m_wavelengthItem); m_wavelengthItem->resetToValue(value); } BeamWavelengthItem* SourceItem::wavelengthItem() const { ASSERT(m_wavelengthItem); return m_wavelengthItem.get(); } double SourceItem::azimuthalAngle() const { ASSERT(m_azimuthalAngleItem); return m_azimuthalAngleItem->azimuthalAngle(); } void SourceItem::setAzimuthalAngle(double value) { ASSERT(m_azimuthalAngleItem); m_azimuthalAngleItem->resetToValue(value); } BeamAzimuthalAngleItem* SourceItem::azimuthalAngleItem() const { ASSERT(m_azimuthalAngleItem); return m_azimuthalAngleItem.get(); } void SourceItem::setGaussianFootprint(double value) { m_footprint.setCurrentItem(new FootprintGaussianItem(value)); } void SourceItem::setSquareFootprint(double value) { m_footprint.setCurrentItem(new FootprintSquareItem(value)); } void SourceItem::setFootprint(const IFootprint* footprint) { if (!footprint) return; if (const auto* const fp = dynamic_cast<const FootprintGauss*>(footprint)) setGaussianFootprint(fp->widthRatio()); else if (const auto* const fp = dynamic_cast<const FootprintSquare*>(footprint)) setSquareFootprint(fp->widthRatio()); } // ************************************************************************************************ // BeamItem // ************************************************************************************************ BeamItem::BeamItem() { m_wavelengthItem.reset(new BeamWavelengthItem); m_inclinationAngleItem.reset(new BeamInclinationAngleItem); } void BeamItem::writeTo(QXmlStreamWriter* w) const { ASSERT(m_inclinationAngleItem); XML::writeAttribute(w, XML::Attrib::version, uint(1)); // parameters from base class w->writeStartElement(Tag::BaseData); SourceItem::writeTo(w); w->writeEndElement(); // inclination angle w->writeStartElement(Tag::InclinationAngle); m_inclinationAngleItem->writeTo(w); w->writeEndElement(); } void BeamItem::readFrom(QXmlStreamReader* r) { const uint version = XML::readUIntAttribute(r, XML::Attrib::version); Q_UNUSED(version) ASSERT(m_inclinationAngleItem); while (r->readNextStartElement()) { QString tag = r->name().toString(); // parameters from base class if (tag == Tag::BaseData) { SourceItem::readFrom(r); XML::gotoEndElementOfTag(r, tag); // inclination angle } else if (tag == Tag::InclinationAngle) { m_inclinationAngleItem->readFrom(r); XML::gotoEndElementOfTag(r, tag); } else r->skipCurrentElement(); } } void BeamItem::setInclinationAngle(double value) { ASSERT(m_inclinationAngleItem); m_inclinationAngleItem->resetToValue(value); } BeamDistributionItem* BeamItem::beamDistributionItem() const { ASSERT(m_inclinationAngleItem); return m_inclinationAngleItem.get(); } double BeamItem::getInclinationAngle() const { return dynamic_cast<BeamInclinationAngleItem*>(beamDistributionItem())->inclinationAngle(); } std::unique_ptr<Beam> BeamItem::createBeam() const { double lambda = wavelength(); double inclination_angle = Units::deg2rad(getInclinationAngle()); double azimuthal_angle = Units::deg2rad(azimuthalAngle()); auto result = std::make_unique<Beam>(intensity(), lambda, inclination_angle, azimuthal_angle); result->setFootprint(m_footprint.currentItem()->createFootprint().get()); return result; } // ************************************************************************************************ // ScanItem // ************************************************************************************************ ScanItem::ScanItem() { m_grazingScanItem.reset(new GrazingScanItem()); m_wavelengthItem.reset(new BeamWavelengthItem); } void ScanItem::setScan(const IBeamScan* scan) { setIntensity(scan->intensity()); if (const auto* s = dynamic_cast<const AlphaScan*>(scan)) setWavelength(s->wavelength()); setAzimuthalAngle(0.0); auto* axis_item = inclinationAxisItem(); const Scale* axis = scan->coordinateAxis(); ASSERT(axis); // TODO do we need to check that axis is equidistant? axis_item->setBinCount(static_cast<int>(axis->size())); axis_item->setMin(axis->min() / Units::deg); axis_item->setMax(axis->max() / Units::deg); setFootprint(scan->footprint()); } void ScanItem::writeTo(QXmlStreamWriter* w) const { XML::writeAttribute(w, XML::Attrib::version, uint(2)); // parameters from base class w->writeStartElement(Tag::BaseData); SourceItem::writeTo(w); w->writeEndElement(); // grazing scan w->writeStartElement(Tag::GrazingScan); m_grazingScanItem->writeTo(w); w->writeEndElement(); } void ScanItem::readFrom(QXmlStreamReader* r) { const uint version = XML::readUIntAttribute(r, XML::Attrib::version); while (r->readNextStartElement()) { QString tag = r->name().toString(); // parameters from base class if (tag == Tag::BaseData) { SourceItem::readFrom(r); XML::gotoEndElementOfTag(r, tag); // footprint (moved to base class since v21 (version == 2)) } else if (version == 1 && tag == Tag::Footprint) { m_footprint.readFrom(r); XML::gotoEndElementOfTag(r, tag); // footprint groupbox: is expanded? (moved to base class since v21 (version == 2)) } else if (version == 1 && tag == Tag::ExpandFootprintGroupbox) { XML::readAttribute(r, XML::Attrib::value, &m_expandFootprint); XML::gotoEndElementOfTag(r, tag); // grazing scan } else if (tag == Tag::GrazingScan) { m_grazingScanItem->readFrom(r); XML::gotoEndElementOfTag(r, tag); } else r->skipCurrentElement(); } } GrazingScanItem* ScanItem::grazingScanItem() const { return m_grazingScanItem.get(); } BasicAxisItem* ScanItem::inclinationAxisItem() const { return grazingScanItem()->alphaAxisItem(); } void ScanItem::updateToData(const Scale& axis, QString units, const Frame& frame) { if (units == "nbins") { grazingScanItem()->initUniformAxis(axis); grazingScanItem()->selectUniformAxis(); } else { grazingScanItem()->initListScan(axis, units, frame); grazingScanItem()->selectListScan(); } }