def test_simtel_event_source_on_gamma_test_one_event(): assert SimTelEventSource.is_compatible(gamma_test_large_path) with SimTelEventSource( input_url=gamma_test_large_path, back_seekable=True, focal_length_choice="nominal", ) as reader: assert not reader.is_stream for event in reader: if event.count > 1: break with pytest.warns(UserWarning): for event in reader: # Check generator has restarted from beginning assert event.count == 0 break
def simtel_event_source(url, camera=None, max_events=None, allowed_tels=None, requested_event=None, use_event_id=False, event_id=None, disable_bar=False): """A generator that streams data from an EventIO/HESSIO MC data file (e.g. a standard CTA data file.) Parameters ---------- url : str path to file to open max_events : int, optional maximum number of events to read allowed_tels : list[int] select only a subset of telescope, if None, all are read. This can be used for example emulate the final CTA data format, where there would be 1 telescope per file (whereas in current monte-carlo, they are all interleaved into one file) requested_event : int Seek to a paricular event index use_event_id : bool If True ,'requested_event' now seeks for a particular event id instead of index disable_bar : Unused, for compatibility with other readers """ if event_id is not None: raise ValueError('Event id feature not implemented yet! \n' 'Use event_id=None') if not SimTelEventSource.is_compatible(url): raise ValueError(url, 'is not a valid simtel file') data = DataContainer() data.meta['origin'] = "hessio" # some hessio_event_source specific parameters data.meta['input'] = url # data.meta['max_events'] = max_events with SimTelFile(url) as file: telescope_descriptions = file.telescope_descriptions subarray_info = SimTelEventSource.prepare_subarray_info( telescope_descriptions, file.header) counter = 0 for array_event in tqdm(file, disable=disable_bar): # Seek to requested event if requested_event is not None: current = counter if use_event_id: current = event_id if not current == requested_event: counter += 1 continue run_id = file.header['run'] event_id = array_event['event_id'] tels_with_data = set(array_event['telescope_events'].keys()) data.inst.subarray = subarray_info data.r0.run_id = run_id data.r0.event_id = event_id data.r0.tels_with_data = tels_with_data data.r1.run_id = run_id data.r1.event_id = event_id data.r1.tels_with_data = tels_with_data data.dl0.run_id = run_id data.dl0.event_id = event_id data.dl0.tels_with_data = tels_with_data # handle telescope filtering by taking the intersection of # tels_with_data and allowed_tels if allowed_tels is not None: selected = data.r0.tels_with_data & allowed_tels if len(selected) == 0: continue # skip event data.r0.tels_with_data = selected data.r1.tels_with_data = selected data.dl0.tels_with_data = selected trigger_information = array_event['trigger_information'] mc_event = array_event['mc_event'] mc_shower = array_event['mc_shower'] data.trig.tels_with_trigger = \ trigger_information['triggered_telescopes'] time_s, time_ns = trigger_information['gps_time'] data.trig.gps_time = Time(time_s * u.s, time_ns * u.ns, format='unix', scale='utc') data.mc.energy = mc_shower['energy'] * u.TeV data.mc.alt = Angle(mc_shower['altitude'], u.rad) data.mc.az = Angle(mc_shower['azimuth'], u.rad) data.mc.core_x = mc_event['xcore'] * u.m data.mc.core_y = mc_event['ycore'] * u.m first_int = mc_shower['h_first_int'] * u.m data.mc.h_first_int = first_int data.mc.x_max = mc_shower['xmax'] * u.g / (u.cm**2) data.mc.shower_primary_id = mc_shower['primary_id'] # mc run header data data.mcheader.run_array_direction = Angle( file.header['direction'] * u.rad) mc_run_head = file.mc_run_headers[-1] data.mcheader.corsika_version = mc_run_head['shower_prog_vers'] data.mcheader.simtel_version = mc_run_head['detector_prog_vers'] data.mcheader.energy_range_min = mc_run_head['E_range'][0] * u.TeV data.mcheader.energy_range_max = mc_run_head['E_range'][1] * u.TeV data.mcheader.prod_site_B_total = mc_run_head['B_total'] * u.uT data.mcheader.prod_site_B_declination = Angle( mc_run_head['B_declination'] * u.rad) data.mcheader.prod_site_B_inclination = Angle( mc_run_head['B_inclination'] * u.rad) data.mcheader.prod_site_alt = mc_run_head['obsheight'] * u.m data.mcheader.spectral_index = mc_run_head['spectral_index'] # this should be done in a nicer way to not re-allocate the # data each time (right now it's just deleted and garbage # collected) data.r0.tel.clear() data.r1.tel.clear() data.dl0.tel.clear() data.dl1.tel.clear() data.mc.tel.clear() # clear the previous telescopes telescope_events = array_event['telescope_events'] tracking_positions = array_event['tracking_positions'] for tel_id, telescope_event in telescope_events.items(): telescope_description = telescope_descriptions[tel_id] camera_monitorings = array_event['camera_monitorings'][tel_id] pedestal = camera_monitorings['pedestal'] laser_calib = array_event['laser_calibrations'][tel_id] data.mc.tel[tel_id].dc_to_pe = laser_calib['calib'] data.mc.tel[tel_id].pedestal = pedestal adc_samples = telescope_event.get('adc_samples') n_pixel = adc_samples.shape[-2] if adc_samples is None: adc_samples = telescope_event['adc_sums'][:, :, np.newaxis] data.r0.tel[tel_id].adc_samples = adc_samples data.r0.tel[tel_id].num_samples = adc_samples.shape[-1] # We should not calculate stuff in an event source # if this is not needed, we calculate it for nothing data.r0.tel[tel_id].adc_sums = adc_samples.sum(axis=-1) baseline = pedestal / adc_samples.shape[1] data.r0.tel[tel_id].digicam_baseline = np.squeeze(baseline) data.r0.tel[tel_id].camera_event_number = event_id pixel_settings = telescope_description['pixel_settings'] data.mc.tel[tel_id].reference_pulse_shape = pixel_settings[ 'refshape'].astype('float64') data.mc.tel[tel_id].meta['refstep'] = float( pixel_settings['ref_step']) data.mc.tel[tel_id].time_slice = float( pixel_settings['time_slice']) data.mc.tel[tel_id].photo_electron_image = array_event.get( 'photoelectrons', {}).get(tel_id) if data.mc.tel[tel_id].photo_electron_image is None: data.mc.tel[tel_id].photo_electron_image = np.zeros( (n_pixel, ), dtype='i2') tracking_position = tracking_positions[tel_id] data.mc.tel[tel_id].azimuth_raw = tracking_position[ 'azimuth_raw'] data.mc.tel[tel_id].altitude_raw = tracking_position[ 'altitude_raw'] data.mc.tel[tel_id].azimuth_cor = tracking_position.get( 'azimuth_cor', 0) data.mc.tel[tel_id].altitude_cor = tracking_position.get( 'altitude_cor', 0) yield data counter += 1 if max_events and counter >= max_events: return