aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/Makefile8
-rw-r--r--src/find_peaks.c141
-rw-r--r--src/find_peaks.h11
-rw-r--r--src/likelihood.c1
-rw-r--r--src/test-find-peaks.c229
-rw-r--r--src/test.c69
7 files changed, 457 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 9820f10..5cc83f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,3 +12,4 @@
*.nav
*.snm
*.toc
+test-find-peaks
diff --git a/src/Makefile b/src/Makefile
index 9739428..d8dfdca 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,7 +3,7 @@ release_hdr := $(shell sh -c './mkreleasehdr.sh')
CFLAGS=-O2 -Wall -g -DSWAP_BYTES
LDLIBS=-lm -lgsl -lgslcblas -lnlopt_cxx -lstdc++
-all: test test-vector test-likelihood fit test-charge test-path calculate-csda-range test-time-pdf test-zebra
+all: test test-vector test-likelihood fit test-charge test-path calculate-csda-range test-time-pdf test-zebra test-find-peaks
Makefile.dep:
-$(CC) -MM *.c > Makefile.dep
@@ -14,7 +14,7 @@ calculate_limits: calculate_limits.c
solid_angle.o: solid_angle.c
-test: test.o solid_angle.o optics.o muon.o vector.o quantum_efficiency.o pdg.o scattering.o misc.o mt19937ar.o sno_charge.o path.o random.o pmt_response.o db.o dict.o siphash.o electron.o proton.o likelihood.o pmt.o quad.o
+test: test.o solid_angle.o optics.o muon.o vector.o quantum_efficiency.o pdg.o scattering.o misc.o mt19937ar.o sno_charge.o path.o random.o pmt_response.o db.o dict.o siphash.o electron.o proton.o likelihood.o pmt.o quad.o find_peaks.o
test-vector: test-vector.o vector.o mt19937ar.o
@@ -28,7 +28,9 @@ test-time-pdf: test-time-pdf.o zebra.o likelihood.o pmt.o vector.o misc.o muon.o
test-zebra: test-zebra.o zebra.o pack2b.o
-fit: fit.o zebra.o likelihood.o pmt.o vector.o misc.o muon.o optics.o quantum_efficiency.o solid_angle.o pdg.o scattering.o zdab_utils.o pack2b.o sno_charge.o db.o dqxx.o dict.o siphash.o path.o pmt_response.o release.o electron.o proton.o
+fit: fit.o zebra.o likelihood.o pmt.o vector.o misc.o muon.o optics.o quantum_efficiency.o solid_angle.o pdg.o scattering.o zdab_utils.o pack2b.o sno_charge.o db.o dqxx.o dict.o siphash.o path.o pmt_response.o release.o electron.o proton.o find_peaks.o
+
+test-find-peaks: test-find-peaks.o zebra.o likelihood.o pmt.o vector.o misc.o muon.o optics.o quantum_efficiency.o solid_angle.o pdg.o scattering.o zdab_utils.o pack2b.o sno_charge.o db.o dqxx.o dict.o siphash.o path.o pmt_response.o release.o electron.o proton.o find_peaks.o
calculate-csda-range: calculate-csda-range.o
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);
+}
diff --git a/src/find_peaks.h b/src/find_peaks.h
new file mode 100644
index 0000000..2abf6fe
--- /dev/null
+++ b/src/find_peaks.h
@@ -0,0 +1,11 @@
+#ifndef FIND_PEAKS
+#define FIND_PEAKS
+
+#include "event.h"
+#include <stddef.h> /* for size_t */
+
+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);
+void get_hough_transform(event *ev, double *pos, double *x, double *y, size_t n, size_t m, double *result);
+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);
+
+#endif
diff --git a/src/likelihood.c b/src/likelihood.c
index 64f28d4..da0614d 100644
--- a/src/likelihood.c
+++ b/src/likelihood.c
@@ -22,6 +22,7 @@
#include "proton.h"
#include "id_particles.h"
#include <gsl/gsl_cdf.h>
+#include "find_peaks.h"
particle *particle_init(int id, double T0, size_t n)
{
diff --git a/src/test-find-peaks.c b/src/test-find-peaks.c
new file mode 100644
index 0000000..c7c2c1d
--- /dev/null
+++ b/src/test-find-peaks.c
@@ -0,0 +1,229 @@
+#include <stdio.h>
+#include "find_peaks.h"
+#include "misc.h"
+#include "zebra.h"
+#include "zdab_utils.h"
+#include <stddef.h> /* for size_t */
+#include <unistd.h> /* for exit() */
+#include "pmt.h"
+#include <math.h> /* for M_PI */
+#include <errno.h> /* for errno */
+#include <string.h> /* for strerror() */
+
+#define EV_RECORD 0x45562020
+#define MCTK_RECORD 0x4d43544b
+#define MCVX_RECORD 0x4d435658
+
+void plot_3d(double *x, double *y, double *z, size_t n, size_t m)
+{
+ size_t i, j;
+
+ FILE *pipe = popen("gnuplot -p", "w");
+
+ if (!pipe) {
+ fprintf(stderr, "error running gnuplot command: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ fprintf(pipe, "set title 'Hough Transform'\n");
+ /* Not entirely sure what these do, but following the instructions from
+ * http://lowrank.net/gnuplot/plot3d2-e.html. */
+ fprintf(pipe, "set dgrid3d %zu,%zu\n",n,m);
+ fprintf(pipe, "set hidden3d\n");
+ fprintf(pipe, "set contour\n");
+ fprintf(pipe, "splot '-' u 1:2:3 with lines\n");
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < m; j++) {
+ fprintf(pipe, "%.10g %.10g %.10g\n", x[i], y[j], z[i*m+j]);
+ }
+ }
+ fprintf(pipe,"e\n");
+
+ /* Pause so that you can rotate the 3D graph. */
+ fprintf(pipe,"pause mouse keypress\n");
+
+ if (pclose(pipe)) {
+ fprintf(stderr, "error closing gnuplot command: %s\n", strerror(errno));
+ exit(1);
+ }
+}
+
+int get_event(zebraFile *f, event *ev, bank *b)
+{
+ /* Read all the PMT banks from the zebra file and update `ev`.
+ *
+ * Returns the last return value from get_bank(). */
+ int i, rv;
+ PMTBank bpmt;
+ int id, crate, card, channel;
+
+ for (i = 0; i < MAX_PMTS; i++) {
+ ev->pmt_hits[i].hit = 0;
+ }
+
+ while (1) {
+ rv = next_bank(f, b);
+
+ if (rv == -1) {
+ break;
+ } else if (rv == 1) {
+ /* EOF */
+ break;
+ }
+
+ switch (b->name) {
+ case PMT_RECORD:
+ unpack_pmt(b->data, &bpmt);
+ card = bpmt.pin/1024;
+ crate = (bpmt.pin % 1024)/32;
+ channel = bpmt.pin % 32;
+ id = crate*512 + card*32 + channel;
+ ev->pmt_hits[id].hit = 1;
+ ev->pmt_hits[id].t = bpmt.pt;
+ ev->pmt_hits[id].qhl = bpmt.phl;
+ ev->pmt_hits[id].qhs = bpmt.phs;
+ ev->pmt_hits[id].qlx = bpmt.plx;
+ ev->pmt_hits[id].flags |= bpmt.pf & KPF_DIS;
+ break;
+ case EV_RECORD:
+ case MAST_RECORD:
+ goto end;
+ }
+ }
+
+end:
+
+ return rv;
+}
+
+void usage(void)
+{
+ fprintf(stderr,"Usage: ./test-find-peaks [options] FILENAME\n");
+ fprintf(stderr," --plot plot hough transform\n");
+ fprintf(stderr," -h display this help message\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+ char *filename = NULL;
+ zebraFile *f;
+ bank b;
+ EVBank bev;
+ event ev = {0};
+ int rv;
+ MCVXBank bmcvx;
+ double pos[3];
+ double peak_theta[10];
+ double peak_phi[10];
+ size_t npeaks;
+ int plot = 0;
+
+ for (i = 1; i < argc; i++) {
+ if (strlen(argv[i]) >= 2 && !strncmp(argv[i], "--", 2)) {
+ if (!strcmp(argv[i]+2,"plot")) {
+ plot = 1;
+ continue;
+ }
+ } else if (argv[i][0] == '-') {
+ switch (argv[i][1]) {
+ case 'h':
+ usage();
+ default:
+ fprintf(stderr, "unrecognized option '%s'\n", argv[i]);
+ exit(1);
+ }
+ } else {
+ filename = argv[i];
+ }
+ }
+
+ if (!filename)
+ usage();
+
+ load_pmt_info();
+
+ f = zebra_open(filename);
+
+ if (!f) {
+ fprintf(stderr, "%s\n", zebra_err);
+ return 1;
+ }
+
+ int skip = 0;
+ while (1) {
+ if (!skip)
+ rv = next_bank(f, &b);
+
+ skip = 0;
+
+ if (rv == -1) {
+ fprintf(stderr, "error getting bank: %s\n", zebra_err);
+ goto err;
+ } else if (rv == 1) {
+ /* EOF */
+ break;
+ }
+
+ switch (b.name) {
+ case MCVX_RECORD:
+ /* New MC vertex. */
+ if (b.status & KMCVX_CRE) {
+ unpack_mcvx(b.data, &bmcvx);
+ }
+ break;
+ case EV_RECORD:
+ unpack_ev(b.data, &bev);
+ ev.run = bev.run;
+ ev.gtid = bev.gtr_id;
+
+ rv = get_event(f,&ev,&b);
+
+ pos[0] = bmcvx.x;
+ pos[1] = bmcvx.y;
+ pos[2] = bmcvx.z;
+
+ size_t n = 100;
+ size_t m = 100;
+
+ 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);
+
+ find_peaks(&ev,pos,n,m,peak_theta,peak_phi,&npeaks,LEN(peak_theta),0.5);
+
+ printf("gtid %i\n", ev.gtid);
+ for (i = 0; i < npeaks; i++) {
+ printf("%.2f %.2f\n", peak_theta[i], peak_phi[i]);
+ }
+
+ if (plot)
+ plot_3d(x,y,result,n,m);
+
+ /* Skip reading in the next bank since get_event() already read in
+ * the next bank. */
+ skip = 1;
+ }
+ }
+
+ zebra_close(f);
+
+ return 0;
+
+err:
+ zebra_close(f);
+
+ return 1;
+}
diff --git a/src/test.c b/src/test.c
index d7839dc..b1fbc34 100644
--- a/src/test.c
+++ b/src/test.c
@@ -24,6 +24,7 @@
#include <gsl/gsl_cdf.h>
#include "sno.h"
#include "quad.h"
+#include "find_peaks.h"
typedef int testFunction(char *err);
@@ -1566,6 +1567,73 @@ err:
return 1;
}
+int test_find_peaks_array(char *err)
+{
+ /* Tests the find_peaks_array() function. */
+ size_t i;
+ double x[4] = {0,1,0,0};
+ size_t imax[10], jmax[10], npeaks;
+
+ find_peaks_array(x,2,2,imax,jmax,&npeaks,LEN(imax),0.1);
+
+ if (npeaks != 1) {
+ sprintf(err, "number of peaks = %zu, but expected %i", npeaks, 1);
+ return 1;
+ }
+
+ if (imax[0] != 0) {
+ sprintf(err, "imax[0] = %zu, but expected %i", imax[0], 0);
+ return 1;
+ }
+
+ if (jmax[0] != 1) {
+ sprintf(err, "jmax[0] = %zu, but expected %i", jmax[0], 1);
+ return 1;
+ }
+
+ double y[10][10] = {
+ {0,0,2,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {4,0,0,0,0,0,0,0,0,5},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0},
+ {0,0,3,0,0,0,0,0,0,0},
+ };
+
+ find_peaks_array(y,10,10,imax,jmax,&npeaks,LEN(imax),0.1);
+
+ if (npeaks != 2) {
+ sprintf(err, "number of peaks = %zu, but expected %i", npeaks, 2);
+ return 1;
+ }
+
+ if (imax[0] != 2) {
+ sprintf(err, "imax[0] = %zu, but expected %i", imax[0], 2);
+ return 1;
+ }
+
+ if (jmax[0] != 9) {
+ sprintf(err, "jmax[0] = %zu, but expected %i", jmax[0], 9);
+ return 1;
+ }
+
+ if (imax[1] != 9) {
+ sprintf(err, "imax[1] = %zu, but expected %i", imax[1], 9);
+ return 1;
+ }
+
+ if (jmax[1] != 2) {
+ sprintf(err, "jmax[1] = %zu, but expected %i", jmax[1], 2);
+ return 1;
+ }
+
+ return 0;
+}
+
struct tests {
testFunction *test;
char *name;
@@ -1606,6 +1674,7 @@ struct tests {
{test_time_cdf, "test_time_cdf"},
{test_quad, "test_quad"},
{test_quad_noise, "test_quad_noise"},
+ {test_find_peaks_array, "test_find_peaks_array"},
};
int main(int argc, char **argv)