/*******************************************************************************
*
* McXtrace, x-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: PSD_monitor
*
* %Identification
* Written by: Erik B Knudsen
* Date: June 22, 2009
* Origin: Risoe
*
* Position-sensitive monitor.
*
* %Description
* Based on neutron component written by Kim Lefmann
* An (nx times ny) pixel PSD monitor. This component may also be used as a beam
* detector. If instead of xwidth, yheight a radius is given, the component has a circular footprint
* and integrates circularly (caking).
*
* Example: PSD_monitor(xwidth=0.1, yheight=0.1,
*          nx=90, ny=90, filename="Output.psd")
*
* %Parameters
* INPUT PARAMETERS:
*
* xwidth: [m]           Width of detector.
* yheight: [m]          Height of detector.
* radius:  [m]          Radius of circular detetor.
* nx: [1]               Number of pixel columns.
* ny: [1]               Number of pixel rows.
* nr: [1]               Number of radial pixels.
* filename: [str]       Name of file in which to store the detector image.
* restore_xray: [1]     If set, the monitor does not influence the xray state.
* nowritefile: [1]      If set, monitor will skip writing to disk
*
* %End
*******************************************************************************/

DEFINE COMPONENT PSD_monitor

SETTING PARAMETERS (string filename=0, xwidth=0.05, yheight=0.05, radius=0, restore_xray=1, 
  int nowritefile=0, int nx=90, int ny=90, int nr=0)

/* X-ray parameters: (x,y,z,kx,ky,kz,phi,t,Ex,Ey,Ez,p) */ 

DECLARE
%{
  DArray2d PSD_N;
  DArray2d PSD_p;
  DArray2d PSD_p2;
  double xmin;
  double xmax;
  double ymin;
  double ymax;
%}

INITIALIZE
%{
  int i, j;
  double *p1, *p2, *p3;

  xmax = xwidth / 2;
  xmin = -xmax;
  ymax = yheight / 2;
  ymin = -ymax;

  if (((xmin >= xmax) || (ymin >= ymax)) && !radius) {
    fprintf (stderr, "ERROR (%s): Null detection area! Aborting.\n", NAME_CURRENT_COMP);
    exit (-1);
  }
  if (!radius) {
    PSD_N = create_darr2d (nx, ny);
    PSD_p = create_darr2d (nx, ny);
    PSD_p2 = create_darr2d (nx, ny);
  } else {
    PSD_N = create_darr2d (1, nr);
    PSD_p = create_darr2d (1, nr);
    PSD_p2 = create_darr2d (1, nr);
  }

  // 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, k;
  double e, p2;

  PROP_Z0;
  if (!radius) {
    if (x > xmin && x < xmax && y > ymin && y < ymax) {
      i = floor ((x - xmin) * nx / (xmax - xmin));
      j = floor ((y - ymin) * ny / (ymax - ymin));
      p2 = p * p;
      #pragma acc atomic
      PSD_N[i][j] += 1;
      #pragma acc atomic
      PSD_p[i][j] += p;
      #pragma acc atomic
      PSD_p2[i][j] += p2;
      SCATTER;
    }
  } else {
    double r = sqrt (x * x + y * y);
    if (r < radius) {
      i = floor (r * nr / radius);
      p2 = p * p;
      #pragma acc atomic
      PSD_N[0][i] += 1;
      #pragma acc atomic
      PSD_p[0][i] += p;
      #pragma acc atomic
      PSD_p2[0][i] += p2;
      SCATTER;
    }
  }
  if (restore_xray) {
    RESTORE_XRAY (INDEX_CURRENT_COMP, x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p);
  }
%}

SAVE
%{
  if (!nowritefile) {
    if (!radius) {
      if (nx == 1 && ny == 1) {
        char title[256];
        snprintf (title, 255, "Intensity monitor %s", NAME_CURRENT_COMP);
        DETECTOR_OUT_0D (title, (double)PSD_N[0][0], PSD_p[0][0], PSD_p2[0][0]);
      } else if (nx == 1) {
        DETECTOR_OUT_1D ("PSD_monitor", "Y Position[m]", "Intensity", "Y", ymin, ymax, ny, &PSD_N[0][0], &PSD_p[0][0], &PSD_p2[0][0], filename);
      } else if (ny == 1) {
        DETECTOR_OUT_1D ("PSD_monitor", "X Position[m]", "Intensity", "X", xmin, xmax, nx, &PSD_N[0][0], &PSD_p[0][0], &PSD_p2[0][0], filename);
      } else {
        DETECTOR_OUT_2D ("PSD monitor", "X position [m]", "Y position [m]", xmin, xmax, ymin, ymax, nx, ny, *PSD_N, *PSD_p, *PSD_p2, filename);
      }
    } else {
      DETECTOR_OUT_1D ("PSD_monitor", "Radial Position[m]", "Intensity", "R", 0, radius, nr, &PSD_N[0][0], &PSD_p[0][0], &PSD_p2[0][0], filename);
    }
  }
%}

FINALLY
%{
  destroy_darr2d (PSD_N);
  destroy_darr2d (PSD_p);
  destroy_darr2d (PSD_p2);
%}

MCDISPLAY
%{

  multiline (5, (double)xmin, (double)ymin, 0.0, (double)xmax, (double)ymin, 0.0, (double)xmax, (double)ymax, 0.0, (double)xmin, (double)ymax, 0.0, (double)xmin,
             (double)ymin, 0.0);
%}

END
