/*******************************************************************************
*
* McXtrace, X-ray tracing package
*         Copyright, All rights reserved
*         DTU Physics, Kgs. Lyngby, Denmark
*         Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: Source_flat
*
* %Identification
* Written by:Erik Knudsen
* Date: September 25, 2009
* Origin: Risoe
* Release: McXtrace 0.1_alpha
*
* A flat rectangular or circular surface emitting x-rays
*
* %Description
* A circular or rectangular xray source. Spectrum may be either gaussian or uniform around a central wavelength/energy
* or read from a datafile. Xrays are considered emitted uniformly into 4pi, but a square target retricts the beam to 
* that window and scales the beam intensity accordingly.
* If an input spectrum datafile (spectrum_file) is not specified, the beam is restricted to emit photons between E0+-dE keV, or lambda0+-dlambda AA, whichever is given.
* The input spectrum file should be formatted such that x-ray energy/wavelength is in the first column and the intensity in the second. Any preceding
* lines starting with # are considered part of the file header. If a datafile is given, a nonzero E0 value indicates that is is parametrized by energy (in keV)
* as opposed to wavelength (in AA). Wavelength is the default.
* Flux is set in the unit photons/s
*
* Example: Source_flat(xwidth=1e-3,yheight=1e-3, focus_xw=0.5e-2, focus_yh=0.45e-2,dist=1, E0=E0, dE=DE)
*
* %Parameters
* radius:   [m]   Radius of circle in (x,y,0) plane where x-rays are generated.
* yheight:  [m]   Height of rectangle in (x,y,0) plane where x-rays are generated.
* xwidth:   [m]   Width of rectangle in (x,y,0) plane where x-rays are generated. Overrides xmin and xmax.
* xmax:     [m]   Upper bound of x-interval where photons are generated.
* xmin:     [m]   Lower bound of x-interval where photons are generated.
* dist:     [m]   Distance to target along z axis.
* focus_xw: [m]   Width of target
* focus_yh: [m]   Height of target
* E0:       [keV] Mean energy of xrays.
* dE:       [keV] Energy half spread of x-rays (flat or gaussian sigma).
* lambda0:  [AA]  Mean wavelength of x-rays.
* dlambda:  [AA]  Wavelength half spread of x-rays.
* gauss:    [1]   Gaussian (1) or Flat (0) energy/wavelength distribution
* flux:     [pht/s] Total flux radiated from the source
* randomphase: [ ] If nonzero, the phase of the emotted photon is random, i.e. source is fully incoherent. otherwise the value of phase is used.
* phase:    [rad] Set phase to something given. 
* spectrum_file: [string] Filename for optional spectrum-file 
* %End
*******************************************************************************/

DEFINE COMPONENT Source_flat

SETTING PARAMETERS (radius=0, yheight=0, xwidth=0,xmin=0,xmax=0, 
  dist=0, focus_xw=.045, focus_yh=.12, 
  E0=0, dE=0, lambda0=0, dlambda=0, flux=0,gauss=0,randomphase=1,phase=0,
  string spectrum_file="")

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

SHARE
%{
  %include "read_table-lib"
%}

DECLARE
%{
  double pmul;
  double srcArea;
  int square;
  t_Table spectrum_T;
%}

INITIALIZE
%{
  square = 0;
  srcArea=0;
  /* Determine source area */

  if (xmin && xmax && !xwidth){
    xwidth=xmax-xmin;
  }

  if (radius && !yheight && !xwidth ) {
    square = 0;
    srcArea = PI*radius*radius;
  } else if(yheight && xwidth) {
    square = 1;
    srcArea = xwidth * yheight;
  }

  
  if (srcArea <= 0) {
    printf("Source_flat: %s: Source area is <= 0 !\n ERROR - Exiting\n",
           NAME_CURRENT_COMP);
    exit(-1);
  }
  if (dist <= 0 || focus_xw <= 0 || focus_yh <= 0) {
    printf("Source_flat: %s: Target area unmeaningful! (negative dist / focus_xw / focus_yh)\n ERROR - Exiting\n",
           NAME_CURRENT_COMP);
    exit(-1);
  }
  
  if (spectrum_file && strlen(spectrum_file)>0 && strcmp(spectrum_file,"NULL")!=0 ){
    /*read spectrum from file*/
    int status=0;
    if ( (status=Table_Read(&(spectrum_T),spectrum_file,0))==-1){
      fprintf(stderr,"Source_flat(%s) Error: Could not parse file \"%s\"\n",NAME_CURRENT_COMP,spectrum_file?spectrum_file:"");
      exit(-1);
    }
    /*data is now in table spectrum_T*/
    /*integrate to get total flux, assuming numbers have been corrected for measuring aperture*/
    int i;
    double pint=0;
    t_Table *T=&(spectrum_T);
    for (i=0;i<spectrum_T.rows-1;i++){
      pint+=((T->data[i*T->columns+1]+T->data[(i+1)*T->columns+1])/2.0)*fabs(T->data[(i+1)*T->columns]-T->data[i*T->columns]); 
    }
    printf("Source_flat(%s) Integrated intensity radiated is %g pht/s\n",NAME_CURRENT_COMP,pint);
    if(E0) printf("Source_flat(%s) E0!=0 -> assuming intensity spectrum is parametrized by energy [keV]\n",NAME_CURRENT_COMP);
  } else if (!E0 && !lambda0){
    fprintf(stderr,"Source_flat(%s): Error: Must specify either wavelength or energy distribution\n",NAME_CURRENT_COMP); 
    exit(-1);
  }
  /*calculate the X-ray weight from the flux*/
  if (flux){
    pmul=flux;
  }else{
    pmul=1;
  }
  pmul*=1.0/((double) mcget_ncount());
%}


TRACE
%{
  double chi,e,k,l,r, xf, yf, rf, dx, dy, pdir;

  phi=0;
  z=0;
  if (square == 1) {
    if (xmin && xmax){
      x = xmin + xwidth*rand01();
    }else{
      x = xwidth * (rand01() - 0.5);
    }
    y = yheight * (rand01() - 0.5);
  } else {
    chi=2*PI*rand01();                          /* Choose point on source */
    r=sqrt(rand01())*radius;                    /* with uniform distribution. */
    x=r*cos(chi);
    y=r*sin(chi);
  }
  randvec_target_rect_real(&xf, &yf, &rf, &pdir,
      0, 0, dist, focus_xw, focus_yh, ROT_A_CURRENT_COMP, x, y, z, 2);

  dx = xf-x;
  dy = yf-y;
  rf = sqrt(dx*dx+dy*dy+dist*dist);
  /*pdir contains the unnormalized solid angle weighting */
  p = pmul*pdir/(4*M_PI);

  if (spectrum_file && strlen(spectrum_file) && strcmp(spectrum_file,"NULL")!=0){
    double pp=0;
    //while (pp<=0){ 
    l=spectrum_T.data[0]+ (spectrum_T.data[(spectrum_T.rows-1)*spectrum_T.columns] -spectrum_T.data[0])*rand01();
    pp=Table_Value(spectrum_T,l,1);
    //}
    p*=pp;
    /*if E0!=0 the tabled value is assumed to be energy in keV*/
    if (E0!=0){
      k=E2K*l;
    }else{
      k=(2*M_PI/l);
    }
  }else if (E0){
    if(!dE){
      e=E0;
    }else if (gauss){
      e=E0+dE*randnorm();
    }else{
      e=randpm1()*dE + E0;
    }
    k=E2K*e;
  }else if (lambda0){
    if (!dlambda){
      l=lambda0;
    }else if (gauss){
      l=lambda0+dlambda*randnorm();
    }else{
      l=randpm1()*dlambda*0.5 + lambda0;
    }
    k=(2*M_PI/l);
  }
  ky=k*dy/rf;
  kx=k*dx/rf;
  kz=k*dist/rf;

  /*randomly pick phase or set to something real*/
  if (randomphase){
    phi=rand01()*2*M_PI;
  }else{
    phi=phase;
  }

  /*set polarization vector*/
  Ex=0;Ey=0;Ez=0;
%}

FINALLY
%{
  Table_Free(&(spectrum_T));
%}

MCDISPLAY
%{
  if (square == 1) {
    
    rectangle("xy",0,0,0,xwidth,yheight);
  } else {
    
    circle("xy",0,0,0,radius);
  }
  if (dist) {
    dashed_line(0,0,0, -focus_xw/2,-focus_yh/2,dist, 4);
    dashed_line(0,0,0,  focus_xw/2,-focus_yh/2,dist, 4);
    dashed_line(0,0,0,  focus_xw/2, focus_yh/2,dist, 4);
    dashed_line(0,0,0, -focus_xw/2, focus_yh/2,dist, 4);
  }
%}

END
