/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright (C) 1997-2011, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: TOF2Q_cylPSD_monitor
*
* %I
* Written by: Anette Vickery, derived from Lefmann TOF_cylPSD
* Date: October 2000
* Origin: Risoe
* Modified by: Anette Vickery, October 9, 2012
*
* Cylindrical (2pi) Time-of-flight to Q monitor.
* Calculates Q from TOF and known nominal grazing angle theta:
* E = VS2E*(L_flight/(t-T_zero))*(L_flight/(t-T_zero));
*    Q=2*sqrt(E/2.072)*sin(theta);
*
* %D
*
* %P
* INPUT PARAMETERS:
*
* radius: [m]           Cylinder radius
* yheight: [m]          Cylinder height
* nQ: [1]               Number of Q bins
* ny: [1]               Number of y bins
* yheight: [m]          Height of cylinder
* ymin: [m]             Minimum value of y monitored
* ymax: [m]             Maximum value of y monitored
* Qmin: []              Beginning of Q-range
* Qmax: []              End of Q-range
* T_zero: [s]           Beginning of time window
* L_flight: []          Nominal flightpath moderator--detector
* theta: []             Nominal grazing angle
* filename: [string]    Name of file in which to store the detector image
* 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:
*
* TOF_N: []             Array of neutron counts
* TOF_p: []             Array of neutron weight counts
* TOF_p2: []            Array of second moments
*
* %E
*******************************************************************************/

DEFINE COMPONENT TOF2Q_cylPSD_monitor

SETTING PARAMETERS (int nQ, int ny, string filename=0, int nowritefile=0, radius, yheight,  Qmin, Qmax, ymin=0, ymax=0, T_zero, L_flight, int restore_neutron=0,theta)


DECLARE
%{
  DArray2d TOF_N;
  DArray2d TOF_p;
  DArray2d TOF_p2;
%}

INITIALIZE
%{
  int i,j;

  TOF_N = create_darr2d(nQ, ny);
  TOF_p = create_darr2d(nQ, ny);
  TOF_p2 = create_darr2d(nQ, ny);

  if (yheight > 0) { ymax = yheight/2; ymin = -ymax; }

  // 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 cyl_t0, cyl_t1, dt, phi;
  double E, Q;

  if(!cylinder_intersect(&cyl_t0, &cyl_t1, x,y,z,vx,vy,vz, radius, yheight))
   /* No hit */
    ABSORB;
  if(cyl_t0>0)  /* Neutron hits cylinder from the outside */
    ABSORB;
  dt = cyl_t1;
  PROP_DT(dt);
  if(y>=yheight/2 || y<= -yheight/2)
    ABSORB;  /* Neutron hits cylinder ends; no detectors here */

  E = VS2E*(L_flight/(t-T_zero))*(L_flight/(t-T_zero));

  j = floor((y - ymin)*ny/(ymax - ymin));

  Q=2*sqrt(E/2.072)*sin(theta);

  i = floor((Q-Qmin)*nQ/(Qmax-Qmin));
  
  if (i>=0 && i<nQ && j>=0 && j<ny) {
    double p2 = p*p;
    #pragma acc atomic
    TOF_N[i][j] = TOF_N[i][j]+1;
    #pragma acc atomic
    TOF_p[i][j] = TOF_p[i][j]+p;
    #pragma acc atomic
    TOF_p2[i][j] = TOF_p2[i][j]+p2;
  }
  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(
      "Cylindrical TOF2E PSD monitor",
      "TOF2Q [Ang^-1]",
      "Y position [cm]",
      Qmin, Qmax, ymin*100.0, ymax*100.0,
      nQ, ny,
      &TOF_N[0][0],&TOF_p[0][0],&TOF_p2[0][0],
      filename);
}
%}

FINALLY
%{
  destroy_darr2d(TOF_N);
  destroy_darr2d(TOF_p);
  destroy_darr2d(TOF_p2);
%}

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

END
