/*******************************************************************************
*
* McXtrace, X-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: SasView_peak_lorentz
*
* %Identification
* Written by: Jose Robledo
* Based on sasmodels from SasView
* Origin: FZJ / DTU / ESS DMSC
*
*
* SasView peak_lorentz model component as sample description.
*
* %Description
*
* SasView_peak_lorentz component, generated from peak_lorentz.c in sasmodels.
*
* Example: 
*  SasView_peak_lorentz(peak_pos, peak_hwhm, 
*     model_scale=1.0, model_abs=0.0, xwidth=0.01, yheight=0.01, zdepth=0.005, R=0, 
*     int target_index=1, target_x=0, target_y=0, target_z=1,
*     focus_xw=0.5, focus_yh=0.5, focus_aw=0, focus_ah=0, focus_r=0, 
*     )
*
* %Parameters
* INPUT PARAMETERS:
* peak_pos: [1/Ang] ([-inf, inf]) Peak postion in q.
* peak_hwhm: [1/Ang] ([-inf, inf]) HWHM of peak.
* Optional parameters:
* model_abs: [ ] Absorption cross section density at 2200 m/s.
* model_scale: [ ] Global scale factor for scattering kernel. For systems without inter-particle interference, the form factors can be related to the scattering intensity by the particle volume fraction.
* xwidth: [m] ([-inf, inf]) Horiz. dimension of sample, as a width.
* yheight: [m] ([-inf, inf]) vert . dimension of sample, as a height for cylinder/box
* zdepth: [m] ([-inf, inf]) depth of sample
* R: [m] Outer radius of sample in (x,z) plane for cylinder/sphere.
* target_x: [m] relative focus target position.
* target_y: [m] relative focus target position.
* target_z: [m] relative focus target position.
* target_index: [ ] Relative index of component to focus at, e.g. next is +1.
* focus_xw: [m] horiz. dimension of a rectangular area.
* focus_yh: [m], vert. dimension of a rectangular area.
* focus_aw: [deg], horiz. angular dimension of a rectangular area.
* focus_ah: [deg], vert. angular dimension of a rectangular area.
* focus_r: [m] case of circular focusing, focusing radius.

*
* %Link
* %End
*******************************************************************************/
DEFINE COMPONENT SasView_peak_lorentz
DEFINITION PARAMETERS ()
SETTING PARAMETERS (
        peak_pos=0.05,
        peak_hwhm=0.005,
        model_scale=1.0,
        model_abs=0.0,
        xwidth=0.01,
        yheight=0.01,
        zdepth=0.005,
        R=0,
        target_x=0,
        target_y=0,
        target_z=1,
        int target_index=1,
        focus_xw=0.5,
        focus_yh=0.5,
        focus_aw=0,
        focus_ah=0,
        focus_r=0)


SHARE %{
%include "sas_kernel_header.c"

/* BEGIN Required header for SASmodel peak_lorentz */
#define HAS_Iq

#ifndef SAS_HAVE_peak_lorentz
#define SAS_HAVE_peak_lorentz

#line 1 "peak_lorentz"
#include <math.h>
    
double Iq_peak_lorentz(double q, double peak_pos, double peak_hwhm);

#pragma acc routine seq
double Iq_peak_lorentz(double q, double peak_pos, double peak_hwhm) {
    double inten = 1.0 / (1.0 + pow((q - peak_pos) / peak_hwhm, 2.0));
    return inten;
}



#endif // SAS_HAVE_peak_lorentz



/* END Required header for SASmodel peak_lorentz */
%}
    DECLARE
%{
  double shape;
  double my_a_k;
%}

INITIALIZE
%{
shape=-1;  /* -1:no shape, 0:cyl, 1:box, 2:sphere  */
if (xwidth && yheight && zdepth)
    shape=1;
  else if (R > 0 && yheight)
    shape=0;
  else if (R > 0 && !yheight)
    shape=2;
  if (shape < 0)
    exit(fprintf(stderr, "SasView_model: %s: sample has invalid dimensions.\n"
                         "ERROR     Please check parameter values.\n", NAME_CURRENT_COMP));

  /* now compute target coords if a component index is supplied */
  if (!target_index && !target_x && !target_y && !target_z) target_index=1;
  if (target_index)
  {
    Coords ToTarget;
    ToTarget = coords_sub(POS_A_COMP_INDEX(INDEX_CURRENT_COMP+target_index),POS_A_CURRENT_COMP);
    ToTarget = rot_apply(ROT_A_CURRENT_COMP, ToTarget);
    coords_get(ToTarget, &target_x, &target_y, &target_z);
  }

  if (!(target_x || target_y || target_z)) {
    printf("SasView_model: %s: The target is not defined. Using direct beam (Z-axis).\n",
      NAME_CURRENT_COMP);
    target_z=1;
  }

  /*TODO fix absorption*/
  my_a_k = model_abs; /* assume absorption is given in 1/m */

%}


TRACE
%{
  double l0, l1, k, l_full, l, dl, d_Phi;
  double aim_x=0, aim_y=0, aim_z=1, axis_x, axis_y, axis_z;
  double f, solid_angle, kx_i, ky_i, kz_i, q, qx, qy, qz;
  char intersect=0;

  /* Intersection photon trajectory / sample (sample surface) */
  if (shape == 0){
    intersect = cylinder_intersect(&l0, &l1, x, y, z, kx, ky, kz, R, yheight);}
  else if (shape == 1){
    intersect = box_intersect(&l0, &l1, x, y, z, kx, ky, kz, xwidth, yheight, zdepth);}
  else if (shape == 2){
    intersect = sphere_intersect(&l0, &l1, x, y, z, kx, ky, kz, R);}
  if(intersect)
  {
    if(l0 < 0)
      ABSORB;

    /* Photon enters at l0. */
    k = sqrt(kx*kx + ky*ky + kz*kz);
    l_full = (l1 - l0);          /* Length of full path through sample */
    dl = rand01()*(l1 - l0) + l0;    /* Point of scattering */
    PROP_DL(dl);                     /* Point of scattering */
    l = (dl-l0);                   /* Penetration in sample */

    kx_i=kx;
    ky_i=ky;
    kz_i=kz;
    if ((target_x || target_y || target_z)) {
      aim_x = target_x-x;            /* Vector pointing at target (anal./det.) */
      aim_y = target_y-y;
      aim_z = target_z-z;
    }
    if(focus_aw && focus_ah) {
      randvec_target_rect_angular(&kx, &ky, &kz, &solid_angle,
        aim_x, aim_y, aim_z, focus_aw, focus_ah, ROT_A_CURRENT_COMP);
    } else if(focus_xw && focus_yh) {
      randvec_target_rect(&kx, &ky, &kz, &solid_angle,
        aim_x, aim_y, aim_z, focus_xw, focus_yh, ROT_A_CURRENT_COMP);
    } else {
      randvec_target_circle(&kx, &ky, &kz, &solid_angle, aim_x, aim_y, aim_z, focus_r);
    }
    NORM(kx, ky, kz);
    kx *= k;
    ky *= k;
    kz *= k;
    qx = (kx_i-kx);
    qy = (ky_i-ky);
    qz = (kz_i-kz);
    q = sqrt(qx*qx+qy*qy+qz*qz);
    


    // Sample dependent. Retrieved from SasView./////////////////////
    float Iq_out;
    Iq_out = 1;

    Iq_out = Iq_peak_lorentz(q, peak_pos, peak_hwhm);


    float vol;
    vol = 1;

    // Scale by 1.0E2 [SasView: 1/cm  ->   McXtrace: 1/m]
    Iq_out = model_scale*Iq_out / vol * 1.0E2;

    
    p *= l_full*solid_angle/(4*PI)*Iq_out*exp(-my_a_k*(l+l1));


    SCATTER;
  }
%}

MCDISPLAY
%{

  if (shape == 0) {	/* cylinder */
    circle("xz", 0,  yheight/2.0, 0, R);
    circle("xz", 0, -yheight/2.0, 0, R);
    line(-R, -yheight/2.0, 0, -R, +yheight/2.0, 0);
    line(+R, -yheight/2.0, 0, +R, +yheight/2.0, 0);
    line(0, -yheight/2.0, -R, 0, +yheight/2.0, -R);
    line(0, -yheight/2.0, +R, 0, +yheight/2.0, +R);
  }
  else if (shape == 1) { 	/* box */
    double xmin = -0.5*xwidth;
    double xmax =  0.5*xwidth;
    double ymin = -0.5*yheight;
    double ymax =  0.5*yheight;
    double zmin = -0.5*zdepth;
    double zmax =  0.5*zdepth;
    multiline(5, xmin, ymin, zmin,
                 xmax, ymin, zmin,
                 xmax, ymax, zmin,
                 xmin, ymax, zmin,
                 xmin, ymin, zmin);
    multiline(5, xmin, ymin, zmax,
                 xmax, ymin, zmax,
                 xmax, ymax, zmax,
                 xmin, ymax, zmax,
                 xmin, ymin, zmax);
    line(xmin, ymin, zmin, xmin, ymin, zmax);
    line(xmax, ymin, zmin, xmax, ymin, zmax);
    line(xmin, ymax, zmin, xmin, ymax, zmax);
    line(xmax, ymax, zmin, xmax, ymax, zmax);
  }
  else if (shape == 2) {	/* sphere */
    circle("xy", 0,  0.0, 0, R);
    circle("xz", 0,  0.0, 0, R);
    circle("yz", 0,  0.0, 0, R);
  }
%}
END

