/*******************************************************************************
*
* McStas, neutron ray-tracing package
*         Copyright (C) 1997-2011, All rights reserved
*         Risoe National Laboratory, Roskilde, Denmark
*         Institut Laue Langevin, Grenoble, France
*
* Component: curved_mirror
*
* %I
* Written by: Henrik Jacobsen
* Date: April 2012
* Origin: RNBI
*
* Single mirror plate that is curved and fits into an elliptic guide. 
*
* %D
*
*
* %P
* INPUT PARAMETERS:
*
* focus_start_w: [m]           Horizontal position of first focal point of ellipse in ABSOLUTE COORDINATES
* focus_start_h: [m]           Vertical position of first focal point of ellipse in ABSOLUTE COORDINATES
* focus_end_w: [m]             Horizontal position of second focal point of ellipse in ABSOLUTE COORDINATES
* focus_end_h: [m]             VErtical position of second focal point of ellipse in ABSOLUTE COORDINATES
* mirror_start: [m]            start of mirror in ABSOLUTE COORDINATES
* guide_start: [m]             start of guide in ABSOLUTE COORDINATES
* smallaxis_w: [m]             Small-axis dimension of horizontal ellipse
* smallaxis_h: [m]             Small-axis dimension of vertical ellipse
* yheight: [m]                 the height of the mirror when not in the guide
* smallaxis: [m]               the smallaxis of the guide
* length: [m]                  the length of the mirror
* R0=0.99:		[]	low angle reflectivity
* Qc: [AA-1]                   critical scattering vector
* alpha: [AA]                  slope of reflectivity
* m:			[]	m-value of material
* W: [AA-1]                    width of supermirror cutoff
* transmit: [0/1]              0: non reflected neutrons are absorbed. 1: non reflected neutrons pass through
* substrate_thickness: [m]     thickness of substrate (for absorption)
* coating_thickness: [m]       thickness of coating (for absorption)
* theta_1: [deg]               angle of mirror wrt propagation direction at start of mirror
* theta_2: [deg]               angle of mirror wrt propagation direction at center of mirror
* theta_3: [deg]               angle of mirror wrt propagation direction at end of mirror
* reflect: [q(Angs-1) R(0-1)]  (str)  Name of relfectivity file. Format 
*
*
*
* %D
*
* %E
*******************************************************************************/

DEFINE COMPONENT Mirror_Elliptic_Bispectral
DEFINITION PARAMETERS ()
SETTING PARAMETERS (string reflect=0,focus_start_w,focus_end_w, focus_start_h, focus_end_h, mirror_start, m,  smallaxis_w, smallaxis_h, length, transmit=0, substrate_thickness=0.0005, coating_thickness=10e-6)
OUTPUT PARAMETERS ()

SHARE
%{
%include "read_table-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 f; //half of distance between focal points
double asquared;
double a; //half of ellipse length
double b; //half of ellipse width

double xprime; //x in coordinates with center of ellipse at (xprime,zprime)=(0,0)
double ymirror; //height of the mirror


//Defining the mirror
double a1;
double b1;
double c1;

//solving the time the neutron hits the sample
double A, B, C, D, E, P, Q, R, U, V, I, J, K;

//finding rotation of mirror
double alpha1, beta1, gamma1;
double theta_m;
double xhi, zeta;


double b_w;
double f_w;
double asquared_w;
double A_w;
double B_w;
double C_w;
double determinant_w;


double b_h;
double f_h;
double asquared_h;
double xprime_h;


double xprime_w;
double zprime_w;
double asquare_z;
double bsquare_x;


double v_n; //speed of neutron perpendicular to surface

double Ref; //reflectivity

double dt;
double q;
  int intersect;

double discriminant;

double xprime_start_w;
double zprime_start_w;

double z_test;
double x_test;
double z_prime_test;

int hit_back_flag;

int prop_case;


double x_2;
double y_2;
double z_2;
double t_2;
int x_hit;
int x_hit_2;

double xprime_h_2;
double ymirror_2;
int intersect_2;

intersect=0;
x_2=0;
y_2=0;
z_2=0;
t_2=-1;
prop_case=0;
   double old_x = x, old_y = y, old_z = z, old_t=t, old_vx=vx, old_vz=vz, old_vy=vy;

// Check if neutron hits mirror. First find which z,x coordinates it hits.



//define the ellipse
b_w=smallaxis_w/2;
f_w=(focus_end_w-focus_start_w)*0.5;
asquared_w=f_w*f_w+b_w*b_w;

//in coordinate system of mirror: xprime_w(t)=xprime_w+vx*t. z-value is zprime(t)=b*sqrt(1-x'^2/a^2)+old_z+vz*t. This gives equation for t: A_w*t^2+B_w*t+C_w=0;

xprime_start_w=old_x-f_w-focus_start_w+mirror_start;
zprime_start_w=z;

A_w=b_w*b_w*vx*vx+asquared_w*vz*vz;
B_w=2*b_w*b_w*xprime_start_w*vx+2*asquared_w*old_z*vz;
C_w=b_w*b_w*xprime_start_w*xprime_start_w+asquared_w*old_z*old_z-asquared_w*b_w*b_w;

//this equation must now be solved for t;

if (A_w!=0){
determinant_w=B_w*B_w-4.0*A_w*C_w;
if (determinant_w>=0){
I=(-B_w-sqrt(determinant_w))/(2.0*A_w);
J=(-B_w+sqrt(determinant_w))/(2.0*A_w);

if (I<=0 && J<=0){dt = -1.0;} //both times are negative.
if (I<=0 && J>0 ){dt = J;} //set dt to only positive value.
if (I>0  && J<=0){dt = I;} //set dt to only positive value.

if (I>0  && J>0 ){prop_case=1; if (I>J) {dt=J;}else{dt=I;}} //set dt to smallest positive value  


} else {dt=-1.0;} //only complex solutions: set dt negative so no scattering

}else{ //end if (A!=0)  
if (B_w!=0){
dt=-C/B_w;
}else{ //end if (B!)=0
 printf("warning: A_w=B_w=C_w=0. Neutron is ignored\n"); }
} //end if (A!=0){}else{
//now intersection time has been found.

//printf("dt=%f\n",dt);

if (dt>0) { //if time is positive, propagate neutron to where it hits mirror. This is done without gravity.

    x += vx*dt;
    y += vy*dt;
    z += vz*dt;
    t += dt;


if (prop_case>0) //also check if neutron can hit mirror at second solution - it might not be in y-range for first solution
{
    x_2=x+vx*fabs(J-I); 
    y_2=y+vy*fabs(J-I);
    z_2=z+vz*fabs(J-I); 
    t_2=t+fabs(J-I); 

}else{
x_2=x;
y_2=y;
z_2=z;
t_2=t;
}

x_hit=(x>=0 &&x<=length);
x_hit_2=(x_2>=0 &&x_2<=length);

// printf("x=%f,y=%f,z=%f\n",x,y,z);
//if (x >=0 && x<=length){ //check if neutron is within x limits of the mirror. If so, check if it is within y limits.
if (x_hit || x_hit_2){

//define the ellipse
b_h=smallaxis_h/2;

f_h=(focus_end_h-focus_start_h)*0.5;

 asquared_h=f_h*f_h+b_h*b_h;

xprime_h=-f_h-focus_start_h+mirror_start+x; //xprime is the x-coordinate in a coordinate system centered at the center of the ellipse

ymirror=b_h*sqrt(1-xprime_h*xprime_h/asquared_h);


xprime_h_2=-f_h-focus_start_h+mirror_start+x_2; //xprime is the x-coordinate in a coordinate system centered at the center of the ellipse

ymirror_2=b_h*sqrt(1-xprime_h_2*xprime_h_2/asquared_h);


intersect = ( y>=-ymirror && y<=ymirror && x>=0 && x<=length && zprime_start_w+vz*dt>=0);

intersect_2 = ( y_2>=-ymirror_2 && y_2<=ymirror_2 && x_2>=0 && x_2<=length && zprime_start_w+vz*(dt+fabs(J-I))>=0);

if (!intersect && intersect_2){ //if neutron doesn't hit mirror with smallest t, but hits with largest t, propagte to largest t
intersect=intersect_2;
x=x_2;
y=y_2;
z=z_2;
t=t_2;
dt=t_2-old_t;
//printf("x=%f,y=%f,z=%f\n",x,y,z);
}

    if (intersect) { //if neutron is within ylimits of the mirror handle reflection/transmission


//now perform reflection. 

//First find out if neutron hits front or back of mirror: propagate backwards a bit and check if neutron is outside ellipse: if so, it hits back of mirror


b_w=smallaxis_w/2.0;

f_w=(focus_end_w-focus_start_w)*0.5;
 asquared_w=f_w*f_w+b_w*b_w;

z_test=zprime_start_w+vz*(dt-1e-6);
x_test=xprime_start_w+vx*(dt-1e-6);
z_prime_test=b_w*sqrt(1-x_test*x_test/asquared_w);

//find velocity in q direction.

xprime_w=xprime_start_w+vx*dt;
zprime_w=zprime_start_w+vz*dt;
asquare_z=asquared_w*zprime_w;
bsquare_x=b_w*b_w*xprime_w;


zeta=(asquare_z)/(sqrt(asquare_z*asquare_z+bsquare_x*bsquare_x));
xhi=-(bsquare_x)/(sqrt(asquare_z*asquare_z+bsquare_x*bsquare_x));

//printf("z_test=%f, z_prime_test=%f\n",z_test,z_prime_test);

if (z_test>z_prime_test) {
hit_back_flag=1;
}
//printf("vx=%f, vz=%f, vy=%f, xhi=%f, zeta=%f, prop_case=%d\n",vx,vz,vy,xhi,zeta,prop_case);
v_n=-xhi*vx+zeta*vz;

q=fabs(2.0*v_n*V2Q);


 //Reflectivity parameters calculated from SWISS neutronics data.
double R0=0.99;
double Qc=0.0217;
double m_value=m*0.9853+0.1978;
double W=-0.0002*m_value+0.0022;
double alpha=0.1204*m_value+5.0944;
double beta=-7.6251*m_value+68.1137;

if (m_value<=3)
{alpha=m_value;
beta=0;}


      /* Reflectivity (see component Guide). */
      if(m == 0)
        ABSORB;
      if (reflect && strlen(reflect) && strcmp(reflect,"NULL") && strcmp(reflect,"0"))
         Ref=Table_Value(pTable, q, 1);
      else {
          Ref = R0;
          if(q > Qc)
          {
            double arg = (q-m_value*Qc)/W;
            if(arg < 10)
              Ref *= .5*(1-tanh(arg))*(1-alpha*(q-Qc)+beta*(q-Qc)*(q-Qc)); //matches data from Swiss Neutronics
            else  Ref=0;
          }
      }
      if (Ref < 0) Ref=0;
      else if (Ref > 1) Ref=1;


//Now comes actual reflection/transmission
      if (!transmit) { //all neutrons are reflected
//printf("v_n=%f,q=%f, Ref=%f, lambda=%f, theta=%f, 1p_before=%f",v_n,q, Ref, (2*PI/V2K)/sqrt(vx*vx + vy*vy + vz*vz),asin((2*PI/V2K)/sqrt(vx*vx + vy*vy + vz*vz)*q/(4*PI))*RAD2DEG,p);
        if (!Ref) ABSORB;
        p *= Ref;
//printf("p_after=%f\n",p);
//handle reflection: change v_n -->-v_n

vx=old_vx*(zeta*zeta-xhi*xhi)+old_vz*(2*zeta*xhi);
vz=+old_vx*(2*zeta*xhi)+old_vz*(xhi*xhi-zeta*zeta);


        SCATTER; //after transmission or reflection

      } else { //if neutrons can be transmitted



//calculate absorption.
// substrate
double lambda=(2*PI/V2K)/sqrt(vx*vx + vy*vy + vz*vz);
double sin_theta=lambda*q/(4*PI);
double substrate_path_length=substrate_thickness/sin_theta;
double mu_substrate=0.0318/lambda+0.0055*lambda-0.0050; //unit: cm^-1
mu_substrate=mu_substrate*100; //unit: m^-1;
               
//For nickel and titanium coating, the following formular is used:
// mu = rho/m(atom)*sigma_a,thermal*lambda/lambda_thermal

// lambda_thermal=1.798 Å

// rho_nickel=8.908g/cm^3
// m(atom)_nickel=58.6934*1.661*10^-27 kg
// sigma_a,thermal_nickel=4.49*10^-28 m^2

// rho_titanium=4.506g/cm^3
// m(atom)_titanium=47.867*1.661*10^-27 kg
// sigma_a,thermal_titanium=6.09*10^-28 m^2

double coating_path_length=coating_thickness/sin_theta;
double Ni_coefficient=22.8180; 
double Ti_coefficient=19.1961;

double mu_coating=(0.5*Ni_coefficient+0.5*Ti_coefficient)*lambda; //it is roughly 50% nickel and 50% titanium



        // transmit when rand > R
        if (Ref == 0 || rand01() >= Ref) { //transmit
if (substrate_thickness>0){ p=p*exp(-mu_substrate*substrate_path_length-mu_coating*coating_path_length);} //reduce weight of neutrons due to attenuation in the mirror

} else {//neutron is reflected
		if (hit_back_flag==1 && substrate_thickness>0) { //if neutron comes from behind the mirror
			p=p*exp(-2*mu_substrate*substrate_path_length-2*mu_coating*coating_path_length);} //reduce weight of neutrons due to attenuation in the mirror
//handle reflection: change v_n -->-v_n

vx=old_vx*(zeta*zeta-xhi*xhi)-old_vz*(2*zeta*xhi);
vz=-old_vx*(2*zeta*xhi)+old_vz*(xhi*xhi-zeta*zeta);
}

//printf("p_before=%f, q=%f",p,q);
        SCATTER; //after transmission or reflection
//printf("p_after=%f\n",p);
      } //end } else { after if (!transmit) {
    } 


 


} // end if (x >=-length/2 && x<=length/2)


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

      z = old_z;
      t = old_t;


    }
  

} //end if (dt>0)


%}

MCDISPLAY
%{




double xstart;
double xend;
double xprime_start;
double ystart;

double xprime_end;
double yend;

double focus_2_h;
double focus_1_h;
double b_h;
double f_h;
double asquared_h;

double focus_2_w;
double focus_1_w;
double b_w;
double f_w;
double asquared_w;


int n_lines;
int j=0;
double xprimepos[51];
double ypos[51];
double x_plot[51];
double zpos[51];
double xstep;
double xprime_w[51];



focus_2_h=focus_end_h; //focus in local coordinates
focus_1_h=focus_start_h;

b_h=smallaxis_h/2.0;

f_h=(focus_2_h-focus_1_h)*0.5;
 asquared_h=f_h*f_h+b_h*b_h;



focus_2_w=focus_end_w; //focus in local coordinates
focus_1_w=focus_start_w;

b_w=smallaxis_w/2.0;

f_w=(focus_2_w-focus_1_w)*0.5;
 asquared_w=f_w*f_w+b_w*b_w;



xstart=0;
xend=length;

n_lines=50;

xstep=length/n_lines;













for (j=0; j<n_lines+1; j++)
{
xprimepos[j]=-f_h-focus_start_h+mirror_start+xstart+xstep*j;

ypos[j]=b_h*sqrt(1-xprimepos[j]*xprimepos[j]/asquared_h); //correct


x_plot[j]=xstart+xstep*j;



xprime_w[j]=-f_w-focus_start_w+mirror_start+xstart+xstep*j; //xprime is the x-coordinate in a coordinate system centered at the center of the ellipse

zpos[j]=b_w*sqrt(1-xprime_w[j]*xprime_w[j]/asquared_w);
//printf("xprime=%f, zpos=%f\n",xprime_w[j], zpos[j]);
}

for (j=0; j<n_lines; j++)
{
line(x_plot[j], -ypos[j], zpos[j], x_plot[j+1], -ypos[j+1],zpos[j+1]);
line(x_plot[j], ypos[j], zpos[j], x_plot[j+1], ypos[j+1],zpos[j+1]);
}


line(x_plot[0],-ypos[0],zpos[0],x_plot[0],ypos[0],zpos[0]);
line(x_plot[50],-ypos[50],zpos[50],x_plot[50],ypos[50],zpos[50]);




//printf("ypos0=%f xpos0=%f ypos50=%f xpos50=%f",ypos[0], x_plot[0], ypos[50], x_plot[50]);

/*  double xmax, xmin, ymax, ymin;
  

  if (center == 0) {
    xmax= x1; xmin=0;
    ymax= yheight; ymin=0;
  } else {
    xmax= x1/2; xmin=-xmax;
    ymax= yheight/2; ymin=-ymax;
  }
  multiline(5, (double)xmin, (double)ymin, 0.0,
               (double)xmax, (double)ymin, 0.0,
               (double)xmax, (double)ymax, 0.0,
               (double)xmin, (double)ymax, 0.0,
               (double)xmin, (double)ymin, 0.0);
*/
%}
END
