diff options
author | Thomas White <taw@physics.org> | 2011-11-15 12:17:59 +0100 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2012-02-22 15:27:40 +0100 |
commit | 469efb904b59f137ac9e85e5ff23edd0c113de5c (patch) | |
tree | 71fab5f5715ec9f88984450cdabb592cd49dd46d /src/peaks.c | |
parent | 38089071300b8e04ed42236dd08d9055094fb3b8 (diff) |
Move a load more stuff into libcrystfel
Diffstat (limited to 'src/peaks.c')
-rw-r--r-- | src/peaks.c | 594 |
1 files changed, 0 insertions, 594 deletions
diff --git a/src/peaks.c b/src/peaks.c deleted file mode 100644 index f1a58d23..00000000 --- a/src/peaks.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * peaks.c - * - * Peak search and other image analysis - * - * (c) 2006-2011 Thomas White <taw@physics.org> - * 2011 Andrew Martin - * - * Part of CrystFEL - crystallography with a FEL - * - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include <assert.h> -#include <gsl/gsl_statistics_int.h> -#include <pthread.h> -#include <fenv.h> - -#include "image.h" -#include "utils.h" -#include "index.h" -#include "peaks.h" -#include "detector.h" -#include "filters.h" -#include "diffraction.h" -#include "reflist-utils.h" -#include "beam-parameters.h" - - -/* How close a peak must be to an indexed position to be considered "close" - * for the purposes of double hit detection and sanity checking. */ -#define PEAK_CLOSE (30.0) - -/* How close a peak must be to an indexed position to be considered "close" - * for the purposes of integration. */ -#define PEAK_REALLY_CLOSE (10.0) - -/* Degree of polarisation of X-ray beam */ -#define POL (1.0) - -static int cull_peaks_in_panel(struct image *image, struct panel *p) -{ - int i, n; - int nelim = 0; - - n = image_feature_count(image->features); - - for ( i=0; i<n; i++ ) { - - struct imagefeature *f; - int j, ncol; - - f = image_get_feature(image->features, i); - if ( f == NULL ) continue; - - if ( f->fs < p->min_fs ) continue; - if ( f->fs > p->max_fs ) continue; - if ( f->ss < p->min_ss ) continue; - if ( f->ss > p->max_ss ) continue; - - /* How many peaks are in the same column? */ - ncol = 0; - for ( j=0; j<n; j++ ) { - - struct imagefeature *g; - - if ( i==j ) continue; - - g = image_get_feature(image->features, j); - if ( g == NULL ) continue; - - if ( p->badrow == 'f' ) { - if ( fabs(f->ss - g->ss) < 2.0 ) ncol++; - } else if ( p->badrow == 's' ) { - if ( fabs(f->fs - g->fs) < 2.0 ) ncol++; - } /* else do nothing */ - - } - - /* More than three? */ - if ( ncol <= 3 ) continue; - - /* Yes? Delete them all... */ - nelim = 0; - for ( j=0; j<n; j++ ) { - struct imagefeature *g; - g = image_get_feature(image->features, j); - if ( g == NULL ) continue; - if ( p->badrow == 'f' ) { - if ( fabs(f->ss - g->ss) < 2.0 ) { - image_remove_feature(image->features, - j); - nelim++; - } - } else if ( p->badrow == 's' ) { - if ( fabs(f->fs - g->ss) < 2.0 ) { - image_remove_feature(image->features, - j); - nelim++; - } - } else { - ERROR("Invalid badrow direction.\n"); - abort(); - } - - } - - } - - return nelim; -} - - -/* Post-processing of the peak list to remove noise */ -static int cull_peaks(struct image *image) -{ - int nelim = 0; - struct panel *p; - int i; - - for ( i=0; i<image->det->n_panels; i++ ) { - p = &image->det->panels[i]; - if ( p->badrow != '-' ) { - nelim += cull_peaks_in_panel(image, p); - } - } - - return nelim; -} - - -/* Returns non-zero if peak has been vetoed. - * i.e. don't use result if return value is not zero. */ -int integrate_peak(struct image *image, int cfs, int css, - double *pfs, double *pss, double *intensity, - double *pbg, double *pmax, double *sigma, - int do_polar, int centroid, int bgsub) -{ - signed int fs, ss; - double lim, out_lim, mid_lim; - double lim_sq, out_lim_sq, mid_lim_sq; - double total = 0.0; - double fsct = 0.0; - double ssct = 0.0; - double noise = 0.0; - int noise_counts = 0; - double max = 0.0; - struct panel *p = NULL; - int pixel_counts = 0; - double noise_mean = 0.0; - double noise_meansq = 0.0; - struct beam_params *beam; - double aduph; - - beam = image->beam; - if ( beam != NULL ) { - aduph = image->beam->adu_per_photon; - } else { - aduph = 1.0; - } - - p = find_panel(image->det, cfs, css); - if ( p == NULL ) return 1; - if ( p->no_index ) return 1; - - lim = p->integr_radius; - mid_lim = 3.0 + lim; - out_lim = 6.0 + lim; - lim_sq = pow(lim, 2.0); - mid_lim_sq = pow(mid_lim, 2.0); - out_lim_sq = pow(out_lim, 2.0); - - for ( fs=-out_lim; fs<+out_lim; fs++ ) { - for ( ss=-out_lim; ss<+out_lim; ss++ ) { - - double val; - double tt = 0.0; - double phi, pa, pb, pol; - uint16_t flags; - struct panel *p2; - int idx; - - /* Outer mask radius */ - if ( fs*fs + ss*ss > out_lim_sq ) continue; - - if ( ((fs+cfs)>=image->width) || ((fs+cfs)<0) ) continue; - if ( ((ss+css)>=image->height) || ((ss+css)<0) ) continue; - - /* Strayed off one panel? */ - p2 = find_panel(image->det, fs+cfs, ss+css); - if ( p2 != p ) return 1; - - idx = fs+cfs+image->width*(ss+css); - - /* Veto this peak if we tried to integrate in a bad region */ - if ( image->flags != NULL ) { - - flags = image->flags[idx]; - - /* It must have all the "good" bits to be valid */ - if ( !((flags & image->det->mask_good) - == image->det->mask_good) ) return 1; - - /* If it has any of the "bad" bits, reject */ - if ( flags & image->det->mask_bad ) return 1; - - } - - val = image->data[idx]; - - if ( do_polar ) { - - tt = get_tt(image, fs+cfs, ss+css); - - phi = atan2(ss+css, fs+cfs); - pa = pow(sin(phi)*sin(tt), 2.0); - pb = pow(cos(tt), 2.0); - pol = 1.0 - 2.0*POL*(1-pa) + POL*(1.0+pb); - - val /= pol; - - } - - if ( val > max ) max = val; - - /* If outside inner mask, estimate noise from this region */ - if ( fs*fs + ss*ss > mid_lim_sq ) { - - /* Noise - * noise and noise_meansq are both in photons (^2) */ - noise += val / image->beam->adu_per_photon; - noise_counts++; - noise_meansq += pow(val, 2.0); - - } else if ( fs*fs + ss*ss < lim_sq ) { - - /* Peak */ - pixel_counts++; - total += val; - fsct += val*(cfs+fs); - ssct += val*(css+ss); - - } - - } - } - - noise_mean = noise / noise_counts; /* photons */ - - /* The centroid is excitingly undefined if there is no intensity */ - centroid = 0; - if ( centroid && (total != 0) ) { - *pfs = ((double)fsct / total) + 0.5; - *pss = ((double)ssct / total) + 0.5; - } else { - *pfs = (double)cfs + 0.5; - *pss = (double)css + 0.5; - } - if ( bgsub ) { - *intensity = total - aduph * pixel_counts*noise_mean; /* ADU */ - } else { - *intensity = total; /* ADU */ - } - - if ( in_bad_region(image->det, *pfs, *pss) ) return 1; - - if ( sigma != NULL ) { - - /* First term is standard deviation of background per pixel - * sqrt(pixel_counts) - increase of error for integrated value - * sqrt(2) - increase of error for background subtraction */ - *sigma = sqrt(noise_meansq/noise_counts-(noise_mean*noise_mean)) - * sqrt(2.0*pixel_counts) * aduph; - - } - - if ( pbg != NULL ) { - *pbg = aduph * (noise / noise_counts); - } - if ( pmax != NULL ) { - *pmax = max; - } - - return 0; -} - - -static void search_peaks_in_panel(struct image *image, float threshold, - float min_gradient, float min_snr, - struct panel *p) -{ - int fs, ss, stride; - float *data; - double d; - int idx; - double f_fs = 0.0; - double f_ss = 0.0; - double intensity = 0.0; - double sigma = 0.0; - double pbg = 0.0; - double pmax = 0.0; - int nrej_dis = 0; - int nrej_pro = 0; - int nrej_fra = 0; - int nrej_bad = 0; - int nrej_snr = 0; - int nacc = 0; - int ncull; - const int pws = p->peak_sep/2; - - data = image->data; - stride = image->width; - - for ( fs = p->min_fs+1; fs <= p->max_fs-1; fs++ ) { - for ( ss = p->min_ss+1; ss <= p->max_ss-1; ss++ ) { - - double dx1, dx2, dy1, dy2; - double dxs, dys; - double grad; - int mask_fs, mask_ss; - int s_fs, s_ss; - double max; - unsigned int did_something; - int r; - - /* Overall threshold */ - if ( data[fs+stride*ss] < threshold ) continue; - - /* Get gradients */ - dx1 = data[fs+stride*ss] - data[(fs+1)+stride*ss]; - dx2 = data[(fs-1)+stride*ss] - data[fs+stride*ss]; - dy1 = data[fs+stride*ss] - data[(fs+1)+stride*(ss+1)]; - dy2 = data[fs+stride*(ss-1)] - data[fs+stride*ss]; - - /* Average gradient measurements from both sides */ - dxs = ((dx1*dx1) + (dx2*dx2)) / 2; - dys = ((dy1*dy1) + (dy2*dy2)) / 2; - - /* Calculate overall gradient */ - grad = dxs + dys; - - if ( grad < min_gradient ) continue; - - mask_fs = fs; - mask_ss = ss; - - do { - - max = data[mask_fs+stride*mask_ss]; - did_something = 0; - - for ( s_ss=biggest(mask_ss-pws/2, - p->min_ss); - s_ss<=smallest(mask_ss+pws/2, - p->max_ss); - s_ss++ ) { - for ( s_fs=biggest(mask_fs-pws/2, - p->min_fs); - s_fs<=smallest(mask_fs+pws/2, - p->max_fs); - s_fs++ ) { - - if ( data[s_fs+stride*s_ss] > max ) { - max = data[s_fs+stride*s_ss]; - mask_fs = s_fs; - mask_ss = s_ss; - did_something = 1; - } - - } - } - - /* Abort if drifted too far from the foot point */ - if ( distance(mask_fs, mask_ss, fs, ss) > - p->peak_sep/2.0 ) - { - break; - } - - } while ( did_something ); - - /* Too far from foot point? */ - if ( distance(mask_fs, mask_ss, fs, ss) > p->peak_sep/2.0 ) { - nrej_dis++; - continue; - } - - /* Should be enforced by bounds used above. Muppet check. */ - assert(mask_fs <= p->max_fs); - assert(mask_ss <= p->max_ss); - assert(mask_fs >= p->min_fs); - assert(mask_ss >= p->min_ss); - - /* Centroid peak and get better coordinates. - * Don't bother doing polarisation/SA correction, because the - * intensity of this peak is only an estimate at this stage. */ - r = integrate_peak(image, mask_fs, mask_ss, - &f_fs, &f_ss, &intensity, - &pbg, &pmax, &sigma, 0, 1, 1); - - if ( r ) { - /* Bad region - don't detect peak */ - nrej_bad++; - continue; - } - - /* It is possible for the centroid to fall outside the image */ - if ( (f_fs < p->min_fs) || (f_fs > p->max_fs) - || (f_ss < p->min_ss) || (f_ss > p->max_ss) ) { - nrej_fra++; - continue; - } - - if (intensity/sigma < min_snr) { - nrej_snr++; - continue; - } - - /* Check for a nearby feature */ - image_feature_closest(image->features, f_fs, f_ss, &d, &idx); - if ( d < p->peak_sep/2.0 ) { - nrej_pro++; - continue; - } - - /* Add using "better" coordinates */ - image_add_feature(image->features, f_fs, f_ss, image, intensity, - NULL); - nacc++; - - } - } - - if ( image->det != NULL ) { - ncull = cull_peaks(image); - nacc -= ncull; - } else { - STATUS("Not culling peaks because I don't have a " - "detector geometry file.\n"); - ncull = 0; - } - -// STATUS("%i accepted, %i box, %i proximity, %i outside panel, " -// "%i in bad regions, %i with SNR < %g, %i badrow culled.\n", -// nacc, nrej_dis, nrej_pro, nrej_fra, nrej_bad, -// nrej_snr, min_snr, ncull); -} - - -void search_peaks(struct image *image, float threshold, float min_gradient, - float min_snr) -{ - int i; - - if ( image->features != NULL ) { - image_feature_list_free(image->features); - } - image->features = image_feature_list_new(); - - for ( i=0; i<image->det->n_panels; i++ ) { - - struct panel *p = &image->det->panels[i]; - - if ( p->no_index ) continue; - search_peaks_in_panel(image, threshold, min_gradient, min_snr, p); - - } -} - - -int peak_sanity_check(struct image *image) -{ - - int i; - int n_feat = 0; - int n_sane = 0; - double ax, ay, az; - double bx, by, bz; - double cx, cy, cz; - double min_dist = 0.25; - - /* Round towards nearest */ - fesetround(1); - - /* Cell basis vectors for this image */ - cell_get_cartesian(image->indexed_cell, &ax, &ay, &az, - &bx, &by, &bz, - &cx, &cy, &cz); - - /* Loop over peaks, checking proximity to nearest reflection */ - for ( i=0; i<image_feature_count(image->features); i++ ) { - - struct imagefeature *f; - struct rvec q; - double h,k,l,hd,kd,ld; - - /* Assume all image "features" are genuine peaks */ - f = image_get_feature(image->features, i); - if ( f == NULL ) continue; - n_feat++; - - /* Reciprocal space position of found peak */ - q = get_q(image, f->fs, f->ss, NULL, 1.0/image->lambda); - - /* Decimal and fractional Miller indices of nearest - * reciprocal lattice point */ - hd = q.u * ax + q.v * ay + q.w * az; - kd = q.u * bx + q.v * by + q.w * bz; - ld = q.u * cx + q.v * cy + q.w * cz; - h = lrint(hd); - k = lrint(kd); - l = lrint(ld); - - /* Check distance */ - if ( (fabs(h - hd) < min_dist) && (fabs(k - kd) < min_dist) - && (fabs(l - ld) < min_dist) ) - { - n_sane++; - continue; - } - - } - - /* return 0 means fail test, return 1 means pass test */ - // printf("%d out of %d peaks are \"sane\"\n",n_sane,n_feat); - if ( (float)n_sane / (float)n_feat < 0.5 ) return 0; - - return 1; -} - - -/* Integrate the list of predicted reflections in "image" */ -void integrate_reflections(struct image *image, int polar, int use_closer, - int bgsub) -{ - Reflection *refl; - RefListIterator *iter; - - for ( refl = first_refl(image->reflections, &iter); - refl != NULL; - refl = next_refl(refl, iter) ) { - - double fs, ss, intensity; - double d; - int idx; - double bg, max; - double sigma; - double pfs, pss; - int r; - - get_detector_pos(refl, &pfs, &pss); - - /* Is there a really close feature which was detected? */ - if ( use_closer ) { - - struct imagefeature *f; - - if ( image->features != NULL ) { - f = image_feature_closest(image->features, - pfs, pss, &d, &idx); - } else { - f = NULL; - } - if ( (f != NULL) && (d < PEAK_REALLY_CLOSE) ) { - - pfs = f->fs; - pss = f->ss; - - } - } - - r = integrate_peak(image, pfs, pss, &fs, &ss, - &intensity, &bg, &max, &sigma, polar, 0, - bgsub); - - /* Record intensity and set redundancy to 1 on success */ - if ( r == 0 ) { - set_int(refl, intensity); - set_esd_intensity(refl, sigma); - set_redundancy(refl, 1); - } else { - set_redundancy(refl, 0); - } - - } -} |