aboutsummaryrefslogtreecommitdiff
path: root/utils/print-event-rate
blob: 6350ea8563027d4c146d31312a3f638259b8defd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/usr/bin/env python
# Copyright (c) 2019, Anthony Latorre <tlatorre at uchicago>
#
# This program 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.
#
# This program 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
# this program. If not, see <https://www.gnu.org/licenses/>.
"""
Script to print the event rate per year for different neutrino interactions. It
works by reading the MCPL files produced by GENIE to determine the number of
neutrino interactions and dividing by the livetime in the autosno run_info.log
file. To run it, just run:

    $ ./print-event-rate /path/to/mcpl/files/*.dat.gz --run-info /path/to/autosno/log/run_info.log

which will print out a latex style table of the event rates.
"""
from __future__ import print_function, division
import numpy as np
import pandas as pd
from sddm import read_hdf, AV_RADIUS, PSUP_RADIUS
import gzip
from sddm.renormalize import *

def get_mcgn(filename):
    ev = read_hdf(filename, "ev")
    mcgn = read_hdf(filename, "mcgn").assign(run=ev.run[0])
    mcgn = mcgn.groupby(['run','evn']).first().reset_index()
    return mcgn

if __name__ == '__main__':
    import argparse
    import sys
    from os.path import join, split
    from sddm import *

    parser = argparse.ArgumentParser("recreate MCPL files")
    parser.add_argument("filenames", nargs='+', help="mcpl filenames")
    parser.add_argument("--run-info", required=True, help="run_info.log autosno file")
    args = parser.parse_args()

    cc_av = {nu: 0 for nu in range(30,36)}
    cc_psup = {nu: 0 for nu in range(30,36)}
    nc_av = {nu: 0 for nu in range(30,36)}
    nc_psup = {nu: 0 for nu in range(30,36)}
    livetime = 0.0
    run_info = np.genfromtxt(args.run_info,usecols=range(4),dtype=(np.int,np.int,np.double,np.double))
    for filename in args.filenames:
        head, tail = split(filename)
        try:
            mcpl = read_mcpl_df(filename)
        except Exception as e:
            print_warning("failed to read mcpl file '%s'" % filename)
            continue
        run = int(tail.split('_')[3])
        for _, row in mcpl.iterrows():
            nu = row['nu_id']
            r = row['nu_r']
            if r < AV_RADIUS:
                if not row['cc']:
                    # nc event
                    nc_av[nu] += row['flux_weight']
                else:
                    # cc event
                    cc_av[nu] += row['flux_weight']
            if r < PSUP_RADIUS:
                if not row['cc']:
                    # nc event
                    nc_psup[nu] += row['flux_weight']
                else:
                    # cc event
                    cc_psup[nu] += row['flux_weight']
        for i in range(run_info.shape[0]):
            if run_info[i][0] == run:
                livetime += run_info[i][3]

    for nu in range(30,36):
        cc_av[nu] *= 3600*24*365/livetime/100
        cc_psup[nu] *= 3600*24*365/livetime/100
        nc_av[nu] *= 3600*24*365/livetime/100
        nc_psup[nu] *= 3600*24*365/livetime/100

    for nu in range(30,36):
        line = [cc_av[nu],nc_av[nu],
                cc_av[nu]+nc_av[nu],
                cc_psup[nu],nc_psup[nu],
                cc_psup[nu]+nc_psup[nu]]
        print(' & '.join(["%.1f" % rate for rate in line]))
class="p">)/(2*a*h*sqrt((u-h*h)*(u+a*a)))); } double get_solid_angle_approx(double *pos, double *pmt, double *n, double r) { /* Returns the approximate solid angle subtended by a circular disk of * radius r at a position `pmt` with a normal vector `n` from a position * `pos`. * * This approximation comes from calculating the solid angle subtended by a * square of equal area, which has a closed form solution. For certain * regimes, the approximation is not very good and so it is modified by a * correction factor which comes from a lookup table. * * This formula comes from "The Solid Angle Subtended at a Point by a * Circular Disk." Gardener et al. 1969. */ double dir[3]; double h, r0, D, a, u1, u2, F; static gsl_spline2d *spline; static gsl_interp_accel *xacc; static gsl_interp_accel *yacc; dir[0] = pos[0] - pmt[0]; dir[1] = pos[1] - pmt[1]; dir[2] = pos[2] - pmt[2]; h = fabs(dir[0]*n[0] + dir[1]*n[1] + dir[2]*n[2]); D = sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); r0 = sqrt(D*D - h*h); a = sqrt(M_PI)*r/2; u1 = h*h + pow(r0-a,2); u2 = h*h + pow(r0+a,2); F = 1.0; if (h/D > 0.1 && h/D < 1.0 && r/D > 0.1 && r/D < 2.0) { if (!spline) { spline = gsl_spline2d_alloc(gsl_interp2d_bilinear, LEN(hd), LEN(Rd)); gsl_spline2d_init(spline, hd, Rd, (double *) lookupTable, LEN(hd), LEN(Rd)); } if (!xacc) xacc = gsl_interp_accel_alloc(); if (!yacc) yacc = gsl_interp_accel_alloc(); F = gsl_spline2d_eval(spline,h/D,r/D,xacc,yacc); } if (r0 < a) { return F*(A(u1,a,h) + A(u2,a,h) + M_PI); } else { return F*(A(u2,a,h) - A(u1,a,h)); } } double get_solid_angle2(double L2, double r2) { double k = 2*sqrt(r2/(pow(L2,2)+pow(1+r2,2))); double a2 = 4*r2/pow(1+r2,2); double L_Rmax = L2/sqrt(pow(L2,2)+pow(1+r2,2)); double r0_r = (r2-1)/(r2+1); double K, P; if (fabs(r2-1) < 1e-5) { /* If r0 is very close to r, the GSL routines below will occasionally * throw a domain error. */ K = gsl_sf_ellint_Kcomp(k, GSL_PREC_DOUBLE); return M_PI - 2*L_Rmax*K; } else if (r2 <= 1) { K = gsl_sf_ellint_Kcomp(k, GSL_PREC_DOUBLE); P = gsl_sf_ellint_Pcomp(k, -a2, GSL_PREC_DOUBLE); return 2*M_PI - 2*L_Rmax*K + (2*L_Rmax)*r0_r*P; } else { K = gsl_sf_ellint_Kcomp(k, GSL_PREC_DOUBLE); P = gsl_sf_ellint_Pcomp(k, -a2, GSL_PREC_DOUBLE); return -2*L_Rmax*K + (2*L_Rmax)*r0_r*P; } } double get_solid_angle_lookup(double L2, double r2) { size_t i, j; static int initialized = 0; static double xs[1000]; static double ys[1000]; static double zs[1000*1000]; static double xlo = 0.0; static double xhi = 1000; static double ylo = 0.0; static double yhi = 1000; if (!initialized) { for (i = 0; i < LEN(xs); i++) { xs[i] = xlo + (xhi-xlo)*i/(LEN(xs)-1); } for (i = 0; i < LEN(ys); i++) { ys[i] = ylo + (yhi-ylo)*i/(LEN(ys)-1); } for (i = 0; i < LEN(xs); i++) { for (j = 0; j < LEN(ys); j++) { zs[i*LEN(ys) + j] = get_solid_angle2(xs[i],ys[j]); } } initialized = 1; } if (L2 < xlo || L2 > xhi || r2 < ylo || r2 > yhi) { /* If the arguments are out of bounds of the lookup table, just call * get_solid_angle2(). */ return get_solid_angle2(L2,r2); } return interp2d(L2,r2,xs,ys,zs,LEN(xs),LEN(ys)); } double get_solid_angle_fast(double *pos, double *pmt, double *n, double r) { double dir[3]; double L, r0, R2; dir[0] = pos[0] - pmt[0]; dir[1] = pos[1] - pmt[1]; dir[2] = pos[2] - pmt[2]; L = fabs(DOT(dir,n)); R2 = DOT(dir,dir); r0 = sqrt(R2 - L*L); return get_solid_angle_lookup(L/r,r0/r); } double get_solid_angle(double *pos, double *pmt, double *n, double r) { /* Returns the solid angle subtended by a circular disk of radius r at a * position `pmt` with a normal vector `n` from a position `pos`. * * See http://www.umich.edu/~ners312/CourseLibrary/SolidAngleOfADiskOffAxis.pdf. */ double dir[3]; double L, r0, R, a2, k, Rmax, K, P; dir[0] = pos[0] - pmt[0]; dir[1] = pos[1] - pmt[1]; dir[2] = pos[2] - pmt[2]; L = fabs(dir[0]*n[0] + dir[1]*n[1] + dir[2]*n[2]); R = sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); r0 = sqrt(R*R - L*L); a2 = 4*r0*r/pow(r0+r,2); Rmax = sqrt(L*L + (r0+r)*(r0+r)); k = sqrt(4*r0*r/(L*L + pow(r0+r,2))); if (fabs(r0-r) < 1e-5) { /* If r0 is very close to r, the GSL routines below will occasionally * throw a domain error. */ K = gsl_sf_ellint_Kcomp(k, GSL_PREC_DOUBLE); return M_PI - 2*L*K/Rmax; } else if (r0 <= r) { K = gsl_sf_ellint_Kcomp(k, GSL_PREC_DOUBLE); P = gsl_sf_ellint_Pcomp(k, -a2, GSL_PREC_DOUBLE); return 2*M_PI - 2*L*K/Rmax + (2*L/Rmax)*(r0-r)*P/(r0+r); } else { K = gsl_sf_ellint_Kcomp(k, GSL_PREC_DOUBLE); P = gsl_sf_ellint_Pcomp(k, -a2, GSL_PREC_DOUBLE); return -2*L*K/Rmax + (2*L/Rmax)*(r0-r)*P/(r0+r); } }