def calculate_chi_square(event_info, zenith, azimuth, energy): target_direction = hp.spherical_to_cartesian(zenith, azimuth) event_direction = hp.spherical_to_cartesian(float(event_info[2]), float(event_info[3])) direction_error = hp.get_angle(target_direction, event_direction) energy_error = np.log10(energy) - np.log10(float(event_info[1])) return (direction_error / sigma_angle)**2 + (energy_error / sigma_log_energy)**2
def load_file_with_labels(i_file, n_events, start_index=0, norm=1e-6): # Load 500 MHz filter filt = np.load("bandpass_filters/500MHz_filter.npy") t0 = time.time() print(f"loading file {i_file}", flush=True) data = np.load(os.path.join(datapath, f"{data_filename}{i_file:04d}.npy"), allow_pickle=True, mmap_mode="r") data = data[start_index:(n_events + start_index), :, :] data = np.fft.irfft(np.fft.rfft(data, axis=-1) * filt, axis=-1) data = data[:, :, :, np.newaxis] labels_tmp = np.load(os.path.join(datapath, f"{label_filename}{i_file:04d}.npy"), allow_pickle=True) print(f"finished loading file {i_file} in {time.time() - t0}s") nu_zenith = np.array(labels_tmp.item()["nu_zenith"]) nu_azimuth = np.array(labels_tmp.item()["nu_azimuth"]) nu_direction = hp.spherical_to_cartesian(nu_zenith, nu_azimuth) nu_direction = nu_direction[start_index:(n_events + start_index), :] # check for nans and remove them idx = ~(np.isnan(data)) idx = np.all(idx, axis=1) idx = np.all(idx, axis=1) idx = np.all(idx, axis=1) data = data[idx, :, :, :] nu_direction = nu_direction[idx] data /= norm return data, nu_direction
def MakeAntennaGeo(antFile, iAnt): x = antFile['CenterX'][iAnt] y = antFile['CenterY'][iAnt] z = antFile['CenterZ'][iAnt] OrientationTheta = np.deg2rad(antFile['OrientationTheta'][iAnt]) OrientationPhi = np.deg2rad(antFile['OrientationPhi'][iAnt]) RotationTheta = np.deg2rad(antFile['RotationTheta'][iAnt]) RotationPhi = np.deg2rad(antFile['RotationPhi'][iAnt]) AntennaType = antFile['AntennaType'][iAnt] AntennaModel = antFile['AntennaModel'][iAnt] AmplifierFilterModel = antFile['AmplifierFilterModel'][iAnt] iceantennaGeo = dataclasses.I3IceAntennaGeo() iceantennaGeo.position = dataclasses.I3Position(x, y, z) sph_orientation = np.array([OrientationTheta, OrientationPhi]) sph_rotation = np.array([RotationTheta, RotationPhi]) car_orientation = hp.spherical_to_cartesian(*sph_orientation) car_rotation = hp.spherical_to_cartesian(*sph_rotation) iceantennaGeo.orientation = dataclasses.I3Direction( car_orientation[0], car_orientation[1], car_orientation[2]) iceantennaGeo.rotation = dataclasses.I3Direction(car_rotation[0], car_rotation[1], car_rotation[2]) if AntennaType == 'dipole': iceantennaGeo.antennaType = dataclasses.I3IceAntennaGeo.IceAntennaType.dipole elif AntennaType == 'lpda': iceantennaGeo.antennaType = dataclasses.I3IceAntennaGeo.IceAntennaType.lpda iceantennaGeo.antennaModel = AntennaModel iceantennaGeo.amplifierFilterModel = AmplifierFilterModel return iceantennaGeo
def get_expected_times(params, channel_positions): zenith, azimuth = params if cosmic_ray: if ((zenith < 0) or (zenith > 0.5 * np.pi)): return np.ones(len(channel_positions)) * np.inf else: if ((zenith < 0.5 * np.pi) or (zenith > np.pi)): return np.ones(len(channel_positions)) * np.inf v = hp.spherical_to_cartesian(zenith, azimuth) c = constants.c * units.m / units.s if not cosmic_ray: c = c / n_ice logger.debug("using speed of light = {:.4g}".format(c)) t_expected = -(np.dot(v, channel_positions.T) / c) return t_expected
def get_angles(corsika): """ Converting angles in corsika coordinates to local coordinates """ zenith = np.deg2rad(corsika['inputs'].attrs["THETAP"][0]) azimuth = hp.get_normalized_angle(3 * np.pi / 2. + np.deg2rad(corsika['inputs'].attrs["PHIP"][0])) Bx, Bz = corsika['inputs'].attrs["MAGNET"] B_inclination = np.arctan2(Bz, Bx) B_strength = (Bx ** 2 + Bz ** 2) ** 0.5 * units.micro * units.tesla # in local coordinates north is + 90 deg magnetic_field_vector = B_strength * hp.spherical_to_cartesian(np.pi * 0.5 + B_inclination, 0 + np.pi * 0.5) return zenith, azimuth, magnetic_field_vector
def obj_plane(params, positions, t_measured): zenith, azimuth = params if cosmic_ray: if ((zenith < 0) or (zenith > 0.5 * np.pi)): return np.inf else: if ((zenith < 0.5 * np.pi) or (zenith > np.pi)): return np.inf v = hp.spherical_to_cartesian(zenith, azimuth) c = constants.c * units.m / units.s if not cosmic_ray: c = c / n_ice logger.debug("using speed of light = {:.4g}".format(c)) t_expected = -(np.dot(v, positions.T) / c) sigma = 1 * units.ns chi2 = np.sum(((t_expected - t_expected.mean()) - (t_measured - t_measured.mean()))**2 / sigma**2) logger.debug("texp = {texp}, tm = {tmeas}, {chi2}".format( texp=t_expected, tmeas=t_measured, chi2=chi2)) return chi2
def run(self, evt, station, det, channels_to_use=None, cosmic_ray=False): """ Fits the direction using templates Parameters ---------- evt: event station: station det: detector channels_to_use: list (default: [0, 1, 2, 3] antenna to use for fit cosmic_ray: bool type to set correlation template """ if channels_to_use is None: channels_to_use = [0, 1, 2, 3] if (cosmic_ray): type_str = 'cr' xcorrelations = chp.cr_xcorrelations else: type_str = 'nu' xcorrelations = chp.nu_xcorrelations station_id = station.get_id() channels = station.iter_channels(channels_to_use) times = [] positions = [] for iCh, channel in enumerate(channels): channel_id = channel.get_id() times.append( channel[xcorrelations]['{}_ref_xcorr_time'.format(type_str)] + channel.get_trace_start_time()) positions.append(det.get_relative_position(station_id, channel_id)) times = np.array(times) positions = np.array(positions) site = det.get_site(station_id) n_ice = ice.get_refractive_index(-0.01, site) from scipy import optimize as opt def obj_plane(params, positions, t_measured): zenith, azimuth = params if cosmic_ray: if ((zenith < 0) or (zenith > 0.5 * np.pi)): return np.inf else: if ((zenith < 0.5 * np.pi) or (zenith > np.pi)): return np.inf v = hp.spherical_to_cartesian(zenith, azimuth) c = constants.c * units.m / units.s if not cosmic_ray: c = c / n_ice logger.debug("using speed of light = {:.4g}".format(c)) t_expected = -(np.dot(v, positions.T) / c) sigma = 1 * units.ns chi2 = np.sum(((t_expected - t_expected.mean()) - (t_measured - t_measured.mean()))**2 / sigma**2) logger.debug("texp = {texp}, tm = {tmeas}, {chi2}".format( texp=t_expected, tmeas=t_measured, chi2=chi2)) return chi2 method = "Nelder-Mead" options = {'maxiter': 1000, 'disp': False} zenith_start = 135 * units.deg if cosmic_ray: zenith_start = 45 * units.deg starting_chi2 = {} for starting_az in np.array([0, 90, 180, 270]) * units.degree: starting_chi2[starting_az] = obj_plane((zenith_start, starting_az), positions, times) azimuth_start = min(starting_chi2, key=starting_chi2.get) res = opt.minimize(obj_plane, x0=[zenith_start, azimuth_start], args=(positions, times), method=method, options=options) output_str = "reconstucted angles theta = {:.1f}, phi = {:.1f}".format( res.x[0] / units.deg, hp.get_normalized_angle(res.x[1]) / units.deg) if station.has_sim_station(): sim_zen = station.get_sim_station()[stnp.zenith] sim_az = station.get_sim_station()[stnp.azimuth] dOmega = hp.get_angle( hp.spherical_to_cartesian(sim_zen, sim_az), hp.spherical_to_cartesian(res.x[0], res.x[1])) output_str += " MC theta = {:.1f}, phi = {:.1f}, dOmega = {:.2f}".format( sim_zen / units.deg, sim_az / units.deg, dOmega / units.deg) logger.info(output_str) station[stnp.zenith] = res.x[0] station[stnp.azimuth] = hp.get_normalized_angle(res.x[1]) if (cosmic_ray): station[stnp.cr_zenith] = res.x[0] station[stnp.cr_azimuth] = hp.get_normalized_angle(res.x[1]) else: station[stnp.nu_zenith] = res.x[0] station[stnp.nu_azimuth] = hp.get_normalized_angle(res.x[1])
data = defaultdict(list) zeniths = np.deg2rad(np.arange(55, 80, 1)) depths = [400] core = np.array([0, 0, 1400]) positions = np.array([ np.linspace(-1000, 1000, 20), np.zeros(20), np.zeros(20) ]).T + core print(positions) print(positions.shape) for zenith in zeniths: print('zenith', np.rad2deg(zenith)) shower_axis = helper.spherical_to_cartesian(zenith, 0) for depth in depths: dist = at.get_distance_xmax_geometric(zenith, depth, observation_level=core[-1]) if dist < 0: continue # sea level point_on_axis = shower_axis * dist + core point_on_axis_height = atm.get_height_above_ground( dist, zenith, observation_level=core[-1]) + core[-1] print("Height of point in inital sys:", point_on_axis_height) for pos in positions:
def update_signal_direction_plot(zenith, azimuth, antenna_type): zenith = zenith * units.deg azimuth = azimuth * units.deg signal_direction = hp.spherical_to_cartesian(zenith, azimuth) data = [] data.append(go.Scatter3d( x=[0, signal_direction[0]], y=[0, signal_direction[1]], z=[0, signal_direction[2]], mode='lines', name='Signal Direction' )) data.append(go.Scatter3d( x=[0, 0], y=[0, 0], z=[0, 1], mode='lines', name='Antenna Orientation' )) rot = hp.spherical_to_cartesian(90.*units.deg, 180*units.deg) data.append(go.Scatter3d( x=[0, rot[0]], y=[0, rot[1]], z=[0, rot[2]], mode='lines', name='Antenna Rotation' )) if antenna_type == 'createLPDA_100MHz_InfFirn': data.append(go.Mesh3d( x=[0, 0, 0], y=[-.25, 0, .25], z=[0, .75, 0], delaunayaxis='x', opacity=.5, color='black' )) else: d_angle = 30 angles = np.arange(0, 360, d_angle) * units.deg r = .05 cylinder_points = [] i = [] j = [] k = [] for i_angle, angle in enumerate(angles): cylinder_points.append([r * np.cos(angle), r * np.sin(angle), -.5]) cylinder_points.append([r * np.cos(angle), r * np.sin(angle), .5]) cylinder_points.append([r * np.cos(angle + d_angle * units.deg), r * np.sin(angle + d_angle * units.deg), -.5]) cylinder_points.append([r * np.cos(angle), r * np.sin(angle), .5]) cylinder_points.append([r * np.cos(angle + d_angle * units.deg), r * np.sin(angle + d_angle * units.deg), -.5]) cylinder_points.append([r * np.cos(angle + d_angle * units.deg), r * np.sin(angle + d_angle * units.deg), .5]) i.append(6 * i_angle) j.append(6 * i_angle + 1) k.append(6 * i_angle + 2) i.append(6 * i_angle + 3) j.append(6 * i_angle + 4) k.append(6 * i_angle + 5) cylinder_points = np.array(cylinder_points) data.append(go.Mesh3d( x=cylinder_points[:, 0], y=cylinder_points[:, 1], z=cylinder_points[:, 2], i=i, j=j, k=k, color='black', opacity=.5 )) fig = go.Figure( data=data ) fig.update_layout( scene=dict( xaxis=dict(range=[-1, 1]), yaxis=dict(range=[-1, 1]), zaxis=dict(range=[-1, 1]), aspectmode='manual', aspectratio=dict(x=1, y=1, z=1) ), showlegend=True, legend=dict(x=-.1, y=1.1), margin=dict( l=10, r=10, t=10, b=10 ) ) return fig
str(np.average(zeniths, weights=weights)) + "\nstd: " + str(varZen**0.5)) plt.subplot(2, 1, 2) plt.hist(zeniths, bins=np.arange(0, 181, 5)) plt.xlabel('zenith angle [deg]') plt.ylabel('unweighted entries') plt.figtext( 1.0, 0.2, "N: " + str(len(zeniths)) + "\nmean: " + str(np.average(zeniths)) + "\nstd: " + str(np.std(zeniths))) plt.suptitle("neutrino direction") plt.savefig(os.path.join(plot_folder, 'neutrino_direction.pdf'), bbox_inches="tight") plt.clf() #plot difference between cherenkov angle and viewing angle # i.e., opposite to the direction of propagation. We need the propagation direction here, so we multiply the shower axis with '-1' shower_axis = -1.0 * hp.spherical_to_cartesian(theta, phi) viewing_angles_d = np.array( [hp.get_angle(x, y) for x, y in zip(shower_axis, launch_vectors[:, 0, 0])]) viewing_angles_r = np.array( [hp.get_angle(x, y) for x, y in zip(shower_axis, launch_vectors[:, 0, 1])]) # calculate correct chereknov angle for ice density at vertex position ice = medium.southpole_simple() n_indexs = np.array( [ice.get_index_of_refraction(x) for x in np.array([xx, yy, zz]).T]) rho = np.arccos(1. / n_indexs) weightsExt = weights for chan in range(1, len(launch_vectors[0])): viewing_angles_d = np.append( viewing_angles_d, np.array([ hp.get_angle(x, y)
def generate_eventlist_cylinder(filename, n_events, Emin, Emax, full_rmin=None, full_rmax=None, full_zmin=None, full_zmax=None, thetamin=0.*units.rad, thetamax=np.pi * units.rad, phimin=0.*units.rad, phimax=2 * np.pi * units.rad, start_event_id=1, flavor=[12, -12, 14, -14, 16, -16], n_events_per_file=None, spectrum='log_uniform', start_file_id=0): """ Event generator Generates neutrino interactions, i.e., vertex positions, neutrino directions, neutrino flavor, charged currend/neutral current and inelastiviy distributions. All events are saved in an hdf5 file. Parameters ---------- filename: string the output filename of the hdf5 file n_events: int number of events to generate Emin: float the minimum neutrino energy (energies are randomly chosen assuming a uniform distribution in the logarithm of the energy) Emax: float the maximum neutrino energy (energies are randomly chosen assuming a uniform distribution in the logarithm of the energy) full_rmin: float (default None) lower r coordinate of simulated volume (if None it is set to 1/3 of the fiducial volume, if second vertices are not activated it is set to the fiducial volume) full_rmax: float (default None) upper r coordinate of simulated volume (if None it is set to 5x the fiducial volume, if second vertices are not activated it is set to the fiducial volume) full_zmin: float (default None) lower z coordinate of simulated volume (if None it is set to 1/3 of the fiducial volume, if second vertices are not activated it is set to the fiducial volume) full_zmax: float (default None) upper z coordinate of simulated volume (if None it is set to 5x the fiducial volume, if second vertices are not activated it is set to the fiducial volume) thetamin: float lower zenith angle for neutrino arrival direction thetamax: float upper zenith angle for neutrino arrival direction phimin: float lower azimuth angle for neutrino arrival direction phimax: float upper azimuth angle for neutrino arrival direction start_event: int default: 1 event number of first event flavor: array of ints default: [12, -12, 14, -14, 16, -16] specify which neutrino flavors to generate. A uniform distribution of all specified flavors is assumed. The neutrino flavor (integer) encoded as using PDF numbering scheme, particles have positive sign, anti-particles have negative sign, relevant for us are: * 12: electron neutrino * 14: muon neutrino * 16: tau neutrino n_events_per_file: int or None the maximum number of events per output files. Default is None, which means that all events are saved in one file. If 'n_events_per_file' is smaller than 'n_events' the event list is split up into multiple files. This is useful to split up the computing on multiple cores. spectrum: string defines the probability distribution for which the neutrino energies are generated * 'log_uniform': uniformly distributed in the logarithm of energy start_file_id: int (default 0) in case the data set is distributed over several files, this number specifies the id of the first file (useful if an existing data set is extended) if True, generate deposited energies instead of primary neutrino energies """ attributes = {} n_events = int(n_events) # save current NuRadioMC version as attribute # save NuRadioMC and NuRadioReco versions attributes['NuRadioMC_EvtGen_version'] = NuRadioMC.__version__ attributes['NuRadioMC_EvtGen_version_hash'] = version.get_NuRadioMC_commit_hash() attributes['start_event_id'] = start_event_id attributes['fiducial_rmin'] = full_rmin attributes['fiducial_rmax'] = full_rmax attributes['fiducial_zmin'] = full_zmin attributes['fiducial_zmax'] = full_zmax attributes['rmin'] = full_rmin attributes['rmax'] = full_rmax attributes['zmin'] = full_zmin attributes['zmax'] = full_zmax attributes['flavors'] = flavor attributes['Emin'] = Emin attributes['Emax'] = Emax attributes['thetamin'] = thetamin attributes['thetamax'] = thetamax attributes['phimin'] = phimin attributes['phimax'] = phimax # define cylinder by two points and the radius h_cylinder = full_zmax - full_zmin r_cylinder = full_rmax pt1 = np.array([0, 0, R_earth + full_zmax]) pt2 = np.array([0, 0, R_earth + full_zmin]) data_sets = {} # calculate maximum width of projected area theta_max = np.arctan(h_cylinder / 2 / r_cylinder) d = 2 * r_cylinder * np.cos(theta_max) + h_cylinder * np.sin(theta_max) # width of area print(f"cylinder r = {r_cylinder/units.km:.1f}km, h = {h_cylinder/units.km:.1f}km -> dmax = {d/units.km:.1f}km") def perp(a) : b = np.empty_like(a) b[0] = -a[1] b[1] = a[0] return b # line segment a given by endpoints a1, a2 # line segment b given by endpoints b1, b2 # return def seg_intersect(a1, a2, b1, b2) : da = a2 - a1 db = b2 - b1 dp = a1 - b1 dap = perp(da) denom = np.dot(dap, db) num = np.dot(dap, dp) return (num / denom) * db + b1 def get_R(t, v, X): """" calculate distance to center of Earth as a function of travel distance Parameters ----------- t: 3dim array travel distance v: 3dim array direction X: 3dim array start point """ return np.linalg.norm(v * t + X) def get_density(t, v, X): """ calculates density as a function of travel distance Parameters ----------- t: 3dim array travel distance v: 3dim array direction X: 3dim array start point """ return earth.density(get_R(t, v, X)) def slant_depth(t, v, X): """ calculates slant depth (grammage) as a function of travel distance Parameters ----------- t: 3dim array travel distance v: 3dim array direction X: 3dim array start point """ res = quad(get_density, 0, t, args=(v, X), limit=200) return res[0] def slant_depth_num(t, v, X, step=50 * units.m): """ calculates slant depth (grammage) as a function of travel distance Parameters ----------- t: 3dim array travel distance v: 3dim array direction X: 3dim array start point """ tt = np.linspace(0, t, t / step) rr = np.linalg.norm(X + np.outer(tt, v), axis=1) res = np.trapz(earth.density(rr), tt) return res def obj_dist_to_surface(t, v, X): return get_R(t, v, X) - R_earth def obj(t, v, X, Lint): """ objective function to determine at which travel distance we reached the interaction point """ return slant_depth(t, v, X) - Lint def points_in_cylinder(pt1, pt2, r, q): """ determines if point lies within a cylinder Parameters ----------- pt1: 3dim array lowest point on cylinder axis pt2: 3dim array highest point on cylinder axis r: float radius of cylinder q: 3dim array point under test Returns True/False """ vec = pt2 - pt1 const = r * np.linalg.norm(vec) return len(np.where(np.dot(q - pt1, vec) >= 0 and np.dot(q - pt2, vec) <= 0 and np.linalg.norm(np.cross(q - pt1, vec)) <= const)[0]) > 0 # precalculate the maximum slant depth to the detector if(not os.path.exists("buffer_Llimit.pkl")): zens = np.arange(0, 180.1 * units.deg, 2 * units.deg) Lint_max = np.zeros_like(zens) Lint_min = np.zeros_like(zens) Xs = np.array([[0, -0.5 * r_cylinder, -h_cylinder + R_earth], [0, -0.5 * r_cylinder, R_earth], [0, 0.5 * r_cylinder, -h_cylinder + R_earth], [0, 0.5 * r_cylinder, R_earth]] ) v_tmps = -hp.spherical_to_cartesian(zens, np.zeros_like(zens)) # neutrino direction for i in range(len(v_tmps)): v = v_tmps[i] sdepth_tmp = np.zeros(4) for j, X in enumerate(Xs): if((X[2] == R_earth) and (zens[i] <= 90 * units.deg)): t = 0 sdepth_tmp[j] = 0 else: t = brentq(obj_dist_to_surface, 100, 2 * R_earth, args=(-v, X)) sdepth_tmp[j] = slant_depth_num(t, -v, X) # print(i, zens[i] / units.deg, X, sdepth_tmp[j]) # enter_point = X + (-v * t) Lint_max[i] = np.max(sdepth_tmp) Lint_min[i] = np.min(sdepth_tmp) pickle.dump([zens, Lint_max, Lint_min], open("buffer_Llimit.pkl", "wb"), protocol=4) else: zens, Lint_max, Lint_min = pickle.load(open("buffer_Llimit.pkl", "rb")) get_Lmax = interp1d(zens, Lint_max, kind='next') get_Lmin = interp1d(zens, Lint_min, kind='previous') if 0: fig, a = plt.subplots(1, 1) ztmp = np.linspace(0, 180 * units.deg, 10000) a.plot(ztmp / units.deg, get_Lmax(ztmp) / units.g * units.cm ** 2, 'C0-', label="max possible Lint") # a.plot(zens / units.deg, Lint_max / units.g * units.cm ** 2, 'oC0') a.plot(ztmp / units.deg, get_Lmin(ztmp) / units.g * units.cm ** 2, 'C1-', label="min possible Lint") # a.plot(zens / units.deg, Lint_min / units.g * units.cm ** 2, 'dC1') a.hlines(cs.get_interaction_length(.1 * units.EeV, 1, 12, "total") / units.g * units.cm ** 2, 0, 180, label="0.1 EeV", colors='C2') a.hlines(cs.get_interaction_length(1 * units.EeV, 1, 12, "total") / units.g * units.cm ** 2, 0, 180 , label="1 EeV", colors='C3') a.hlines(cs.get_interaction_length(10 * units.EeV, 1, 12, "total") / units.g * units.cm ** 2, 0, 180 , label="10 EeV", colors='C4') a.set_xlabel("zenith angle [deg]") a.set_ylabel("slant depth [g/cm^2]") a.semilogy(True) a.set_xticks(np.arange(0, 181, 10)) a.set_ylim(5e5) a.legend() fig.tight_layout() fig.savefig("Lvszen.png") plt.show() failed = 0 if(spectrum == 'log_uniform'): Enu = 10 ** np.random.uniform(np.log10(Emin), np.log10(Emax), n_events) flavors = np.array([flavor[i] for i in np.random.randint(0, high=len(flavor), size=n_events)]) az = np.random.uniform(phimin, phimax, n_events) zen = np.arccos(np.random.uniform(np.cos(thetamax), np.cos(thetamin), n_events)) # generate random positions on an area perpendicular do neutrino direction ax, ay = np.random.uniform(-0.5 * d, 0.5 * d, (2, n_events)) # az = np.ones(n_events) * (R_earth - .5 * h_cylinder) # move plane to the center of the cylinder # calculate grammage (g/cm^2) after which neutrino interacted Lint = np.random.exponential(cs.get_interaction_length(Enu, 1, flavors, "total"), n_events) mask = (Lint < get_Lmax(zen)) & (Lint > get_Lmin(zen)) print(f"{np.sum(mask)}/{n_events} = {np.sum(mask)/n_events:.2g} can potentially interact in simulation volume") # calculate position where neutrino interacts data_sets = {'xx': [], 'yy': [], 'zz': [], 'azimuths': [], 'zeniths': [], 'flavors': [], 'energies': []} # calculate rotation matrix to transform position on area to 3D mask_int = np.zeros_like(mask, dtype=np.bool) t0 = time.perf_counter() n_cylinder = 0 for j, i in enumerate(np.arange(n_events, dtype=np.int)[mask]): if(j % 1000 == 0 and i > 0): eta = (time.perf_counter() - t0) * (n_events - i) / i logger.info(f"{i}/{n_events} interacting = {np.sum(mask_int)}, failed = {failed}, n_cylinder = {n_cylinder}, eta = {pretty_time_delta(eta)}") # print(f"calculating interaction point of event {i}"), c, s = np.cos(az[i]), np.sin(az[i]) Raz = np.array(((c, -s, 0), (s, c, 0), (0, 0, 1))) c, s = np.cos(zen[i]), np.sin(zen[i]) # Rzen = np.array(((c, 1, -s), (0, 1, 0), (s, 0, c))) Rzen = hp.get_rotation(hp.spherical_to_cartesian(0, az[i]), hp.spherical_to_cartesian(zen[i], az[i])) # R = hp.get_rotation(np.array([0, 0, 1]), hp.spherical_to_cartesian(zen[i], az[i])) R = np.matmul(Rzen, Raz) v = -hp.spherical_to_cartesian(zen[i], az[i]) # neutrino direction X = np.matmul(R, np.array([ax[i], ay[i], 0])) + np.array([0, 0, -0.5 * h_cylinder]) if 0: import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from mpl_toolkits.mplot3d.art3d import Poly3DCollection fig = plt.figure() a = fig.add_subplot(111, projection='3d') # Cylinder x = np.linspace(-r_cylinder, r_cylinder, 100) z = np.linspace(0, -h_cylinder, 100) Xc, Zc = np.meshgrid(x, z) Yc = np.sqrt(r_cylinder ** 2 - Xc ** 2) # Draw parameters rstride = 20 cstride = 10 a.plot_surface(Xc, Yc, Zc, alpha=0.2, rstride=rstride, cstride=cstride) a.plot_surface(Xc, -Yc, Zc, alpha=0.2, rstride=rstride, cstride=cstride) a.set_title(f"zenith = {zen[i]/units.deg:.0f}") xx = [] yy = [] zz = [] for vert in np.array([[-0.5 * d, -0.5 * d, 0], [0.5 * d, -0.5 * d, 0], [0.5 * d, 0.5 * d, 0], [-0.5 * d, 0.5 * d, 0]]): t = np.matmul(Raz, vert) + np.array([0, 0, -0.5 * h_cylinder]) xx.append(t[0]) yy.append(t[1]) zz.append(t[2]) verts = [list(zip(xx, yy, zz))] a.add_collection3d(Poly3DCollection(verts, alpha=0.5)) xx = [] yy = [] zz = [] for vert in np.array([[-0.5 * d, -0.5 * d, 0], [0.5 * d, -0.5 * d, 0], [0.5 * d, 0.5 * d, 0], [-0.5 * d, 0.5 * d, 0]]): t = np.matmul(Rzen, np.matmul(Raz, vert)) + np.array([0, 0, -0.5 * h_cylinder]) xx.append(t[0]) yy.append(t[1]) zz.append(t[2]) verts = [list(zip(xx, yy, zz))] a.add_collection3d(Poly3DCollection(verts, alpha=0.5)) s = np.array([0, 0, -0.5 * h_cylinder]) t = v * 10 * units.km + s a.plot([s[0], t[0]], [s[1], t[1]], [s[2], t[2]], '-d') s = np.array([0, 0, -0.5 * h_cylinder]) t = -hp.spherical_to_cartesian(90 * units.deg, az[i]) * 10 * units.km + s a.plot([s[0], t[0]], [s[1], t[1]], [s[2], t[2]], '--d') # check if neutrino axis is perpendicular t = np.array(verts[0][0]) - np.array(verts[0][1]) t /= np.linalg.norm(t) print(np.dot(t, v)) a.set_xlabel("x") a.set_zlabel("z") a.set_ylabel("y") plt.show() # check if trajectory passes through cylinder # if(not points_in_cylinder(pt1, pt2, r_cylinder, X)): # we rotate everything in the plane defined by z and the propagration direction (such that v_y = 0) Xaz = np.matmul(Raz.T, X) rmin = Xaz[1] # the closest distance to the z axis (center of cyllinder) if(abs(rmin) >= r_cylinder): continue # define the projected square of the cylinder # the two endpoints of the two horizontal lines are xtmp = (r_cylinder ** 2 - rmin ** 2) ** 0.5 Lh1 = np.array([[-xtmp, 0], [xtmp, 0]]) Lh2 = np.array([[-xtmp, -h_cylinder], [xtmp, -h_cylinder]]) # the two endpoints of the two vertical lines are Lv1 = np.array([[-xtmp, 0], [-xtmp, -h_cylinder]]) Lv2 = np.array([[xtmp, 0], [xtmp, -h_cylinder]]) # define line of neutrino propagation by two points vaz = np.matmul(Raz.T, v) if(abs(vaz[1]) > 1e-10): a = 1 / 0 v2d = np.array([vaz[0], vaz[2]]) X2d = np.array([Xaz[0], Xaz[2]]) t = 2 * d Paz = np.array([X2d + -t * v2d, X2d + t * v2d]) # calculate points that intersect any of the 4 area (projected cylinder) boundaries intersects = [] for k, (a1, a2) in enumerate([Lh1, Lh2]): tmp = seg_intersect(a1, a2, Paz[0], Paz[1]) if((tmp[0] >= a1[0]) and (tmp[0] <= a2[0])): intersects.append(tmp) for k, (a1, a2) in enumerate([Lv1, Lv2]): tmp = seg_intersect(a1, a2, Paz[0], Paz[1]) if((tmp[1] <= a1[1]) and (tmp[1] >= a2[1])): intersects.append(tmp) intersects = np.array(intersects) if(len(intersects) != 2): if 0: print(len(intersects)) import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() a = fig.add_subplot(111, projection='3d') # Cylinder x = np.linspace(-r_cylinder, r_cylinder, 100) z = np.linspace(0, -h_cylinder, 100) Xc, Zc = np.meshgrid(x, z) Yc = np.sqrt(r_cylinder ** 2 - Xc ** 2) # Draw parameters rstride = 20 cstride = 10 a.plot_surface(Xc, Yc, Zc, alpha=0.2, rstride=rstride, cstride=cstride) a.plot_surface(Xc, -Yc, Zc, alpha=0.2, rstride=rstride, cstride=cstride) X_enter = X + 10 * units.km * v X_leave = X - 10 * units.km * v a.plot([X_enter[0], X_leave[0]], [X_enter[1], X_leave[1]], [X_enter[2], X_leave[2]], '-o') a.set_xlabel("x") a.set_zlabel("z") a.set_ylabel("y") a.legend() a.set_title("no intersection") fig = plt.figure() a = fig.add_subplot(111, projection='3d') for (a1, a2) in [Lh1, Lh2, Lv1, Lv2]: a.plot([a1[0], a2[0]], [rmin, rmin], [a1[1], a2[1]]) a.plot([Paz[0][0], Paz[1][0]], [rmin, rmin], [Paz[0][1], Paz[1][1]]) a.set_xlabel("x") a.set_zlabel("z") a.set_ylabel("y") a.legend() plt.show() continue # neutrino is not passing through cylinder n_cylinder += 1 ss = [] for tmp in intersects: ss.append(np.dot(tmp - X2d, v2d.T)) argsort = np.argsort(np.array(ss)) # check which intersection happens first along neutrino path if 0: if(len(intersects)): import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() a = fig.add_subplot(111, projection='3d') for (a1, a2) in [Lh1, Lh2, Lv1, Lv2]: a.plot([a1[0], a2[0]], [rmin, rmin], [a1[1], a2[1]]) a.plot([Paz[0][0], Paz[1][0]], [rmin, rmin], [Paz[0][1], Paz[1][1]]) for k, tmp in enumerate(intersects): a.plot([tmp[0]], [rmin], [tmp[1]], 'o', label=f"s = {ss[k]:.0f}") a.set_xlabel("x") a.set_zlabel("z") a.set_ylabel("y") a.legend() # plt.ion() plt.show() # calculate the 3D points where the neutrino enters/leaves the cylinder and transform to outside Earth X_enter = np.matmul(Raz, np.array([intersects[argsort][0][0], rmin, intersects[argsort][0][1]])) + np.array([0, 0, R_earth]) X_leave = np.matmul(Raz, np.array([intersects[argsort][1][0], rmin, intersects[argsort][1][1]])) + np.array([0, 0, R_earth]) X += np.array([0, 0, R_earth]) # calculate point where neutrino enters Earth if(np.linalg.norm(X_enter) > R_earth): # if enter point is outside of Earth (can happen because cylinder does not account for Earth curvature) if(np.linalg.norm(X_leave) > R_earth): # check if leave point is also outside of Earth (can also happen because cylinder does not account for Earth curvature) continue t = brentq(obj_dist_to_surface, 0, 5 * d, args=(-v, X_leave)) enter_point = X_leave + (-v * t) X_enter = enter_point # define point where neutrino enters the cylinder as the point where it enters the Earth else: t = brentq(obj_dist_to_surface, 0, 2 * R_earth, args=(-v, X_enter)) enter_point = X_enter + (-v * t) # logger.debug(f"zen = {zen[i]/units.deg:.0f}deg, trajectory enters Earth at {enter_point[0]:.1f}, {enter_point[0]:.1f}, {enter_point[0]:.1f}. Dist to core = {np.linalg.norm(enter_point)/R_earth:.5f}, dist to (0,0,R) = {np.linalg.norm(enter_point - np.array([0,0,R_earth]))/R_earth:.4f}") # check if event interacts at all # calcualte slant depth to point of entering cylinder t = np.linalg.norm(enter_point - X_enter) slant_depth_min = slant_depth(t, v, enter_point) if(t == 0): slant_depth_min = 0 # calculate slant depth through the cylinder s = np.linalg.norm(X_leave - X_enter) slant_depth_max = slant_depth(s, v, X_enter) + slant_depth_min # full slant depth from outside Earth to point when it leaves the cylinder if 0: import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure() a = fig.add_subplot(111, projection='3d') # Cylinder x = np.linspace(-r_cylinder, r_cylinder, 100) z = np.linspace(0, -h_cylinder, 100) Xc, Zc = np.meshgrid(x, z) Yc = np.sqrt(r_cylinder ** 2 - Xc ** 2) # Draw parameters rstride = 20 cstride = 10 a.plot_surface(Xc, Yc, Zc, alpha=0.2, rstride=rstride, cstride=cstride) a.plot_surface(Xc, -Yc, Zc, alpha=0.2, rstride=rstride, cstride=cstride) a.plot([X_enter[0], X_leave[0]], [X_enter[1], X_leave[1]], [X_enter[2] - R_earth, X_leave[2] - R_earth], '-o') a.set_xlabel("x") a.set_zlabel("z") a.set_ylabel("y") print(f"Lmin = {slant_depth_min:.2g}, Lmax = {slant_depth_max:.2g}, Lnu = {Lint[i]:.2g}") a.legend() plt.show() # a = 1 / 0 if((Lint[i] <= slant_depth_min) or (Lint[i] >= slant_depth_max)): logger.debug("neutrino does not interact in cylinder, skipping to next event") continue try: # calculate interaction point by inegrating the density of Earth along the neutrino path until we wind the interaction length t = brentq(obj, 0, s, args=(v, X_enter, Lint[i] - slant_depth_min), maxiter=500) except: logger.warning("failed to converge, skipping event") failed += 1 continue Xint = X_enter + v * t # calculate interaction point is_in_cylinder = points_in_cylinder(pt1, pt2, r_cylinder, Xint) mask_int[i] = is_in_cylinder if(is_in_cylinder): logger.debug(f"event {i}, interaction point ({Xint[0]:.1f}, {Xint[1]:.1f}, {Xint[2]-R_earth:.1f}), in cylinder {is_in_cylinder}") data_sets['xx'].append(Xint[0]) data_sets['yy'].append(Xint[1]) data_sets['zz'].append(Xint[2] - R_earth) data_sets['zeniths'].append(zen[i]) data_sets['azimuths'].append(az[i]) data_sets['flavors'].append(flavors[i]) data_sets['energies'].append(Enu[i]) else: logger.error("interaction is not in cylinder but it should be") a = 1 / 0 data_sets['event_ids'] = range(np.sum(mask_int)) data_sets['flavors'] = np.ones(np.sum(mask_int)) data_sets["event_ids"] = np.arange(np.sum(mask_int)) + start_event_id data_sets["n_interaction"] = np.ones(np.sum(mask_int), dtype=np.int) data_sets["vertex_times"] = np.zeros(np.sum(mask_int), dtype=np.float) data_sets["interaction_type"] = inelasticities.get_ccnc(np.sum(mask_int)) data_sets["inelasticity"] = inelasticities.get_neutrino_inelasticity(np.sum(mask_int)) attributes['n_events'] = n_events logger.info(f"{np.sum(mask_int)} event interacted in simulation volume") write_events_to_hdf5(filename, data_sets, attributes, n_events_per_file=n_events_per_file, start_file_id=start_file_id)
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)
def __init__(self, zenith, azimuth, magnetic_field_vector=None, site=None): """ Initialization with signal/air-shower direction and magnetic field configuration. All parameters should be specified according to the default coordinate system of the radiotools package (the Auger coordinate system). Parameters ---------- zenith : float zenith angle of the incoming signal/air-shower direction (0 deg is pointing to the zenith) azimuth : float azimuth angle of the incoming signal/air-shower direction (0 deg is North, 90 deg is South) magnetic_field_vector (optional): 3-vector, default None the magnetic field vector in the cartesian ground coordinate system, if no magnetic field vector is specified, the default value for the site specified in the 'site' function argument is used. site (optional): string, default 'Auger' this argument has only effect it 'magnetic_field_vector' is None the site for which the magnetic field vector should be used. Currently, default values for for the sites 'auger' and 'arianna' are available """ showeraxis = -1 * hp.spherical_to_cartesian( zenith, azimuth) # -1 is because shower is propagating towards us if (magnetic_field_vector is None): magnetic_field_vector = hp.get_magnetic_field_vector(site=site) magnetic_field_normalized = magnetic_field_vector / \ linalg.norm(magnetic_field_vector) vxB = np.cross(showeraxis, magnetic_field_normalized) e1 = vxB e2 = np.cross(showeraxis, vxB) e3 = np.cross(e1, e2) e1 /= linalg.norm(e1) e2 /= linalg.norm(e2) e3 /= linalg.norm(e3) self.__transformation_matrix_vBvvB = copy.copy(np.matrix([e1, e2, e3])) self.__inverse_transformation_matrix_vBvvB = np.linalg.inv( self.__transformation_matrix_vBvvB) # initilize transformation matrix to on-sky coordinate system (er, etheta, ephi) ct = np.cos(zenith) st = np.sin(zenith) cp = np.cos(azimuth) sp = np.sin(azimuth) e1 = np.array([st * cp, st * sp, ct]) e2 = np.array([ct * cp, ct * sp, -st]) e3 = np.array([-sp, cp, 0]) self.__transformation_matrix_onsky = copy.copy(np.matrix([e1, e2, e3])) self.__inverse_transformation_matrix_onsky = np.linalg.inv( self.__transformation_matrix_onsky) # initilize transformation matrix from magnetic north to geographic north coordinate system declination = hp.get_declination(magnetic_field_vector) c = np.cos(-1 * declination) s = np.sin(-1 * declination) e1 = np.array([c, -s, 0]) e2 = np.array([s, c, 0]) e3 = np.array([0, 0, 1]) self.__transformation_matrix_magnetic = copy.copy( np.matrix([e1, e2, e3])) self.__inverse_transformation_matrix_magnetic = np.linalg.inv( self.__transformation_matrix_magnetic) # initilize transformation matrix from ground (geographic) cs to ground # cs where x axis points into shower direction projected on ground c = np.cos(-1 * azimuth) s = np.sin(-1 * azimuth) e1 = np.array([c, -s, 0]) e2 = np.array([s, c, 0]) e3 = np.array([0, 0, 1]) self.__transformation_matrix_azimuth = copy.copy( np.matrix([e1, e2, e3])) self.__inverse_transformation_matrix_azimuth = np.linalg.inv( self.__transformation_matrix_azimuth) # initilize transformation matrix from ground (geographic) cs to shower plane (early-late) cs # rotation along z axis -> shower axis along y axis c = np.cos(-azimuth + np.pi / 2) s = np.sin(-azimuth + np.pi / 2) e1 = np.matrix([[c, -s, 0], [s, c, 0], [0, 0, 1]]) # rotation along x axis -> rotation in shower plane c = np.cos(zenith) s = np.sin(zenith) e2 = np.matrix([[1, 0, 0], [0, c, -s], [0, s, c]]) self.__transformation_matrix_early_late = copy.copy(np.matmul(e2, e1)) self.__inverse_transformation_matrix_early_late = np.linalg.inv( self.__transformation_matrix_early_late)
def run(self, evt, station, det, n_index=None, ZenLim=None, AziLim=None, channel_pairs=((0, 2), (1, 3)), use_envelope=False): """ reconstruct signal arrival direction for all events Parameters ---------- evt: Event The event to run the module on station: Station The station to run the module on det: Detector The detector description n_index: float the index of refraction ZenLim: 2-dim array/list of floats (default: [0 * units.deg, 90 * units.deg]) the zenith angle limits for the fit AziLim: 2-dim array/list of floats (default: [0 * units.deg, 360 * units.deg]) the azimuth angle limits for the fit channel_pairs: pair of pair of integers specify the two channel pairs to use, default ((0, 2), (1, 3)) use_envelope: bool (default False) if True, the hilbert envelope of the traces is used """ if ZenLim is None: ZenLim = [0 * units.deg, 90 * units.deg] if AziLim is None: AziLim = [0 * units.deg, 360 * units.deg] use_correlation = True def ll_regular_station(angles, corr_02, corr_13, sampling_rate, positions, trace_start_times): """ Likelihood function for a four antenna ARIANNA station, using correction. Using correlation, has no built in wrap around, pulse needs to be in the middle """ zenith = angles[0] azimuth = angles[1] times = [] for pos in positions: tmp = [geo_utl.get_time_delay_from_direction(zenith, azimuth, pos[0], n=n_index), geo_utl.get_time_delay_from_direction(zenith, azimuth, pos[1], n=n_index)] times.append(tmp) delta_t_02 = times[0][1] - times[0][0] delta_t_13 = times[1][1] - times[1][0] # take different trace start times into account delta_t_02 -= (trace_start_times[0][1] - trace_start_times[0][0]) delta_t_13 -= (trace_start_times[1][1] - trace_start_times[1][0]) delta_t_02 *= sampling_rate delta_t_13 *= sampling_rate pos_02 = int(corr_02.shape[0] / 2 - delta_t_02) pos_13 = int(corr_13.shape[0] / 2 - delta_t_13) # weight_02 = np.sum(corr_02 ** 2) # Normalize crosscorrelation # weight_13 = np.sum(corr_13 ** 2) # # likelihood = -1 * (corr_02[pos_02] ** 2 / weight_02 + corr_13[pos_13] ** 2 / weight_13) # After deliberating a bit, I don't think we should use the square because anti-correlating # pulses would be wrong, given that it is not a continous waveform weight_02 = np.sum(np.abs(corr_02)) # Normalize crosscorrelation weight_13 = np.sum(np.abs(corr_13)) likelihood = -1 * (corr_02[pos_02] / weight_02 + corr_13[pos_13] / weight_13) return likelihood def ll_regular_station_fft(angles, corr_02_fft, corr_13_fft, sampling_rate, positions, trace_start_times): """ Likelihood function for a four antenna ARIANNA station, using FFT convolution Using FFT convolution, has built-in wrap around, but ARIANNA signals are too short for it to be accurate will show problems at zero time delay """ zenith = angles[0] azimuth = angles[1] times = [] for pos in positions: tmp = [geo_utl.get_time_delay_from_direction(zenith, azimuth, pos[0], n=n_index) * sampling_rate, geo_utl.get_time_delay_from_direction(zenith, azimuth, pos[1], n=n_index) * sampling_rate] times.append(tmp) delta_t_02 = (times[0][1] + trace_start_times[0][1] * sampling_rate) - (times[0][0] + trace_start_times[0][0] * sampling_rate) delta_t_13 = (times[1][1] + trace_start_times[1][1] * sampling_rate) - (times[1][0] + trace_start_times[1][0] * sampling_rate) if delta_t_02 < 0: pos_02 = int(delta_t_02 + corr_02_fft.shape[0]) else: pos_02 = int(delta_t_02) if delta_t_13 < 0: pos_13 = int(delta_t_13 + corr_13_fft.shape[0]) else: pos_13 = int(delta_t_13) weight_02 = np.sum(np.abs(corr_02_fft)) # Normalize crosscorrelation weight_13 = np.sum(np.abs(corr_13_fft)) likelihood = -1 * (np.abs(corr_02_fft[pos_02]) ** 2 / weight_02 + np.abs(corr_13[pos_13]) ** 2 / weight_13) return likelihood station_id = station.get_id() positions_pairs = [[det.get_relative_position(station_id, channel_pairs[0][0]), det.get_relative_position(station_id, channel_pairs[0][1])], [det.get_relative_position(station_id, channel_pairs[1][0]), det.get_relative_position(station_id, channel_pairs[1][1])]] sampling_rate = station.get_channel(0).get_sampling_rate() # assume that channels have the same sampling rate trace_start_time_pairs = [[station.get_channel(channel_pairs[0][0]).get_trace_start_time(), station.get_channel(channel_pairs[0][1]).get_trace_start_time()], [station.get_channel(channel_pairs[1][0]).get_trace_start_time(), station.get_channel(channel_pairs[1][1]).get_trace_start_time()]] # determine automatically if one channel has an inverted waveform with respect to the other signs = [1., 1.] for iPair, pair in enumerate(channel_pairs): antenna_type = det.get_antenna_type(station_id, pair[0]) if("LPDA" in antenna_type): otheta, ophi, rot_theta, rot_azimuth = det.get_antenna_orientation(station_id, pair[0]) otheta2, ophi2, rot_theta2, rot_azimuth2 = det.get_antenna_orientation(station_id, pair[1]) if(np.isclose(np.abs(rot_azimuth - rot_azimuth2), 180 * units.deg, atol=1 * units.deg)): signs[iPair] = -1 if use_correlation: # Correlation if not use_envelope: corr_02 = signal.correlate(station.get_channel(channel_pairs[0][0]).get_trace(), signs[0] * station.get_channel(channel_pairs[0][1]).get_trace()) corr_13 = signal.correlate(station.get_channel(channel_pairs[1][0]).get_trace(), signs[1] * station.get_channel(channel_pairs[1][1]).get_trace()) else: corr_02 = signal.correlate(np.abs(signal.hilbert(station.get_channel(channel_pairs[0][0]).get_trace())), np.abs(signal.hilbert(station.get_channel(channel_pairs[0][1]).get_trace()))) corr_13 = signal.correlate(np.abs(signal.hilbert(station.get_channel(channel_pairs[1][0]).get_trace())), np.abs(signal.hilbert(station.get_channel(channel_pairs[1][1]).get_trace()))) else: # FFT convolution corr_02_fft = fftpack.ifft(-1 * fftpack.fft(station.get_channel(channel_pairs[0][0]).get_trace()).conjugate() * fftpack.fft(station.get_channel(channel_pairs[0][1]).get_trace())) corr_13_fft = fftpack.ifft(-1 * fftpack.fft(station.get_channel(channel_pairs[1][0]).get_trace()).conjugate() * fftpack.fft(station.get_channel(channel_pairs[1][1]).get_trace())) if use_correlation: # Using correlation ll = opt.brute( ll_regular_station, ranges=(slice(ZenLim[0], ZenLim[1], 0.01), slice(AziLim[0], AziLim[1], 0.01)), args=(corr_02, corr_13, sampling_rate, positions_pairs, trace_start_time_pairs), full_output=True, finish=opt.fmin) # slow but does the trick else: ll = opt.brute(ll_regular_station_fft, ranges=(slice(ZenLim[0], ZenLim[1], 0.05), slice(AziLim[0], AziLim[1], 0.05)), args=(corr_02_fft, corr_13_fft, sampling_rate, positions_pairs, trace_start_time_pairs), full_output=True, finish=opt.fmin) # slow but does the trick if self.__debug: import peakutils zenith = ll[0][0] azimuth = ll[0][1] times = [] for pos in positions_pairs: tmp = [geo_utl.get_time_delay_from_direction(zenith, azimuth, pos[0], n=n_index), geo_utl.get_time_delay_from_direction(zenith, azimuth, pos[1], n=n_index)] times.append(tmp) delta_t_02 = times[0][1] - times[0][0] delta_t_13 = times[1][1] - times[1][0] # take different trace start times into account delta_t_02 -= (trace_start_time_pairs[0][1] - trace_start_time_pairs[0][0]) delta_t_13 -= (trace_start_time_pairs[1][1] - trace_start_time_pairs[1][0]) delta_t_02 *= sampling_rate delta_t_13 *= sampling_rate toffset = -(np.arange(0, corr_02.shape[0]) - corr_02.shape[0] / 2) / sampling_rate fig, (ax, ax2) = plt.subplots(2, 1, sharex=True) ax.plot(toffset, corr_02) ax.axvline(delta_t_02 / sampling_rate, label='time', c='k') indices = peakutils.indexes(corr_02, thres=0.8, min_dist=5) ax.plot(toffset[indices], corr_02[indices], 'o') imax = np.argmax(corr_02[indices]) self.logger.debug("offset 02= {:.3f}".format(toffset[indices[imax]] - (delta_t_02 / sampling_rate))) ax2.plot(toffset, corr_13) indices = peakutils.indexes(corr_13, thres=0.8, min_dist=5) ax2.plot(toffset[indices], corr_13[indices], 'o') ax2.axvline(delta_t_13 / sampling_rate, label='time', c='k') ax2.set_xlabel("time") ax2.set_ylabel("Correlation Ch 1/ Ch3", fontsize='small') ax.set_ylabel("Correlation Ch 0/ Ch2", fontsize='small') plt.tight_layout() # plt.close("all") station[stnp.zenith] = max(ZenLim[0], min(ZenLim[1], ll[0][0])) station[stnp.azimuth] = ll[0][1] output_str = "reconstucted angles theta = {:.1f}, phi = {:.1f}".format(station[stnp.zenith] / units.deg, station[stnp.azimuth] / units.deg) if station.has_sim_station(): sim_zen = None sim_az = None if(station.get_sim_station().is_cosmic_ray()): sim_zen = station.get_sim_station()[stnp.zenith] sim_az = station.get_sim_station()[stnp.azimuth] elif(station.get_sim_station().is_neutrino()): # in case of a neutrino simulation, each channel has a slightly different arrival direction -> compute the average sim_zen = [] sim_az = [] for efield in station.get_sim_station().get_electric_fields_for_channels(ray_path_type='direct'): sim_zen.append(efield[efp.zenith]) sim_az.append(efield[efp.azimuth]) sim_zen = np.array(sim_zen) sim_az = hp.get_normalized_angle(np.array(sim_az)) ops = "average incident zenith {:.1f} +- {:.1f}".format(np.mean(sim_zen) / units.deg, np.std(sim_zen) / units.deg) ops += " (individual: " for x in sim_zen: ops += "{:.1f}, ".format(x / units.deg) ops += ")" self.logger.debug(ops) ops = "average incident azimuth {:.1f} +- {:.1f}".format(np.mean(sim_az) / units.deg, np.std(sim_az) / units.deg) ops += " (individual: " for x in sim_az: ops += "{:.1f}, ".format(x / units.deg) ops += ")" self.logger.debug(ops) sim_zen = np.mean(np.array(sim_zen)) sim_az = np.mean(np.array(sim_az)) if(sim_zen is not None): dOmega = hp.get_angle(hp.spherical_to_cartesian(sim_zen, sim_az), hp.spherical_to_cartesian(station[stnp.zenith], station[stnp.azimuth])) output_str += " MC theta = {:.2f}, phi = {:.2f}, dOmega = {:.2f}, dZen = {:.1f}, dAz = {:.1f}".format(sim_zen / units.deg, hp.get_normalized_angle(sim_az) / units.deg, dOmega / units.deg, (station[stnp.zenith] - sim_zen) / units.deg, (station[stnp.azimuth] - hp.get_normalized_angle(sim_az)) / units.deg) self.__zenith.append(sim_zen) self.__azimuth.append(sim_az) self.__delta_zenith.append(station[stnp.zenith] - sim_zen) self.__delta_azimuth.append(station[stnp.azimuth] - hp.get_normalized_angle(sim_az)) self.logger.info(output_str) # Still have to add fit quality parameter to output if self.__debug: import peakutils # access simulated efield and high level parameters sim_present = False if(station.has_sim_station()): if(station.get_sim_station().has_parameter(stnp.zenith)): sim_station = station.get_sim_station() azimuth_orig = sim_station[stnp.azimuth] zenith_orig = sim_station[stnp.zenith] sim_present = True self.logger.debug("True CoREAS zenith {0}, azimuth {1}".format(zenith_orig, azimuth_orig)) self.logger.debug("Result of direction fitting: [zenith, azimuth] {}".format(np.rad2deg(ll[0]))) # Show fit space zen = np.arange(ZenLim[0], ZenLim[1], 1 * units.deg) az = np.arange(AziLim[0], AziLim[1], 2 * units.deg) x_plot = np.zeros(zen.shape[0] * az.shape[0]) y_plot = np.zeros(zen.shape[0] * az.shape[0]) z_plot = np.zeros(zen.shape[0] * az.shape[0]) i = 0 for a in az: for z in zen: # Evaluate fit function for grid if use_correlation: z_plot[i] = ll_regular_station([z, a], corr_02, corr_13, sampling_rate, positions_pairs, trace_start_time_pairs) else: z_plot[i] = ll_regular_station_fft([z, a], corr_02_fft, corr_13_fft, sampling_rate, positions_pairs, trace_start_time_pairs) x_plot[i] = a y_plot[i] = z i += 1 fig, ax = plt.subplots(1, 1) ax.scatter(np.rad2deg(x_plot), np.rad2deg(y_plot), c=z_plot, cmap='gnuplot2_r', lw=0) # ax.imshow(z_plot, cmap='gnuplot2_r', extent=(0, 360, 90, 180)) if sim_present: ax.plot(np.rad2deg(hp.get_normalized_angle(azimuth_orig)), np.rad2deg(zenith_orig), marker='d', c='g', label="True") ax.scatter(np.rad2deg(ll[0][1]), np.rad2deg(ll[0][0]), marker='o', c='k', label='Fit') # ax.colorbar(label='Fit parameter') ax.set_ylabel('Zenith [rad]') ax.set_xlabel('Azimuth [rad]') plt.tight_layout() # plot allowed solution separately for each pair of channels toffset = -(np.arange(0, corr_02.shape[0]) - corr_02.shape[0] / 2.) / sampling_rate indices = peakutils.indexes(corr_02, thres=0.8, min_dist=5) t02s = toffset[indices][np.argsort(corr_02[indices])[::-1]] + (trace_start_time_pairs[0][1] - trace_start_time_pairs[0][0]) toffset = -(np.arange(0, corr_13.shape[0]) - corr_13.shape[0] / 2.) / sampling_rate indices = peakutils.indexes(corr_13, thres=0.8, min_dist=5) t13s = toffset[indices][np.argsort(corr_13[indices])[::-1]] + (trace_start_time_pairs[1][1] - trace_start_time_pairs[1][0]) from scipy import constants c = constants.c * units.m / units.s dx = -6 * units.m def get_deltat13(dt, phi): t = -1. * dt * c / (dx * np.cos(phi) * n_index) t[t < 0] = np.nan return np.arcsin(t) def get_deltat02(dt, phi): t = -1 * dt * c / (dx * np.sin(phi) * n_index) t[t < 0] = np.nan return np.arcsin(t) def getDeltaTCone(r, dt): dist = np.linalg.norm(r) t0 = -dist * n_index / c Phic = np.arccos(dt / t0) # cone angle for allowable solutions self.logger.debug('dist = {}, dt = {}, t0 = {}, phic = {}'.format(dist, dt, t0, Phic)) nr = r / dist # normalize p = np.cross([0, 0, 1], nr) # create a perpendicular normal vector to r p = p / np.linalg.norm(p) q = np.cross(nr, p) # nr, p, and q form an orthonormal basis self.logger.debug('nr = {}\np = {}\nq = {}\n'.format(nr, p, q)) ThetaC = np.linspace(0, 2 * np.pi, 1000) Phis = np.zeros(len(ThetaC)) Thetas = np.zeros(len(ThetaC)) for i, thetac in enumerate(ThetaC): # create a set of vectors that point along the cone defined by r and PhiC rc = nr + np.tan(Phic) * (np.sin(thetac) * p + np.cos(thetac) * q) nrc = rc / np.linalg.norm(rc) theta = np.arccos(nrc[2]) phi = np.arctan2(nrc[1], nrc[0]) Phis[i] = phi Thetas[i] = theta return Phis, Thetas # phis = np.deg2rad(np.linspace(0, 360, 10000)) r0_2 = positions_pairs[0][1] - positions_pairs[0][0] # vector pointing from Ch2 to Ch0 r1_3 = positions_pairs[1][1] - positions_pairs[1][0] # vector pointing from Ch3 to Ch1 self.logger.debug('r02 {}\nr13 {}'.format(r0_2, r1_3)) linestyles = ['-', '--', ':', '-.'] for i, t02 in enumerate(t02s): # theta02 = get_deltat02(t02, phis) phi02, theta02 = getDeltaTCone(r0_2, t02) theta02[theta02 < 0] += np.pi phi02[phi02 < 0] += 2 * np.pi jumppos02 = np.where(np.abs(np.diff(phi02)) >= 5.0) for j, pos in enumerate(jumppos02): phi02 = np.insert(phi02, pos + 1 + j, np.nan) theta02 = np.insert(theta02, pos + 1 + j, np.nan) # mask02 = ~np.isnan(theta02) ax.plot(np.rad2deg(phi02), np.rad2deg(theta02), '{}C3'.format(linestyles[i % 4]), label='c 0+2 dt = {}'.format(t02)) for i, t13 in enumerate(t13s): # theta13 = get_deltat13(t13, phis) phi13, theta13 = getDeltaTCone(r1_3, t13) theta13[theta13 < 0] += np.pi phi13[phi13 < 0] += 2 * np.pi jumppos13 = np.where(np.abs(np.diff(phi13)) >= 5.0) for j, pos in enumerate(jumppos13): phi13 = np.insert(phi13, pos + 1 + j, np.nan) theta13 = np.insert(theta13, pos + 1 + j, np.nan) # mask13 = ~np.isnan(theta13) ax.plot(np.rad2deg(phi13), np.rad2deg(theta13), '{}C2'.format(linestyles[i % 4]), label='c 1+3 dt = {}'.format(t13)) ax.legend(fontsize='small') ax.set_ylim(ZenLim[0] / units.deg, ZenLim[1] / units.deg) ax.set_xlim(AziLim[0] / units.deg, AziLim[1] / units.deg)
def update_sim_event_3d(i_event, filename, station_id, juser_id): if filename is None or station_id is None: return {} user_id = json.loads(juser_id) ariio = provider.get_arianna_io(user_id, filename) evt = ariio.get_event_i(i_event) station = evt.get_station(station_id) sim_station = station.get_sim_station() if sim_station is None: return {} data = [ plotly.graph_objs.Scatter3d(x=[0], y=[0], z=[0], mode='markers', name='Station') ] if sim_station.has_parameter(stnp.nu_vertex): vertex = sim_station.get_parameter(stnp.nu_vertex) data.append( plotly.graph_objs.Scatter3d(x=[vertex[0]], y=[vertex[1]], z=[vertex[2]], mode='markers', name='Interaction Vertex')) plot_range = 1.5 * np.max(np.abs(vertex)) if sim_station.has_parameter( stnp.nu_zenith) and sim_station.has_parameter(stnp.nu_azimuth): neutrino_path = hp.spherical_to_cartesian( sim_station.get_parameter(stnp.nu_zenith), sim_station.get_parameter(stnp.nu_azimuth)) data.append( plotly.graph_objs.Scatter3d( x=[ vertex[0], vertex[0] + .25 * plot_range * neutrino_path[0] ], y=[ vertex[1], vertex[1] + .25 * plot_range * neutrino_path[1] ], z=[ vertex[2], vertex[2] + .25 * plot_range * neutrino_path[2] ], name='Neutrino Direction', mode='lines')) else: plot_range = 1 * units.km fig = plotly.graph_objs.Figure(data=data, layout=plotly.graph_objs.Layout( width=1000, height=1000, legend={ 'orientation': 'h', 'y': 1.1 }, scene={ 'aspectmode': 'manual', 'aspectratio': { 'x': 2, 'y': 2, 'z': 1 }, 'xaxis': { 'range': [-plot_range, plot_range] }, 'yaxis': { 'range': [-plot_range, plot_range] }, 'zaxis': { 'range': [-plot_range, 0] } })) return fig
xx = np.append(xx, np.array(fin['xx'])) yy = np.append(yy, np.array(fin['yy'])) zz = np.append(zz, np.array(fin['zz'])) zeniths = np.append(zeniths, np.array(fin['zeniths'])) azimuths = np.append(azimuths, np.array(fin['azimuths'])) inelasticity = np.append(inelasticity, np.array(fin['inelasticity'])) weight = np.append(weight, np.array(fin['weights'])) st = np.append(st, np.array(fin['ray_tracing_solution_type']), axis=0) launch_vectors = np.append(launch_vectors, np.array(fin['launch_vectors']), axis=0) receive_vectors = np.append(receive_vectors, np.array(fin['receive_vectors']), axis=0) shower_axis = -1.0 * hp.spherical_to_cartesian(zeniths, azimuths) viewing_angles_d = np.array( [hp.get_angle(x, y) for x, y in zip(shower_axis, launch_vectors[:, 5, 0])]) viewing_angles_r = np.array( [hp.get_angle(x, y) for x, y in zip(shower_axis, launch_vectors[:, 5, 1])]) launch_angles_d, launch_azimuths_d = hp.cartesian_to_spherical_vectorized( launch_vectors[:, 5, 0, 0].flatten(), launch_vectors[:, 5, 0, 1].flatten(), launch_vectors[:, 5, 0, 2].flatten()) launch_angles_r, launch_azimuths_r = hp.cartesian_to_spherical_vectorized( launch_vectors[:, 5, 1, 0].flatten(), launch_vectors[:, 5, 1, 1].flatten(), launch_vectors[:, 5, 1, 2].flatten()) rec_angles_d, rec_azimuths_d = hp.cartesian_to_spherical_vectorized( receive_vectors[:, 5, 0, 0].flatten(), receive_vectors[:, 5, 0, 1].flatten(), receive_vectors[:, 5, 0, 2].flatten()) rec_angles_r, rec_azimuths_r = hp.cartesian_to_spherical_vectorized(
from astropy.time import Time pio.renderers.default = "browser" det = detector.GenericDetector(json_filename=sys.argv[1], default_station=101) det.update(Time.now()) sid = 101 ll = 1 * units.m data = [] for cid in det.get_channel_ids(sid): ori_zen, ori_az, rot_zen, rot_az = det.get_antenna_orientation(sid, cid) x, y, z = det.get_relative_position(sid, cid) dx, dy, dz = hp.spherical_to_cartesian(ori_zen, ori_az) xx = [x, x - ll * dx] yy = [y, y - ll * dy] zz = [z, z - ll * dz] dx, dy, dz = hp.spherical_to_cartesian(rot_zen, rot_az) xx.insert(0, x + 0.5 * ll * dx) yy.insert(0, y + 0.5 * ll * dy) zz.insert(0, z + 0.5 * ll * dz) print( f"channel {cid:d}, rot = {dx:.1f}, {dy:.1f}, {dz:.1f}, ({rot_zen / units.deg:.0f}, {rot_az / units.deg:.0f})" ) data.append(go.Scatter3d(x=xx, y=yy, z=zz, mode='lines+markers')) if "LPDA" in det.get_antenna_type(sid, cid): ori = hp.spherical_to_cartesian(ori_zen, ori_az)
zz = np.array([]) for i in range(flav.size): if (flav[i]): launch_vectors = np.append(launch_vectors, [lvtemp[i]], axis=0) zenith_inp = np.append(zenith_inp, [zeniths[i]], axis=0) azimuth_inp = np.append(azimuth_inp, [azimuths[i]], axis=0) xx = np.append(xx, xtemp[i]) yy = np.append(yy, ytemp[i]) zz = np.append(zz, ztemp[i]) launch_vectors = np.delete(launch_vectors, 0, axis=0) zenith_inp = np.delete(zenith_inp, 0, axis=0) azimuth_inp = np.delete(azimuth_inp, 0, axis=0) shower_axis = -1 * hp.spherical_to_cartesian(zenith_inp, azimuth_inp) viewing_angles = np.array([hp.get_angle(x, y) for x, y in zip(shower_axis, launch_vectors[:, 0, 0])]) # calculate correct chereknov angle for ice density at vertex position ice = medium.southpole_simple() n_indexs = np.array([ice.get_index_of_refraction(x) for x in np.array([xx, yy, zz]).T]) rho = np.arccos(1. / n_indexs) mask = ~np.isnan(viewing_angles) fig, ax = php.get_histogram((viewing_angles[mask] - rho[mask]) / units.deg, weights=weightstemp[mask], bins=np.arange(-30, 30, 1), xlabel='viewing - cherenkov angle [deg] - ' + title, figsize=(6, 6)) fig.savefig(os.path.join(plot_folder, title + '_{}_dCherenkov.pdf'.format(key))) ########################### # plot flavor ratios ###########################
ax.plot([x2[0]], [x2[1]], [x2[2]], 'ko') if (j != 0 and (~(np.array(triggered_deep[iE], dtype=np.bool) & mask))[j]): continue vertex = np.array([fin['xx'][iE], fin['yy'][iE], fin['zz'][iE]]) # print(fin.keys()) # l1 = fin['launch_vectors'][iE][3] / units.deg l2 = fin['station_101']['launch_vectors'][iE][j * 4 + 3] # r1 = ray.ray_tracing(vertex, x1, med, log_level=logging.DEBUG) # # r1.find_solutions() # r1.set_solution(fin['ray_tracing_C0'][iE][3], fin['ray_tracing_C1'][iE][3], fin['ray_tracing_solution_type'][iE][3]) # path1 = r1.get_path(0) zen, az = fin['zeniths'][iE], fin['azimuths'][iE] v = hp.spherical_to_cartesian(zen, az) if (plot): r2 = ray.ray_tracing(vertex, x2, med, log_level=logging.INFO) r2.set_solution( fin['station_101']['ray_tracing_C0'][iE][iC], fin['station_101']['ray_tracing_C1'][iE][iC], fin['station_101']['ray_tracing_solution_type'][iE][iC]) path2 = r2.get_path(0) # ax.plot3D(path1.T[0], path1.T[1], path1.T[2], label='path 1') ax.plot3D(path2.T[0], path2.T[1], path2.T[2], label='path {}'.format(j)) ax.plot3D([vertex[0], vertex[0] + 500 * v[0]], [vertex[1], vertex[1] + 500 * v[1]],
def plot_event_overview(evt_counter, filename, station_id, station_mode, channel_station, juser_id): if filename is None or station_id is None: return {} user_id = json.loads(juser_id) ariio = provider.get_arianna_io(user_id, filename) evt = ariio.get_event_i(evt_counter) station = evt.get_station(station_id) plots = [] if station.is_neutrino(): if station.has_sim_station(): sim_station = station.get_sim_station() sim_vertex = sim_station.get_parameter(stnp.nu_vertex) sim_zenith = sim_station.get_parameter(stnp.nu_zenith) sim_azimuth = sim_station.get_parameter(stnp.nu_azimuth) sim_direction = hp.spherical_to_cartesian( sim_zenith, sim_azimuth) * 300. + sim_vertex plots.append( plotly.graph_objs.Scatter3d(x=[sim_vertex[0]], y=[sim_vertex[1]], z=[sim_vertex[2]], text=['Sim Vertex'], mode='markers', marker={ 'size': 3, 'color': 'red' }, showlegend=False, name='Vertex')) plots.append( plotly.graph_objs.Scatter3d( x=[sim_vertex[0], sim_direction[0]], y=[sim_vertex[1], sim_direction[1]], z=[sim_vertex[2], sim_direction[2]], mode='lines', line={'color': 'red'}, showlegend=False, name='Neutrino direction')) if evt.has_parameter( evp.sim_config) and ariio.get_detector() is not None: det = ariio.get_detector() det.update(station.get_station_time()) sim_config = evt.get_parameter(evp.sim_config) import NuRadioMC.SignalProp.analyticraytracing import NuRadioMC.utilities.medium attenuation_model = sim_config['propagation'][ 'attenuation_model'] ice_model = NuRadioMC.utilities.medium.get_ice_model( sim_config['propagation']['ice_model']) n_reflections = sim_config['propagation']['n_reflections'] for channel_id in det.get_channel_ids(station_id): channel_pos = det.get_relative_position( station_id, channel_id) + det.get_absolute_position(station_id) raytracer = NuRadioMC.SignalProp.analyticraytracing.ray_tracing( sim_vertex, channel_pos, ice_model, attenuation_model, n_reflections=n_reflections) raytracer.find_solutions() for iS, solution in enumerate(raytracer.get_results()): path = raytracer.get_path(iS, 100) plots.append( plotly.graph_objs.Scatter3d( x=path[:, 0], y=path[:, 1], z=path[:, 2], mode='lines', line={'color': 'orange'}, showlegend=False, name='Ch. {}, {}'.format( channel_id, NuRadioMC.SignalProp.analyticraytracing. solution_types[solution['type']]))) cherenkov_cone, i_ch, j_ch, k_ch = get_cherenkov_cone( ice_model, sim_vertex, hp.spherical_to_cartesian(sim_zenith, sim_azimuth)) plots.append( plotly.graph_objs.Mesh3d(x=cherenkov_cone[:, 0], y=cherenkov_cone[:, 1], z=cherenkov_cone[:, 2], i=i_ch, j=j_ch, k=k_ch, color='red', opacity=.5, name='Cherenkov ring')) if station.is_cosmic_ray(): for sim_shower in evt.get_sim_showers(): sim_core = sim_shower.get_parameter(shp.core) sim_zenith = sim_shower.get_parameter(shp.zenith) sim_azimuth = sim_shower.get_parameter(shp.azimuth) sim_direction = hp.spherical_to_cartesian(sim_zenith, sim_azimuth) plots.append( plotly.graph_objs.Scatter3d(x=[sim_core[0]], y=[sim_core[1]], z=[sim_core[2]], mode='markers', marker={'color': 'red'}, showlegend=False, name='Core position')) dir_points = np.array([sim_core, sim_core + 100 * sim_direction]) plots.append( plotly.graph_objs.Scatter3d(x=dir_points[:, 0], y=dir_points[:, 1], z=dir_points[:, 2], mode='lines', line={'color': 'red'}, showlegend=False, name='Shower direction')) if ariio.get_detector() is not None: det = ariio.get_detector() det.update(station.get_station_time()) channel_positions = [] channel_comments = [] station_positions = [] station_comments = [] if station_mode == 'selected': draw_stations = [station_id] else: draw_stations = det.get_station_ids() for stat_id in draw_stations: station_positions.append(det.get_absolute_position(stat_id)) station_comments.append('Station {}'.format(stat_id)) for channel_id in det.get_channel_ids(stat_id): channel_comments.append('Ch.{}[{}]'.format( channel_id, det.get_channel(stat_id, channel_id)['ant_comment'])) channel_positions.append( det.get_absolute_position(stat_id) + det.get_relative_position(stat_id, channel_id)) channel_positions = np.array(channel_positions) station_positions = np.array(station_positions) if 'station' in channel_station: plots.append( plotly.graph_objs.Scatter3d(x=station_positions[:, 0], y=station_positions[:, 1], z=station_positions[:, 2], text=station_comments, mode='markers', marker={'size': 4}, showlegend=False, name='Stations')) if 'channel' in channel_station: plots.append( plotly.graph_objs.Scatter3d(x=channel_positions[:, 0], y=channel_positions[:, 1], z=channel_positions[:, 2], text=channel_comments, mode='markers', marker={'size': 3}, showlegend=False, name='Channels')) fig = plotly.graph_objs.Figure(data=plots) return fig
maxy = ax.get_ylim() php.get_histogram(p_ratio[mask], bins=bins, xlabel='vertical/horizonal polarization ratio', stats=False, ax=ax, kwargs={'facecolor': 'C0', 'alpha': 1, 'edgecolor': "k", 'label': 'direct rays'}) # ax.set_xticks(bins) ax.legend() ax.set_ylim(maxy) fig.tight_layout() fig.savefig(os.path.join(plot_folder, '{}_polarization_unweighted.png'.format(key))) ########################### # plot viewing angle ########################### shower_axis = -1 * hp.spherical_to_cartesian(np.array(fin['zeniths'])[triggered], np.array(fin['azimuths'])[triggered]) launch_vectors = np.array(station['launch_vectors'])[triggered] viewing_angles = np.array([hp.get_angle(x, y) for x, y in zip(shower_axis, launch_vectors[:, 0, 0])]) # calculate correct chereknov angle for ice density at vertex position ice = medium.southpole_simple() n_indexs = np.array([ice.get_index_of_refraction(x) for x in np.array([np.array(fin['xx'])[triggered], np.array(fin['yy'])[triggered], np.array(fin['zz'])[triggered]]).T]) rho = np.arccos(1. / n_indexs) mask = ~np.isnan(viewing_angles) fig, ax = php.get_histogram((viewing_angles[mask] - rho[mask]) / units.deg, weights=weights[mask], bins=np.arange(-30, 30, 1), xlabel='viewing - cherenkov angle [deg]', figsize=(6, 6)) fig.savefig(os.path.join(plot_folder, '{}_dCherenkov.png'.format(key))) ########################### # plot flavor ratios
def draw_station_view(station_id, checklist): """ Draws the 3D view of the selected station Parameters: ----------------------- station_id: int ID of the selected station checklist: array Array containing state of the station view options checkboxes """ if station_id is None: return go.Figure([]) detector_provider = NuRadioReco.detector.detector_browser.detector_provider.DetectorProvider( ) detector = detector_provider.get_detector() channel_positions = [] channel_ids = detector.get_channel_ids(station_id) antenna_types = [] antenna_orientations = [] antenna_rotations = [] data = [] for channel_id in channel_ids: channel_position = detector.get_relative_position( station_id, channel_id) channel_positions.append(channel_position) antenna_types.append(detector.get_antenna_type(station_id, channel_id)) orientation = detector.get_antenna_orientation(station_id, channel_id) ant_ori = hp.spherical_to_cartesian(orientation[0], orientation[1]) antenna_orientations.append(channel_position) antenna_orientations.append(channel_position + ant_ori) antenna_orientations.append([None, None, None]) ant_rot = hp.spherical_to_cartesian(orientation[2], orientation[3]) antenna_rotations.append(channel_position) antenna_rotations.append(channel_position + ant_rot) antenna_rotations.append([None, None, None]) if 'createLPDA' in detector.get_antenna_type( station_id, channel_id) and 'sketch' in checklist: antenna_tip = channel_position + ant_ori antenna_tine_1 = channel_position + np.cross(ant_ori, ant_rot) antenna_tine_2 = channel_position - np.cross(ant_ori, ant_rot) data.append( go.Mesh3d( x=[antenna_tip[0], antenna_tine_1[0], antenna_tine_2[0]], y=[antenna_tip[1], antenna_tine_1[1], antenna_tine_2[1]], z=[antenna_tip[2], antenna_tine_1[2], antenna_tine_2[2]], opacity=.5, color='black', delaunayaxis='x', hoverinfo='skip')) channel_positions = np.array(channel_positions) antenna_types = np.array(antenna_types) antenna_orientations = np.array(antenna_orientations) antenna_rotations = np.array(antenna_rotations) channel_ids = np.array(channel_ids) lpda_mask = (np.char.find(antenna_types, 'createLPDA') >= 0) vpol_mask = (np.char.find(antenna_types, 'bicone_v8') >= 0) | (np.char.find(antenna_types, 'greenland_vpol') >= 0) hpol_mask = (np.char.find(antenna_types, 'fourslot') >= 0) | (np.char.find( antenna_types, 'trislot') >= 0) if len(channel_positions[:, 0][lpda_mask]) > 0: data.append( go.Scatter3d(x=channel_positions[:, 0][lpda_mask], y=channel_positions[:, 1][lpda_mask], z=channel_positions[:, 2][lpda_mask], ids=channel_ids[lpda_mask], text=channel_ids[lpda_mask], mode='markers+text', name='LPDAs', textposition='middle right', marker_symbol='diamond-open', marker=dict(size=4))) if len(channel_positions[:, 0][vpol_mask]) > 0: data.append( go.Scatter3d(x=channel_positions[:, 0][vpol_mask], y=channel_positions[:, 1][vpol_mask], z=channel_positions[:, 2][vpol_mask], ids=channel_ids[vpol_mask], text=channel_ids[vpol_mask], mode='markers+text', name='V-pol', textposition='middle right', marker_symbol='x', marker=dict(size=4))) if len(channel_positions[:, 0][hpol_mask]) > 0: data.append( go.Scatter3d(x=channel_positions[:, 0][hpol_mask], y=channel_positions[:, 1][hpol_mask], z=channel_positions[:, 2][hpol_mask], ids=channel_ids[hpol_mask], text=channel_ids[hpol_mask], mode='markers+text', name='H-pol', textposition='middle right', marker_symbol='cross', marker=dict(size=4))) if len(channel_positions[:, 0][(~lpda_mask) & (~vpol_mask) & (~hpol_mask)]) > 0: data.append( go.Scatter3d( x=channel_positions[:, 0][(~lpda_mask) & (~vpol_mask) & (~hpol_mask)], y=channel_positions[:, 1][(~lpda_mask) & (~vpol_mask) & (~hpol_mask)], z=channel_positions[:, 2][(~lpda_mask) & (~vpol_mask) & (~hpol_mask)], ids=channel_ids[(~lpda_mask) & (~vpol_mask) & (~hpol_mask)], text=channel_ids[(~lpda_mask) & (~vpol_mask) & (~hpol_mask)], mode='markers+text', name='other', textposition='middle right', marker=dict(size=3))) if len(channel_positions[:, 0]) > 0: data.append( go.Scatter3d(x=antenna_orientations[:, 0], y=antenna_orientations[:, 1], z=antenna_orientations[:, 2], mode='lines', name='Orientations', marker_color='red', hoverinfo='skip')) data.append( go.Scatter3d(x=antenna_rotations[:, 0], y=antenna_rotations[:, 1], z=antenna_rotations[:, 2], mode='lines', name='Rotations', marker_color='blue', hoverinfo='skip')) fig = go.Figure(data) fig.update_layout(scene=dict(aspectmode='data'), legend_orientation='h', legend=dict(x=.0, y=1.), height=600, margin=dict(l=10, r=10, t=30, b=10)) return fig
def get_weight(theta_nu, pnu, flavors, mode='simple', cross_section_type='ctw', vertex_position=None, phi_nu=None): """ calculates neutrino weight due to Earth absorption for different models Parameters ---------- theta_nu: float or array of floats the zenith angle of the neutrino direction (where it came from, i.e., opposite to the direction of propagation) pnu: float or array of floats the momentum of the neutrino mode: string * 'simple': assuming interaction happens at the surface and approximating the Earth with constant density * 'core_mantle_crust_simple': assuming interaction happens at the surface and approximating the Earth with 3 layers of constant density * 'core_mantle_crust': approximating the Earth with 3 layers of constant density, path through Earth to interaction vertex is considered * 'PREM': density of Earth is parameterized as a fuction of radius, path through Earth to interaction vertex is considered cross_section_type: string 'ghandi', 'ctw' or 'csms' (see description in `cross_sections.py`) vertex_position: 3-dim array or None (default) the position of the neutrino interaction phi_nu: float the azimuth angle of the neutrino direction """ if (mode == 'simple'): return get_simple_weight(theta_nu, pnu, cross_section_type=cross_section_type) elif (mode == "core_mantle_crust_simple"): return get_core_mantle_crust_weight( theta_nu, pnu, flavors, cross_section_type=cross_section_type) elif (mode == "core_mantle_crust"): earth = CoreMantleCrustModel() direction = hp.spherical_to_cartesian(theta_nu, phi_nu) slant_depth = earth.slant_depth(vertex_position, direction) # by requesting the interaction length for a density of 1, we get it in units of length**2/weight L_int = cross_sections.get_interaction_length( pnu, density=1., flavor=flavors, inttype='total', cross_section_type=cross_section_type) return np.exp(-slant_depth / L_int) elif (mode == "PREM"): earth = PREM() direction = hp.spherical_to_cartesian(theta_nu, phi_nu) slant_depth = earth.slant_depth(vertex_position, direction) # by requesting the interaction length for a density of 1, we get it in units of length**2/weight L_int = cross_sections.get_interaction_length( pnu, density=1., flavor=flavors, inttype='total', cross_section_type=cross_section_type) return np.exp(-slant_depth / L_int) elif (mode == "None"): return 1. else: logger.error('mode {} not supported'.format(mode)) raise NotImplementedError