/* * detector.c * * Detector properties * * (c) 2007-2009 Thomas White * * pattern_sim - Simulate diffraction patterns from small crystals * */ #include #include #include #include #include "image.h" #include "utils.h" #include "diffraction.h" /* Pulse energy density in J/m^2 */ #define PULSE_ENERGY_DENSITY (30.0e7) /* Detector's quantum efficiency */ #define DQE (0.9) /* Detector's saturation value */ #define SATURATION (60000) /* Radius of X-ray beam */ #define BEAM_RADIUS (3.0e-6) /* Bleed excess intensity into neighbouring pixels */ static void bloom_values(double *tmp, int x, int y, int width, int height, double val) { double overflow; overflow = val - SATURATION; /* Intensity which bleeds off the edge of the detector is lost */ if ( x > 0 ) { tmp[x-1 + width*y] += overflow / 6.0; if ( y > 0 ) { tmp[x-1 + width*(y-1)] += overflow / 12.0; } if ( y < height-1 ) { tmp[x-1 + width*(y+1)] += overflow / 12.0; } } if ( x < width-1 ) { tmp[x+1 + width*y] += overflow / 6.0; if ( y > 0 ) { tmp[x+1 + width*(y-1)] += overflow / 12.0; } if ( y < height-1 ) { tmp[x+1 + width*(y+1)] += overflow / 12.0; } } if ( y > 0 ) { tmp[x + width*(y-1)] += overflow / 6.0; } if ( y < height-1 ) { tmp[x + width*(y+1)] += overflow / 6.0; } } static uint16_t *bloom(double *hdr_in, int width, int height) { int x, y; uint16_t *data; double *tmp; double *hdr; int did_something; data = malloc(width * height * sizeof(uint16_t)); tmp = malloc(width * height * sizeof(double)); hdr = malloc(width * height * sizeof(double)); memcpy(hdr, hdr_in, width*height*sizeof(double)); /* Apply DQE (once only) */ for ( x=0; xxray_energy; ph_per_e = fluence * pow(THOMSON_LENGTH, 2.0); printf("Fluence = %5e photons / m^2, %5e photons total\n", fluence, fluence*area); /* Solid angle subtended by a single pixel at the centre of the CCD */ sa_per_pixel = pow(1.0/(image->resolution * image->camera_len), 2.0); printf("Solid angle of one pixel (at centre of CCD) = %e sr\n", sa_per_pixel); image->hdr = malloc(image->width * image->height * sizeof(double)); for ( x=0; xwidth; x++ ) { for ( y=0; yheight; y++ ) { double counts, intensity, sa, water; double complex val; val = image->sfacs[x + image->width*y]; intensity = pow(cabs(val), 2.0); /* Add intensity contribution from water */ water = water_intensity(image->qvecs[x + image->width*y], image->xray_energy, BEAM_RADIUS, 1.5e-6); //printf("%e, %e, ", intensity, water); intensity += water; /* What solid angle is subtended by this pixel? */ sa = sa_per_pixel * cos(image->twotheta[x + image->width*y]); counts = intensity * ph_per_e * sa; //printf("%e counts\n", counts); counts += poisson_noise(counts); image->hdr[x + image->width*y] = counts; } progress_bar(x, image->width-1, "Adding water and noise"); } if ( do_bloom ) { image->data = bloom(image->hdr, image->width, image->height); } else { image->data = malloc(image->width * image->height * sizeof(uint16_t)); for ( x=0; xwidth; x++ ) { for ( y=0; yheight; y++ ) { double val; val = image->hdr[x + image->width*y]; if ( val > SATURATION ) val = SATURATION; image->data[x + image->width*y] = (uint16_t)val; } } } }