//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      Sample/StandardSample/SizeDistributionModelsBuilder.cpp
//! @brief     Implements class ParticlesInSSCABuilder.
//!
//! @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 "Sample/StandardSample/SizeDistributionModelsBuilder.h"
#include "Param/Distrib/Distributions.h"
#include "Sample/Aggregate/InterferenceRadialParacrystal.h"
#include "Sample/Aggregate/ParticleLayout.h"
#include "Sample/HardParticle/Cylinder.h"
#include "Sample/Multilayer/Layer.h"
#include "Sample/Multilayer/MultiLayer.h"
#include "Sample/Particle/Particle.h"
#include "Sample/StandardSample/ReferenceMaterials.h"

MultiLayer* ExemplarySamples::createSizeDistributionDAModel()
{
    // cylindrical particle 1
    double radius1(5);
    double height1 = radius1;
    Cylinder cylinder_ff1(radius1, height1);
    Particle cylinder1(refMat::Particle, cylinder_ff1);

    // cylindrical particle 2
    double radius2(8);
    double height2(radius2);
    Cylinder cylinder_ff2(radius2, height2);
    Particle cylinder2(refMat::Particle, cylinder_ff2);

    // interference function
    InterferenceRadialParacrystal interference(18.0, 1e3);
    Profile1DGauss pdf(3);
    interference.setProbabilityDistribution(pdf);

    // assembling the sample
    ParticleLayout particle_layout;
    particle_layout.addParticle(cylinder1, 0.8);
    particle_layout.addParticle(cylinder2, 0.2);
    particle_layout.setInterference(interference);

    Layer vacuum_layer(refMat::Vacuum);
    vacuum_layer.addLayout(particle_layout);
    Layer substrate_layer(refMat::Substrate);

    auto* sample = new MultiLayer();
    sample->addLayer(vacuum_layer);
    sample->addLayer(substrate_layer);
    return sample;
}

// ----------------------------------------------------------------------------

MultiLayer* ExemplarySamples::createSizeDistributionLMAModel()
{
    // cylindrical particle 1
    double radius1(5);
    double height1 = radius1;
    Cylinder cylinder_ff1(radius1, height1);
    Particle cylinder1(refMat::Particle, cylinder_ff1);

    // cylindrical particle 2
    double radius2(8);
    double height2(radius2);
    Cylinder cylinder_ff2(radius2, height2);
    Particle cylinder2(refMat::Particle, cylinder_ff2);

    // interference function1
    InterferenceRadialParacrystal interference1(16.8, 1e3);
    Profile1DGauss pdf(3);
    interference1.setProbabilityDistribution(pdf);

    // interference function2
    InterferenceRadialParacrystal interference2(22.8, 1e3);
    interference2.setProbabilityDistribution(pdf);

    // assembling the sample
    ParticleLayout particle_layout1;
    particle_layout1.addParticle(cylinder1, 0.8);
    particle_layout1.setInterference(interference1);

    ParticleLayout particle_layout2;
    particle_layout2.addParticle(cylinder2, 0.2);
    particle_layout2.setInterference(interference2);

    Layer vacuum_layer(refMat::Vacuum);
    vacuum_layer.addLayout(particle_layout1);
    vacuum_layer.addLayout(particle_layout2);
    Layer substrate_layer(refMat::Substrate);

    auto* sample = new MultiLayer();
    sample->addLayer(vacuum_layer);
    sample->addLayer(substrate_layer);
    return sample;
}

// ----------------------------------------------------------------------------

MultiLayer* ExemplarySamples::createSizeDistributionSSCAModel()
{
    // cylindrical particle 1
    double radius1(5);
    double height1 = radius1;
    Cylinder cylinder_ff1(radius1, height1);
    Particle cylinder1(refMat::Particle, cylinder_ff1);

    // cylindrical particle 2
    double radius2(8);
    double height2(radius2);
    Cylinder cylinder_ff2(radius2, height2);
    Particle cylinder2(refMat::Particle, cylinder_ff2);

    // interference function
    InterferenceRadialParacrystal interference(18.0, 1e3);
    Profile1DGauss pdf(3);
    interference.setProbabilityDistribution(pdf);
    interference.setKappa(1.0);

    // assembling the sample
    ParticleLayout particle_layout;
    particle_layout.addParticle(cylinder1, 0.8);
    particle_layout.addParticle(cylinder2, 0.2);
    particle_layout.setInterference(interference);

    Layer vacuum_layer(refMat::Vacuum);
    vacuum_layer.addLayout(particle_layout);
    Layer substrate_layer(refMat::Substrate);

    auto* sample = new MultiLayer();
    sample->addLayer(vacuum_layer);
    sample->addLayer(substrate_layer);
    return sample;
}

// ----------------------------------------------------------------------------

MultiLayer* ExemplarySamples::createCylindersInSSCA()
{
    throw std::runtime_error(
        "This sample used ParticleDistribution which is not supported any more.");

    // #baRemoveParticleDistribution The following code is outdated. However, it is still kept,
    // since it may be useful once the new particle distribution approach is implemented.
    /*
    Layer vacuum_layer(refMat::Vacuum);

    InterferenceRadialParacrystal interparticle(15.0, 1e3);
    Profile1DGauss pdf(5);
    interparticle.setProbabilityDistribution(pdf);
    interparticle.setKappa(4.02698);
    ParticleLayout particle_layout;

    Cylinder ff_cylinder(5.0, 5.0);
    Particle particle_prototype(refMat::Particle, ff_cylinder);

    DistributionGaussian gauss(5.0, 1.25);
    ParameterPattern pattern_radius;
    pattern_radius.add("Particle").add("Cylinder").add("Radius");
    ParameterDistribution par_distr(pattern_radius.toStdString(), gauss, 30, 3.0);
    ParameterPattern pattern_height;
    pattern_height.add("Particle").add("Cylinder").add("Height");
    par_distr.linkParameter(pattern_height.toStdString());
    ParticleDistribution particle_collection(particle_prototype, par_distr);
    particle_layout.addParticle(particle_collection);

    particle_layout.setInterference(interparticle);

    vacuum_layer.addLayout(particle_layout);

    auto* sample = new MultiLayer();
    sample->addLayer(vacuum_layer);
    return sample;
    */
}
