/*******************************************************************************
*
* McXtrace, X-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: Source_lab
*
* %Identification
* Written by: Erik Bergbaeck Knudsen 
* Date: May 2012
* Version: 1.0
* Origin: Kgs. Lyngby
*
* Laboratory x-ray source.
*
* %Description
* Model of a laboratory x-ray tube, generating x-rays by bombarding a target by electrons.
* Given a input energy E0 of the electron beam, x-rays are emitted from the accessible emission lines
* The geometry of the tube is assumed to be:
* # The electron beam hits a slab of surface material surface at a right angle illuminating an area of width by height,
* # where width is measured along the component X-axis.
* # The centre of the electron beam at the anode surface is the origin of the component.
* # The Z-axis of the component points at the centre of the exit window (focus_xw by focus yh) 
* placed at a distance dist from the origin.
* # The angle between the Z-axis and the anode surface is the take_off angle.
* For a detailed sketch of the geometry see the componnent manual.
* 
* The Bremsstrahlung emitted is modelled using the model of Kramer (1923) as restated in International
* Tables of Crystallography C 4.1
* Characteristic radiation is modelled by Lorentzian (default) or Gaussian energy profiles with
* line-energies from Bearden (1967), widths from Krause (1979) and intensity from Honkimäki (1990) and x-ray data booklet.
* Absoprtion of emitted x-rays while travelling through the target anode is included. 
* 
* Example: Source_lab(material_datafile="Cu.txt",Emin=1, E0=80)
*
* %Parameters
* width:      [m]    Width of electron beam impinging on the anode.
* height:     [m]    Height of electron beam impinging on the anode.
* xwidth:     [m]    Width of the anode material slab.
* yheight:    [m]    Height of the anode material slab.
* thickness:  [m]    Thickness of the anode material slab.
* take_off:   [deg]  Take off angle of beam centre.
* dist:       [m]    Distance between centre of illuminated target and exit window.
* E0:         [kV]   Acceleration voltage of xray tube.
* tube_current: [A]  Electron beam current.
* Emax:       [keV]  Maximum energy to sample. Default (Emax=0) is to set it to E0.
* Emin:       [keV]  Minimum energy to sample.
* focus_xw:   [m]    Width of exit window.
* focus_yh:   [m]    Height of exit window.
* frac:       [0-1]  Fraction of statistic to use for Bremsstrahlung.
* material_datafile: [string] Name of datafile which describes the target material.
* lorentzian: [0/1]  If nonzero Lorentzian (more correct) line profiles are used.
* exit_window_refpt: [m] If set, the AT position and exit window will coincide (legacy behaviour).
*
* %End
*************************************************************************/

DEFINE COMPONENT Source_lab

SETTING PARAMETERS (string material_datafile="Cu.txt", width=1e-3, height=1e-3, thickness=100e-6, E0=20, Emax=0, Emin=1, focus_xw=5e-3, focus_yh=5e-3,
    take_off=6, dist=1, tube_current=1e-3, frac=0.1, lorentzian=1, xwidth=0, yheight=0, exit_window_refpt=0 )

/* X-ray parameters: (x,y,z,kx,ky,kz,phi,t,Ex,Ey,Ez,p) */ 

SHARE
%{
  %include "read_table-lib"
#ifndef MX_SOURCE_LAB
#define MX_SOURCE_LAB
  /*here are some material data- currently only for Cu, Mo, W, and Ag*/
  struct xray_em_data{
    int _Z;/*atom number*/
    double Ek;/*ionazation energy*/
    double w_k;/*flourescence yield*/
    int linec;
    double e[6];/*line energy*/
    double w[6];/*natural width of line FWHM*/
    double i[6];/*relative intensity*/
  };
  struct xray_em_data xray_mat_data[8]={
    {24, 5.989 ,0.265, 3, {5.41472,5.40551,5.94671,0,0,0}, {1.97e-3,2.39e-3,3.05e-3,0,0,0}, {100,50,15,0,0,0}},
    {27, 7.709 ,0.391, 3, {6.93032,6.9153,7.6494,0,0,0}, {2.26e-3,3.08e-3,4.36e-3,0,0,0}, {100,51,17,0,0,0}},
    {29, 8.979 ,0.407,2,{8.02783,8.04778,0,0,0,0},{2.11e-3,2.17e-3,0,0,0,0},{0.51,1.0,0,0,0,0}},
    {31, 10.367,0.0  ,2,{9.22482,9.25174,0,0,0,0},{2.59e-3,2.66e-3,0,0,0,0},{0.51,1.0,0,0,0,0}},
    {42, 20.00 ,0.770,5,{17.3743,17.47934,19.5903, 19.6083, 19.965,0},{6.31e-3,6.49e-3,12e-3, 12e-3, 12e-3,0},{0.52,1.0,0.08,0.15,0.03,0}},
    {47, 25.52, 0.8,2,{21.99030,22.162917, 0,0,0,0},{9.32e-3,9.16e-3,0,0,0,0}, {0.53, 1, 0,0,0,0}}, /* Ag fluorscence yield just guessed */
    {74, 69.525,0.945,5,{57.9817,59.31824,66.9514,67.2443,69.067,0},{44.9e-3,45.2e-3, 51.1e-3, 50.8e-3 , 50.2,0},{0.58,1.0,0.11,0.22,0.08,0}},
    {0,0.0,0.0,0,{0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0}}

  };
#pragma acc declare create(xray_mat_data)
#endif

%}

DECLARE
%{
  Rotation R_xray_gen;
  Rotation R_xray_geni;
  Coords O_xray_gen;
  int Z;
  double At;
  double rho;
  t_Table T;
  int em_idx;
  double Icont;
  double Ichar;
  int linemin;
  int linemax;
  double p_continous;
  double pmul_c;
  double mu_electron;

  double BKRAMER;
%}

INITIALIZE
%{
  BKRAMER=2e-6; /*photons /keV /electron*/
#pragma acc update device(xray_mat_data[0:6])

  int status,ii;
  if (E0<=0){
    fprintf(stderr,"Error %s: Impinging electron energy (E0) must be >0, was %g\n",NAME_CURRENT_COMP, E0);
    exit(-1);
  }

  if (!Emax){/*if Emax is not set use the impinging electron energy*/
    Emax=E0;
  }
  if(Emin<=0){
    fprintf(stderr,"Error (%s): Emin must be > 0 (%g)\n",NAME_CURRENT_COMP,Emin);exit(-1);
  }
  if(Emax<Emin){
    fprintf(stderr,"Error (%s): Nonsensical emission energy interval [Emin,Emax]=[%g %g] at E0=%g\n",NAME_CURRENT_COMP,Emin,Emax,E0);
    exit(-1);
  }
 
  if ( (status=Table_Read(&(T),material_datafile,0))==-1){
    fprintf(stderr,"Error %s: Could not parse file \"%s\"\n",NAME_CURRENT_COMP,material_datafile?material_datafile:"");
    exit(-1);
  }
  char **header_parsed;
  header_parsed=Table_ParseHeader(T.header,"Z","A[r]","rho","Z/A","sigma[a]",NULL);
  if(header_parsed[2]){rho=strtod(header_parsed[2],NULL);}
  if(header_parsed[0]){Z=strtod(header_parsed[0],NULL);}
  if(header_parsed[1]){At=strtod(header_parsed[1],NULL);}

  /*use the atom number to get at the right data structure*/  
  int idx=0;
  while (Z!=xray_mat_data[idx]._Z){
    idx++;
    if ((xray_mat_data[idx]._Z)==0){
      fprintf(stderr,"Error: %s (Z=%d) anode not implemented yet. Please contact the McXtrace team to fix this. Aborting.\n",material_datafile,Z);
      exit(-1);
    }
  }
  em_idx=idx;
  struct xray_em_data *em_p = &(xray_mat_data[em_idx]);
  
  /*Integrate the continuous spectrum and the characteristic so as to get the relative intenisities right*/
  Icont=tube_current/CELE*BKRAMER*Z*(E0*log(Emax)-E0*log(Emin) - Emax + Emin);
  /*check if E0 >Ek. If not, no characteristic emission can take place*/
  if (E0>em_p->Ek){
    double Bk=1.2e-5*pow(em_p->Ek,1.67)*exp(-0.077*Z);
    Ichar=tube_current/CELE*4*M_PI*(E0/em_p->Ek-1)*Bk;
    double Ichar_tot=0;
    int linec=0;
    linemin=0;
    linemax=em_p->linec;
    for (ii=0;ii<em_p->linec;ii++){
      /*if the interval [Emin,Emax] contains 5 sigma of the characteristic peak - use full peak.*/
      if (Emin>em_p->e[ii]+5*em_p->w[ii] ){
        /*way below of energy limit - do not use.*/
        linemin=ii;
      }else if ( Emax<em_p->e[ii]-5*em_p->w[ii]){
        /*way above of energy limit - do not use.*/
        linemax= linemax<ii?linemax:ii;
      }else{
        linec++;
      }
      if(Emax>em_p->e[ii]+5*em_p->w[ii] && Emin<em_p->e[ii]-5*em_p->w[ii]){
        Ichar_tot+=em_p->i[ii];
      }else{
        if(!lorentzian){
	  /*We only partially use the peak - so update the relative intensity to reflect that*/
          Ichar_tot+=em_p->i[ii]*0.5*( erf(Emax-em_p->e[ii]/em_p->w[ii]/M_SQRT2) - erf( Emin-em_p->e[ii]/em_p->w[ii]/M_SQRT2) );
          em_p->i[ii]= em_p->i[ii]*0.5*( erf((Emax-em_p->e[ii]/M_SQRT2)/em_p->w[ii]/M_SQRT2) - erf((Emin-em_p->e[ii])/em_p->w[ii]/M_SQRT2) );
        }else{
	  /* 1/pi atan(2x/w)) is integrated lorentzian of fwhm w, MHM, April 2015 */
          Ichar_tot+=em_p->i[ii]*(1.0/M_PI)*( atan(2*(Emax-em_p->e[ii])/em_p->w[ii]) - atan(2*(Emin-em_p->e[ii])/em_p->w[ii]) );
        }
      }
    }

    p_continous=Icont/(Ichar*Ichar_tot+Icont);
  }else{
    /*characteristic K-emission is not possible*/
    p_continous=1;
    frac=1;
  }
  O_xray_gen=coords_set(0,0,0);
  rot_set_rotation(R_xray_gen,-take_off*DEG2RAD,0,0);
  rot_set_rotation(R_xray_geni,take_off*DEG2RAD,0,0);

  pmul_c=1.0/(mcget_ncount());

  mu_electron=0;

%}

TRACE
%{
  double x1,y1,z1,x2,y2,z2,r,e,k,pdir,pmul;
  /* pick a point in the generating volume*/
  x1=rand01()*width-width/2.0;
  z1=rand01()*height-height/2.0;
  /* y is the absorption depth of the electron getting converted to an xray*/
  y1=log(rand01())*mu_electron;

  double px,py,pz; 
  Coords P;

  /* transform initial coords to ones in a frame with origin at the center of e-beam with optical axis pointing towards exit window*/
  P=coords_set(x1,y1,z1);
  P=coords_add(rot_apply(R_xray_gen,P),O_xray_gen);
  coords_get(P,&x,&y,&z);

  /*randvec_target_rect_real computes a target point and a solid angle correction factor, hence the k-vector has to be computed from
    generation point and target point. The (0,0,1) location of the target is due to a silent assumption in randvec() that
    the target cannot be situated in the origin.*/
  randvec_target_rect_real(&px,&py,&pz,&pdir,0,0,dist,focus_xw,focus_yh, R_xray_gen,x1,y1,z1,2);
  /*k is parallell to the line between generation and target points*/
  kx=px-x1;
  ky=py-y1;
  kz=pz-z1;

  /*Now for wavelength selection*/
  r=rand01();
  if(r<frac){
    /*bremsstrahlung*/
    e=rand01()*(Emax-Emin)+Emin;
    k=e*E2K;
    pmul=tube_current/CELE*BKRAMER*Z*(E0/e-1);
    /*correct for not having the full E-window*/
    pmul*=(Emax-Emin)/E0;
    /*correct for monte-carlo statistics*/
    pmul*=p_continous/frac;
  }else{
    struct xray_em_data *pt=&(xray_mat_data[em_idx]);
    /*characteristic radiation*/
    /*first pick a possible line*/
    r=rand01()*(linemax-linemin) + linemin;
    int lineno=(int)floor(r);
    if (lineno==pt->linec) {
      lineno--;/*we might get overflow*/
    }

    if(!lorentzian){
      pmul=pt->i[lineno]*Ichar;
      e=(randnorm()*pt->w[lineno]+pt->e[lineno]);
      /*this can be very inefficient*/
      while (e<Emin || e>Emax){
        e=(randnorm()*pt->w[lineno]+pt->e[lineno]);
      }
    }else{/* tan((rand-0.5)/pi) is Lorentzian with FWHM of 2, MHM April 2015 */
      /* compute upper and lower random range to map onto energy bounds such that a*tan(u)+b = energy. Note -0.5<u<0.5 */
      double umin=atan(2*(Emin-pt->e[lineno])/pt->w[lineno])/M_PI;
      double umax=atan(2*(Emax-pt->e[lineno])/pt->w[lineno])/M_PI;
      pmul=pt->i[lineno]*Ichar*(umax-umin); /* weight intensity for partial line strength */
      e=tan(((umax-umin)*rand01()+umin)*M_PI)*pt->w[lineno]/2+pt->e[lineno];
    }
    k=E2K*e;
    pmul*=(1-p_continous)/frac;
  }

  /*scale k accordingly*/
  NORM(kx,ky,kz);
  kx*=k;ky*=k;kz*=k;
  
  /*set the x-ray weight to whatever we computed just before and correct for only sampling the exit window, and correct for number of issued photons*/
  p=pmul*pmul_c;
    

  int ie;
  /*Correct for absorption*/
  double mu_abs,l0,l1,lx,ly,lz,klx,kly,klz,xw,yh;
  l0=0;l1=0;
  /*if dimensions are set the anode has a limited size - otherwise use a
    practically infinite slab*/
  if(!xwidth) xw=FLT_MAX;
  if(!yheight) yh=FLT_MAX;
  coords_get(rot_apply(R_xray_geni,coords_set(x,y,z)),&lx,&ly,&lz);
  coords_get(rot_apply(R_xray_geni,coords_set(kx,ky,kz)),&klx,&kly,&klz);
  /*find path length inside anode material*/
  ie=box_intersect(&l0,&l1,lx,ly+thickness/2.0,lz,klz,kly,klz,xw,thickness,yh);
  if(!ie || l0>0){
    /*photon is somehow outside the anode - this should not happen*/
    ABSORB;
  }

  mu_abs=Table_Value(T, k*K2E, 5)*rho*1e2; /*mu_abs in m^-1*/
  p*=exp(-l1*mu_abs);
  /*set a random phase*/
  phi=rand01()*2*M_PI;

  /*Finally, if exit_window_refpt is set revert to legacy behaviour where the centre of the exit window is the
    reference point of the component*/
  if(exit_window_refpt){
    z=z-dist;
  }
  /*set a scatter pt at the generation pt*/
  SCATTER;
%}

MCDISPLAY
%{
  _class_particle p1,p2;
  
  double x1,y1,z1,x2,y2,z2,width_2,height_2;
  double dx,dy,dz;
  /*these are just dummies*/
  double d1,d2,d3,d4,d5,d6;  

  width_2=width/2.0;
  height_2=height/2.0;
  p1.x=-width_2;p1.y=0;p1.z=-height_2;
  p2.x=-width_2;p2.y=0;p2.z= height_2;

  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  line(p1.x,p1.y,p1.z,p2.x,p2.y,p2.z);

  p1.x=width_2;p1.y=0;p1.z=height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);
  
  p2.x=width_2;p2.y=0;p2.z=-height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  line(p1.x,p1.y,p1.z,p2.x,p2.y,p2.z);

  p1.x=-width_2;p1.y=0;p1.z=-height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);

  /*this is the mean penetration depth of electron that get converted to x-rays*/  
  p1.x=-width_2;p1.y=-mu_electron;p1.z=-height_2;
  p2.x=-width_2;p2.y=-mu_electron;p2.z= height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  dashed_line(p1.x,p1.y,p1.z,p2.x,p2.y,p2.z,5);
  p1.x=width_2;p1.y=-mu_electron;p1.z=height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  dashed_line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z,5);
  p2.x= width_2;p2.y=-mu_electron;p2.z=-height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  dashed_line(p1.x,p1.y,p1.z,p2.x,p2.y,p2.z,5);
  p1.x=-width_2;p1.y=-mu_electron;p1.z=-height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  dashed_line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z,5);
  
  p1.x=-width_2;p1.y=-mu_electron;p1.z=-height_2;
  p2.x=-width_2;p2.y=0;p2.z=-height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);
  p1.x=width_2;p1.y=-mu_electron;p1.z=-height_2;
  p2.x=width_2;p2.y=0;p2.z=-height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);
  p1.x=-width_2;p1.y=-mu_electron;p1.z=height_2;
  p2.x=-width_2;p2.y=0;p2.z=height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);
  p1.x=width_2;p1.y=-mu_electron;p1.z=height_2;
  p2.x=width_2;p2.y=0;p2.z=height_2;
  mccoordschange(O_xray_gen,R_xray_gen,&p1);
  mccoordschange(O_xray_gen,R_xray_gen,&p2);
  line(p2.x,p2.y,p2.z,p1.x,p1.y,p1.z);


  /*now draw "exit" window*/
  rectangle("xy",0,0,0,focus_xw,focus_yh);
%}

END
