diff --git a/Examples/bayesian/likelihood_sampling.py b/Examples/bayesian/likelihood_sampling.py new file mode 100644 index 0000000000000000000000000000000000000000..1c7b14600ca95c74f1b70570244f29e81ae88389 --- /dev/null +++ b/Examples/bayesian/likelihood_sampling.py @@ -0,0 +1,167 @@ +""" +An example of using the Bayesian sampling library emcee with BornAgain. + +author: Andrew McCluskey (andrew.mccluskey@ess.eu) +""" + +# Import necessary modules +from os import path, getenv +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import differential_evolution +import emcee +import corner +import bornagain as ba +from bornagain import ba_fitmonitor + +np.random.seed(1) + +datadir = getenv('BORNAGAIN_EXAMPLE_DATA_DIR', '') + + +# Define the sample +def get_sample(ni_thickness, ti_thickness): + """ + Creates a sample and returns it + :float ni_thickness: a value of the Ni thickness in nanometres + :float ti_thickness: a value of the Ti thickness in nanometres + :return: the sample defined + """ + + # pure real scattering-length densities (in angstrom^-2) + si_sld_real = 2.0704e-06 # Si (substrate) + ni_sld_real = 9.4245e-06 # Ni + ti_sld_real = -1.9493e-06 # Ti + + n_repetitions = 10 + + # defining materials + m_vacuum = ba.MaterialBySLD() + m_ni = ba.MaterialBySLD("Ni", ni_sld_real, 0) + m_ti = ba.MaterialBySLD("Ti", ti_sld_real, 0) + m_substrate = ba.MaterialBySLD("SiSubstrate", si_sld_real, 0) + + # vacuum layer and substrate form multi layer + vacuum_layer = ba.Layer(m_vacuum) + ni_layer = ba.Layer(m_ni, ni_thickness) + ti_layer = ba.Layer(m_ti, ti_thickness) + substrate_layer = ba.Layer(m_substrate) + multi_layer = ba.MultiLayer() + multi_layer.addLayer(vacuum_layer) + for i in range(n_repetitions): + multi_layer.addLayer(ti_layer) + multi_layer.addLayer(ni_layer) + multi_layer.addLayer(substrate_layer) + return multi_layer + + +# Source the real data and add an uncertainty to the ordinate +def get_real_data(): + """ + Loading data from genx_interchanging_layers.dat + Returns a Nx3 array (N - the number of experimental data entries) + with first column being coordinates, + second one being values, and the third the uncertainties. + """ + if not hasattr(get_real_data, "data"): + filepath = path.join(datadir, 'genx_interchanging_layers.dat.gz') + real_data = ba.IntensityDataIOFactory.readIntensityData( + filepath).array() + # translating axis values from double incident angle (degs) + # to incident angle (radians) + real_data[:, 0] *= np.pi/360 + # setting artificial uncertainties (uncertainty sigma equals a ten + # percent of experimental data value) + real_data[:, 2] = real_data[:, 1]*0.1 + return real_data + + +# Define the simulation +def get_simulation(alpha): + """ + Defines and returns a specular simulation. + """ + wavelength = 0.154 #nm + scan = ba.AngularSpecScan(wavelength, alpha) + simulation = ba.SpecularSimulation() + simulation.setScan(scan) + return simulation + + +# Run the simulation +def run_simulation(alpha, ni_thickness, ti_thickness): + """ + Runs simulation and returns its result. + :array q: q-values to be simulated + :float ni_thickness: a value of the Ni thickness + :float ti_thickness: a value of the Ti thickness + :return: simulated reflected intensity + """ + sample = get_sample(ni_thickness, ti_thickness) + simulation = get_simulation(alpha) + simulation.setSample(sample) + simulation.runSimulation() + return simulation.result().array() + + +# Define a log-likelihood function +def log_likelihood(theta, x, y, yerr): + """ + Calculate the log-likelihood for the normal uncertainties + + :tuple theta: the variable parameters + :array x: the abscissa data (q-values) + :array y: the ordinate data (R-values) + :array x: the ordinate uncertainty (dR-values) + :return: log-likelihood + """ + model = run_simulation(x, *theta) + sigma2 = yerr**2 + model**2 + return -0.5*np.sum((y - model)**2/sigma2 + np.log(sigma2)) + + +if __name__ == '__main__': + # Using scipy.optimize.differential_evolution find the + # maximum likelihood estimate + nll = lambda *args: -log_likelihood(*args) + initial = np.array([9.0, 1.0]) + 0.1*np.random.randn(2) + soln = differential_evolution(nll, ((5.0, 9.0), (1.0, 10.0)), + args=(get_real_data()[:, 0], + get_real_data()[:, 1], + get_real_data()[:, 2])) + ni_thickness_ml, ti_thickness_ml = soln.x + print('MLE Ni Thickness', ni_thickness_ml, 'nm') + print('MLE Ti Thickness', ti_thickness_ml, 'nm') + + # Perform the likelihood sampling + pos = soln.x + 1e-4*np.random.randn(32, 2) + nwalkers, ndim = pos.shape + + sampler = emcee.EnsembleSampler(nwalkers, + ndim, + log_likelihood, + args=(get_real_data()[:, 0], + get_real_data()[:, 1], + get_real_data()[:, 2])) + sampler.run_mcmc(pos, 1000, progress=True) + + # Plot and show corner plot of samples + flat_samples = sampler.get_chain(flat=True) + corner.corner(flat_samples, + labels=['Ni-thickness/nm', 'Ti-thickness/nm']) + plt.show() + + # Plot and show MLE and data of reflectivity + plt.errorbar(get_real_data()[:, 0], + get_real_data()[:, 1], + get_real_data()[:, 2], + marker='.', + ls='') + plt.plot( + get_real_data()[:, 0], + run_simulation(get_real_data()[:, 0], *flat_samples.mean(axis=0)), + '-') + plt.xlabel('$\\alpha$/deg') + plt.ylabel('$R$') + plt.yscale('log') + plt.show() diff --git a/GUI/coregui/Models/GUIDomainSampleVisitor.cpp b/GUI/coregui/Models/GUIDomainSampleVisitor.cpp index d6dfdc2031d666dd398ccb5d9d514c852719f4f6..7e5b309bc67a5c626479bece9ba13e888bb10fe1 100644 --- a/GUI/coregui/Models/GUIDomainSampleVisitor.cpp +++ b/GUI/coregui/Models/GUIDomainSampleVisitor.cpp @@ -600,8 +600,7 @@ ExternalProperty GUIDomainSampleVisitor::createMaterialFromDomain(const Material "Unsupported material"); } - materialItem->item<VectorItem>(MaterialItem::P_MAGNETIZATION) - ->setVector(material->magnetization()); + materialItem->setMagnetization(material->magnetization()); return MaterialItemUtils::materialProperty(*materialItem); } diff --git a/GUI/coregui/Models/JobModelFunctions.cpp b/GUI/coregui/Models/JobModelFunctions.cpp index c51d9d0e0af8c034b3c2a35020d7af52ddaf1f4e..823bb7b136e5ec495f891d5fdda85b2eb3a4627e 100644 --- a/GUI/coregui/Models/JobModelFunctions.cpp +++ b/GUI/coregui/Models/JobModelFunctions.cpp @@ -178,12 +178,12 @@ void JobModelFunctions::setupJobItemForFit(JobItem* jobItem, const RealDataItem* void JobModelFunctions::muteMagnetizationData(JobItem* jobItem) { - auto container = + MaterialItemContainer* container = static_cast<MaterialItemContainer*>(jobItem->getItem(JobItem::T_MATERIAL_CONTAINER)); - for (auto item : container->getItems(MaterialItemContainer::T_MATERIALS)) - item->getItem(MaterialItem::P_MAGNETIZATION)->setVisible(false); + for (SessionItem* item : container->getItems(MaterialItemContainer::T_MATERIALS)) + static_cast<MaterialItem*>(item)->hideMagnetization(); - auto sample = static_cast<MultiLayerItem*>(jobItem->getItem(JobItem::T_SAMPLE)); + MultiLayerItem* sample = static_cast<MultiLayerItem*>(jobItem->getItem(JobItem::T_SAMPLE)); sample->getItem(MultiLayerItem::P_EXTERNAL_FIELD)->setVisible(false); } diff --git a/GUI/coregui/Models/MaterialDataItems.h b/GUI/coregui/Models/MaterialDataItems.h index 286769699e4b786fac9d2241e7602b1cd7ccdcff..6062018dbe366a60a4bc4dd57e98c3feae6adbdb 100644 --- a/GUI/coregui/Models/MaterialDataItems.h +++ b/GUI/coregui/Models/MaterialDataItems.h @@ -23,19 +23,25 @@ protected: }; class BA_CORE_API_ MaterialRefractiveDataItem : public MaterialDataItem { -public: +private: static const QString P_DELTA; static const QString P_BETA; +public: MaterialRefractiveDataItem(); + + friend class MaterialItem; }; class BA_CORE_API_ MaterialSLDDataItem : public MaterialDataItem { -public: +private: static const QString P_SLD_REAL; static const QString P_SLD_IMAG; +public: MaterialSLDDataItem(); + + friend class MaterialItem; }; #endif // BORNAGAIN_GUI_COREGUI_MODELS_MATERIALDATAITEMS_H diff --git a/GUI/coregui/Models/MaterialItem.cpp b/GUI/coregui/Models/MaterialItem.cpp index 1dc95168c07331c6e61771d8842c33899c5b64d4..98147ee4e724527c02cac2262632a1676bb07007 100644 --- a/GUI/coregui/Models/MaterialItem.cpp +++ b/GUI/coregui/Models/MaterialItem.cpp @@ -43,7 +43,7 @@ MaterialItem::MaterialItem() : SessionItem("Material") //! Turns material into refractive index material. -void MaterialItem::setRefractiveData(double delta, double beta) +void MaterialItem::setRefractiveIndex(const double delta, const double beta) { auto refractiveData = setGroupProperty(P_MATERIAL_DATA, "MaterialRefractiveData"); refractiveData->setItemValue(MaterialRefractiveDataItem::P_DELTA, delta); @@ -52,11 +52,41 @@ void MaterialItem::setRefractiveData(double delta, double beta) //! Turns material into SLD based material. -void MaterialItem::setSLDData(double sld_real, double sld_imag) +void MaterialItem::setScatteringLengthDensity(const complex_t sld) { auto sldData = setGroupProperty(P_MATERIAL_DATA, "MaterialSLDData"); - sldData->setItemValue(MaterialSLDDataItem::P_SLD_REAL, sld_real); - sldData->setItemValue(MaterialSLDDataItem::P_SLD_IMAG, sld_imag); + sldData->setItemValue(MaterialSLDDataItem::P_SLD_REAL, sld.real()); + sldData->setItemValue(MaterialSLDDataItem::P_SLD_IMAG, sld.imag()); +} + +bool MaterialItem::hasRefractiveIndex() const +{ + SessionItem* data = getGroupItem(P_MATERIAL_DATA); + ASSERT(data); + return dynamic_cast<MaterialRefractiveDataItem*>(data) != nullptr; +} + +double MaterialItem::refractiveIndexDelta() const +{ + ASSERT(hasRefractiveIndex()); + return getGroupItem(P_MATERIAL_DATA) + ->getItemValue(MaterialRefractiveDataItem::P_DELTA).toDouble(); +} + +double MaterialItem::refractiveIndexBeta() const +{ + ASSERT(hasRefractiveIndex()); + return getGroupItem(P_MATERIAL_DATA) + ->getItemValue(MaterialRefractiveDataItem::P_BETA).toDouble(); +} + +complex_t MaterialItem::scatteringLengthDensity() const +{ + ASSERT(!hasRefractiveIndex()); + SessionItem* ri = getGroupItem(P_MATERIAL_DATA); + double real = ri->getItemValue(MaterialSLDDataItem::P_SLD_REAL).toDouble(); + double imag = ri->getItemValue(MaterialSLDDataItem::P_SLD_IMAG).toDouble(); + return complex_t(real, imag); } QString MaterialItem::identifier() const @@ -64,12 +94,32 @@ QString MaterialItem::identifier() const return getItemValue(P_IDENTIFIER).toString(); } +void MaterialItem::setIdentifier(const QString& id) +{ + setItemValue(P_IDENTIFIER, id); +} + QColor MaterialItem::color() const { ExternalProperty property = getItemValue(P_COLOR).value<ExternalProperty>(); return property.color(); } +void MaterialItem::setColor(const QColor& color) +{ + setItemValue(P_COLOR, MaterialItemUtils::colorProperty(color).variant()); +} + +void MaterialItem::setMagnetization(const kvector_t& magnetization) +{ + item<VectorItem>(P_MAGNETIZATION)->setVector(magnetization); +} + +void MaterialItem::hideMagnetization() +{ + getItem(MaterialItem::P_MAGNETIZATION)->setVisible(false); +} + std::unique_ptr<Material> MaterialItem::createMaterial() const { auto dataItem = getGroupItem(P_MATERIAL_DATA); diff --git a/GUI/coregui/Models/MaterialItem.h b/GUI/coregui/Models/MaterialItem.h index a057c70873eb900f72cc4e9d0f21ba72253f0355..1ea52dc4d2a044f3b99d04db090429f89e5cc3ef 100644 --- a/GUI/coregui/Models/MaterialItem.h +++ b/GUI/coregui/Models/MaterialItem.h @@ -15,24 +15,43 @@ #ifndef BORNAGAIN_GUI_COREGUI_MODELS_MATERIALITEM_H #define BORNAGAIN_GUI_COREGUI_MODELS_MATERIALITEM_H +#include "Base/Vector/Vectors3D.h" +#include "Base/Types/Complex.h" #include "GUI/coregui/Models/SessionItem.h" class Material; class BA_CORE_API_ MaterialItem : public SessionItem { -public: +private: static const QString P_COLOR; static const QString P_MATERIAL_DATA; static const QString P_MAGNETIZATION; static const QString P_IDENTIFIER; +public: MaterialItem(); - void setRefractiveData(double delta, double beta); - void setSLDData(double sld_real, double sld_imag); - + /// set refractive index as in 1 - delta + i * beta + void setRefractiveIndex(const double delta, const double beta); + void setScatteringLengthDensity(const complex_t index); + /// \return true iff refractive index was given, otherwise SLD was given + bool hasRefractiveIndex() const; + /// \pre hasRefractiveIndex + double refractiveIndexDelta() const; + /// \pre hasRefractiveIndex + double refractiveIndexBeta() const; + /// \pre ! hasRefractiveIndex + complex_t scatteringLengthDensity() const; + QString identifier() const; + void setIdentifier(const QString& id); + QColor color() const; + void setColor(const QColor& color); + + void setMagnetization(const kvector_t& magnetization); + void hideMagnetization(); + std::unique_ptr<Material> createMaterial() const; }; diff --git a/GUI/coregui/Models/MaterialItemContainer.cpp b/GUI/coregui/Models/MaterialItemContainer.cpp index 13027e107028dea1a3a9bb83575d6c9c73713153..63a809328de274e797b6f5e49d38502cb5879bca 100644 --- a/GUI/coregui/Models/MaterialItemContainer.cpp +++ b/GUI/coregui/Models/MaterialItemContainer.cpp @@ -28,7 +28,7 @@ MaterialItemContainer::MaterialItemContainer() : SessionItem("MaterialContainer" MaterialItem* MaterialItemContainer::insertCopy(MaterialItem* material_item) { MaterialItem* item_copy = model()->copyItem(material_item, this, T_MATERIALS); - item_copy->setItemValue(MaterialItem::P_IDENTIFIER, GUIHelpers::createUuid()); + item_copy->setIdentifier(GUIHelpers::createUuid()); return item_copy; } diff --git a/GUI/coregui/Models/MaterialModel.cpp b/GUI/coregui/Models/MaterialModel.cpp index 7b1d02a414c5c765b35ad0e5d282e77fcda75a5b..7dbfa780d332a80bfb483061f993b7946f5b9587 100644 --- a/GUI/coregui/Models/MaterialModel.cpp +++ b/GUI/coregui/Models/MaterialModel.cpp @@ -41,14 +41,14 @@ MaterialModel* MaterialModel::createCopy(SessionItem* parent) MaterialItem* MaterialModel::addRefractiveMaterial(const QString& name, double delta, double beta) { auto materialItem = createMaterial(name); - materialItem->setRefractiveData(delta, beta); + materialItem->setRefractiveIndex(delta, beta); return materialItem; } MaterialItem* MaterialModel::addSLDMaterial(const QString& name, double sld, double abs_term) { auto materialItem = createMaterial(name); - materialItem->setSLDData(sld, abs_term); + materialItem->setScatteringLengthDensity(complex_t(sld, abs_term)); return materialItem; } @@ -83,8 +83,8 @@ MaterialItem* MaterialModel::cloneMaterial(const QModelIndex& index) if (!origMaterial) return nullptr; - auto clonedMaterial = copyItem(origMaterial, 0); - clonedMaterial->setItemValue(MaterialItem::P_IDENTIFIER, GUIHelpers::createUuid()); + auto clonedMaterial = copyItem(origMaterial, nullptr); + clonedMaterial->setIdentifier(GUIHelpers::createUuid()); clonedMaterial->setItemName(origMaterial->itemName() + " (clone)"); return dynamic_cast<MaterialItem*>(clonedMaterial); } @@ -97,7 +97,7 @@ MaterialItem* MaterialModel::createMaterial(const QString& name) result->setItemName(name); QColor color = MaterialItemUtils::suggestMaterialColor(name); - result->setItemValue(MaterialItem::P_COLOR, MaterialItemUtils::colorProperty(color).variant()); + result->setColor(color); return result; } diff --git a/GUI/coregui/Models/RealDataItem.h b/GUI/coregui/Models/RealDataItem.h index c63d5a6f4ca085ce6a9158e8cc5b2663eaa5c608..0f5a47b9b37c617fb82f199d9668b2c6ce937530 100644 --- a/GUI/coregui/Models/RealDataItem.h +++ b/GUI/coregui/Models/RealDataItem.h @@ -39,10 +39,8 @@ class BA_CORE_API_ RealDataItem : public QObject, public SessionItem { friend class TestView; -public: - static const QString P_INSTRUMENT_ID; - private: + static const QString P_INSTRUMENT_ID; static const QString T_INTENSITY_DATA; static const QString P_INSTRUMENT_NAME; static const QString T_NATIVE_DATA; diff --git a/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.cpp b/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.cpp index ffd8aa32a6dcb06838be61e561db2e591ce221c0..c2902c2331d039f332ee3546cdb0b21290ab93f4 100644 --- a/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.cpp +++ b/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.cpp @@ -65,7 +65,7 @@ ExternalProperty MaterialItemUtils::defaultMaterialProperty() if (!AppSvc::materialModel()) return ExternalProperty(); - auto materials = AppSvc::materialModel()->topItems(); + auto materials = AppSvc::materialModel()->topItems<MaterialItem>(); return materials.isEmpty() ? ExternalProperty() : MaterialItemUtils::materialProperty(*materials.front()); } @@ -126,14 +126,13 @@ QStringList MaterialItemUtils::materialRelatedModelTypes() //! Constructs material property for given material. -ExternalProperty MaterialItemUtils::materialProperty(const SessionItem& materialItem) +ExternalProperty MaterialItemUtils::materialProperty(const MaterialItem& materialItem) { ExternalProperty result; - ExternalProperty colorProperty = - materialItem.getItemValue(MaterialItem::P_COLOR).value<ExternalProperty>(); - result.setIdentifier(materialItem.getItemValue(MaterialItem::P_IDENTIFIER).toString()); - result.setColor(colorProperty.color()); + QColor color = materialItem.color(); + result.setIdentifier(materialItem.identifier()); + result.setColor(color); result.setText(materialItem.itemName()); return result; diff --git a/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.h b/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.h index d545b5effb6b5128d2cb1fff2be57ed1a3b04f33..fca6911bd8afc3cf986cc37839a00dce5e1c1049 100644 --- a/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.h +++ b/GUI/coregui/Views/MaterialEditor/MaterialItemUtils.h @@ -38,7 +38,7 @@ QString materialTag(const SessionItem& item); QStringList materialRelatedModelTypes(); //! Constructs material property corresponding to given material. -ExternalProperty materialProperty(const SessionItem& materialItem); +ExternalProperty materialProperty(const MaterialItem& materialItem); //! Constructs color property from given color. ExternalProperty colorProperty(const QColor& color); diff --git a/Tests/Functional/GUI/Translate/GUITranslationTest.cpp b/Tests/Functional/GUI/Translate/GUITranslationTest.cpp index e6c4ff98f918b5c5bcf4bfc9bcafc5c4ef92f02a..457a0fa6d6cbea542c0f9326476fba20c92c1d96 100644 --- a/Tests/Functional/GUI/Translate/GUITranslationTest.cpp +++ b/Tests/Functional/GUI/Translate/GUITranslationTest.cpp @@ -50,7 +50,7 @@ bool containsNames(const QString& text, const QStringList& names) const QVector<QPair<QStringList, QStringList>> black_list{ {// Global scope {""}, - {"Sigma factor", "MaterialRefractiveData", "MaterialSLDData", MaterialItem::P_MAGNETIZATION}}, + {"Sigma factor", "MaterialRefractiveData", "MaterialSLDData", "Magnetization"}}, {// Instrument scope {"GISASInstrument", "OffSpecularInstrument", "SpecularInstrument"}, {// Distribution types @@ -74,7 +74,7 @@ const QVector<QPair<QStringList, QStringList>> black_list{ // Beam angle parameters BeamItem::P_INCLINATION_ANGLE, BeamItem::P_AZIMUTHAL_ANGLE}}}; -//! Returns true, if it makes sence to look for GUI translation for given domain name. +//! Returns true, if it makes sense to look for GUI translation for given domain name. //! Intended to supress warnings about not-yet implemented translations. bool requiresTranslation(ParameterItem* parItem) { diff --git a/Tests/UnitTests/GUI/TestLayerItems.cpp b/Tests/UnitTests/GUI/TestLayerItems.cpp index 9475a5bfe3525e09ace4f109d9f114bb87e4cf0b..bc53ce8280f42eb78255b70d2d5f42c8f506dd89 100644 --- a/Tests/UnitTests/GUI/TestLayerItems.cpp +++ b/Tests/UnitTests/GUI/TestLayerItems.cpp @@ -15,12 +15,11 @@ TEST_F(TestLayerItems, test_LayerDefaultMaterial) { ApplicationModels models; auto layer = models.sampleModel()->insertItem<LayerItem>(); - auto materials = models.materialModel()->topItems(); + auto materials = models.materialModel()->topItems<MaterialItem>(); auto defMaterial = materials.front(); ExternalProperty material = layer->getItemValue(LayerItem::P_MATERIAL).value<ExternalProperty>(); EXPECT_EQ(material.text(), "Default"); - EXPECT_EQ(material.identifier(), - defMaterial->getItemValue(MaterialItem::P_IDENTIFIER).toString()); + EXPECT_EQ(material.identifier(), defMaterial->identifier()); } diff --git a/Tests/UnitTests/GUI/TestMaterialModel.cpp b/Tests/UnitTests/GUI/TestMaterialModel.cpp index 1aae2389cb5985023201b7acd8b8cc3c19981fd6..c4f26a669751f4c584734eed4302f10bdec06808 100644 --- a/Tests/UnitTests/GUI/TestMaterialModel.cpp +++ b/Tests/UnitTests/GUI/TestMaterialModel.cpp @@ -15,16 +15,16 @@ TEST_F(TestMaterialModel, addRefractiveMaterial) const double delta(0.2), beta(0.1); const QString name("MaterialName"); - auto material = model->addRefractiveMaterial(name, delta, beta); + MaterialItem* material = model->addRefractiveMaterial(name, delta, beta); EXPECT_EQ(model->rowCount(QModelIndex()), 1); EXPECT_EQ(model->itemForIndex(material->index()), material); EXPECT_EQ(model->rowCount(QModelIndex()), 1); EXPECT_EQ(material->itemName(), name); - auto materialData = material->getGroupItem(MaterialItem::P_MATERIAL_DATA); - EXPECT_EQ(materialData->getItemValue(MaterialRefractiveDataItem::P_DELTA), delta); - EXPECT_EQ(materialData->getItemValue(MaterialRefractiveDataItem::P_BETA), beta); + EXPECT_TRUE(material->hasRefractiveIndex()); + EXPECT_EQ(material->refractiveIndexDelta(), delta); + EXPECT_EQ(material->refractiveIndexBeta(), beta); } TEST_F(TestMaterialModel, addSLDMaterial) @@ -35,19 +35,19 @@ TEST_F(TestMaterialModel, addSLDMaterial) const double sld_real(0.2), sld_imag(0.1); const QString name("MaterialName"); - auto material = model->addSLDMaterial(name, sld_real, sld_imag); + MaterialItem* material = model->addSLDMaterial(name, sld_real, sld_imag); EXPECT_EQ(model->rowCount(QModelIndex()), 1); EXPECT_EQ(model->itemForIndex(material->index()), material); EXPECT_EQ(model->rowCount(QModelIndex()), 1); EXPECT_EQ(material->itemName(), name); - auto materialData = material->getGroupItem(MaterialItem::P_MATERIAL_DATA); - EXPECT_EQ(materialData->getItemValue(MaterialSLDDataItem::P_SLD_REAL), sld_real); - EXPECT_EQ(materialData->getItemValue(MaterialSLDDataItem::P_SLD_IMAG), sld_imag); + EXPECT_FALSE(material->hasRefractiveIndex()); + EXPECT_EQ(material->scatteringLengthDensity(), + complex_t(sld_real, sld_imag)); } -TEST_F(TestMaterialModel, cloneMaterial) +TEST_F(TestMaterialModel, cloneMaterialRefractive) { std::unique_ptr<MaterialModel> model(new MaterialModel); @@ -55,24 +55,51 @@ TEST_F(TestMaterialModel, cloneMaterial) const double delta(0.2), beta(0.1); const QString name("MaterialName"); - auto material = model->addRefractiveMaterial(name, delta, beta); + MaterialItem* material = model->addRefractiveMaterial(name, delta, beta); const QString origIdentifier = material->identifier(); - auto clonedMaterial = model->cloneMaterial(material->index()); + MaterialItem* clonedMaterial = model->cloneMaterial(material->index()); EXPECT_EQ(model->rowCount(QModelIndex()), 2); // clone should not change identifier of original material (as it once happened) EXPECT_EQ(material->identifier(), origIdentifier); // cloned material should have different identifier - EXPECT_TRUE(clonedMaterial->identifier() != material->identifier()); + EXPECT_NE(clonedMaterial->identifier(), material->identifier()); // checking name of cloned material EXPECT_EQ(material->itemName() + " (clone)", clonedMaterial->itemName()); + EXPECT_EQ(material->hasRefractiveIndex(), + clonedMaterial->hasRefractiveIndex()); + EXPECT_EQ(material->refractiveIndexDelta(), delta); + EXPECT_EQ(material->refractiveIndexBeta(), beta); +} + +TEST_F(TestMaterialModel, cloneMaterialSLD) +{ + std::unique_ptr<MaterialModel> model(new MaterialModel); + + EXPECT_EQ(model->rowCount(QModelIndex()), 0); + + const double real(0.7), imag(0.5); + const QString name("MaterialName"); + MaterialItem* material = model->addSLDMaterial(name, real, imag); + const QString origIdentifier = material->identifier(); - auto materialData = clonedMaterial->getGroupItem(MaterialItem::P_MATERIAL_DATA); - EXPECT_EQ(materialData->getItemValue(MaterialRefractiveDataItem::P_DELTA), delta); - EXPECT_EQ(materialData->getItemValue(MaterialRefractiveDataItem::P_BETA), beta); + MaterialItem* clonedMaterial = model->cloneMaterial(material->index()); + EXPECT_EQ(model->rowCount(QModelIndex()), 2); + + // clone should not change identifier of original material (as it once happened) + EXPECT_EQ(material->identifier(), origIdentifier); + + // cloned material should have different identifier + EXPECT_NE(clonedMaterial->identifier(), material->identifier()); + + // checking name of cloned material + EXPECT_EQ(material->itemName() + " (clone)", clonedMaterial->itemName()); + EXPECT_EQ(material->hasRefractiveIndex(), + clonedMaterial->hasRefractiveIndex()); + EXPECT_EQ(material->scatteringLengthDensity(), complex_t(real, imag)); } //! Checks the method which returns MaterialItem from known identifier. @@ -80,11 +107,11 @@ TEST_F(TestMaterialModel, cloneMaterial) TEST_F(TestMaterialModel, materialFromIdentifier) { MaterialModel model; - auto material1 = model.addRefractiveMaterial("aaa", 1.0, 2.0); - auto material2 = model.addRefractiveMaterial("bbb", 3.0, 4.0); - EXPECT_TRUE(material1 == model.materialFromIdentifier(material1->identifier())); - EXPECT_TRUE(material2 == model.materialFromIdentifier(material2->identifier())); - EXPECT_TRUE(nullptr == model.materialFromIdentifier("non-existing-identifier")); + MaterialItem* material1 = model.addRefractiveMaterial("aaa", 1.0, 2.0); + MaterialItem* material2 = model.addRefractiveMaterial("bbb", 3.0, 4.0); + EXPECT_EQ(material1, model.materialFromIdentifier(material1->identifier())); + EXPECT_EQ(material2, model.materialFromIdentifier(material2->identifier())); + EXPECT_EQ(nullptr, model.materialFromIdentifier("non-existing-identifier")); } //! Checks the method which returns MaterialItem from material name. @@ -92,11 +119,11 @@ TEST_F(TestMaterialModel, materialFromIdentifier) TEST_F(TestMaterialModel, test_materialFromName) { MaterialModel model; - auto material1 = model.addRefractiveMaterial("aaa", 1.0, 2.0); - auto material2 = model.addRefractiveMaterial("bbb", 3.0, 4.0); - EXPECT_TRUE(material1 == model.materialFromName(material1->itemName())); - EXPECT_TRUE(material2 == model.materialFromName(material2->itemName())); - EXPECT_TRUE(nullptr == model.materialFromName("non-existing-name")); + MaterialItem* material1 = model.addRefractiveMaterial("aaa", 1.0, 2.0); + MaterialItem* material2 = model.addRefractiveMaterial("bbb", 3.0, 4.0); + EXPECT_EQ(material1, model.materialFromName(material1->itemName())); + EXPECT_EQ(material2, model.materialFromName(material2->itemName())); + EXPECT_EQ(nullptr, model.materialFromName("non-existing-name")); } //! Checks the method which construct MaterialProperty from MaterialItem. @@ -104,7 +131,7 @@ TEST_F(TestMaterialModel, test_materialFromName) TEST_F(TestMaterialModel, test_materialPropertyFromMaterial) { MaterialModel model; - auto material = model.addRefractiveMaterial("Something", 1.0, 2.0); + MaterialItem* material = model.addRefractiveMaterial("Something", 1.0, 2.0); ExternalProperty property = MaterialItemUtils::materialProperty(*material); EXPECT_EQ(property.text(), "Something"); @@ -124,7 +151,7 @@ TEST_F(TestMaterialModel, defaultMaterialProperty) EXPECT_FALSE(property.isValid()); // adding materials to the model, default property should refer to first material in a model - auto mat1 = model.addRefractiveMaterial("Something1", 1.0, 2.0); + MaterialItem* mat1 = model.addRefractiveMaterial("Something1", 1.0, 2.0); model.addRefractiveMaterial("Something2", 3.0, 4.0); ExternalProperty property2 = MaterialItemUtils::defaultMaterialProperty(); EXPECT_EQ(property2.text(), "Something1");