/*******************************************************************************
* McXtrace, x-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: SAXSNanodiscs
*
* %Identification
* Written by: Martin Cramer Pedersen (mcpe@nbi.dk)
* Date: May 2, 2012
* Origin: KU-Science
*
* A sample of monodisperse phospholipid bilayer nanodiscs in solution (water).
*
* %Description
* A component simulating the scattering from a box-shaped, thin solution (water)
* of monodisperse phospholipid bilayer nanodiscs.
*
* Example: SAXSNanodiscs( xwidth = 0.01, yheight = 0.01, zdepth = 0.01, SampleToDetectorDistance = 0.48, DetectorRadius = 0.1 )
*
* %Parameters
* AxisRatio: []         Axis ratio of the bilayer patch.
* NumberOfLipids: []    Number of lipids per nanodisc.
* AreaPerLipidHeadgroup: [AA^2] Area per lipid headgroup - default is POPC.
* HeightOfMSP: [AA]     Height of the belt protein - default is MSP1D1.
* VolumeOfOneMSP: [AA^3]    Volume of one belt protein - default is MSP1D1.
* VolumeOfHeadgroup: [AA^3] Volume of one lipid headgroup - default is POPC.
* VolumeOfCH2Tail: [AA^3]   Volume of the CH2-chains of one lipid - default is POPC.
* VolumeOfCH3Tail: [AA^3]   Volume of the CH3-tails of one lipid - default is POPC.
* ScatteringLengthOfOneMSP: [cm]    Scattering length of one belt protein - default is MSP1D1.
* ScatteringLengthOfHeadgroup: [cm] Scattering length of one lipid headgroup - default is POPC.
* ScatteringLengthOfCH2Tail: [cm]   Scattering length of the CH2-chains of one lipid - default is POPC.
* ScatteringLengthOfCH3Tail: [cm]   Scattering length of the CH3-tails of one lipid - default is POPC.
* Roughness: []         Factor used to smear the interfaces of the nanodisc.
* Concentration: [mM]   Concentration of sample.
* AbsorptionCrosssection: [1/m]	Absorption cross section of the sample.
* xwidth: [m]  		Dimension of component in the x-direction.
* yheight: [m]		Dimension of component in the y-direction.
* zdepth: [m]		Dimension of component in the z-direction.
* SampleToDetectorDistance: [m] Distance from sample to detector (for focusing the scattered x-rays).
* DetectorRadius: [m]   Radius of the detector (for focusing the scattered x-rays).
*
* %End
*******************************************************************************/

DEFINE COMPONENT SAXSNanodiscs

DEFINITION PARAMETERS ()

SETTING PARAMETERS (AxisRatio = 1.4, NumberOfLipids = 130.0, AreaPerLipidHeadgroup = 65.0, HeightOfMSP = 24.0, 
    VolumeOfOneMSP = 26296.5, VolumeOfHeadgroup = 319.0, VolumeOfCH2Tail = 818.8, VolumeOfCH3Tail = 108.6,
    ScatteringLengthOfOneMSP = 3.34E-9, ScatteringLengthOfHeadgroup = 4.62E-11, ScatteringLengthOfCH2Tail = 6.71E-11, ScatteringLengthOfCH3Tail = 5.08E-12,
    Roughness = 3.5, Concentration = 0.01, AbsorptionCrosssection = 0.0,
    xwidth, yheight, zdepth, SampleToDetectorDistance, DetectorRadius)
OUTPUT PARAMETERS ()
DEPENDENCY " @GSLFLAGS@ "
NOACC

/*X-ray Parameters (x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p)*/
SHARE
  %{
#include <gsl/gsl_sf_bessel.h>

  /* Functions used to compute the formfactor of a nanodisc */
  double ND_FormfactorCylinder(double q, double MajorSemiAxis, double MinorSemiAxis, double Height, double Alpha, double Beta)
  {
    double ProjectedRadius = sqrt(pow(MajorSemiAxis * sin(Beta), 2) + pow(MinorSemiAxis * cos(Beta), 2));

    double Formfactor1 = gsl_sf_bessel_J1(q * ProjectedRadius * sin(Alpha)) / (q * ProjectedRadius * sin(Alpha));
    double Formfactor2 = sin(q * Height * cos(Alpha) / 2.0) / (q * Height * cos(Alpha) / 2.0);

    return 2 * Formfactor1 * Formfactor2;
  }

  double ND_IntensityOfEmptyNanodiscs(double q, double MajorSemiAxis, double MinorSemiAxis, double ThicknessOfBelt,
				      double HeightOfBelt, double HeightOfLipids, double HeightOfTails, double HeightOfCH3,
				      double DeltaRhoBelt, double DeltaRhoHead, double DeltaRhoCH2Tail, double DeltaRhoCH3Tail)
  {
    double Intensity;
    double IntensityPart;

    double AmplitudeOfBelt;
    double AmplitudeOfHeads;
    double AmplitudeOfCH2Tail;
    double AmplitudeOfCH3Tail;

    double FormfactorOfBelt;
    double FormfactorOfHeads;
    double FormfactorOfCH2Tail;
    double FormfactorOfCH3Tail;

    double OuterMajorSemiAxis = MajorSemiAxis + ThicknessOfBelt;
    double OuterMinorSemiAxis = MinorSemiAxis + ThicknessOfBelt;

    double VolumeOfBelt    = PI * HeightOfBelt * OuterMajorSemiAxis * OuterMinorSemiAxis - PI * HeightOfBelt * MajorSemiAxis * MinorSemiAxis;
    double VolumeOfHeads   = PI * HeightOfLipids * MajorSemiAxis * MinorSemiAxis         - PI * HeightOfTails * MajorSemiAxis * MinorSemiAxis;
    double VolumeOfCH2Tail = PI * HeightOfTails * MajorSemiAxis * MinorSemiAxis          - PI * HeightOfCH3 * MajorSemiAxis * MinorSemiAxis;
    double VolumeOfCH3Tail = PI * HeightOfCH3 * MajorSemiAxis * MinorSemiAxis;

    // Variables needed for integration over alpha
    int i;
    int NumberOfStepsInAlpha = 50;
    double Alpha;
    double AlphaMin = 0.0;
    double AlphaMax = PI / 2.0;
    double AlphaStep = (AlphaMax - AlphaMin) / (1.0 * NumberOfStepsInAlpha);

    // Variables needed in integration over beta
    int j;
    int NumberOfStepsInBeta = 50;
    double Beta;
    double BetaMin = 0.0;
    double BetaMax = PI / 2.0;
    double BetaStep = (BetaMax - BetaMin) / (1.0 * NumberOfStepsInBeta);

    // Computation
    Intensity = 0.0;

    for (i = 0; i < NumberOfStepsInAlpha; ++i) {
      Alpha = (i + 0.5) * AlphaStep;

      for (j = 0; j < NumberOfStepsInBeta; ++j) {
	Beta = (j + 0.5) * BetaStep;

	// Compute formfactors
	FormfactorOfBelt = (PI * HeightOfBelt * OuterMajorSemiAxis * OuterMinorSemiAxis * ND_FormfactorCylinder(q, OuterMajorSemiAxis, OuterMinorSemiAxis, HeightOfBelt, Alpha, Beta) -
			    PI * HeightOfBelt * MajorSemiAxis * MinorSemiAxis * ND_FormfactorCylinder(q, MajorSemiAxis, MinorSemiAxis, HeightOfBelt, Alpha, Beta)) /
	  (PI * HeightOfBelt * OuterMajorSemiAxis * OuterMinorSemiAxis - PI * HeightOfBelt * MajorSemiAxis * MinorSemiAxis);

	FormfactorOfHeads = (PI * HeightOfLipids * MajorSemiAxis * MinorSemiAxis * ND_FormfactorCylinder(q, MajorSemiAxis, MinorSemiAxis, HeightOfLipids, Alpha, Beta) -
			     PI * HeightOfTails  * MajorSemiAxis * MinorSemiAxis * ND_FormfactorCylinder(q, MajorSemiAxis, MinorSemiAxis, HeightOfTails , Alpha, Beta)) /
	  (PI * HeightOfLipids * MajorSemiAxis * MinorSemiAxis - PI * HeightOfTails * MajorSemiAxis * MinorSemiAxis);

	FormfactorOfCH2Tail = (PI * HeightOfTails * MajorSemiAxis * MinorSemiAxis * ND_FormfactorCylinder(q, MajorSemiAxis, MinorSemiAxis, HeightOfTails, Alpha, Beta) -
			       PI * HeightOfCH3   * MajorSemiAxis * MinorSemiAxis * ND_FormfactorCylinder(q, MajorSemiAxis, MinorSemiAxis, HeightOfCH3  , Alpha, Beta)) /
	  (PI * HeightOfTails * MajorSemiAxis * MinorSemiAxis - PI * HeightOfCH3 * MajorSemiAxis * MinorSemiAxis);

	FormfactorOfCH3Tail = ND_FormfactorCylinder(q, MajorSemiAxis, MinorSemiAxis, HeightOfCH3, Alpha, Beta);

	// Compute amplitudes
	AmplitudeOfBelt    = DeltaRhoBelt * VolumeOfBelt * FormfactorOfBelt;
	AmplitudeOfHeads   = DeltaRhoHead * VolumeOfHeads * FormfactorOfHeads;
	AmplitudeOfCH2Tail = DeltaRhoCH2Tail * VolumeOfCH2Tail * FormfactorOfCH2Tail;
	AmplitudeOfCH3Tail = DeltaRhoCH3Tail * VolumeOfCH3Tail * FormfactorOfCH3Tail;

	// Perform integration
	IntensityPart = pow(AmplitudeOfBelt + AmplitudeOfHeads + AmplitudeOfCH2Tail + AmplitudeOfCH3Tail, 2);

	Intensity += 2 / PI * sin(Alpha) * IntensityPart * AlphaStep * BetaStep;
      }
    }

    return Intensity;
  }

%}

DECLARE
%{
	// Declarations
	double Absorption;
	double NumberDensity;

	// Scattering lengths
	double DeltaRhoHead;
	double DeltaRhoBelt;
	double DeltaRhoCH2Tail;
	double DeltaRhoCH3Tail;

	// Geometric properties
	double MajorSemiAxis;
	double MinorSemiAxis;
	double ThicknessOfBelt;

	double HeightOfLipids;
	double HeightOfTails;
	double HeightOfCH3;
%}

INITIALIZE
%{
    // Rescale concentration into number of aggregates per m^3 times 10^-4
    NumberDensity = Concentration * 6.02214129e19;

    // Computations
    if (!xwidth || !yheight || !zdepth) {
      printf("%s: Sample has no volume, check parameters!\n", NAME_CURRENT_COMP);
    }

    Absorption = AbsorptionCrosssection;

    // Scattering properties of different components
    const double ScatteringLengthOfWater = 2.82E-12;
    const double VolumeOfWater = 30.0;
    // Scattering lengths
    double RhoWater;
    double RhoBelt;
    double RhoHead;
    double RhoCH2Tail;
    double RhoCH3Tail;

    RhoWater   = ScatteringLengthOfWater     / VolumeOfWater;
    RhoBelt    = ScatteringLengthOfOneMSP    / VolumeOfOneMSP;
    RhoHead    = ScatteringLengthOfHeadgroup / VolumeOfHeadgroup;
    RhoCH2Tail = ScatteringLengthOfCH2Tail   / VolumeOfCH2Tail;
    RhoCH3Tail = ScatteringLengthOfCH3Tail   / VolumeOfCH3Tail;

    DeltaRhoBelt = RhoBelt - RhoWater;
    DeltaRhoHead = RhoHead - RhoWater;
    DeltaRhoCH2Tail = RhoCH2Tail - RhoWater;
    DeltaRhoCH3Tail = RhoCH3Tail - RhoWater;

    // Geometric properties of different components
    const double AreaOfLipids = NumberOfLipids * AreaPerLipidHeadgroup / 2.0;

    MinorSemiAxis = sqrt(AreaOfLipids / (PI * AxisRatio));
    MajorSemiAxis = MinorSemiAxis * AxisRatio;

    HeightOfLipids = 2.0 * (VolumeOfHeadgroup + VolumeOfCH2Tail + VolumeOfCH3Tail) / AreaPerLipidHeadgroup;
    HeightOfTails  = 2.0 * (VolumeOfCH2Tail + VolumeOfCH3Tail) / AreaPerLipidHeadgroup;
    HeightOfCH3    = 2.0 * VolumeOfCH3Tail / AreaPerLipidHeadgroup;

    ThicknessOfBelt = sqrt(pow(MinorSemiAxis + MajorSemiAxis, 2) / 4.0 + 2.0 * VolumeOfOneMSP / (PI * HeightOfMSP)) - (MajorSemiAxis + MinorSemiAxis) / 2.0;
%}

TRACE
%{
	// Declarations	
	double l0; 
	double l1; 
	double l_full;
	double l;
	double l_1;
	double Intensity;
	double Weight;
	double IntensityPart;
	double SolidAngle;
	double q;
        double qx;
	double qy;
	double qz;
	double k;
	double dl;
	double kx_i;
	double ky_i;
	double kz_i;
	char Intersect = 0;

	// Computation
	Intersect = box_intersect(&l0, &l1, x, y, z, kx, ky, kz, xwidth, yheight, zdepth);

	if (Intersect) {

		if (l0 < 0.0) {
			fprintf(stderr, "Photon already inside sample %s - absorbing...\n", NAME_CURRENT_COMP);
			ABSORB;
                }

                // Compute properties of photon
		k = sqrt(pow(kx, 2) + pow(ky, 2) + pow(kz, 2));
		l_full = l1 - l0;
		dl = rand01() * (l1 - l0) + l0; 
		PROP_DL(dl);                  
		l = dl - l0;

		// Store properties of incoming photon
		kx_i = kx;
		ky_i = ky;
		kz_i = kz;

		// Generate new direction of photon
		randvec_target_circle(&kx, &ky, &kz, &SolidAngle, 0, 0, SampleToDetectorDistance, DetectorRadius);

		NORM(kx, ky, kz);

		kx *= k;
		ky *= k;
		kz *= k;
		
		// Compute q
		qx = kx_i - kx;
		qy = ky_i - ky;
		qz = kz_i - kz;

		q = sqrt(pow(qx, 2) + pow(qy, 2) + pow(qz, 2));

		// Compute scattering
		Intensity = exp(- pow(q * Roughness, 2))* ND_IntensityOfEmptyNanodiscs(q, MajorSemiAxis, MinorSemiAxis, ThicknessOfBelt, HeightOfMSP, HeightOfLipids, 
										       HeightOfTails, HeightOfCH3, DeltaRhoBelt, DeltaRhoHead, DeltaRhoCH2Tail, DeltaRhoCH3Tail);
		
		p *= l_full * SolidAngle / (4.0 * PI) * NumberDensity * Intensity * exp(- Absorption * (l + l1));

		SCATTER;
	}
%}

MCDISPLAY
%{
	
	box(0, 0, 0, xwidth, yheight, zdepth);
%}

END
