#!/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
from matplotlib import pyplot as plt

default_cylinder_radius = 10*nm
default_cylinder_height = 20*nm


def get_sample(cylinder_radius, cylinder_height):
    # Materials
    vacuum = ba.RefractiveMaterial("Vacuum", 0, 0)
    material_substrate = ba.RefractiveMaterial("Substrate", 6e-6, 2e-8)
    material_particle = ba.RefractiveMaterial("Particle", 6e-4, 2e-8)

    # Particle layout
    cylinder_ff = ba.Cylinder(cylinder_radius, cylinder_height)
    cylinder = ba.Particle(material_particle, cylinder_ff)
    particle_layout = ba.ParticleLayout()
    particle_layout.addParticle(cylinder)

    # Layers
    vacuum_layer = ba.Layer(vacuum)
    vacuum_layer.addLayout(particle_layout)
    substrate_layer = ba.Layer(material_substrate)

    # Sample
    sample = ba.MultiLayer()
    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 = 11
    det = ba.Detector2D(3*deg, 3*deg, n, n, 0, 1.5*deg)
    simulation = ba.ScatteringSimulation(beam, sample, det)
    simulation.options().setMonteCarloIntegration(integration_flag, 50)
    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__':
    bp.parse_args(fontsize=12)
    results = simulate()
    bp.make_plot(results, 2)
    bp.show_or_export()
