#!/usr/bin/env python3
"""
Fake GISAS data for testing and benchmarking 2D fits.
The sample model basically consists of dilute cylinders on a substrate.
There are, however, some systematic distortions:
  * Refractive indices changed, and absorption strongly enhanced;
  * Cylinders replaced by a mixture of cones and segmented spheroids;
  * Beam wavelength and alpha_i slightly changed.
  * Detector x-axis skewed;
"""

import bornagain as ba
from bornagain import deg, nm
import numpy as np

mat_vacuum = ba.HomogeneousMaterial("Vacuum", 0, 0)
# nominal material constants are (6e-6, 2e-8) and (6e-4, 2e-8)
mat_substrate = ba.HomogeneousMaterial("Substrate", 6.3e-6, 4e-7)
mat_particle = ba.HomogeneousMaterial("Particle", 5.8e-4, 2e-7)


def get_sample(params):
    h = params["cylinder_height"]
    r = params["cylinder_radius"]

    ff1 = ba.FormFactorCone(1.1*r, h, 80*deg)
    ff2 = ba.FormFactorTruncatedSpheroid(r, 3.3*h, 2.5*h/r, 2.2*h)

    layout = ba.ParticleLayout()
    layout.addParticle(ba.Particle(mat_particle, ff1), .4)
    layout.addParticle(ba.Particle(mat_particle, ff2), .6)

    layer_1 = ba.Layer(mat_vacuum)
    layer_1.addLayout(layout)
    layer_2 = ba.Layer(mat_substrate)

    sample = ba.MultiLayer()
    sample.addLayer(layer_1)
    sample.addLayer(layer_2)
    return sample


def get_simulation(params):
    # nominal beam parameters are 0.1*nm, 0.2*deg
    beam = ba.Beam(10**params['lg(intensity)'], 0.0993*nm,
                   ba.Direction(0.202*deg, 0))

    # nominal detector x-axis starts from -1.5*deg
    det = ba.SphericalDetector(100, -1.49*deg, 1.5*deg, 100, 0, 3*deg)

    sample = get_sample(params)

    simulation = ba.GISASSimulation(beam, sample, det)
    if 'lg(background)' in params:
        simulation.setBackground(
            ba.ConstantBackground(10**params['lg(background)']))

    return simulation


def model_parameters():
    return {
        'lg(intensity)': 6,
        'lg(background)': 0.5,
        'cylinder_height': 4*nm,
        'cylinder_radius': 5*nm,
    }


def fake_data():
    """
    Generate fake "experimental" data, and save them as numpy array.
    """

    params = model_parameters()

    # Compute model distribution
    simulation = get_simulation(params)
    simulation.runSimulation()
    theory = simulation.result().array()

    # Draw noisy data
    np.random.seed(0)
    data = np.random.poisson(theory)

    # Save to numpy
    np.savetxt("faked-gisas1.txt.gz", data)


if __name__ == '__main__':
    fake_data()
