/**************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright 1997-2006, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: Pol_triafield
* 
* %I
* Written by: Morten Sales, based on Pol_constBfield by Peter Christiansen
* Date: 2013
* Origin: Helmholtz-Zentrum Berlin
*
* Constant magnetic field in a isosceles triangular coil
*
* %D
*
* Rectangular box with constant B field along y-axis (up) in a isosceles triangle. 
* There is a guide (or precession) field as well. It is along y in the entire rectangular box.
* A neutron hitting outside the box opening or the box sides is absorbed.
*
*
*     __________________
*    |        /\        |
*    | Bguide/  \Bguide |      x
*    |      /    \      |      ^
*    |     /      \     |      |
*    |    /   B    \    |      |-----> z
*    |   /   and    \   |
*    |  /   Bguide   \  |
*    | /              \ |
*    |/________________\|
*
* The angle of the inclination of the triangular field boundary is given by the arctangent to xwidth/(0.5*zdepth)
*
* This component does NOT take gravity into account.
*
* Example: Pol_triafield(xwidth=0.1, yheight=0.1, zdepth=0.2, B=1e-3, Bguide=0.0)
*
* %P
* INPUT PARAMETERS:
*
* xwidth: [m]   Width of opening 
* yheight: [m]  Height of opening 
* zdepth: [m]   zdepth of field 
* B: [T]        Magnetic field along y-direction inside triangle 
* Bguide: [T]   Magnetic field along y-direction inside entire box 
*
* CALCULATED PARAMETERS:
*
* %E
*******************************************************************************/

DEFINE COMPONENT Pol_triafield
SETTING PARAMETERS (xwidth, yheight, zdepth, B=0, Bguide=0)

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

SHARE
%{
double IntersectWall(double pos, double vel, double wallpos) {
    /* Function to calculate where the neutron hit the wall */

    if(vel==0)
      return -1;
    
    if(vel>0)
      return (wallpos-pos)/vel;
    else 
      return (-wallpos-pos)/vel;
  }
%}

DECLARE
%{
  /* Larmor frequency */
  double omegaL;
  double omegaLguide;
%}

INITIALIZE
%{
  omegaL = 0;  
  omegaLguide = 0;  


  double velocity = 0, time = 0;
  
  if ((xwidth<=0) || (yheight<=0) || (zdepth<=0)) {
    fprintf(stderr, "Pol_filter: %s: Null or negative volume!\n"
	    "ERROR      (xwidth, yheight, zdepth). Exiting\n",
	    NAME_CURRENT_COMP);
    exit(1);
  }
  
  omegaL	  = -1.832472e8 * (B - Bguide); // B and Bguide is in Tesla
  omegaLguide = -1.832472e8 * Bguide;       // Bguide is in Tesla
  %}

TRACE
%{
  double deltaT, deltaTx, deltaTy, sx_in1, sz_in1, sx_in2, sz_in2, iz1, iz2, denom1, denom2, deltaTtria;
  
  PROP_Z0;
  if (!inside_rectangle(x, y, xwidth, yheight))
    ABSORB;
  
  // Time spent in Bguide-field
  deltaT = zdepth/vz;
    
  // This calculates the intersections on the xz-plane between the neutron trajectory and the triangular field boundaries
  // The neutron trajectory is given by the points    (        x, 0,       0) and (     x+vx, 0,       vz)
  // The first field boundary is given by the points  (-xwidth/2, 0,       0) and ( xwidth/2, 0, zdepth/2)
  // The second field boundary is given by the points ( xwidth/2, 0,zdepth/2) and (-xwidth/2, 0,   zdepth)
  // iz1 and iz2 are the z-values for the intersection
    denom1 = (-vz)*((-xwidth/2)-xwidth/2)-(x-(x+vx))*(-zdepth/2);
    iz1    = ((-x*vz)*(-zdepth/2)-(-vz)*(-(-xwidth/2)*zdepth/2))/denom1;
    
    denom2 = (-vz)*(xwidth/2-(-xwidth/2))-(x-(x+vx))*(zdepth/2-zdepth);
    iz2    = ((-x*vz)*(zdepth/2-zdepth)-(-vz)*(zdepth/2*(-xwidth/2)-xwidth/2*zdepth))/denom2;
  // Time spent in triangular B-field
    deltaTtria	= (iz2-iz1)/vz;

  // check that track goes throgh without hitting the walls
  if (!inside_rectangle(x+vx*deltaT, y+vy*deltaT, xwidth, yheight)) {
    
    // Propagate to the wall and absorb
    deltaTx = IntersectWall(x, vx, xwidth/2);
    deltaTy = IntersectWall(y, vy, yheight/2);

    if (deltaTx>=0 && deltaTx<deltaTy)
      deltaT = deltaTx;
    else
      deltaT = deltaTy;
    
    PROP_DT(deltaT);  
    
    ABSORB;
  }  
  
  PROP_DT(deltaT);  
  
  // These are the incoming spin directions 
  sx_in1 = sx;
  sz_in1 = sz;
  
  // This calculates the spin rotation caused by the guide/precession field
  sz_in2 = cos(omegaLguide*deltaT)*sz_in1 - sin(omegaLguide*deltaT)*sx_in1;
  sx_in2 = sin(omegaLguide*deltaT)*sz_in1 + cos(omegaLguide*deltaT)*sx_in1;

  // This calculated the spin rotation caused by the triangular field
  sz = cos(omegaL*deltaTtria)*sz_in2 - sin(omegaL*deltaTtria)*sx_in2;
  sx = sin(omegaL*deltaTtria)*sz_in2 + cos(omegaL*deltaTtria)*sx_in2;
  %}

MCDISPLAY
%{
  
  
  box(0, 0, 0, xwidth, yheight, zdepth,0, 0, 1, 0);
%}

END
