/**************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2006, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Pol_monitor
*
* %I
* Written by: Peter Christiansen
* Modified by  Erik B Knudsen
* Date: July 2006
* Origin: Risoe
*
* Polarisation sensitive monitor.
*
* %D A square single monitor that measures the projection of the
* polarisation along a given normalized m-vector (mx, my, mz).
* The measured quantity is: sx*mx+sy*my+mz*sz
*
* Example: Pol_monitor(xwidth=0.1, yheight=0.1, nchan=11, mx=0, my=1, mz=0)
*
* %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)
* 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:
*
* Pol_N: []             Array of neutron counts
* Pol_p: []             Array of neutron weight counts
* Pol_p2: []            Array of second moments
*
* %E
*************************************************************************/
DEFINE COMPONENT Pol_monitor

DEFINITION PARAMETERS ()

SETTING PARAMETERS (xwidth=0.1, yheight=0.1, int restore_neutron=0, mx=0, my=0, mz=0, int nowritefile=0)

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

DECLARE
%{
  double Pol_N;
  double Pol_p;
  double Pol_p2;
  double Psum;
  char titlestring[128];
%}

INITIALIZE
%{
  // Check that input parameteters makes sense
  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);
  }
  sprintf(titlestring, "Polarisation monitor m=(%g %g %g) %s", mx, my, mz, NAME_CURRENT_COMP);

  // Initialize variables

  NORM(mx, my, mz);
  Psum=0;
  Pol_N = 0;
  Pol_p = 0;
  Pol_p2 = 0;
%}

TRACE
%{
  double pol_proj;

  PROP_Z0;
  if (inside_rectangle(x, y, xwidth, yheight)){

    pol_proj = scalar_prod(mx, my, mz, sx, sy, sz);

    if(fabs(pol_proj)>1) {
        if (fabs(pol_proj)<1+FLT_EPSILON){
            pol_proj=1;
        }else{
            ABSORB;
        }
    }
    double p2 = p*p;
    double pp = pol_proj*p;
    double p2p = pol_proj*pol_proj*p;
    #pragma acc atomic
    Pol_N = Pol_N+1;

    #pragma acc atomic
    Psum = Psum+p;

    #pragma acc atomic
    Pol_p = Pol_p+pp;

    #pragma acc atomic
    Pol_p2 = Pol_p2+p2p;
    
    SCATTER;
  }
  if (restore_neutron) {
    RESTORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
  }
%}

SAVE
%{
    if (!nowritefile) {
  if (Psum && Pol_N){
      Pol_p  /= Psum;
#ifdef USE_MPI
      Pol_p /= mpi_node_count;
#endif
      Pol_p2 /= Psum;
      Pol_p2 -= Pol_p*Pol_p;
      Pol_p2 /= Pol_N;
  }
  DETECTOR_OUT_0D(titlestring, Pol_N, Pol_p, Pol_p2);
    }
%}

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

END
