def get_test_emission(self, frame): propagator = propagation.get_propagation_module('analytic') ice = medium.get_ice_model('ARAsim_southpole') # work up a simple example to test functionality ant = np.array([0,0,-100]) vertex = np.array([-2543.18,2319.96,-1828.74]) azi = 2.4658 zen = 1.0863 inelast = 0.55 inttype = 'cc' flavor = 14 energy = 9.20e+18 n_index = ice.get_index_of_refraction(vertex) cherenkov_angle = np.arccos(1./n_index) shower_axis = -1 * hp.spherical_to_cartesian(zen, azi) r = propagator(vertex, ant, medium=ice, attenuation_model='SP1', n_frequencies_integration=25, n_reflections=0 ) r.find_solutions() num_solutions = r.get_number_of_solutions() viewing_angles = [] distances = [] launch_vectors = [] receive_vectors = [] # print('num solutions is {}'.format(num_solutions)) for iS in range(num_solutions): launch_vectors.append(r.get_launch_vector(iS)) receive_vectors.append(r.get_receive_vector(iS)) # launch_vector = r.get_launch_vector(iS) viewing_angles.append(hp.get_angle(shower_axis, launch_vectors[iS])) distances.append(r.get_path_length(iS)) # viewing_angle = hp.get_angle(shower_axis, launch_vector) #fem, fhad = helper._get_em_had_fraction(inelast, inttype, flavor) fem=0 fhad=0.55 signal = askaryan.get_time_trace( energy = energy * fhad, theta = viewing_angles[0], N = self._n_samples, dt = self._dt, shower_type='HAD', n_index = n_index, R=distances[0], model=self._askaryan_model, seed=self._seed ) polarization_direction_onsky = util_geo.calculate_polarization_vector(launch_vectors[0], shower_axis) icetray.logging.log_debug("Polarization direction on sky {}".format(polarization_direction_onsky)) this_eR, this_eTheta, this_ePhi = np.outer(polarization_direction_onsky, signal) # create traces for the eR, eTheta, and ePhi components inside eR = icetradio.I3Trace() eTheta = icetradio.I3Trace() ePhi = icetradio.I3Trace() eR.trace = this_eR eR.traceStartTime = 0 eR.samplingRate = self._sampling_rate eTheta.trace = this_eTheta eTheta.traceStartTime = 0 eTheta.samplingRate = self._sampling_rate ePhi.trace = this_ePhi ePhi.traceStartTime = 0 eTheta.samplingRate = self._sampling_rate # put those traces inside an EField field = icetradio.I3EField() field.eR = eR field.eTheta = eTheta field.ePhi = ePhi frame.Put("DummyEField", field)
models = ['Alvarez2009', 'ARZ2020'] """ The times are not returned by the signal generator module, so we have to construct our own time array using the input time step. We have chosen the middle of the trace to be at t = 0. When using the ARZ2019 or ARZ2020 modules, the t=0 in our times array defined like this marks the moment when the signal from the vertex arrives at the observer's location. """ times = np.arange(0, N * dt, dt) # Array containing times times = times + 0.5 * dt - times.mean() """ We are now ready to plot a trace from both models. """ for model in models: trace = get_time_trace(energy, theta, N, dt, shower_type, n_index, R, model) plt.plot(times, trace / (units.microvolt / units.m), label=model) plt.legend() plt.xlim((-5, 5)) plt.xlabel('Time [ns]') plt.ylabel(r'Electric field [$\mu$V/m]') plt.show() """ One important thing to keep in mind is that the Alvarez2009 model varies the length of the electromagnetic shower randomly, and also the ARZ models chooses a random shower from the library to account for random fluctuations. This means that each time we call the functions, the showers are different and so the electric fields are also different. This is not practical when we want to calculate the field from a fixed shower at different locations. In order to do so, we can use the argument same_shower=True.
n_samples = 256 ff = np.fft.rfftfreq(n_samples, dt) tt = np.arange(0, n_samples * dt, dt) R = 1 * units.km models = ['Alvarez2009', 'ARZ2019', 'Alvarez2000', 'ARZ2020'] shower_types = ['EM', 'HAD'] Es = 10**np.linspace(15, 19, 5) * units.eV domegas = np.linspace(-5, 5, 10) * units.deg thetas = np.arccos(1. / n_index) + domegas output = [] for model in models: for E in Es: for shower_type in shower_types: for theta in thetas: trace = get_time_trace(E, theta, n_samples, dt, shower_type, n_index, R, model, seed=1234) output.append(trace) with open("reference_v1.pkl", "wb") as fout: pickle.dump(output, fout, protocol=4)
def generate_signal(deposited_energy, shower_axis, em_or_had, launch_vector, distance, arrival_time, n_index, attenuation_values, dt, n_samples, model, seed, keep_unattenuated_fields=False): """ A function to generate askaryan fields at the antennas Get the askaryan signals/fields at the antenna. This means that the fields returned by this function will already include the polarization factors, the 1/R, and the attenuation due to the ice. Parameters ---------- deposited_energy: double or float energy deposited in the shower in eV shower_axis: I3Position the shower axis launch_vector: I3Position the launch vector of the ray that makes the signal distance: float the path length traveled by the signal in m (including ray bending!) arrival_time: float the time the field arrives at the antenna, in seconds (including ray bending!) n_index: float the index of refraction at the vertex atttenuation_values: complex np array the complex frequency-dependent attenuation factors dt: float the time between samples for the askaryan emission, in seconds n_samples: int the number of samples to have in the Askaryan emission model: string what Askaryan model should be used to generate the emission options are described in NuRadioMC.SignalGen.askaryan https://github.com/nu-radio/NuRadioMC/blob/master/NuRadioMC/SignalGen/askaryan.py seed: int what random number seed should be used in generating the askaryan emission keep_unattenuated_fields: bool whether or not to keep a copy of the E-fields that does not have attenuation factors applied default is False, to reduce file output sizes Returns ------- signal: I3RadioSignal the radio signal container for this event """ local_launch_vector = util_dataclasses.i3pos_to_np(launch_vector) local_shower_axis = util_dataclasses.i3pos_to_np(shower_axis) viewing_angle = hp.get_angle(local_shower_axis, local_launch_vector) signal = askaryan.get_time_trace(energy=deposited_energy, theta=viewing_angle, N=n_samples, dt=dt, shower_type=em_or_had, n_index=n_index, R=distance, model=model, seed=seed) signal_spectrum = fft.time2freq(signal, 1. / dt) attenuated_signal_spectrum = signal_spectrum * attenuation_values attenuated_signal = fft.freq2time(attenuated_signal_spectrum, 1. / dt) # calculate the polarization polarization_direction_onsky = util_geo.calculate_polarization_vector( local_launch_vector, local_shower_axis) icetray.logging.log_debug("Polarization direction on sky {}".format( polarization_direction_onsky)) # create the e-fields at the antenna this_eR_attenuated, this_eTheta_attenuated, this_ePhi_attenuated = np.outer( polarization_direction_onsky, attenuated_signal) # store the eR, eTheta, ePhi components in trace for attenuated field sampling_rate = 1. / dt eR_attenuated = util_dataclasses.fill_I3Trace(this_eR_attenuated, arrival_time, sampling_rate) eTheta_attenuated = util_dataclasses.fill_I3Trace(this_eTheta_attenuated, arrival_time, sampling_rate) ePhi_attenuated = util_dataclasses.fill_I3Trace(this_ePhi_attenuated, arrival_time, sampling_rate) # put those traces into fields field_watt = util_dataclasses.fill_I3EField(eR_attenuated, eTheta_attenuated, ePhi_attenuated) # and finally, create and return a signal object signal = icetradio.I3RadioSignal() signal.view_angle = viewing_angle * icetray.I3Units.rad signal.polarization_vector = util_dataclasses.np_to_i3pos( polarization_direction_onsky, 'sph') signal.field_watt = field_watt if keep_unattenuated_fields: # make a copy of the fields that doesn't include the attenuation factor # we can generally *not* save this information as a space saving measure this_eR, this_eTheta, this_ePhi = np.outer( polarization_direction_onsky, signal) eR = util_dataclasses.fill_I3Trace(this_eR, arrival_time, sampling_rate) eTheta = util_dataclasses.fill_I3Trace(this_eTheta, arrival_time, sampling_rate) ePhi = util_dataclasses.fill_I3Trace(this_ePhi, arrival_time, sampling_rate) field_noatt = util_dataclasses.fill_I3EField(eR, eTheta, ePhi) signal.field_noatt = field_noatt return signal
E = 1e20 * units.eV n_index = 1.78 theta = np.arccos(1. / n_index) dt = 0.01 * units.ns n_samples = 2048 ff = np.fft.rfftfreq(n_samples, dt) tt = np.arange(0, n_samples * dt, dt) R = 1 * units.km model = 'Alvarez2000' shower_type = 'EM' domega = 0.1 * units.deg trace_1 = get_time_trace(E, theta + domega, n_samples, dt, shower_type, n_index, R, model) domega = 0.3 * units.deg trace_2 = get_time_trace(E, theta + domega, n_samples, dt, shower_type, n_index, R, model) spectrum_1 = fft.time2freq(trace_1) spectrum_2 = fft.time2freq(trace_2) spectrum_1 *= 1. / units.V * units.MHz * dt spectrum_2 *= 1. / units.V * units.MHz * dt freqs = np.fft.rfftfreq(n_samples, dt) fig = plt.figure(figsize=(10, 5)) ax1 = fig.add_subplot(121) ax1.plot(tt, trace_1, color='black', label='$\\theta_C+0.1\degree$',
n_index = 1.78 theta_C = np.arccos(1. / n_index) N = 512 * 2 dt = 0.1 * units.ns R = 1 * units.km tt = np.arange(0, dt * N, dt) thetas = theta_C + np.array([0, 1, 2, 3, 4, 5]) * units.deg fig, ax = plt.subplots(2, 3, sharex=True) ax = ax.flatten() for iTheta, theta in enumerate(thetas): trace = ask.get_time_trace(E, theta, N, dt, shower_type, n_index, R, "ARZ2019", interp_factor=interp_factor) ax[iTheta].plot(tt, trace[1], '-C0'.format(iTheta), label="$\Delta \Theta$ = {:.1f}".format( (theta - theta_C) / units.deg)) trace = ask.get_time_trace(E, theta, N, dt, shower_type, n_index, R, "Alvarez2000") trace = np.roll(trace, int(-1 * units.ns / dt)) ax[iTheta].plot(tt, trace, '--C1'.format(iTheta),