コード例 #1
0
def calculate_flux(energies, veffs, stations=1, years=1):
    """Calculate flux (m^-2 s^-1 sr^-1 GeV^-1) for energies in GeV and veffs in km3sr and livetime in years"""
    energies = np.asarray(energies)
    veffs = np.asarray(veffs)

    # Get number of energy bins per decade
    log_energy = np.log10(energies)
    d_log_energy = np.diff(log_energy)
    for d_log in d_log_energy:
        if not np.isclose(d_log, d_log_energy[0]):
            raise ValueError("Energies should be evenly spaced in log-10-space")
    bins_per_decade = 1/d_log_energy[0]

    # Get average interaction lengths (harmonic mean, since average should be in cross section)
    int_len = np.zeros(len(energies))
    for i, e in enumerate(energies):
        nu = pyrex.Particle('nu_e', (0, 0, 0), (0, 0, -1), e)
        nubar = pyrex.Particle('nu_e_bar', (0, 0, 0), (0, 0, -1), e)
        avg_int = 2/((1/nu.interaction.total_interaction_length)+(1/nubar.interaction.total_interaction_length))
        int_len[i] = avg_int # cmwe

    # Get effective area
    ice_density = 0.92 # g/cm^3
    ice_density *= 1e15 # convert to g/km^3 = nucleons/km^3
    aeffs = veffs * ice_density / int_len # cm^2 sr
    aeffs *= 1e-4 # convert to m^2 sr

    aeff_tots = aeffs * stations * (years * 365.25 * 24 * 60 * 60)

    # Upper limit on events
    # 2.3 for Neyman UL w/ 0 background,
    # 2.44 for F-C UL w/ 0 background, etc
    upper_limit = 2.44

    return upper_limit / aeff_tots * bins_per_decade / np.log(10) / energies
コード例 #2
0
def test_filter_attenuation():
    # filtered_spectrum = self.spectrum
    # responses = np.array(freq_response(self.frequencies))
    # filtered_spectrum *= responses
    # self.values = np.real(scipy.fftpack.ifft(filtered_spectrum))

    # freq_response = pf.attenuation
    # self = AskaryanSignal(times=np.linspace(-20e-9, 80e-9, 2048, endpoint=False),
    #                       energy=p.energy*1e-3, theta=psi, n=n)
    t = 0

    pf = pyrex.PathFinder(pyrex.IceModel(), (0,0,-2800), (5000,5000,-200))
    while not(pf.exists):
        z = np.random.random()*-2800
        pf = pyrex.PathFinder(pyrex.IceModel(), (0,0,z), (5000,5000,-200))

    p = pyrex.Particle(vertex=pf.from_point,
                       direction=(1/np.sqrt(2),1/np.sqrt(2),0), energy=1e6)

    k = pf.emitted_ray
    epol = np.vdot(k, p.direction) * k - p.direction
    epol = epol / np.linalg.norm(epol)
    psi = np.arccos(np.vdot(p.direction, k))
    n = pyrex.IceModel.index(p.vertex[2])

    pulse = pyrex.AskaryanSignal(times=np.linspace(-20e-9, 80e-9, 2048, endpoint=False),
                                 energy=p.energy, theta=psi, n=n)

    t += performance_test("filtered_spectrum = pulse.spectrum", number=1000,
                          use_globals={"pulse": pulse})

    t += performance_test("fs = pulse.frequencies", number=1000,
                          use_globals={"pulse": pulse})

    fs = pulse.frequencies

    # performance_test("alen = ice.attenuation_length(-1000, fa*1e-6)", number=100,
    #                  use_globals={"ice": pyrex.IceModel(), "fa": np.abs(fs)})

    t += performance_test("responses = freq_response(fs)", number=1000,
                          use_globals={"freq_response": pf.attenuation, "fs": fs})

    # t += performance_test("responses = np.array(freq_response(pulse.frequencies))",
    #                       number = 100, setup="import numpy as np",
    #                       use_globals={"freq_response": pf.attenuation,
    #                                    "pulse": pulse})

    filtered_spectrum = pulse.spectrum * np.array(pf.attenuation(pulse.frequencies))

    t += performance_test("np.real(scipy.fftpack.ifft(filtered_spectrum))",
                          number=1000, setup="import numpy as np; import scipy.fftpack",
                          use_globals={"filtered_spectrum": filtered_spectrum})

    print("Total time:", round(t*1000, 1), "milliseconds for", len(fs), "frequencies")
    print("           ", round(t*1e6/len(fs), 1), "microseconds per frequency")
コード例 #3
0
 def get_good_path():
     z = np.random.random() * -2800
     p = pyrex.Particle(vertex=(0,0,z), direction=(0,0,1), energy=energy)
     pf = pyrex.PathFinder(ice, p.vertex, ant.position)
     k = pf.emitted_ray
     epol = np.vdot(k, p.direction) * k - p.direction
     epol = epol / np.linalg.norm(epol)
     psi = np.arccos(np.vdot(p.direction, k))
     if pf.exists and psi<np.pi/2:
         return p, pf, psi
     else:
         return get_good_path()
コード例 #4
0
def test_PathFinder_propagate():
    t = 0

    pf = pyrex.PathFinder(pyrex.IceModel(), (0,0,-2800), (5000,5000,-200))
    while not(pf.exists):
        z = np.random.random()*-2800
        pf = pyrex.PathFinder(pyrex.IceModel(), (0,0,z), (5000,5000,-200))

    p = pyrex.Particle(vertex=pf.from_point,
                       direction=(1/np.sqrt(2),1/np.sqrt(2),0), energy=1e6)

    k = pf.emitted_ray
    epol = np.vdot(k, p.direction) * k - p.direction
    epol = epol / np.linalg.norm(epol)
    psi = np.arccos(np.vdot(p.direction, k))
    n = pyrex.IceModel.index(p.vertex[2])

    pulse = pyrex.AskaryanSignal(times=np.linspace(-20e-9, 80e-9, 2048, endpoint=False),
                                 energy=p.energy, theta=psi, n=n)

    t += performance_test("signal.values *= 1 / pf.path_length", repeats=100,
                          setup="import pyrex;"+
                                "signal = pyrex.Signal(pulse.times, pulse.values)",
                          use_globals={"pf": pf, "pulse": pulse})

    pulse.values *= 1 / pf.path_length

    t += performance_test("signal.filter_frequencies(pf.attenuation)", repeats=100,
                          setup="import pyrex;"+
                                "signal = pyrex.Signal(pulse.times, pulse.values)",
                          use_globals={"pf": pf, "pulse": pulse})

    # pulse.filter_frequencies(pf.attenuation)

    t += performance_test("signal.times += pf.tof", repeats=100,
                          setup="import pyrex;"+
                                "signal = pyrex.Signal(pulse.times, pulse.values)",
                          use_globals={"pf": pf, "pulse": pulse})

    print("Total time:", round(t*1000, 1), "milliseconds per signal")
コード例 #5
0
plt.xlabel("Neutrino Energy (GeV)")
plt.ylabel("Effective Volume (m^3)")
plt.tight_layout()
plt.show()

# Then from the effective volumes, we can calculate the effective areas.
# The effective area is given by the effective volume divided by the neutrino
# interaction length in the ice. The interaction length given by a PyREx
# Particle object is the water-equivalent interaction length, so it needs to
# be scaled by the relative density of ice. The interaction length used will
# be the harmonic mean of the neutrino and antineutrino interaction lengths
# (since the cross sections are what should be averaged).
int_lens = np.zeros(len(energies))
for i, energy in enumerate(energies):
    nu = pyrex.Particle(particle_id="nu_e",
                        vertex=(0, 0, 0),
                        direction=(0, 0, 1),
                        energy=energy)
    nu_bar = pyrex.Particle(particle_id="nu_e_bar",
                            vertex=(0, 0, 0),
                            direction=(0, 0, 1),
                            energy=energy)
    int_lens[i] = 2 / ((1 / nu.interaction.total_interaction_length) +
                       (1 / nu_bar.interaction.total_interaction_length))
int_lens *= 1e-2  # convert from cm to m (water-equivalent)
ice_density = 0.92  # g/cm^3, relative to 1 g/cm^3 for water
effective_areas = effective_volumes * ice_density / int_lens
area_errors = volume_errors * ice_density / int_lens

plt.errorbar(energies,
             effective_areas,
             yerr=area_errors,
コード例 #6
0
import numpy as np
import matplotlib.pyplot as plt
import pyrex

# First, set up a neutrino source and find the index of refraction at its depth.
# Then use that index of refraction to calculate the Cherenkov angle.
source = pyrex.Particle("nu_e", vertex=(0, 0, -1000), direction=(0, 0, -1),
                        energy=1e8)
n = pyrex.ice.index(source.vertex[2])
ch_angle = np.arccos(1/n)

# Now, for a range of dthetas, generate an Askaryan pulse dtheta away from the
# Chereknov angle and plot its frequency spectrum.
for dtheta in np.radians(np.logspace(-1, 1, 5)):
    n_pts = 10001
    pulse = pyrex.AskaryanSignal(times=np.linspace(-20e-9, 80e-9, n_pts),
                                 particle=source,
                                 viewing_angle=ch_angle+dtheta,
                                 viewing_distance=1000)
    plt.plot(pulse.frequencies[:int(n_pts/2)] * 1e-6, # Convert from Hz to MHz
             np.abs(pulse.spectrum)[:int(n_pts/2)],
             label=f"$\\Delta\\theta = {np.degrees(dtheta):.2f}$")
plt.legend(loc='upper right')
plt.title("Frequency Spectrum of Askaryan Pulse\n"+
          "For Different Off-Cone Angles")
plt.xlabel("Frequency (MHz)")
plt.xlim(0, 3000)
plt.tight_layout()
plt.show()

# Actually, we probably really want to see the frequency content after the
コード例 #7
0
ax[0].set_title("Detector Top View")
ax[0].set_xlabel("x-position")
ax[0].set_ylabel("y-position")
ax[1].scatter([ant.position[0] for ant in det],
              [ant.position[2] for ant in det],
              c='k')
ax[1].set_title("Detector Side View")
ax[1].set_xlabel("x-position")
ax[1].set_ylabel("z-position")
plt.tight_layout()
plt.show()

# Now set up a particle generator that will just throw the one event we're
# interested in, and create an event kernel with our detector and our generator.
p = pyrex.Particle(particle_id=pyrex.Particle.Type.electron_neutrino,
                   vertex=[1002.65674195, -421.95118348, -486.0953201],
                   direction=[-0.90615395, -0.41800062, -0.06450191],
                   energy=3e9)
p.interaction.kind = p.interaction.Type.neutral_current
p.interaction.em_frac = 0
p.interaction.had_frac = 1
gen = pyrex.ListGenerator(pyrex.Event(p))
kern = pyrex.EventKernel(antennas=det, generator=gen)

# Then make sure our detector is cleared out and throw the event!
# reset_noise will make sure we get new noise waveforms every time.
det.clear(reset_noise=True)
kern.event()

# Now let's take a look at the waveforms of the event. Since each event has a
# first and second ray, plot their waveforms side-by-side for each antenna.
for i, ant in enumerate(det):