/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright (C) 1997-2009, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: PSD_monitor_4PI_spin
*
* %I
* Written by: Erik B Knudsen
* Date: April 17, 2010s
* Origin: DTU
*
* Spherical position-sensitive detector with spin weighting
*
* %D
* An (n times m) pixel spherical PSD monitor using a cylindrical projection.
* Mostly for test and debugging purposes.
*
* Example: PSD_monitor_4PI(radius=0.1,
            nx=90, ny=90, filename="Output.psd")
*
* %P
* INPUT PARAMETERS:
*
* radius:          [m] Radius of detector 
* nx:              [1] Number of pixel columns
* ny:              [1] Number of pixel rows
* filename:      [str] Name of file in which to store the detector image
* restore_neutron: [1] If set, the monitor does not influence the neutron state x
* mx:              [1] x-component of spin reference-vector
* my:              [1] y-component of spin reference-vector
* mz:              [1] z-component of spin reference-vector
*
* OUTPUT PARAMETERS:
*
* PSD_N:    Array of neutron counts
* PSD_p:    Array of neutron weight counts
* PSD_p2:   Array of second moments
*
* %L
* <A HREF="http://neutron.risoe.dk/mcstas/components/tests/powder/">Test
* results</A> (not up-to-date).
*
* %E
*******************************************************************************/


DEFINE COMPONENT PSD_monitor_4PI_spin
DEFINITION PARAMETERS ()
SETTING PARAMETERS (int nx=90, int ny=90, radius, string filename=0, int restore_neutron=0, mx=0, my=1, mz=0)
OUTPUT PARAMETERS (PSD_N, PSD_p, PSD_p2)

DECLARE
%{
  DArray2d PSD_N;
  DArray2d PSDu_p;
  DArray2d PSDd_p;
  DArray2d PSDu_p2;
  DArray2d PSDd_p2;
%}
INITIALIZE
%{
  PSD_N = create_darr2d(nx, ny);
  PSDu_p = create_darr2d(nx, ny);
  PSDd_p = create_darr2d(nx, ny);
  PSDu_p2 = create_darr2d(nx, ny);
  PSDd_p2 = create_darr2d(nx, ny);
  // Use instance name for monitor output if no input was given
  if (!strcmp(filename,"\0")) sprintf(filename,"%s",NAME_CURRENT_COMP);
%}
TRACE
%{
  double t0, t1, phi, theta;
  int i,j;

  if(sphere_intersect(&t0, &t1, x, y, z, vx, vy, vz, radius) && t1 > 0)
  {
    if(t0 < 0)
      t0 = t1;
    /* t0 is now time of intersection with the sphere. */
    PROP_DT(t0);
    phi = atan2(x,z);
    i = floor(nx*(phi/(2*PI)+0.5));
    if(i >= nx)
      i = nx-1;                      /* Special case for phi = PI. */
    else if(i < 0)
      i = 0;
    theta=asin(y/radius);
    j = floor(ny*(theta+PI/2)/PI+0.5);
    if(j >= ny)
      j = ny-1;                      /* Special case for y = radius. */
    else if(j < 0)
      j = 0;
    /*look at spin-down neutrons*/
    double n_up=(1+scalar_prod(sx,sy,sz,mx,my,mz))*p/2;
    /*look at spin-down neutrons*/
    double n_down=(1-scalar_prod(sx,sy,sz,mx,my,mz))*p/2;

    double n_up2 = n_up*n_up;
    double n_down2 = n_down*n_down;
    #pragma acc atomic
    PSD_N[i][j] = PSD_N[i][j] + 1;
    #pragma acc atomic
    PSDu_p[i][j] = PSDu_p[i][j] + n_up;
    #pragma acc atomic
    PSDu_p2[i][j] = PSDu_p2[i][j] + n_up2;
    #pragma acc atomic
    PSDd_p[i][j] = PSDd_p[i][j] + n_down;
    #pragma acc atomic
    PSDd_p2[i][j] = PSDd_p2[i][j] + n_down2;
    SCATTER;
  }
  if (restore_neutron) {
    RESTORE_NEUTRON(INDEX_CURRENT_COMP, x, y, z, vx, vy, vz, t, sx, sy, sz, p);
  }
%}

SAVE
%{
   char title[256];
   char fn[256];
   snprintf(title,256,"4PI PSD Monitor spin %s (parallel to m=%g,%g,%g).","up",mx,my,mz); 
   snprintf(fn,256,"%s.up",filename);
   DETECTOR_OUT_2D(
          title,
          "Longitude [deg]",
          "Lattitude [deg]",
          -180, 180, -90, 90,
          nx, ny,
          &PSD_N[0][0],&PSDu_p[0][0],&PSDu_p2[0][0],
          fn);
   snprintf(title,256,"4PI PSD Monitor spin %s (antiparallel to m=%g,%g,%g).","down",mx,my,mz); 
   snprintf(fn,256,"%s.down",filename);
   DETECTOR_OUT_2D(
          title,
          "Longitude [deg]",
          "Lattitude [deg]",
          -180, 180, -90, 90,
          nx, ny,
          &PSD_N[0][0],&PSDd_p[0][0],&PSDd_p2[0][0],
          fn);

%}

FINALLY %{
  destroy_darr2d(PSD_N);
  destroy_darr2d(PSDu_p);
  destroy_darr2d(PSDd_p);
  destroy_darr2d(PSDu_p2);
  destroy_darr2d(PSDd_p2);
%}

MCDISPLAY
%{
  magnify("");
  circle("xy",0,0,0,radius);
  circle("xz",0,0,0,radius);
  circle("yz",0,0,0,radius);
%}

END
