aboutsummaryrefslogtreecommitdiff
path: root/src/find_peaks.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/find_peaks.c')
-rw-r--r--src/find_peaks.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/find_peaks.c b/src/find_peaks.c
new file mode 100644
index 0000000..e3a2fc6
--- /dev/null
+++ b/src/find_peaks.c
@@ -0,0 +1,141 @@
+#include "find_peaks.h"
+#include "vector.h"
+#include "event.h"
+#include "pmt.h"
+#include <stddef.h> /* for size_t */
+#include <stdlib.h> /* for malloc() */
+#include "optics.h"
+#include <math.h> /* for exp() */
+
+void find_peaks_array(double *x, size_t n, size_t m, size_t *imax, size_t *jmax, size_t *npeaks, size_t max_peaks, double threshold)
+{
+ /* Find a maximum of `max_peaks` in the 2D array `x` indexed as:
+ *
+ * x[i,j] = x[i*m + j]
+ *
+ * and store the indices in the two arrays `imax` and `jmax`.
+ *
+ * Peaks are defined as any array element which is greater than all 8 of
+ * it's neighbors. Peaks are also required to be at least max*threshold
+ * times as high as the highest peak. */
+ size_t i, j;
+ double max;
+
+ if (n*m == 0) {
+ *npeaks = 0;
+ return;
+ }
+
+ /* First, find the highest value in the array (which is guaranteed to be a peak). */
+ max = x[0];
+ imax[0] = 0;
+ jmax[0] = 0;
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < m; j++) {
+ if (x[i*m + j] > max) {
+ max = x[i*m + j];
+ imax[0] = i;
+ jmax[0] = j;
+ }
+ }
+ }
+
+ *npeaks = 1;
+
+ /* Now we look for other peaks which are at least max*threshold high. */
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < m; j++) {
+ if (x[i*m + j] <= max*threshold) continue;
+
+ if (i == imax[0] && j == jmax[0]) continue;
+
+ /* Check to see if it is actually a peak. */
+ if (x[i*m + (j+1) % m] < x[i*m + j] && /* 0 +1 */
+ x[i*m + (j+m-1) % m] < x[i*m + j] && /* 0 -1 */
+ x[((i+1) % n)*m + j] < x[i*m + j] && /* +1 0 */
+ x[((i+1) % n)*m + (j+1) % m] < x[i*m + j] && /* +1 +1 */
+ x[((i+1) % n)*m + (j+m-1) % m] < x[i*m + j] && /* +1 -1 */
+ x[((i+n-1) % n)*m + j] < x[i*m + j] && /* -1 0 */
+ x[((i+n-1) % n)*m + (j+1) % m] < x[i*m + j] && /* -1 +1 */
+ x[((i+n-1) % n)*m + (j+m-1) % m] < x[i*m + j]) { /* -1 -1 */
+ imax[*npeaks] = i;
+ jmax[*npeaks] = j;
+ *npeaks += 1;
+
+ if (*npeaks >= max_peaks) goto end;
+ }
+ }
+ }
+
+end:
+ return;
+}
+
+void get_hough_transform(event *ev, double *pos, double *x, double *y, size_t n, size_t m, double *result)
+{
+ /* Computes the "Hough transform" of the event `ev` and stores it in `result`. */
+ size_t i, j, k;
+ double dir[3], pmt_dir[3], cos_theta;
+
+ double wavelength0 = 400.0;
+ double n_d2o = get_index_snoman_d2o(wavelength0);
+
+ for (i = 0; i < MAX_PMTS; i++) {
+ if (pmts[i].pmt_type != PMT_NORMAL || !ev->pmt_hits[i].hit) continue;
+
+ SUB(pmt_dir,pmts[i].pos,pos);
+
+ normalize(pmt_dir);
+
+ for (j = 0; j < n; j++) {
+ for (k = 0; k < m; k++) {
+ double r = 1+x[j]*x[j]+y[k]*y[k];
+ dir[0] = 2*x[j]/r;
+ dir[1] = 2*y[k]/r;
+ dir[2] = (-1+x[j]*x[j]+y[k]*y[k])/r;
+
+ cos_theta = DOT(pmt_dir,dir);
+
+ result[j*m + k] += ev->pmt_hits[i].qhs*exp(-fabs(cos_theta-1.0/n_d2o)/0.1);
+ }
+ }
+ }
+}
+
+void find_peaks(event *ev, double *pos, size_t n, size_t m, double *peak_theta, double *peak_phi, size_t *npeaks, size_t max_peaks, double threshold)
+{
+ size_t i;
+
+ double *x = calloc(n,sizeof(double));
+ double *y = calloc(m,sizeof(double));
+ double *result = calloc(n*m,sizeof(double));
+
+ for (i = 0; i < n; i++) {
+ x[i] = -10 + 20.0*i/(n-1);
+ }
+
+ for (i = 0; i < m; i++) {
+ y[i] = -10 + 20.0*i/(m-1);
+ }
+
+ get_hough_transform(ev,pos,x,y,n,m,result);
+
+ size_t *imax = calloc(max_peaks,sizeof(size_t));
+ size_t *jmax = calloc(max_peaks,sizeof(size_t));
+
+ find_peaks_array(result,n,m,imax,jmax,npeaks,max_peaks,threshold);
+
+ for (i = 0; i < *npeaks; i++) {
+ double R, theta;
+ R = sqrt(x[imax[i]]*x[imax[i]]+y[jmax[i]]*y[jmax[i]]);
+ theta = atan2(y[jmax[i]],x[imax[i]]);
+ peak_theta[i] = 2*atan(1/R);
+ peak_phi[i] = theta;
+ }
+
+ free(imax);
+ free(jmax);
+ free(x);
+ free(y);
+ free(result);
+}