/************************************************
* McXtrace, x-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* %Identification
* Written by: Erik Knudsen
* Date: September 25th, 2009
* Origin: Risoe
*
* A cylindrically curved mirror (in YZ)
*
* %Description
* mirror is in the YZ-plane curved towards positive X if radius is positive
*
* Example: Mirror_curved( radius=2, length=20e-3, width=40e-3, coating="AlMgF2_disco.dat")
* 
* %Parameters
* radius: [m]   Radius of curvature, along Z.
* yheight:[m]   Width of the mirror along Y.
* zdepth: [m]   Length of the unbent mirror along Z.
* coating:[str] Name of file containing the material data (i.e. f1 and f2) for the coating
* R0:     [1]   Constant reflectivity value (mostly relevant for debugging, when coating="").
* width:  [m]   Width of the mirror along Y = yheight
* length: [m]   Length of the unbent mirror along Z = zdepth
*
* %End
***********************************************************************/

DEFINE COMPONENT Mirror_curved
DEFINITION PARAMETERS ()
SETTING PARAMETERS (radius=1, R0=1, string coating="Be.txt",
  zdepth=0.2, yheight=0.2, 
  length=0, width=0)
OUTPUT PARAMETERS()
/* X-ray parameters: (x,y,z,kx,ky,kz,phi,t,Ex,Ey,Ez,p) */ 

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

DECLARE
%{
  int Z;
  double At;
  double rho;
  t_Table T;
  t_Reflec re;
%}

INITIALIZE
%{
  int status;

  if (coating && strlen(coating)) {
    status=reflec_Init(&re,COATING_UNDEFINED,coating,NULL);
  }else{
    /*assume a constant reflectivity*/
    status=reflec_Init(&re,CONSTANT,NULL, &(R0));
  }
  if (!radius) radius=1e6;
  // compatibility with older use
  if (length) zdepth =length;
  if (width)  yheight=width;
%}

TRACE
%{
  double l0,l1,dl,alpha,n,nx,nz,s,k,knx,knz;

  /*do we hit the mirror within range?*/
  //PROP_Z0;
  k=sqrt(scalar_prod(kx,0,kz,kx,0,kz));
  knx=kx/k;
  knz=kz/k;
  if (solve_2nd_order(&l0,&l1, knx*knx+knz*knz,2*(x*knx+z*knz-radius*knx),x*x-2*x*radius+z*z))
  {
    if (l0<0 && l1>0){
      dl=l1;
    }else if(l1<0 && l0>0){
      dl=l0;
    }else if( l0>0 && l1>0){
      if (fabs(z+knz*l0) <zdepth/2.0  && fabs(x+knx*l0)<fabs(radius)) {
      /*this means that the first positive match is on the mirror z-wise
        - this should be picked. This would work even if mirror is hit from behind*/
        dl=l0;
      }else{
        dl=l1;
      }
    }else{
        /*particle misses the mirror completely (l0<0 and l1<0)*/
        RESTORE_XRAY(INDEX_CURRENT_COMP, x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p);
    }

    /*correction for only solving in xz-plane*/
    dl*=sqrt(scalar_prod(kx,ky,kz,kx,ky,kz)/scalar_prod(kx,0,kz,kx,0,kz));

    PROP_DL(dl);
    alpha=asin(z/radius);
    if ( (zdepth<radius*alpha) || (fabs(y)>yheight/2.0)) {
      RESTORE_XRAY(INDEX_CURRENT_COMP, x, y, z, kx, ky, kz, phi, t, Ex, Ey, Ez, p);
    }else{
      SCATTER;
      /*reflection*/
      nx=radius-x;
      nz=-z;
      n=sqrt(nx*nx+nz*nz);
      nx/=n;
      nz/=n;
      
      s=scalar_prod(kx,0,kz,nx,0,nz);
      kx=kx-2*s*nx;
      kz=kz-2*s*nz;
      
      double Q;
      /*length of wavevector transfer may be compute from s and n_ above*/
      Q=fabs(2*s*sqrt(nx*nx+nz*nz));
      double complex R=refleccq(re,Q,0,k,fabs(90-acos(s/k)*RAD2DEG));
      p*=sqrt(creal(R*conj(R)));
      phi+=atan2(cimag(R),creal(R));
    }
  }else if(fabs(kx)<DBL_EPSILON && fabs(kz)<DBL_EPSILON && ky!=0){
    /*This to catch the extreme case where k//y.*/
    if (y==0){
      /*We hit the "side" of the mirror.*/
      ABSORB;
    }
  }

%}

MCDISPLAY
%{
  double x0,y0,z0,x1,y1,z1,alpha;
  int N=20;

  y0=yheight/2.0;
  y1=-y0;

  alpha=-(zdepth/2.0)/fabs(radius);
  x0=radius*(1-cos(alpha));
  z0=radius*sin(alpha);
  line(x0,y0,z0,x0,y1,z0);
  while (alpha<(zdepth/2.0/fabs(radius))){
    alpha+=zdepth/N/fabs(radius);
    x1=radius*(1-cos(alpha));
    z1=radius*sin(alpha);
    line(x0,y0,z0,x1,y0,z1);
    line(x0,y1,z0,x1,y1,z1);
    x0=x1;z0=z1;
    line(x0,y0,z0,x0,y1,z0);
  }
%}

END
