1/*******************************************************************************
2*
3* McXtrace, X-ray tracing package
4*         Copyright, All rights reserved
5*         Technical University of Denmark, Kgs. Lyngby, Denmark
6*         Institut Laue Langevin, Grenoble, France
7*         University of Copenhagen, Copenhagen, Denmark
8*
9* Component: Source_lab
10*
11* %I
12* Written by: Erik Bergbaeck Knudsen
13* Date: May 2012
14* Version: 1.0
15* Release: McXtrace 1.1
16* Origin: Kgs. Lyngby
17*
18* Laboratory x-ray source.
19*
20* %D
21* Model of a laboratory x-ray tube, generating x-rays by bombarding a target by electrons.
22* Given a input energy E0 of the electron beam, x-rays are emitted from the accessible emission lines
23* The geometry of the tube is assumed to be:
24* # The electron beam hits a slab of surface material surface at a right angle illuminating an area of width by height,
25* # where width is measured along the component X-axis.
26* # The centre of the electron beam at the anode surface is the origin of the component.
27* # The Z-axis of the component points at the centre of the exit window (focus_xw by focus yh)
28* placed at a distance dist from the origin.
29* # The angle between the Z-axis and the anode surface is the take_off angle.
30* For a detailed sketch of the geometry see the componnent manual.
31*
32* The Bremsstrahlung emitted is modelled using the model of Kramer (1923) as restated in International
33* Tables of Crystallography C 4.1
34* Characteristic radiation is modelled by Gaussian energy profiles with line-energies from Bearden (1967), widths from
35* Krause (1979) and intensity from Honkimäki (1990) and x-ray data booklet.
36* Absoprtion of emitted x-rays while travelling through the target anode is included.
37*
38* Example: Source_lab(material_datafile="Cu.txt",Emin=1, E0=80)
39*
40* %P
41* width:    [m] Width of electron beam impinging on the anode.
42* height:    [m] Height of electron beam impinging on the anode.
43* thickness: [m] Thickness of the anode material slab.
44* take_off: [deg] Take off angle of beam centre.
45* dist:  [m] Distance between centre of illuminated target and exit window.
46* E0:    [kV] Acceleration voltage of xray tube.
47* tube_current: [A] Electron beam current.
48* Emax:  [keV] Maximum energy to sample. Default (Emax=0) is to set it to E0.
49* Emin:  [keV] Minimum energy to sample.
50* focus_xw: [m] Width of exit window.
51* focus_yh:[m] Height of exit window.
52* frac:  [] Fraction of statistic to use for Bremsstrahlung.
53* material_datafile: [] Name of datafile which describes the target material.
54*
55* %E
56*************************************************************************/
57
58DEFINE COMPONENT Source_lab
59DEFINITION PARAMETERS (string material_datafile="Cu.txt")
60SETTING PARAMETERS (width=1e-3, height=1e-3, thickness=100e-6, E0=20, Emax=0, Emin=1, focus_xw=5e-3, focus_yh=5e-3,
61      take_off=6, dist=1, tube_current=1e-3, frac=0.5)
62OUTPUT PARAMETERS (R_xray_gen,R_xray_geni, O_xray_gen, prms,pmul_c,mu,p_continous)
63/* X-ray parameters: (x,y,z,kx,ky,kz,phi,t,Ex,Ey,Ez,p) */
64
65SHARE
66%{
67  %include "read_table-lib"
68
69  /*here are some material data- currently only for Cu, Mo and W*/
70  const struct xray_em_data{
71    int Z;/*atom number*/
72    double Ek;/*ionazation energy*/
73    double w_k;/*flourescence yield*/
74    int linec;
75    double e[6];/*line energy*/
76    double w[6];/*natural width of line FWHM*/
77    double i[6];/*relative intensity*/
78  } xray_mat_data[]={
79    {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}},
80    {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}},
81    {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}},
82    {74,69.525,0.945,2,{57.9817,59.31824,0,0,0,0},{44.9e-3,45.2e-3,0,0,0,0},{0.58,1.0,0,0,0,0}},
83    {0,0.0,0.0,0,{0,0,0,0,0,0},{0,0,0,0,0,0},{0,0,0,0,0,0}}
84  };
85
86%}
87
88DECLARE
89%{
90  Rotation R_xray_gen,R_xray_geni;
91  Coords O_xray_gen;
92  const double BKRAMER=2e-6; /*photons /keV /electron*/
93  struct {
94    int Z;
95    double At,rho;
96    t_Table T;
97    const struct xray_em_data *em_p;
98    double Icont,Ichar;
99  } prms;
100  double p_continous;
101  double mu=0.2e-6;
102  double pmul_c;
103%}
104
105INITIALIZE
106%{
107  int status,ii;
108  if (E0<=0){
109    fprintf(stderr,"Error %s: Impinging electron energy (E0) must be >0, was %g\n",NAME_CURRENT_COMP, E0);
110    exit(-1);
111  }
112
113  if (!Emax){/*if Emax is not set use the impinging electron energy*/
114    Emax=E0;
115  }
116  if(Emin<=0){
117    fprintf(stderr,"Error (%s): Emin must be > 0 (%g)\n",NAME_CURRENT_COMP,Emin);exit(-1);
118  }
119  if(Emax<Emin){
120    fprintf(stderr,"Error (%s): Nonsensical emission energy interval [Emin,Emax]=[%g %g] at E0=%g\n",NAME_CURRENT_COMP,Emin,Emax,E0);
121    exit(-1);
122  }
123
124  if ( (status=Table_Read(&(prms.T),material_datafile,0))==-1){
125    fprintf(stderr,"Error %s: Could not parse file \"%s\"\n",NAME_CURRENT_COMP,material_datafile?material_datafile:"");
126    exit(-1);
127  }
128  char **header_parsed;
129  header_parsed=Table_ParseHeader(prms.T.header,"Z","A[r]","rho","Z/A","sigma[a]",NULL);
130  if(header_parsed[2]){prms.rho=strtod(header_parsed[2],NULL);}
131  if(header_parsed[0]){prms.Z=strtod(header_parsed[0],NULL);}
132  if(header_parsed[1]){prms.At=strtod(header_parsed[1],NULL);}
133  /*use the atom number to get at the right data structure*/
134  prms.em_p=&(xray_mat_data[0]);
135  while (prms.Z!=prms.em_p->Z){
136    prms.em_p++;
137    if ((prms.em_p->Z)==0){
138      fprintf(stderr,"Error: %s (Z=%d) anode not implemented yet. Please contact the McXtrace team to fix this. Aborting.\n",material_datafile,prms.Z);
139      exit(-1);
140    }
141  }
142
143  /*Integrate the continuous spectrum and the characteristic so as to get the relative intenisities right*/
144  prms.Icont=tube_current/CELE*BKRAMER*prms.Z*(E0*log(Emax)-E0*log(Emin) - Emax + Emin);
145  /*check if E0 >Ek. If not, no characteristic emission can take place*/
146  if (E0>prms.em_p->Ek){
147    double Bk=1.2e-5*pow(prms.em_p->Ek,1.67)*exp(-0.077*prms.Z);
148    prms.Ichar=tube_current/CELE*4*M_PI*(E0/prms.em_p->Ek-1)*Bk;
149    double Ichar_tot=0;
150    for (ii=0;ii<prms.em_p->linec;ii++){
151      if(Emax>prms.em_p->e[ii]+5*prms.em_p->w[ii] && Emin<prms.em_p->e[ii]-5*prms.em_p->w[ii]){
152        Ichar_tot+=prms.em_p->i[ii];
153      }else{
154        Ichar_tot+=prms.em_p->i[ii]*0.5*( erf(M_SQRT1_2*(Emax-prms.em_p->e[ii])/prms.em_p->w[ii]) - erf(M_SQRT1_2*(Emin-prms.em_p->e[ii])/prms.em_p->w[ii]) );
155      }
156    }
157    p_continous=prms.Icont/(prms.Ichar*Ichar_tot+prms.Icont);
158    printf("Bk,Ico,Ich,Icht,p_c=%g %g %g %g %g\n",Bk,prms.Icont,prms.Ichar,Ichar_tot,p_continous);
159  }else{
160    /*characteristic K-emission is not possible*/
161    p_continous=1;
162    frac=1;
163  }
164  O_xray_gen=coords_set(0,0,0);
165  rot_set_rotation(R_xray_gen,-take_off*DEG2RAD,0,0);
166  rot_set_rotation(R_xray_geni,take_off*DEG2RAD,0,0);
167
168  pmul_c=1.0/(mcget_ncount());
169
170%}
171
172TRACE
173%{
174  double x1,y1,z1,x2,y2,z2,r,e,k,pdir,pmul;
175  /* pick a point in the generating volume*/
176  x1=rand01()*width-width/2.0;
177  z1=rand01()*height-height/2.0;
178  /* y is the absorption depth of the electron getting converted to an xray*/
179  y1=log(rand01())*mu;
180
181  double px,py,pz;
182  Coords P;
183
184  /* transform initial coords to ones relative to the exit window which is our reference point*/
185  P=coords_set(x1,y1,z1);
186  P=coords_add(rot_apply(R_xray_gen,P),O_xray_gen);
187  coords_get(P,&x,&y,&z);
188
189  //mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1, 0,0,0, 0,0,0);
190
191  /*set a scatter pt at the generation pt*/
192  //x=x1;y=y1;z=z1;
193  SCATTER;
194
195  /*randvec_target_rect_real computes a target point and a solid angle correction factor, hence the k-vector has to be computed from
196    generation point and target point. The (0,0,1) location of the target is due to a silent assumption in randvec() that
197    the target cannot be situated in the origin.*/
198  randvec_target_rect_real(&px,&py,&pz,&pdir,0,0,dist,focus_xw,focus_yh, R_xray_gen,x1,y1,z1,2);
199  /*k is parallell to the line between generation and target points*/
200  kx=px-x1;
201  ky=py-y1;
202  kz=pz-z1;
203
204  /*Now for wavelength selection*/
205  r=rand01();
206  //printf("brems %g %g\n",r,p_continous);
207  if(r<frac){
208    //printf("brems %g \n",r);
209    /*bremsstrahlung*/
210    double e=rand01()*(Emax-Emin)+Emin;
211    k=e*E2K;
212    pmul=tube_current/CELE*BKRAMER*prms.Z*(E0/e-1);
213    /*correct for not having the full E-window*/
214    pmul*=(Emax-Emin)/E0;
215    /*correct for monte-carlo statistics*/
216    pmul*=p_continous/frac;
217  }else{
218    const struct xray_em_data *pt=prms.em_p;
219    /*characteristic radiation*/
220    /*first pick a possible line*/
221    r=rand01()*pt->linec;
222    int lineno=(int)floor(r);
223    if (lineno==pt->linec) {
224      lineno--;/*we might get overflow*/
225    }
226    pmul=pt->i[lineno]*prms.Ichar;
227    k=E2K*(randnorm()*pt->w[lineno]+pt->e[lineno]);
228
229    pmul*=(1-p_continous)/frac;
230    /*correct for not having the full E-window if so*/
231
232  }
233
234  /*scale k accordingly*/
235  NORM(kx,ky,kz);
236  kx*=k;ky*=k;kz*=k;
237
238  /*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*/
239  p=pmul*pmul_c;
240
241  double mu_abs,l0;
242  int ie;
243  /*Correct for absorption*/
244  if (take_off<0){
245    double px,py,pz,nx,ny,nz;
246    coords_get(rot_apply(R_xray_gen,coords_set(0,1,0)),&nx,&ny,&nz);
247    coords_get(rot_apply(R_xray_gen,coords_set(0,-thickness,0)),&px,&py,&pz);
248    /*this means we exit through the bottom of the anode slab*/
249    ie=plane_intersect(&l0,x,y,z,kx,ky,kz,nx,ny,nz,px,py,pz);
250  }else{
251    double nx,ny,nz;
252    coords_get(rot_apply(R_xray_gen,coords_set(0,1,0)),&nx,&ny,&nz);
253    /*exit through top of anode slab*/
254    ie=plane_intersect(&l0,x,y,z,kx,ky,kz,nx,ny,nz,0,0,0);
255    if(l0<0){
256    }
257  }
258  mu_abs=Table_Value(prms.T, k*K2E, 5)*prms.rho*1e2; /*mu_abs in m^-1*/
259  p*=exp(-l0*mu_abs);
260  //printf("%g %g %g %g\n",k*K2E,mu_abs,exp(-l0*mu_abs),Table_Value(prms.T, k*K2E, 5) );
261  /*set a random phase - and propagate to the exit window*/
262  phi=rand01()*2*M_PI;
263%}
264
265MCDISPLAY
266%{
267  magnify("xy");
268  double x1,y1,z1,x2,y2,z2,width_2,height_2;
269  double dx,dy,dz;
270  /*these are just dummies*/
271  double d1,d2,d3,d4,d5,d6;
272
273  width_2=width/2.0;
274  height_2=height/2.0;
275  x1=-width_2;y1=0;z1=-height_2;
276  x2=-width_2;y2=0;z2= height_2;
277  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
278  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
279  line(x1,y1,z1,x2,y2,z2);
280
281  x1=width_2;y1=0;z1=height_2;
282  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
283  line(x2,y2,z2,x1,y1,z1);
284
285  x2=width_2;y2=0;z2=-height_2;
286  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
287  line(x1,y1,z1,x2,y2,z2);
288
289  x1=-width_2;y1=0;z1=-height_2;
290  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
291  line(x2,y2,z2,x1,y1,z1);
292
293  /*this is the mean penetration depth of electron that get converted to x-rays*/
294  x1=-width_2;y1=-mu;z1=-height_2;
295  x2=-width_2;y2=-mu;z2= height_2;
296  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
297  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
298  dashed_line(x1,y1,z1,x2,y2,z2,5);
299  x1=width_2;y1=-mu;z1=height_2;
300  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
301  dashed_line(x2,y2,z2,x1,y1,z1,5);
302  x2= width_2;y2=-mu;z2=-height_2;
303  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
304  dashed_line(x1,y1,z1,x2,y2,z2,5);
305  x1=-width_2;y1=-mu;z1=-height_2;
306  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
307  dashed_line(x2,y2,z2,x1,y1,z1,5);
308
309  x1=-width_2;y1=-mu;z1=-height_2;
310  x2=-width_2;y2=0;z2=-height_2;
311  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
312  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
313  line(x2,y2,z2,x1,y1,z1);
314  x1=width_2;y1=-mu;z1=-height_2;
315  x2=width_2;y2=0;z2=-height_2;
316  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
317  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
318  line(x2,y2,z2,x1,y1,z1);
319  x1=-width_2;y1=-mu;z1=height_2;
320  x2=-width_2;y2=0;z2=height_2;
321  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
322  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
323  line(x2,y2,z2,x1,y1,z1);
324  x1=width_2;y1=-mu;z1=height_2;
325  x2=width_2;y2=0;z2=height_2;
326  mccoordschange(O_xray_gen,R_xray_gen,&x1,&y1,&z1,&d1,&d2,&d3,&d4,&d5,&d6);
327  mccoordschange(O_xray_gen,R_xray_gen,&x2,&y2,&z2,&d1,&d2,&d3,&d4,&d5,&d6);
328  line(x2,y2,z2,x1,y1,z1);
329
330
331  /*now draw "exit" window*/
332  rectangle("xy",0,0,0,focus_xw,focus_yh);
333%}
334
335END
336