/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2006, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Pollambda_monitor
*
* %I
* Written by: Peter Christiansen
* Date: July 2006
* Origin: Risoe
*
* Polarisation and wavelength sensitive monitor.
*
* %D A square single monitor that measures the projection of the
* polarisation along a given normalized m-vector (mx, my, mz) as a
* function of wavelength.
*
* Example: Pollambda_monitor(Lmin=1, Lmax=20, nL=20, xwidth=0.1, yheight=0.1, npol=11, mx=0, my=1, mz=0, filename="pollambdaMon.data")
*
* %P
* INPUT PARAMETERS:
*
* xwidth: [m]           Width of detector
* yheight: [m]          Height of detector
* mx: [1]               X-component of monitor vector (can be negative)
* my: [1]               Y-component of monitor vector (can be negative)
* mz: [1]               Z-component of monitor vector (can be negative)
* nL: [1]               Number of bins in wavelength
* npol: [1]             Number of bins in Pol
* Lmin: [AA]            Minimum wavelength detected
* Lmax: [AA]            Maximum wavelength detected
* filename: [string]    Name of file in which to store the data
* restore_neutron: [1]  If set, the monitor does not influence the neutron state
* nowritefile: [1]      If set, monitor will skip writing to disk
*
* OUTPUT PARAMETERS:
*
* PolL_N: []            Array of neutron counts
* PolL_p: []            Array of neutron weight counts
* PolL_p2: []           Array of second moments
*
* %E
*******************************************************************************/

DEFINE COMPONENT PolLambda_monitor
DEFINITION PARAMETERS ()
SETTING PARAMETERS (xwidth=0.1, yheight=0.1, int nL=20, int npol=21, int restore_neutron=0,
  string filename=0, int nowritefile=0, mx=0, my=0, mz=0, Lmin, Lmax)
OUTPUT PARAMETERS ()
/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */

DECLARE
%{
  DArray2d PolL_N;
  DArray2d PolL_p;
  DArray2d PolL_p2;
%}

INITIALIZE
%{
  // Check that input parameteters makes sense
  if (Lmax<=Lmin) {
    fprintf(stderr, "Pol_monitor: %s: l1 <= l0!\n"
	   "ERROR. Exiting",
           NAME_CURRENT_COMP);
    exit(1);
  }

  if (mx==0 && my==0 && mz==0) {
    fprintf(stderr, "Pol_monitor: %s: NULL vector defined!\n"
	   "ERROR      (mx, my, mz). Exiting",
           NAME_CURRENT_COMP);
    exit(1);
  }

  if ((xwidth<=0) || (yheight <= 0)) {
    fprintf(stderr, "Pol_monitor: %s: Null detection area !\n"
	   "ERROR      (xwidth,yheight). Exiting",
           NAME_CURRENT_COMP);
    exit(1);
  }

  // Initialize variables
  NORM(mx, my, mz);

  PolL_N = create_darr2d(nL, npol);
  PolL_p = create_darr2d(nL, npol);
  PolL_p2 = create_darr2d(nL, npol);

  // Use instance name for monitor output if no input was given
  if (!strcmp(filename,"\0")) sprintf(filename,"%s",NAME_CURRENT_COMP);
%}

TRACE
%{
  int i, j;
  double pol_proj;
  double lambda;

  PROP_Z0;
  lambda = (2*PI/V2K)/sqrt(vx*vx + vy*vy + vz*vz);

  if (inside_rectangle(x, y, xwidth, yheight) &&
      lambda > Lmin && lambda < Lmax) {

    pol_proj = scalar_prod(mx, my, mz, sx, sy, sz);
    /*protect from rounding errors introduced by trig functions*/
    if (fabs(pol_proj-1)<FLT_EPSILON)
      i = npol-1;
    else if (fabs(pol_proj+1.0)<FLT_EPSILON)
      i=0;
    else
      i = floor((pol_proj+1.0)*npol/2.0);
    j = floor((lambda - Lmin)*nL/(Lmax - Lmin));

    double p2 = p*p;
    #pragma acc atomic
    PolL_N[j][i] = PolL_N[j][i]+1;

    #pragma acc atomic
    PolL_p[j][i] = PolL_p[j][i]+p;

    #pragma acc atomic
    PolL_p2[j][i] = PolL_p2[j][i]+p2;

    SCATTER;
  }
  if (restore_neutron) {
    RESTORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
  }
%}

SAVE
%{
if (!nowritefile) {
  DETECTOR_OUT_2D("Pol-wavelength monitor",
		  "Wavelength [AA]", "Polarisation projection",
		  Lmin, Lmax, -1.0, 1.0,
		  nL, npol,
		  &PolL_N[0][0],&PolL_p[0][0],&PolL_p2[0][0],
		  filename);
}
%}

FINALLY
%{
  destroy_darr2d(PolL_N);
  destroy_darr2d(PolL_p);
  destroy_darr2d(PolL_p2);
%}

MCDISPLAY
%{
  rectangle("xy", 0, 0, 0, xwidth, yheight);
%}

END
