Ejemplo n.º 1
0
 def test_properties(self, ray_tracer):
     """Test basic properties of ray_tracer"""
     assert ray_tracer.z_turn_proximity == 1 / 10
     assert ray_tracer.z0 == -500
     assert ray_tracer.z1 == -100
     assert ray_tracer.n0 == ice.index(-500)
     assert ray_tracer.rho == np.sqrt(100**2 + 200**2)
Ejemplo n.º 2
0
 def test_properties(self, ray_tracer):
     """Test basic properties of paths from ray_tracer"""
     path_1 = ray_tracer.solutions[0]
     path_2 = ray_tracer.solutions[1]
     assert path_1.z_turn_proximity == ray_tracer.z_turn_proximity
     assert path_1.z0 == -500
     assert path_1.z1 == -100
     assert path_1.n0 == ice.index(-500)
     assert path_1.rho == ray_tracer.rho
     assert path_1.phi == np.arctan2(-200, -100)
     assert path_2.z_turn_proximity == ray_tracer.z_turn_proximity
     assert path_2.z0 == -500
     assert path_2.z1 == -100
     assert path_2.n0 == ice.index(-500)
     assert path_2.rho == ray_tracer.rho
     assert path_2.phi == np.arctan2(-200, -100)
Ejemplo n.º 3
0
 def test_max_angle(self, ray_tracer, ray_tracer2, ray_tracer3):
     """Test the maximum launch angle between the ray_tracer points"""
     expected = np.arcsin(ice.index(-100)/ice.index(-500))
     assert ray_tracer.max_angle == expected
     expected2 = np.arcsin(ice.index(-200)/ice.index(-300))
     assert ray_tracer2.max_angle == expected2
     expected3 = np.arcsin(ice.index(-200)/ice.index(-1500))
     assert ray_tracer3.max_angle == expected3
Ejemplo n.º 4
0
def arz_pulse():
    """Example Askaryan pulse from https://arxiv.org/pdf/1106.6283v3.pdf"""
    # Create particle to ensure shower energy is 3e9 GeV
    particle = Particle(particle_id=Particle.Type.electron_neutrino,
                        vertex=(0, 0, -1000),
                        direction=(0, 0, 1),
                        energy=3e9,
                        interaction_type="cc")
    particle.interaction.em_frac = 1
    particle.interaction.had_frac = 0
    n = ice.index(particle.vertex[2])
    cherenkov_angle = np.arcsin(np.sqrt(1 - 1 / n**2))
    return AskaryanSignal(times=np.linspace(0, 3e-9, 301),
                          particle=particle,
                          viewing_angle=cherenkov_angle - np.radians(0.3),
                          t0=1e-9)
Ejemplo n.º 5
0
    def triggered(self, beam_threshold, delays=None, angles=None,
                  require_mc_truth=False):
        """
        Check if the string is triggered based on its current state.

        String is triggered if the maximum value of the phased voltage waveform
        for any of the beams formed (according to `delays` or `angles`) exceeds
        the `beam_threshold` times the expected noise RMS of the beams
        (calculated as the sum of all antenna noise RMS values divided by the
        square root of the number of antennas).

        Parameters
        ----------
        beam_threshold : float
            Factor of expected noise RMS above which a phased beam waveform
            will trigger.
        delays : array_like or None
            Time delays (s) between each pair of antennas to use for beam
            forming. If ``None`` calculates the time delays based on the
            desired beam angles in `angles`.
        angles : array_like or None
            Polar angles (degrees) at which to form phased beams. If ``None``
            and `delays` is ``None``, default beam delays are used based on
            the typical ARA phased array delays (19 delays from -5.94 ns to
            5.94 ns).
        require_mc_truth : boolean, optional
            Whether or not the trigger should be based on the Monte-Carlo
            truth. If ``True``, noise-only triggers are removed.

        Returns
        -------
        boolean
            Whether or not the string is triggered in its current state.

        """
        # Explanation of default delays:
        # Delays from 5.94 ns to -5.94 ns cover the edge case of
        # n=1.78 (z=inf) for elevation angles of 90 to -90 degrees.
        # For another edge case of n=1.35 (z=0), only need to cover
        # 4.5 ns to -4.5 ns really, but having extra won't hurt.
        # (All this assuming a z-spacing of 1 m, otherwise multiply
        # by the spacing to get true time bounds)
        # 19 points in the larger range gives a delay resolution of
        # 660 ps (phased array FPGA sampling rate from
        # https://github.com/vPhase/fpga-sim/blob/master/config.py),
        # or equivalently an angular resolution of about 8 or 6 degrees
        # for the edge cases above.
        # I think this is different from the true phased array trigger,
        # which only looks down, so there are 15 positive (or neg?)
        # delays from 0 to 9.24 ns.
        if delays is None:
            dz = self[0].position[2] - self[1].position[2]
            if angles is None:
                # Use default delays described above
                t_max = 5.94e-9 * np.abs(dz)
                delays = np.linspace(-t_max, t_max, 19)
            else:
                # Calculate delays based on elevation angles
                thetas = np.radians(angles)
                n = np.mean([ice.index(ant.position[2]) for ant in self])
                v = 3e8 / n
                delays = dz / v * np.sin(thetas)

        rms = 0

        # Iterate over all waveforms (assume that the antennas are close
        # enough to all see the same rays, i.e. the same index of
        # ant.all_waveforms will be from the same ray for each antenna)
        # TODO: Warn if this assumption will cause problems (shouldn't be often)
        j = -1
        while True:
            j += 1
            # Center around most central antenna that sees ray
            center_i = None
            for i in sorted(range(len(self)),
                            key=lambda x: np.abs(x-len(self)/2)):
                if len(self[i].all_waveforms)>j:
                    center_i = i
                    break
            # Stop waveform iteration once no more waveforms are available
            if center_i is None:
                break

            # Preset the waveforms since the ant.full_waveform call can be
            # computationally expensive
            center_wave = self[center_i].all_waveforms[j]
            waveforms = []
            for i, ant in enumerate(self):
                if i==center_i:
                    waveforms.append(center_wave)
                    continue
                tmin = min(center_wave.times[0] - (center_i-i)*delay
                           for delay in delays)
                tmax = max(center_wave.times[-1] - (center_i-i)*delay
                           for delay in delays)
                n_pts = int((tmax-tmin)/center_wave.dt)
                times = np.linspace(tmin, tmax, n_pts+1)
                waveforms.append(ant.full_waveform(times))

            # Set rms value (if first time around) after noise_masters have
            # been set for the antennas. Pass through front end to ensure
            # more accurate rms values
            if rms==0:
                for ant in self:
                    noise = ant.antenna.make_noise(center_wave.times)
                    processed_noise = ant.front_end(noise)
                    rms += np.sqrt(np.mean(processed_noise.values**2))
                rms /= np.sqrt(len(self))

            # Check each delay for trigger
            for delay in delays:
                total = Signal(center_wave.times, center_wave.values)
                for i, wave in enumerate(waveforms):
                    if i==center_i:
                        continue
                    times = total.times - (center_i-i)*delay
                    add_wave = wave.with_times(times)
                    add_wave.times += (center_i-i)*delay
                    total += add_wave.with_times(total.times)
                if np.max(np.abs(total.values))>np.abs(beam_threshold*rms):
                    return True

        return False