diff options
Diffstat (limited to 'libcrystfel/src/peakfinder8.c')
-rw-r--r-- | libcrystfel/src/peakfinder8.c | 1195 |
1 files changed, 1195 insertions, 0 deletions
diff --git a/libcrystfel/src/peakfinder8.c b/libcrystfel/src/peakfinder8.c new file mode 100644 index 00000000..417465df --- /dev/null +++ b/libcrystfel/src/peakfinder8.c @@ -0,0 +1,1195 @@ +/* + * peakfinder8.c + * + * The peakfinder8 algorithm + * + * Copyright © 2012-2017 Deutsches Elektronen-Synchrotron DESY, + * a research centre of the Helmholtz Association. + * + * Authors: + * 2017 Valerio Mariani <valerio.mariani@desy.de> + * 2017 Anton Barty <anton.barty@desy.de> + * 2017 Oleksandr Yefanov <oleksandr.yefanov@desy.de> + * + * This file is part of CrystFEL. + * + * CrystFEL is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CrystFEL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <math.h> +#include <stdlib.h> + +#include "peakfinder8.h" + + +// CrystFEL-only block 1 +struct radius_maps +{ + float **r_maps; + int n_rmaps; +}; + + +struct peakfinder_mask +{ + char **masks; + int n_masks; +}; + + +struct peakfinder_panel_data +{ + float **panel_data; + int *panel_h; + int *panel_w; + int num_panels; +}; +// End of CrystFEL-only block 1 + + +struct radial_stats +{ + float *roffset; + float *rthreshold; + float *lthreshold; + float *rsigma; + int *rcount; + int n_rad_bins; +}; + + +struct peakfinder_intern_data +{ + char *pix_in_peak_map; + int *infs; + int *inss; + int *peak_pixels; +}; + + +struct peakfinder_peak_data +{ + int num_found_peaks; + int *npix; + float *com_fs; + float *com_ss; + int *com_index; + float *tot_i; + float *max_i; + float *sigma; + float *snr; +}; + + +// CrystFEL-only block 2 +static struct radius_maps *compute_radius_maps(struct detector *det) +{ + int i, u, iss, ifs; + struct panel p; + struct radius_maps *rm = NULL; + + rm = (struct radius_maps *)malloc(sizeof(struct radius_maps)); + if ( rm == NULL ) { + return NULL; + } + + rm->r_maps = (float **)malloc(det->n_panels*sizeof(float*)); + if ( rm->r_maps == NULL ) { + free(rm); + return NULL; + } + + rm->n_rmaps = det->n_panels; + + for( i=0 ; i<det->n_panels ; i++ ) { + + p = det->panels[i]; + rm->r_maps[i] = (float *)malloc(p.h*p.w*sizeof(float)); + + if ( rm->r_maps[i] == NULL ) { + for ( u = 0; u<i; u++ ) { + free(rm->r_maps[u]); + } + free(rm); + return NULL; + } + + for ( iss=0 ; iss<p.h ; iss++ ) { + for ( ifs=0; ifs<p.w; ifs++ ) { + + int rmi; + int x,y; + + rmi = ifs + p.w * iss; + + x = (p.cnx + ifs * p.fsx + iss * p.ssx); + y = (p.cny + ifs * p.fsy + iss * p.ssy); + + rm->r_maps[i][rmi] = sqrt(x * x + y * y); + } + } + } + return rm; +} + + +static void free_radius_maps(struct radius_maps *r_maps) +{ + int i; + + for ( i=0 ; i<r_maps->n_rmaps ; i++ ) { + free(r_maps->r_maps[i]); + } + free(r_maps->r_maps); + free(r_maps); +} + + +static struct peakfinder_mask *create_peakfinder_mask(struct image *img, + struct radius_maps *rmps, + int min_res, + int max_res) +{ + int i; + struct peakfinder_mask *msk; + + msk = (struct peakfinder_mask *)malloc(sizeof(struct peakfinder_mask)); + msk->masks =(char **) malloc(img->det->n_panels*sizeof(char*)); + msk->n_masks = img->det->n_panels; + for ( i=0; i<img->det->n_panels; i++) { + + struct panel p; + int iss, ifs; + + p = img->det->panels[i]; + + msk->masks[i] = (char *)calloc(p.w*p.h,sizeof(char)); + + for ( iss=0 ; iss<p.h ; iss++ ) { + for ( ifs=0 ; ifs<p.w ; ifs++ ) { + + int idx; + + idx = ifs + iss*p.w; + + if ( rmps->r_maps[i][idx] < max_res + && rmps->r_maps[i][idx] > min_res ) { + + if (! ( ( img->bad != NULL ) + && ( img->bad[i] != NULL ) + && ( img->bad[i][idx] != 0 ) ) ) { + msk->masks[i][idx] = 1; + } + + } + } + } + } + return msk; +} + + +static void free_peakfinder_mask(struct peakfinder_mask * pfmask) +{ + int i; + + for ( i=0 ; i<pfmask->n_masks ; i++ ) { + free(pfmask->masks[i]); + } + free(pfmask->masks); + free(pfmask); +} + + +static struct peakfinder_panel_data *allocate_panel_data(int num_panels) +{ + + struct peakfinder_panel_data *pfdata; + + pfdata = (struct peakfinder_panel_data *)malloc(sizeof(struct peakfinder_panel_data)); + if ( pfdata == NULL ) { + return NULL; + } + + pfdata->panel_h = (int *)malloc(num_panels*sizeof(int)); + if ( pfdata->panel_h == NULL ) { + free(pfdata); + return NULL; + } + + pfdata->panel_w = (int *)malloc(num_panels*sizeof(int)); + if ( pfdata->panel_w == NULL ) { + free(pfdata->panel_h); + free(pfdata); + return NULL; + } + + pfdata->panel_data = (float **)malloc(num_panels*sizeof(float*)); + if ( pfdata->panel_data == NULL ) { + free(pfdata->panel_w); + free(pfdata->panel_h); + free(pfdata); + return NULL; + } + + pfdata->num_panels = num_panels; + + return pfdata; +} + + +static void free_panel_data(struct peakfinder_panel_data *pfdata) +{ + free(pfdata->panel_data); + free(pfdata->panel_w); + free(pfdata->panel_h); + free(pfdata); +} + + +static void compute_num_radial_bins(int w, int h, float *r_map, float *max_r) +{ + int ifs, iss; + int pidx; + + for ( iss=0 ; iss<h ; iss++ ) { + for ( ifs=0 ; ifs<w ; ifs++ ) { + pidx = iss * w + ifs; + if ( r_map[pidx] > *max_r ) { + *max_r = r_map[pidx]; + } + } + } +} +// End of CrystFEL-only block 2 + + +static struct radial_stats* allocate_radial_stats(int num_rad_bins) +{ + struct radial_stats* rstats; + + rstats = (struct radial_stats *)malloc(sizeof(struct radial_stats)); + if ( rstats == NULL ) { + return NULL; + } + + rstats->roffset = (float *)malloc(num_rad_bins*sizeof(float)); + if ( rstats->roffset == NULL ) { + free(rstats); + return NULL; + } + + rstats->rthreshold = (float *)malloc(num_rad_bins*sizeof(float)); + if ( rstats->rthreshold == NULL ) { + free(rstats); + free(rstats->roffset); + return NULL; + } + + rstats->lthreshold = (float *)malloc(num_rad_bins*sizeof(float)); + if ( rstats->lthreshold == NULL ) { + free(rstats); + free(rstats->rthreshold); + free(rstats->roffset); + return NULL; + } + + rstats->rsigma = (float *)malloc(num_rad_bins*sizeof(float)); + if ( rstats->rsigma == NULL ) { + free(rstats); + free(rstats->roffset); + free(rstats->rthreshold); + free(rstats->lthreshold); + return NULL; + } + + rstats->rcount = (int *)malloc(num_rad_bins*sizeof(int)); + if ( rstats->rcount == NULL ) { + free(rstats); + free(rstats->roffset); + free(rstats->rthreshold); + free(rstats->lthreshold); + free(rstats->rsigma); + return NULL; + } + + rstats->n_rad_bins = num_rad_bins; + + return rstats; +} + + +static void free_radial_stats(struct radial_stats *rstats) +{ + free(rstats->roffset); + free(rstats->rthreshold); + free(rstats->lthreshold); + free(rstats->rsigma); + free(rstats->rcount); + free(rstats); +} + + +static void fill_radial_bins(float *data, + int w, + int h, + float *r_map, + char *mask, + float *rthreshold, + float *lthreshold, + float *roffset, + float *rsigma, + int *rcount) +{ + int iss, ifs; + int pidx; + + int curr_r; + float value; + + for ( iss = 0; iss<h ; iss++ ) { + for ( ifs = 0; ifs<w ; ifs++ ) { + pidx = iss * w + ifs; + if ( mask[pidx] != 0 ) { + curr_r = (int)rint(r_map[pidx]); + value = data[pidx]; + if ( value < rthreshold[curr_r ] && value>lthreshold[curr_r]) { + roffset[curr_r] += value; + rsigma[curr_r] += (value * value); + rcount[curr_r] += 1; + } + } + } + } +} + + +static void compute_radial_stats(float *rthreshold, + float *lthreshold, + float *roffset, + float *rsigma, + int *rcount, + int num_rad_bins, + float min_snr, + float acd_threshold) +{ + int ri; + float this_offset, this_sigma; + + for ( ri=0 ; ri<num_rad_bins ; ri++ ) { + + if ( rcount[ri] == 0 ) { + roffset[ri] = 0; + rsigma[ri] = 0; + rthreshold[ri] = 1e9; + lthreshold[ri] = -1e9; + } else { + this_offset = roffset[ri] / rcount[ri]; + this_sigma = rsigma[ri] / rcount[ri] - (this_offset * this_offset); + if ( this_sigma >= 0 ) { + this_sigma = sqrt(this_sigma); + } + + roffset[ri] = this_offset; + rsigma[ri] = this_sigma; + rthreshold[ri] = roffset[ri] + min_snr*rsigma[ri]; + lthreshold[ri] = roffset[ri] - min_snr*rsigma[ri]; + + if ( rthreshold[ri] < acd_threshold ) { + rthreshold[ri] = acd_threshold; + } + } + } + +} + + +struct peakfinder_peak_data *allocate_peak_data(int max_num_peaks) +{ + struct peakfinder_peak_data *pkdata; + + pkdata = (struct peakfinder_peak_data*)malloc(sizeof(struct peakfinder_peak_data)); + if ( pkdata == NULL ) { + return NULL; + } + + pkdata->npix = (int *)malloc(max_num_peaks*sizeof(int)); + if ( pkdata->npix == NULL ) { + free(pkdata); + free(pkdata->npix); + return NULL; + } + + pkdata->com_fs = (float *)malloc(max_num_peaks*sizeof(float)); + if ( pkdata->com_fs == NULL ) { + free(pkdata->npix); + free(pkdata); + return NULL; + } + + pkdata->com_ss = (float *)malloc(max_num_peaks*sizeof(float)); + if ( pkdata->com_ss == NULL ) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata); + return NULL; + } + + pkdata->com_index = (int *)malloc(max_num_peaks*sizeof(int)); + if ( pkdata->com_ss == NULL ) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata->com_ss); + free(pkdata); + return NULL; + } + + pkdata->tot_i = (float *)malloc(max_num_peaks*sizeof(float)); + if ( pkdata->tot_i == NULL ) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata->com_ss); + free(pkdata->com_index); + free(pkdata); + return NULL; + } + + pkdata->max_i = (float *)malloc(max_num_peaks*sizeof(float)); + if ( pkdata->max_i == NULL ) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata->com_ss); + free(pkdata->com_index); + free(pkdata->tot_i); + free(pkdata); + return NULL; + } + + pkdata->sigma = (float *)malloc(max_num_peaks*sizeof(float)); + if ( pkdata->sigma == NULL ) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata->com_ss); + free(pkdata->com_index); + free(pkdata->tot_i); + free(pkdata->max_i); + free(pkdata); + return NULL; + } + + pkdata->snr = (float *)malloc(max_num_peaks*sizeof(float)); + if ( pkdata->snr == NULL ) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata->com_ss); + free(pkdata->com_index); + free(pkdata->tot_i); + free(pkdata->max_i); + free(pkdata->sigma); + free(pkdata); + return NULL; + } + + return pkdata; +} + + +static void free_peak_data(struct peakfinder_peak_data *pkdata) { + free(pkdata->npix); + free(pkdata->com_fs); + free(pkdata->com_ss); + free(pkdata->com_index); + free(pkdata->tot_i); + free(pkdata->max_i); + free(pkdata->sigma); + free(pkdata->snr); + free(pkdata); +} + + +static struct peakfinder_intern_data *allocate_peakfinder_intern_data(int data_size, + int max_pix_count) +{ + + struct peakfinder_intern_data *intern_data; + + intern_data = (struct peakfinder_intern_data *)malloc(sizeof(struct peakfinder_intern_data)); + if ( intern_data == NULL ) { + return NULL; + } + + intern_data->pix_in_peak_map =(char *)calloc(data_size, sizeof(char)); + if ( intern_data->pix_in_peak_map == NULL ) { + free(intern_data); + return NULL; + } + + intern_data->infs =(int *)calloc(data_size, sizeof(int)); + if ( intern_data->infs == NULL ) { + free(intern_data->pix_in_peak_map); + free(intern_data); + return NULL; + } + + intern_data->inss =(int *)calloc(data_size, sizeof(int)); + if ( intern_data->inss == NULL ) { + free(intern_data->pix_in_peak_map); + free(intern_data->infs); + free(intern_data); + return NULL; + } + + intern_data->peak_pixels =(int *)calloc(max_pix_count, sizeof(int)); + if ( intern_data->peak_pixels == NULL ) { + free(intern_data->pix_in_peak_map); + free(intern_data->infs); + free(intern_data->inss); + free(intern_data); + return NULL; + } + + return intern_data; +} + + +static void free_peakfinder_intern_data(struct peakfinder_intern_data *pfid) +{ + free(pfid->peak_pixels); + free(pfid->pix_in_peak_map); + free(pfid->infs); + free(pfid->inss); + free(pfid); +} + + + +static void peak_search(int p, + struct peakfinder_intern_data *pfinter, + float *copy, char *mask, float *r_map, + float *rthreshold, float *roffset, + int *num_pix_in_peak, int asic_size_fs, + int asic_size_ss, int aifs, int aiss, + int num_pix_fs, float *sum_com_fs, + float *sum_com_ss, float *sum_i, int max_pix_count) +{ + + int k, pi; + int curr_radius; + float curr_threshold; + int curr_fs; + int curr_ss; + float curr_i; + + int search_fs[9] = { 0, -1, 0, 1, -1, 1, -1, 0, 1 }; + int search_ss[9] = { 0, -1, -1, -1, 0, 0, 1, 1, 1 }; + int search_n = 9; + + // Loop through search pattern + for ( k=0; k<search_n; k++ ) { + + if ( (pfinter->infs[p] + search_fs[k]) < 0 ) continue; + if ( (pfinter->infs[p] + search_fs[k]) >= asic_size_fs ) continue; + if ( (pfinter->inss[p] + search_ss[k]) < 0 ) continue; + if ( (pfinter->inss[p] + search_ss[k]) >= asic_size_ss ) continue; + + // Neighbour point in big array + curr_fs = pfinter->infs[p] + search_fs[k] + aifs * asic_size_fs; + curr_ss = pfinter->inss[p] + search_ss[k] + aiss * asic_size_ss; + pi = curr_fs + curr_ss * num_pix_fs; + + curr_radius = (int)rint(r_map[pi]); + curr_threshold = rthreshold[curr_radius]; + + // Above threshold? + if ( copy[pi] > curr_threshold + && pfinter->pix_in_peak_map[pi] == 0 + && mask[pi] != 0 ) { + + curr_i = copy[pi] - roffset[curr_radius]; + *sum_i += curr_i; + *sum_com_fs += curr_i * ((float)curr_fs); // for center of mass x + *sum_com_ss += curr_i * ((float)curr_ss); // for center of mass y + + pfinter->inss[*num_pix_in_peak] = pfinter->inss[p] + search_ss[k]; + pfinter->infs[*num_pix_in_peak] = pfinter->infs[p] + search_fs[k]; + pfinter->pix_in_peak_map[pi] = 1; + if ( *num_pix_in_peak < max_pix_count ) { + pfinter->peak_pixels[*num_pix_in_peak] = pi; + } + *num_pix_in_peak = *num_pix_in_peak + 1; + } + } +} + + +static void search_in_ring(int ring_width, int com_fs_int, int com_ss_int, + float *copy, float *r_map, + float *rthreshold, float *roffset, + char *pix_in_peak_map, char *mask, int asic_size_fs, + int asic_size_ss, int aifs, int aiss, + int num_pix_fs,float *local_sigma, float *local_offset, + float *background_max_i, int com_idx, + int local_bg_radius) +{ + int ssj, fsi; + float pix_radius; + int curr_fs, curr_ss; + int pi; + int curr_radius; + float curr_threshold; + float curr_i; + + int np_sigma; + int np_counted; + int local_radius; + + float sum_i; + float sum_i_squared; + + ring_width = 2 * local_bg_radius; + + sum_i = 0; + sum_i_squared = 0; + np_sigma = 0; + np_counted = 0; + local_radius = 0; + + for ( ssj = -ring_width ; ssj<ring_width ; ssj++ ) { + for ( fsi = -ring_width ; fsi<ring_width ; fsi++ ) { + + // Within-ASIC check + if ( (com_fs_int + fsi) < 0 ) continue; + if ( (com_fs_int + fsi) >= asic_size_fs ) continue; + if ( (com_ss_int + ssj) < 0 ) continue; + if ( (com_ss_int + ssj) >= asic_size_ss ) + continue; + + // Within outer ring check + pix_radius = sqrt(fsi * fsi + ssj * ssj); + if ( pix_radius>ring_width ) continue; + + // Position of this point in data stream + curr_fs = com_fs_int + fsi + aifs * asic_size_fs; + curr_ss = com_ss_int + ssj + aiss * asic_size_ss; + pi = curr_fs + curr_ss * num_pix_fs; + + curr_radius = (int)rint(r_map[pi]); + curr_threshold = rthreshold[curr_radius]; + + // Intensity above background ??? just intensity? + curr_i = copy[pi]; + + // Keep track of value and value-squared for offset and sigma calculation + if ( curr_i < curr_threshold && pix_in_peak_map[pi] == 0 && mask[pi] != 0 ) { + + np_sigma++; + sum_i += curr_i; + sum_i_squared += (curr_i * curr_i); + + if ( curr_i > *background_max_i ) { + *background_max_i = curr_i; + } + } + np_counted += 1; + } + } + + // Calculate local background and standard deviation + if ( np_sigma != 0 ) { + *local_offset = sum_i / np_sigma; + *local_sigma = sum_i_squared / np_sigma - (*local_offset * *local_offset); + if (*local_sigma >= 0) { + *local_sigma = sqrt(*local_sigma); + } else { + *local_sigma = 0.01; + } + } else { + local_radius = (int)rint(r_map[(int)rint(com_idx)]); + *local_offset = roffset[local_radius]; + *local_sigma = 0.01; + } +} + + +static void process_panel(int asic_size_fs, int asic_size_ss, int num_pix_fs, + int aiss, int aifs, float *rthreshold, + float *roffset, int *peak_count, + float *copy, struct peakfinder_intern_data *pfinter, + float *r_map, char *mask, int *npix, float *com_fs, + float *com_ss, int *com_index, float *tot_i, + float *max_i, float *sigma, float *snr, + int min_pix_count, int max_pix_count, + int local_bg_radius, float min_snr, int max_n_peaks) +{ + int pxss, pxfs; + int num_pix_in_peak; + + // Loop over pixels within a module + for ( pxss=1 ; pxss<asic_size_ss-1 ; pxss++ ) { + for ( pxfs=1 ; pxfs<asic_size_fs-1 ; pxfs++ ) { + + float curr_thresh; + int pxidx; + int curr_rad; + + pxidx = (pxss + aiss * asic_size_ss) * num_pix_fs + + pxfs + aifs * asic_size_fs; + + curr_rad = (int)rint(r_map[pxidx]); + curr_thresh = rthreshold[curr_rad]; + + if ( copy[pxidx] > curr_thresh + && pfinter->pix_in_peak_map[pxidx] == 0 + && mask[pxidx] != 0 ) { //??? not sure if needed + + // This might be the start of a new peak - start searching + float sum_com_fs, sum_com_ss; + float sum_i; + float peak_com_fs, peak_com_ss; + float peak_com_fs_int, peak_com_ss_int; + float peak_tot_i, pk_tot_i_raw; + float peak_max_i, pk_max_i_raw; + float peak_snr; + float local_sigma, local_offset; + float background_max_i; + int lt_num_pix_in_pk; + int ring_width; + int peak_idx; + int com_idx; + int p; + + pfinter->infs[0] = pxfs; + pfinter->inss[0] = pxss; + pfinter->peak_pixels[0] = pxidx; + num_pix_in_peak = 0; //y 1; + + sum_i = 0; + sum_com_fs = 0; + sum_com_ss = 0; + + // Keep looping until the pixel count within this peak does not change + do { + lt_num_pix_in_pk = num_pix_in_peak; + + // Loop through points known to be within this peak + for ( p=0; p<=num_pix_in_peak; p++ ) { //changed from 1 to 0 by O.Y. + peak_search(p, + pfinter, copy, mask, + r_map, + rthreshold, + roffset, + &num_pix_in_peak, + asic_size_fs, + asic_size_ss, + aifs, aiss, + num_pix_fs, + &sum_com_fs, + &sum_com_ss, + &sum_i, + max_pix_count); + } + + } while ( lt_num_pix_in_pk != num_pix_in_peak ); + + // Too many or too few pixels means ignore this 'peak'; move on now + if ( num_pix_in_peak < min_pix_count || num_pix_in_peak > max_pix_count ) continue; + + // If for some reason sum_i is 0 - it's better to skip + if ( fabs(sum_i) < 1e-10 ) continue; + + // Calculate center of mass for this peak from initial peak search + peak_com_fs = sum_com_fs / fabs(sum_i); + peak_com_ss = sum_com_ss / fabs(sum_i); + + com_idx = (int)rint(peak_com_fs) + (int)rint(peak_com_ss) * num_pix_fs; + + peak_com_fs_int = (int)rint(peak_com_fs) - aifs * asic_size_fs; + peak_com_ss_int = (int)rint(peak_com_ss) - aiss * asic_size_ss; + + // Calculate the local signal-to-noise ratio and local background in an annulus around + // this peak (excluding pixels which look like they might be part of another peak) + local_sigma = 0.0; + local_offset = 0.0; + background_max_i = 0.0; + + ring_width = 2 * local_bg_radius; + + search_in_ring(ring_width, peak_com_fs_int, + peak_com_ss_int, + copy, r_map, rthreshold, + roffset, + pfinter->pix_in_peak_map, + mask, asic_size_fs, + asic_size_ss, + aifs, aiss, + num_pix_fs, + &local_sigma, + &local_offset, + &background_max_i, + com_idx, local_bg_radius); + + // Re-integrate (and re-centroid) peak using local background estimates + peak_tot_i = 0; + pk_tot_i_raw = 0; + peak_max_i = 0; + pk_max_i_raw = 0; + sum_com_fs = 0; + sum_com_ss = 0; + + for ( peak_idx = 0 ; + peak_idx < num_pix_in_peak && peak_idx < max_pix_count ; + peak_idx++ ) { + + int curr_idx; + float curr_i; + float curr_i_raw; + int curr_fs, curr_ss; + + curr_idx = pfinter->peak_pixels[peak_idx]; + curr_i_raw = copy[curr_idx]; + curr_i = curr_i_raw - local_offset; + peak_tot_i += curr_i; + pk_tot_i_raw += curr_i_raw; + + // Remember that curr_idx = curr_fs + curr_ss*num_pix_fs + curr_fs = curr_idx % num_pix_fs; + curr_ss = curr_idx / num_pix_fs; + sum_com_fs += curr_i * ((float)curr_fs); + sum_com_ss += curr_i * ((float)curr_ss); + + if ( curr_i_raw > pk_max_i_raw ) pk_max_i_raw = curr_i_raw; + if ( curr_i > peak_max_i ) peak_max_i = curr_i; + } + + + // This CAN happen! Better to skip... + if ( fabs(peak_tot_i) < 1e-10 ) continue; + + peak_com_fs = sum_com_fs / fabs(peak_tot_i); + peak_com_ss = sum_com_ss / fabs(peak_tot_i); + + // Calculate signal-to-noise and apply SNR criteria + if ( fabs(local_sigma) > 1e-10 ) { + peak_snr = peak_tot_i / local_sigma; + } else { + peak_snr = 0; + } + + if (peak_snr < min_snr) continue; + + // Is the maximum intensity in the peak enough above intensity in background region to + // be a peak and not noise? The more pixels there are in the peak, the more relaxed we + // are about this criterion + //f_background_thresh = background_max_i - local_offset; //!!! Ofiget'! If I uncomment + // if (peak_max_i < f_background_thresh) { // these lines the result is + // different! + if (peak_max_i < background_max_i - local_offset) continue; + + // This is a peak? If so, add info to peak list + if ( num_pix_in_peak >= min_pix_count + && num_pix_in_peak <= max_pix_count ) { + + // Bragg peaks in the mask + for ( peak_idx = 0 ; + peak_idx < num_pix_in_peak && + peak_idx < max_pix_count ; + peak_idx++ ) { + pfinter->pix_in_peak_map[pfinter->peak_pixels[peak_idx]] = 2; + } + + int peak_com_idx; + peak_com_idx = (int)rint(peak_com_fs) + (int)rint(peak_com_ss) * + num_pix_fs; + // Remember peak information + if ( *peak_count < max_n_peaks ) { + + int pidx; + pidx = *peak_count; + + npix[pidx] = num_pix_in_peak; + com_fs[pidx] = peak_com_fs; + com_ss[pidx] = peak_com_ss; + com_index[pidx] = peak_com_idx; + tot_i[pidx] = peak_tot_i; + max_i[pidx] = peak_max_i; + sigma[pidx] = local_sigma; + snr[pidx] = peak_snr; + } + *peak_count += 1; + } + } + } + } +} + + +static int peakfinder8_base(float *roffset, float *rthreshold, + float *data, char *mask, float *r_map, + int asic_size_fs, int num_asics_fs, + int asic_size_ss, int num_asics_ss, + int max_n_peaks, int *num_found_peaks, + int *npix, float *com_fs, + float *com_ss, int *com_index, float *tot_i, + float *max_i, float *sigma, float *snr, + int min_pix_count, int max_pix_count, + int local_bg_radius, float min_snr, + char* outliersMask) +{ + + int num_pix_fs, num_pix_ss, num_pix_tot; + int aifs, aiss; + int peak_count; + struct peakfinder_intern_data *pfinter; + + num_pix_fs = asic_size_fs * num_asics_fs; + num_pix_ss = asic_size_ss * num_asics_ss; + num_pix_tot = num_pix_fs * num_pix_ss; + + pfinter = allocate_peakfinder_intern_data(num_pix_tot, max_pix_count); + if ( pfinter == NULL ) { + return 1; + } + + peak_count = 0; + + // Loop over modules (nxn array) + for ( aiss=0 ; aiss<num_asics_ss ; aiss++ ) { + for ( aifs=0 ; aifs<num_asics_fs ; aifs++ ) { // ??? to change to proper panels need + process_panel(asic_size_fs, asic_size_ss, num_pix_fs, // change copy, mask, r_map + aiss, aifs, rthreshold, roffset, + &peak_count, data, pfinter, r_map, mask, + npix, com_fs, com_ss, com_index, tot_i, + max_i, sigma, snr, min_pix_count, + max_pix_count, local_bg_radius, min_snr, + max_n_peaks); + } + } + *num_found_peaks = peak_count; + + if (outliersMask != NULL) { + memcpy(outliersMask, pfinter->pix_in_peak_map, num_pix_tot*sizeof(char)); + } + + free_peakfinder_intern_data(pfinter); + + return 0; +} + + +int peakfinder8(struct image *img, int max_n_peaks, + float threshold, float min_snr, + int min_pix_count, int max_pix_count, + int local_bg_radius, int min_res, + int max_res, int use_saturated) +{ + struct radius_maps *rmaps; + struct peakfinder_mask *pfmask; + struct peakfinder_panel_data *pfdata; + struct radial_stats *rstats; + struct peakfinder_peak_data *pkdata; + int num_rad_bins; + int pi; + int i, it_counter; + int num_found_peaks; + int remaining_max_num_peaks; + int iterations; + float max_r; + + iterations = 5; + + if ( img-> det == NULL) { + return 1; + } + + rmaps = compute_radius_maps(img->det); + if ( rmaps == NULL ) { + return 1; + } + + pfmask = create_peakfinder_mask(img, rmaps, min_res, max_res); + if ( pfmask == NULL ) { + free_radius_maps(rmaps); + return 1; + } + + pfdata = allocate_panel_data(img->det->n_panels); + if ( pfdata == NULL) { + free_radius_maps(rmaps); + free_peakfinder_mask(pfmask); + return 1; + } + + for ( pi=0 ; pi<img->det->n_panels ; pi++ ) { + pfdata->panel_h[pi] = img->det->panels[pi].h; + pfdata->panel_w[pi] = img->det->panels[pi].w; + pfdata->panel_data[pi] = img->dp[pi]; + pfdata->num_panels = img->det->n_panels; + } + + max_r = -1e9; + + for ( pi=0 ; pi<pfdata->num_panels ; pi++ ) { + + compute_num_radial_bins(pfdata->panel_w[pi], + pfdata->panel_h[pi], + rmaps->r_maps[pi], + &max_r); + } + + num_rad_bins = (int)ceil(max_r) + 1; + + rstats = allocate_radial_stats(num_rad_bins); + if ( rstats == NULL ) { + free_radius_maps(rmaps); + free_peakfinder_mask(pfmask); + free_panel_data(pfdata); + return 1; + } + + for ( i=0 ; i<rstats->n_rad_bins ; i++) { + rstats->rthreshold[i] = 1e9; + } + + for ( it_counter=0 ; it_counter<iterations ; it_counter++ ) { + + for ( i=0; i<num_rad_bins; i++ ) { + rstats->roffset[i] = 0; + rstats->rsigma[i] = 0; + rstats->rcount[i] = 0; + } + + for ( pi=0 ; pi<pfdata->num_panels ; pi++ ) { + + fill_radial_bins(pfdata->panel_data[pi], + pfdata->panel_w[pi], + pfdata->panel_h[pi], + rmaps->r_maps[pi], + pfmask->masks[pi], + rstats->rthreshold, + rstats->lthreshold, + rstats->roffset, + rstats->rsigma, + rstats->rcount); + + } + + compute_radial_stats(rstats->rthreshold, + rstats->lthreshold, + rstats->roffset, + rstats->rsigma, + rstats->rcount, + num_rad_bins, + min_snr, + threshold); + + } + + pkdata = allocate_peak_data(max_n_peaks); + if ( pkdata == NULL ) { + free_radius_maps(rmaps); + free_peakfinder_mask(pfmask); + free_panel_data(pfdata); + free_radial_stats(rstats); + return 1; + } + + remaining_max_num_peaks = max_n_peaks; + + for ( pi=0 ; pi<img->det->n_panels ; pi++) { + + int peaks_to_add; + int pki; + int ret; + + num_found_peaks = 0; + + if ( img->det->panels[pi].no_index ) { + continue; + } + + ret = peakfinder8_base(rstats->roffset, + rstats->rthreshold, + pfdata->panel_data[pi], + pfmask->masks[pi], + rmaps->r_maps[pi], + pfdata->panel_w[pi], 1, + pfdata->panel_h[pi], 1, + max_n_peaks, + &num_found_peaks, + pkdata->npix, + pkdata->com_fs, + pkdata->com_ss, + pkdata->com_index, + pkdata->tot_i, + pkdata->max_i, + pkdata->sigma, + pkdata->snr, + min_pix_count, + max_pix_count, + local_bg_radius, + min_snr, + NULL); + + if ( ret != 0 ) { + free_radius_maps(rmaps); + free_peakfinder_mask(pfmask); + free_panel_data(pfdata); + free_radial_stats(rstats); + return 1; + } + + peaks_to_add = num_found_peaks; + + if ( num_found_peaks > remaining_max_num_peaks ) { + peaks_to_add = remaining_max_num_peaks; + } + + remaining_max_num_peaks -= peaks_to_add; + + for ( pki=0 ; pki<peaks_to_add ; pki++ ) { + + struct panel *p; + + p = &img->det->panels[pi]; + + img->num_peaks += 1; + if ( pkdata->max_i[pki] > p->max_adu ) { + img->num_saturated_peaks++; + if ( !use_saturated ) { + continue; + } + } + + image_add_feature(img->features, + pkdata->com_fs[pki]+0.5, + pkdata->com_ss[pki]+0.5, + p, + img, + pkdata->tot_i[pki], + NULL); + } + } + + free_radius_maps(rmaps); + free_peakfinder_mask(pfmask); + free_panel_data(pfdata); + free_radial_stats(rstats); + free_peak_data(pkdata); + return 0; +} |