/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2006, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: MeanPollambda_monitor
*
* %I
* Written by: Peter Christiansen
* Date: July 2006
* Origin: Risoe
*
* Polarisation and wavelength sensitive monitor.
*
* %D A square single monitor that measures the MEAN projection of the
* polarisation along a given normalized m-vector (mx, my, mz) as a
* function of wavelength.
*
* Example: MeanPollambda_monitor(xwidth=0.1, yheight=0.1, npol=11, my=1, filename="meanpollambdaMon.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
* 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
*
* CALCULATED PARAMETERS:
*
* PolL_N: [1]           Array of neutron counts
* PolL_p: [1]           Array of neutron weight counts
* PolL_p2: [1]          Array of second moments
* HelpArray: [1]        Array of weight counts used for normalization
*
* %E
*******************************************************************************/

DEFINE COMPONENT MeanPolLambda_monitor



SETTING PARAMETERS (xwidth=0.1, yheight=0.1, int nL=20, int restore_neutron=0, string filename=0, int nowritefile=0, mx=0, my=0, mz=0, Lmin, Lmax)


/* Neutron parameters: (x,y,z,vx,vy,vz,t,sx,sy,sz,p) */

DECLARE
%{
  DArray1d PolL_N;
  DArray1d PolL_p;
  DArray1d PolL_p2;
  DArray1d HelpArray;
%}

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_darr1d(nL);
  PolL_p = create_darr1d(nL);
  PolL_p2 = create_darr1d(nL);
  HelpArray = create_darr1d(nL);

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

TRACE
%{
  int i;
  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);

    i= floor((lambda - Lmin)*nL/(Lmax - Lmin));

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

    #pragma acc atomic
    HelpArray[i] = HelpArray[i] + p;

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

    #pragma acc atomic
    PolL_p2[i] = PolL_p2[i] + pol_proj*pol_proj*p; /* Shouldn't this be p2?? */

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

SAVE
%{
if (!nowritefile) {
  int i;
  double mpifactor=1;

  /*1st order correction: As polarisation is not an additive signal we should downweight by the node count.
    This asssumes that all nodes have equal weight sum.*/
#ifdef USE_MPI
  mpifactor=mpi_node_count;
#endif

  // Average output
  for (i=0; i<nL; i++) {

    if(HelpArray[i] == 0)
      continue;

    PolL_p[i]  /= HelpArray[i]*mpifactor;
    // Mcstas uses the error sigma**2=sum p_i**2 for intensities
    // But here we have the mean so the error**2 should be VAR/N:
    // sigma**2 = [sum s_i*s_i*p_i/sum p_i - (sum s_i*p_i/sum p_i)**2]/N
    PolL_p2[i] /= HelpArray[i]*mpifactor;
    PolL_p2[i] -= PolL_p[i]*PolL_p[i];
    PolL_p2[i] /= PolL_N[i];
  }

  DETECTOR_OUT_1D("Pol-wavelength monitor",
		  "Wavelength [AA]",
		  "Mean Polarisation",
		  "Wavelength", Lmin, Lmax, nL,
		  &PolL_N[0],&PolL_p[0],&PolL_p2[0],
		  filename);
}
%}

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

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

END
