/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright (C) 1997-2006, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Guide_curved
*
* %I
* Written by: Ross Stewart
* Date: November 18 2003
*
* Non-focusing curved neutron guide.
*
* %D
* Models a rectangular curved guide tube with entrance centered on the Z axis.
* The entrance lies in the X-Y plane.  Unlike Bender.comp, draws a true depiction
* of the guide, and trajectories.  Guide is not focusing
*
* Example: Guide(w1=0.1, h1=0.1, l=2.0, R0=0.99, Qc=0.021,
*                alpha=6.07, m=2, W=0.003, r=2700)
*
* %BUGS
* This component does not work with gravitation on. Use component Guide_gravity then.
*
* %P
* INPUT PARAMETERS:
*
* w:       [m]    Width at the guide entry
* h:       [m]    Height at the guide entry
* l:       [m]    length of guide
* 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
* r:       [m]    Radius of curvature of the guide
*
* %L
* <a href="../optics/Bender.comp.html">Bender</a>
*
* %E
*******************************************************************************/

DEFINE COMPONENT Guide_curved
DEFINITION PARAMETERS ()
SETTING PARAMETERS (w, h, l, R0=0.99, Qc=0.0219, alpha=6.07, m=2, W=0.003, r=2700)
STATE PARAMETERS (x,y,z,vx,vy,vz,t,s1,s2,p)

INITIALIZE
%{
  if (mcgravitation) fprintf(stderr,"WARNING: Guide_curved: %s: "
    "This component produces wrong results with gravitation !\n"
    "Use Guide_gravity.\n",
    NAME_CURRENT_COMP);
%}

TRACE
%{
  double t11, t12, t21, t22, theta, alpha, endtime, phi;
  double time, time1, time2, q, R;
  int ii, i_bounce;

  double whalf  = 0.5*w, hhalf = 0.5*h;   /* half width and height of guide */
  double z_off  = r*sin(l/r);       /* z-component of total guide length */
  double R1     = r - whalf;        /* radius of curvature of inside mirror */
  double R2     = r + whalf;        /* radius of curvature of outside mirror */
  double vel    = sqrt(vx*vx + vy*vy + vz*vz);  /* neutron velocity */
  double vel_xz = sqrt(vx*vx + vz*vz);      /* in plane velocity */
  double K      = V2K*vel;        /* neutron wavevector */
  double lambda = 2.0*PI/K;       /* neutron wavelength */

/* Propagate neutron to guide entrance. */

  PROP_Z0;
  if(x <= -whalf || x >= whalf || y <= -hhalf || y >= hhalf)
    ABSORB;

  for(;;)
  {
    /* Find itersection points of neutron with inside and outside guide walls */
    ii = cylinder_intersect(&t11, &t12 ,x - r, y, z, vx, vy, vz, R1, h);
    ii = cylinder_intersect(&t21, &t22 ,x - r, y, z, vx, vy, vz, R2, h);

    /* Choose appropriate reflection time */
    time1 = (t11 < 1e-7) ? t12 : t11;
    time2 = (t21 < 1e-7) ? t22 : t21;
    time  = (time1 < 1e-7 || time2 < time1) ? time2 : time1;

    /* Has neutron left the guide? */
    endtime = (z_off - z)/vz;
    if (time > endtime || time <= 1e-7) break;

    PROP_DT(time);

    /* Find reflection surface */
    R = (time == time1) ? R1 : R2;
    i_bounce = (fabs(y - hhalf) < 1e-7 || fabs(y + hhalf) < 1e-7) ? 2 : 1;
    switch(i_bounce) {
  case 1:           /* Inside or Outside wall */
            phi   = atan(vx/vz);        /* angle of neutron trajectory */
    alpha = asin(z/R);      /* angle of guide wall */
    theta = fabs(phi - alpha);    /* angle of reflection */
            vz    = vel_xz*cos(2.0*alpha - phi);
    vx    = vel_xz*sin(2.0*alpha - phi);
    break;
  case 2:       /* Top or Bottom wall */
    theta = fabs(atan(vy/vz));
    vy    = -vy;
    break;
    }
    /* Now compute reflectivity. */
    if (m == 0) ABSORB;

    q = 4.0*PI*sin(theta)/lambda;
    if(q > Qc)
    {
      double arg = (q - m*Qc)/W;
      if (arg < 10)
        p *= .5*(1 - tanh(arg))*(1 - alpha*(q - Qc));
      else
        ABSORB;                               /* Cutoff ~ 1E-10 */
    }
    p *= R0;
    SCATTER;
  }
%}

MCDISPLAY
%{
  double x1, x2, z1, z2;
  double xplot1[100], xplot2[100], zplot1[100], zplot2[100];
  int n = 100;
  int j = 1;
  double R1 = (r - 0.5*w);    /* radius of inside arc */
  double R2 = (r + 0.5*w);    /* radius of outside arc */

  magnify("xy");

  for(;;) {
    if(j == n + 1) break;
      z1 = ((double)j - 1.0)*(R1*l/r)/(double)(n - 1);
      z2 = ((double)j - 1.0)*(R2*l/r)/(double)(n - 1);
    x1 = r - sqrt(R1*R1 - z1*z1);
    x2 = r - sqrt(R2*R2 - z2*z2);
            xplot1[j] = x1;
    xplot2[j] = x2;
    zplot1[j] = z1;
    zplot2[j] = z2;
    j++;
  }
  j = 1;
  line(xplot1[j], 0.5*h,zplot1[j],xplot2[j], 0.5*h,zplot2[j]);
      line(xplot1[j], 0.5*h,zplot1[j],xplot1[j],-0.5*h,zplot1[j]);
      line(xplot2[j],-0.5*h,zplot2[j],xplot2[j], 0.5*h,zplot2[j]);
      line(xplot1[j],-0.5*h,zplot1[j],xplot2[j],-0.5*h,zplot2[j]);
  for(;;) {
    if(j == n) break;
    line(xplot1[j],  0.5*h, zplot1[j], xplot1[j+1],  0.5*h, zplot1[j+1]);
    line(xplot2[j],  0.5*h, zplot2[j], xplot2[j+1],  0.5*h, zplot2[j+1]);
    line(xplot1[j], -0.5*h, zplot1[j], xplot1[j+1], -0.5*h, zplot1[j+1]);
    line(xplot2[j], -0.5*h, zplot2[j], xplot2[j+1], -0.5*h, zplot2[j+1]);
    j++;
  }
      line(xplot1[j], 0.5*h,zplot1[j],xplot2[j], 0.5*h,zplot2[j]);
      line(xplot1[j], 0.5*h,zplot1[j],xplot1[j],-0.5*h,zplot1[j]);
      line(xplot2[j],-0.5*h,zplot2[j],xplot2[j], 0.5*h,zplot2[j]);
      line(xplot1[j],-0.5*h,zplot1[j],xplot2[j],-0.5*h,zplot2[j]);
%}

END
