/*******************************************************************************
*
* McXtrace, x-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: Mirror_elliptic
* 
* %Identification
* Written by: Erik Knudsen
* Date: Feb 11, 2010
* Version: $Revision$
* Origin: Risoe
* Modified by: Bac Stephane, Padovani Antoine, 09th May 2022 : melded Bragg_crystal_bent.comp into here.
*
* Idealized elliptic mirror.
* 
* %Description
* Takes a reflectivity as input and reflects rays in a ideal geometry
* elliptic mirror.
* The mirror is positioned such that the a-axis of the mirror ellipsoid is on the
* x-axis, the b-axis is along the y-axis and the c is along the z-axis.
* The reference point of the mirror is the ellipsoid centre, offset by one 
* half-axis along the y-axis (See the component manual for a drawing). 
* This means that to position the mirror correctly,
* the user positions the ellipsoid governing the mirror shape, not the mirror itself.
*
* Example: Mirror_elliptic( length=150e-3, width=150e-3, x_a=1.025, y_b=1.025, z_c=1.025)
* 
* %Parameters
* INPUT PARAMETERS
* x_a:     [m]   1st short half axis (along x). Commonly set to zero, which really implies infinite value, so crystal is an elliptic cylinder.
* y_b:     [m]   2nd short half axis (along y), which is also the presumed near-normal direction, reflection near the y-z plane.
* z_c:     [m]   long  half axis (along z). Commonly a=0. b=c, which creates a circular cylindrical surface.
* xwidth:  [m]   Width of the mirror along X.
* zdepth:  [m]   Depth (length) of the mirror along Z.
* coating: [str] Datafile containing either mirror material constants or reflectivity  numbers.
* R0:      [1]   Reflectivity of mirror (mostly relevant for debugging, when coating="")
* radius:  [m]   Spherical radius, Sets x_a=y_b=z_c=radius
* length:  [m]   alternate name for zdepth (obsolete)
* width:   [m]   alternate name for xwidth (obsolete)
*
* %End
*******************************************************************************/

DEFINE COMPONENT Mirror_elliptic
SETTING PARAMETERS (x_a=0, y_b=1.0, z_c=1.0, 
        zdepth=0.2,  xwidth=0.2,  
        R0=1,string coating="Be.txt",
        length=0,    width=0, radius=0)
DEPENDENCY "-std=c99"

SHARE
%{
  %include "perfect_crystals-lib"
  #include <complex.h>
  %include "read_table-lib"
  %include "reflectivity-lib"
%}

DECLARE
%{
  double a2inv;
  double b2inv;
  double c2inv; /* 1/r^2 for physical ellipse */
  t_Reflec re;
%}

INITIALIZE
%{
  int status;

  if (radius)
    x_a = y_b = z_c = radius;

  if (coating && strlen (coating)) {
    status = reflec_Init (&re, COATING_UNDEFINED, coating, NULL);
  } else {
    /*assume a constant reflectivity*/
    status = reflec_Init (&re, CONSTANT, NULL, &(R0));
  }

  a2inv = (x_a) ? 1 / (x_a * x_a) : 0; /* 0 really means infinity for x direction */
  b2inv = (y_b) ? 1 / (y_b * y_b) : 0;
  c2inv = (z_c) ? 1 / (z_c * z_c) : 0;

  printf ("Component %s: initialized\n", NAME_CURRENT_COMP);

  fflush (NULL); // put diagnostics in order!

  // compatibility with older use
  if (zdepth)
    length = zdepth;
  if (xwidth)
    width = xwidth;
%}

TRACE
%{
  double E;             // (keV) x-ray energy
  double K;             // length of k-vector
  double kxu, kyu, kzu; // unit vector in the direction of k-vector.
  double x_int, y_int, z_int;
  double R;

  /* get the photon's kvector and energy */
  K = sqrt (kx * kx + ky * ky + kz * kz);
  E = K2E * K; /* use built-in constants for consistency */
  /* make unit vector in the direction of k :*/
  kxu = kx;
  kyu = ky;
  kzu = kz;
  NORM (kxu, kyu, kzu);

  double A, B, C, xt, yt, zt;
  double t0, t1;
  /*an offset to the mirror parameters perhaps*/

  xt = x;
  zt = z;
  yt = y - y_b;

  C = xt * xt * a2inv + yt * yt * b2inv + zt * zt * c2inv - 1;
  B = 2 * (kxu * xt * a2inv + kyu * yt * b2inv + kzu * zt * c2inv);
  A = kxu * kxu * a2inv + kyu * kyu * b2inv + kzu * kzu * c2inv;

  if (solve_2nd_order (&t0, &t1, A, B, C)) {
    double xx0, xx1, yy0, yy1, zz0, zz1; /* we will have to tentatively propagate twice to see which surface we hit */
    xx0 = x + kxu * t0;
    yy0 = y + kyu * t0;
    zz0 = z + kzu * t0;
    xx1 = x + kxu * t1;
    yy1 = y + kyu * t1;
    zz1 = z + kzu * t1;

    /*Check if we hit the mirror and whether the hit it is in front of the ray.
     * This does not account for mirror curvature */

    int hit0 = (fabs (xx0) < width / 2.0) && (fabs (zz0) < length / 2.0) && t0 > 0;
    int hit1 = (fabs (xx1) < width / 2.0) && (fabs (zz1) < length / 2.0) && t1 > 0;
    int doit = hit0 || hit1;

    if (hit0 && !hit1)
      PROP_DL (t0); /* only one intersection actually on mirror */
    else if (hit1 && !hit0)
      PROP_DL (t1);          /* other intersection */
    else if (hit0 && hit1) { /* both, take first strike (which may be back of mirror) */
      PROP_DL (t0 < t1 ? t0 : t1);
    } else {
      RESTORE_XRAY (INDEX_CURRENT_COMP, x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p);
    }

    if (doit) {
      SCATTER;
      xt = x;
      yt = y - y_b;
      zt = z; /* update shifted coordinates to intersection point */
      double nx, ny, nz;
      /* grad is the inner normal to the surface at this point */
      nx = -xt * a2inv;
      ny = -yt * b2inv;
      nz = -zt * c2inv;
      NORM (nx, ny, nz);

      double kdotn;
      kdotn = -scalar_prod (kx, ky, kz, nx, ny, nz);
      double kfx, kfy, kfz;
      kfx = kx + 2 * kdotn * nx;
      kfy = ky + 2 * kdotn * ny;
      kfz = kz + 2 * kdotn * nz;

      kx = kfx;
      ky = kfy;
      kz = kfz;

      /*adjust weight of ray*/

      double q = 2.0 * kdotn;
      double R = reflecq (re, q, 0, K, fabs (90 - acos (kdotn / K) * RAD2DEG));
      p *= R;
      /*update phase - as an approximation turn by 180 deg.*/;
      phi += M_PI;

      /*catch dead rays*/

      // if (p==0) ABSORB;
    } else {
      RESTORE_XRAY (INDEX_CURRENT_COMP, x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p);
    }
  }
%}

MCDISPLAY
%{
  int i, j, N = 12;
  double t, xx, yy, zz, xx0, yy0, zz0;
  double a2, b2, c2;
  a2 = 1.0 / a2inv;
  b2 = 1.0 / b2inv;
  c2 = 1.0 / c2inv;
  if (xwidth && zdepth) {
    for (i = 0; i < N; i++) {
      xx0 = -xwidth / 2.0;
      zz = i * zdepth / (N - 1) - zdepth / 2.0;
      yy0 = -(1) * sqrt (b2 * (1 - xx0 * xx0 / a2 - zz * zz / c2)) + sqrt (b2);
      for (j = 1; j < N; j++) {
        xx = j * xwidth / (N - 1) - xwidth / 2.0;
        yy = -(1) * sqrt (b2 * (1 - xx * xx / a2 - zz * zz / c2)) + sqrt (b2);
        line (xx0, yy0, zz, xx, yy, zz);
        xx0 = xx;
        yy0 = yy;
      }
    }
    for (i = 0; i < N; i++) {
      zz0 = -zdepth / 2.0;
      xx = i * xwidth / (N - 1) - xwidth / 2.0;
      yy0 = -(1) * sqrt (b2 * (1 - xx * xx / a2 - zz0 * zz0 / c2)) + sqrt (b2);
      for (j = 1; j < N; j++) {
        zz = j * zdepth / (N - 1) - zdepth / 2.0;
        yy = -(1) * sqrt (b2 * (1 - xx * xx / a2 - zz * zz / c2)) + sqrt (b2);
        line (xx, yy0, zz0, xx, yy, zz);
        zz0 = zz;
        yy0 = yy;
      }
    }
  }
%}

END
