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