1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
|
/*******************************************************************************
*
* McXtrace, x-ray tracing package
* Copyright, All rights reserved
* DTU Physics, Kgs. Lyngby, Denmark
* Synchrotron SOLEIL, Saint-Aubin, France
*
* Component: Source_extended
*
* %Identification
* Written by:Arne 'S Jegers
* Date: May 6, 2019
* Origin: Technical University of Denmark
* Release: McXtrace 1.4
*
* A plane source emitting x-rays to emulate a distant extended source, such as a
* nebula or galaxy
*
* %Description
* A rectangular x-ray source that samples ray intensity from an image, and
* deflects the emitted ray to reflect having been emitted from the sampled part
* of the extended source. Rays that are sampled from the same point on the image
* are collimated, but can be emitted from anywhere on the rectangular source.
* The image should be provided as a 2D-ascii table, whose header includes the
* following entries:
*
* w_pixels and h_pixels: The width and height of the image in pixels
* x_ref and y_ref: x and y reference values of the FITS image
* r_max: The maximum distance from the point (x_ref, y_ref) to any corner of the image
* iCD11, iCD12, iCD21 and iCD22: The values of the FITS image's CD matrix
*
* %Parameters
* 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.
* 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
* incoherent: [] Source is fully incoherent
* phase: [] Set phase to something given.
* image_path: [string] Path to file containing the heat map of the source
* %End
*******************************************************************************/
DEFINE COMPONENT Source_extended
SETTING PARAMETERS (string spectrum_file=NULL,yheight=0, xwidth=0,
dist=0, E0=0, dE=0, lambda0=0, dlambda=0, flux=0,gauss=0,incoherent=1,phase=0, string image_path="")
SHARE
%{
%include "read_table-lib"
struct Sextended_prms {
double l0,dl;
double pmul,pint;
t_Table T;
};
struct Sextended_table_prms {
double xref, yref, rmax;
int pw, ph;
t_Table data;
double iCD[2][2];
};
double* sphericalToCartesian(double r, double theta, double Phi, double* cartesian){
cartesian[0] = r*cos(theta)*cos(Phi);
cartesian[1] = r*cos(theta)*sin(Phi);
cartesian[2] = r*sin(theta);
}
double* cartesianToSpherical(double x, double y, double z, double* spherical){
spherical[0] = sqrt(x*x + y*y + z*z);
spherical[1] = atan2(z, sqrt(x*x + y*y));
spherical[2] = atan2(y, x);
}
%}
DECLARE
%{
double srcArea;
int square;
struct Sextended_prms prms;
struct Sextended_table_prms extendedParams;
%}
INITIALIZE
%{
square = 0;srcArea=0;
square = 1;
srcArea = xwidth * yheight;
if (srcArea <= 0) {
printf("Source_flat: %s: Source area is <= 0 !\n ERROR - Exiting\n",
NAME_CURRENT_COMP);
exit(0);
}
int status = 0;
if (status=Table_Read(&(extendedParams.data), image_path, 0)==-1){
fprintf(stderr,"Source_extended(%s) Error: Could not parse file \"%s\"\n",NAME_CURRENT_COMP,image_path?image_path:"");
exit(-1);
}
char** header_parsed = Table_ParseHeader(extendedParams.data.header,
"w_pixels=","h_pixels=", "x_ref=", "y_ref=", "r_max=", "iCD11=", "iCD12=", "iCD21=", "iCD22=", NULL);
if (header_parsed[0] && header_parsed[1] && header_parsed[2] && header_parsed[3] &&
header_parsed[4] && header_parsed[5] && header_parsed[6] && header_parsed[7])
{
printf(header_parsed[0]);printf("\n");
extendedParams.pw=strtod(header_parsed[0],NULL);
extendedParams.ph=strtod(header_parsed[1],NULL);
extendedParams.xref=strtod(header_parsed[2],NULL);
extendedParams.yref=strtod(header_parsed[3],NULL);
extendedParams.rmax=strtod(header_parsed[4],NULL);
extendedParams.iCD[0][0] = strtod(header_parsed[5], NULL);
extendedParams.iCD[0][1] = strtod(header_parsed[6], NULL);
extendedParams.iCD[1][0] = strtod(header_parsed[7], NULL);
extendedParams.iCD[1][1] = strtod(header_parsed[8], NULL);
}
if (spectrum_file){
/*read spectrum from file*/
int status=0;
if ( (status=Table_Read(&(prms.T),spectrum_file,0))==-1){
fprintf(stderr,"Source_extended(%s) Error: Could not parse file \"%s\"\n",NAME_CURRENT_COMP,spectrum_file?spectrum_file:"");
exit(-1);
}
/*data is now in table t*/
/*integrate to get total flux, assuming raw numbers have been corrected for measuring aperture*/
int i;
prms.pint=0;
t_Table *T=&(prms.T);
for (i=0;i<prms.T.rows-1;i++){
prms.pint+=((T->data[i*T->columns+1]+T->data[(i+1)*T->columns+1])/2.0)*(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,prms.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(0);
}
/*calculate the X-ray weight from the flux*/
if (flux){
prms.pmul=flux;
}else{
prms.pmul=1;
}
prms.pmul*=1.0/((double) mcget_ncount());
%}
TRACE
%{
double chi,e,k,l,r, pdir;
char done = 0;
double xpix, ypix, theta, Phi;
double xDeg, yDeg, xRel, yRel;
Phi=0;
z=0;
if (square == 1) {
x = xwidth * (rand01() - 0.5);
y = yheight * (rand01() - 0.5);
}
/*pdir contains the unnormalized solid angle weighting */
p = 1;
if (spectrum_file){
double pp=0;
//while (pp<=0){
l=prms.T.data[0]+ (prms.T.data[(prms.T.rows-1)*prms.T.columns] -prms.T.data[0])*rand01();
pp=Table_Value(prms.T,l,1);
//}
p*=pp;
/*if E0!=0 convert the tabled value to wavelength*/
}else if (E0){
if(!dE){
e=E0;
}else if (gauss){
e=E0+dE*randnorm();
}else{
e=randpm1()*dE*0.5 + 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);
}
// ===========================================================================
// This section randomly picks a direction to emit a ray to, and samples the
// source image for an intensity at the appropriate point
while(!done){
theta = sqrt(rand01())*extendedParams.rmax/180*M_PI; //normalized
Phi = rand01()*2*M_PI;
xDeg = tan(theta)*cos(Phi)*180/M_PI;
yDeg = tan(theta)*sin(Phi)*180/M_PI;
xRel = extendedParams.iCD[0][0]*xDeg + extendedParams.iCD[0][1]*yDeg;
yRel = extendedParams.iCD[1][0]*xDeg + extendedParams.iCD[1][1]*yDeg;
xpix = xRel + extendedParams.xref;
ypix = yRel + extendedParams.yref;
if(xpix > 0 && xpix < extendedParams.pw && ypix > 0 && ypix < extendedParams.ph){
done = 1;
}
}
//Both are inverted because, relative to the spherical coordinate system of
//theta and Phi, the rays are emitted 'backwards'
kx = -sin(theta)*cos(Phi)*k;
ky = -sin(theta)*sin(Phi)*k;
kz = cos(theta)*k;
p = Table_Value2d(extendedParams.data, ypix, xpix);
/*randomly pick phase or set to something real*/
if (incoherent){
Phi=rand01()*2*M_PI;
}else{
Phi=phase;
}
/*set polarization vector*/
Ex=0;Ey=0;Ez=0;
%}
FINALLY
%{
Table_Free(&(prms.T));
Table_Free(&(extendedParams.data));
%}
MCDISPLAY
%{
if (square == 1) {
magnify("xy");
rectangle("xy",0,0,0,xwidth,yheight);
}
%}
END
|