#!/usr/bin/env python3
"""
Large cylinders in DWBA.

This example demonstrates that for large particles (~1000nm) the form factor
oscillates rapidly within one detector bin and analytical calculations
(performed for the bin center) give completely wrong intensity pattern.
In this case Monte-Carlo integration over detector bin should be used.
"""
import bornagain as ba
from bornagain import angstrom, ba_plot as bp, deg, nm, nm2

default_cylinder_radius = 10*nm
default_cylinder_height = 20*nm


def get_sample(cylinder_radius, cylinder_height):
    # Materials
    vacuum = ba.Vacuum()
    substrate_color = (0.28, 0.57, 0.82)
    substrate_mat = ba.RefractiveMaterial("Substrate", substrate_color, 6e-6, 2e-8)
    particle_color = (0.86, 0.24, 0.18)
    particle_mat = ba.RefractiveMaterial("Particle", particle_color, 6e-4, 2e-8)

    # Particle
    ff = ba.Cylinder(cylinder_radius, cylinder_height)
    particle = ba.Particle(particle_mat, ff)

    # Layers
    vacuum_layer = ba.Layer(vacuum)
    vacuum_layer.deposit2D(ba.Dilute2D(0.01/nm2, particle))
    substrate_layer = ba.Layer(substrate_mat)

    # Sample
    sample = ba.Sample()
    sample.addLayer(vacuum_layer)
    sample.addLayer(substrate_layer)
    return sample


def get_simulation(sample, integration_flag):
    """
    A GISAXS simulation with defined beam and detector.
    If integration_flag=True, the simulation will integrate over detector bins.
    """
    beam = ba.Beam(1, 1*angstrom, 0.2*deg)
    n = 201
    det = ba.SphericalDetector(n, -1.5*deg, 1.5*deg, n, 0, 3*deg)
    simulation = ba.ScatteringSimulation(beam, sample, det)
    simulation.options().setMonteCarloIntegration(integration_flag, 50)
    simulation.options().setUseAvgMaterials(False)
    if not "__no_terminal__" in globals():
        simulation.setTerminalProgressMonitor()
    return simulation


def simulate():
    ret = []

    # conditions to define cylinders scale factor and integration flag
    conditions = [{
        'title': "Small cylinders, analytical calculations",
        'scale': 1,
        'integration': False,
        'zmin': 1e-5,
        'zmax': 1e2
    }, {
        'title': "Small cylinders, Monte-Carlo integration",
        'scale': 1,
        'integration': True,
        'zmin': 1e-5,
        'zmax': 1e2
    }, {
        'title': "Large cylinders, analytical calculations",
        'scale': 100,
        'integration': False,
        'zmin': 1e-5,
        'zmax': 1e10
    }, {
        'title': "Large cylinders, Monte-Carlo integration",
        'scale': 100,
        'integration': True,
        'zmin': 1e-5,
        'zmax': 1e10
    }]

    # run simulation 4 times
    for i_plot, condition in enumerate(conditions):
        scale = condition['scale']
        integration_flag = condition['integration']

        sample = get_sample(default_cylinder_radius*scale,
                            default_cylinder_height*scale)
        simulation = get_simulation(sample, integration_flag)
        result = simulation.simulate()
        result.setTitle(condition['title'])
        ret.append(result)

    return ret


if __name__ == '__main__':
    results = simulate()
    sample = get_sample(default_cylinder_radius, default_cylinder_height)
    ba.showSample3D(sample, sample_size=100*nm, seed=0)
    bp.plot2d_to_grid(results, 2, unit_aspect=1, spacing=(0.2, 0.25))
    bp.plt.show()
