/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2002, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Mirror
*
* %I
* Written by: Kristian Nielsen
* Date: August 1998
* Origin: Risoe
*
* Single mirror plate.
*
* %D
* Single mirror plate (used to build guides in compound components).
* The component Mirror models a single rectangular neutron mirror plate.
* It can be used as a sample component or to e.g. assemble a complete neutron
* guide by putting multiple mirror components at appropriate locations and
* orientations in the instrument definition, much like a real guide is build
* from individual mirrors.
* Additionally, it may be centered in order to be used as a sample or
* monochromator plate, else it starts from AT position.
* Reflectivity is either defined by an analytical model (see Component Manual)
* or from a two-columns file with q [Angs-1] as first and R [0-1] as second.
* In the local coordinate system, the mirror lies in the first quadrant of the
* x-y plane, with one corner at (0, 0, 0). Plane is thus perpendicular to the
* incoming beam, and should usually be rotated.
*
* Example: Mirror(xwidth=.1, yheight=.1,R0=0.99,Qc=0.021,alpha=6.1,m=2,W=0.003)
*
* %P
* INPUT PARAMETERS:
*
* xwidth: [m]     width of mirror plate
* yheight: [m]    height of mirror plate
* R0: [1]         Low-angle reflectivity
* Qc: [AA-1]      Critical scattering vector
* alpha: [AA]     Slope of reflectivity
* m: [1]          m-value of material. Zero means completely absorbing.
* W: [AA-1]       Width of supermirror cut-off
* reflect: [str]  Name of reflectivity file. Format q(Angs-1) R(0-1)
* transmit: [1]   When true, non reflected neutrons are transmitted through the mirror, instead of being absorbed.
* center: [1]     if true (1), the Mirror is centered arount AT position.
*
* %D
* Example values: m=4 Qc=0.02 W=1/300 alpha=6.49 R0=1
*
* %E
*******************************************************************************/

DEFINE COMPONENT Mirror

SETTING PARAMETERS (string reflect=0, xwidth, yheight,R0=0.99,Qc=0.021,alpha=6.07,m=2,W=0.003, center=0, transmit=0)

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

SHARE
%{
%include "read_table-lib"
%include "ref-lib"
%}

DECLARE
%{
  t_Table pTable;
%}

INITIALIZE
%{
  if (reflect && strlen (reflect) && strcmp (reflect, "NULL") && strcmp (reflect, "0")) {
    if (Table_Read (&pTable, reflect, 1) <= 0) /* read 1st block data from file into pTable */
      exit (fprintf (stderr, "Mirror: %s: can not read file %s\n", NAME_CURRENT_COMP, reflect));
  }
%}

TRACE
%{
  double dt, q, B;
  char intersect = 0;

  /* First check if neutron has the right direction. */
  if (vz != 0.0 && (dt = -z / vz) >= 0) {
    double old_x = x, old_y = y;
    x += vx * dt;
    y += vy * dt;
    /* Now check if neutron intersects mirror. */
    intersect = (center == 0 ? x >= 0 && x <= xwidth && y >= 0 && y <= yheight : x >= -xwidth / 2 && x <= xwidth / 2 && y >= -yheight / 2 && y <= yheight / 2);
    if (intersect) {
      z = 0;
      t += dt;
      q = fabs (2 * vz * V2Q);
      vz = -vz;
      /* Reflectivity (see component Guide). */
      if (reflect && strlen (reflect) && strcmp (reflect, "NULL") && strcmp (reflect, "0"))
        TableReflecFunc (q, &pTable, &B);
      else {
        double par[] = { R0, Qc, alpha, m, W };
        StdReflecFunc (q, par, &B);
      }
      /* now handle either probability when transmit or weight */
      if (!transmit) {
        if (B <= 0)
          ABSORB;
        p *= B;
        SCATTER;
      } else {
        /* transmit when rand > B: restore original vz */
        if (B == 0 || rand01 () >= B) {
          vz = -vz;
        }
        SCATTER;
      }
    }

    if (!intersect) {
      /* No intersection: restore neutron position. */
      x = old_x;
      y = old_y;
    }
  }
%}

MCDISPLAY
%{
  double xmax, xmin, ymax, ymin;

  if (center == 0) {
    xmax = xwidth;
    xmin = 0;
    ymax = yheight;
    ymin = 0;
  } else {
    xmax = xwidth / 2;
    xmin = -xmax;
    ymax = yheight / 2;
    ymin = -ymax;
  }
  polygon (4, (double)xmin, (double)ymin, 0.0, (double)xmax, (double)ymin, 0.0, (double)xmax, (double)ymax, 0.0, (double)xmin, (double)ymax, 0.0);
%}
END
