def test_science_state(): assert erfa_astrom.get().__class__ is ErfaAstrom res = 300 * u.s with erfa_astrom.set(ErfaAstromInterpolator(res)): assert isinstance(erfa_astrom.get(), ErfaAstromInterpolator) erfa_astrom.get().mjd_resolution == res.to_value(u.day) # context manager should have switched it back assert erfa_astrom.get().__class__ is ErfaAstrom # must be a subclass of BaseErfaAstrom with pytest.raises(TypeError): erfa_astrom.set('foo')
def test_interpolation_broadcasting(): from astropy.coordinates.angle_utilities import golden_spiral_grid from astropy.coordinates import SkyCoord, EarthLocation, AltAz from astropy.time import Time import astropy.units as u from astropy.coordinates.erfa_astrom import (erfa_astrom, ErfaAstromInterpolator) # 1000 gridded locations on the sky rep = golden_spiral_grid(100) coord = SkyCoord(rep) # 30 times over the space of 1 hours times = Time('2020-01-01T20:00') + np.linspace(-0.5, 0.5, 30) * u.hour lst1 = EarthLocation( lon=-17.891498 * u.deg, lat=28.761443 * u.deg, height=2200 * u.m, ) # note the use of broadcasting so that 300 times are broadcast against 1000 positions aa_frame = AltAz(obstime=times[:, np.newaxis], location=lst1) aa_coord = coord.transform_to(aa_frame) with erfa_astrom.set(ErfaAstromInterpolator(300 * u.s)): aa_coord_interp = coord.transform_to(aa_frame) assert aa_coord.shape == aa_coord_interp.shape assert np.all(aa_coord.separation(aa_coord_interp) < 1 * u.microarcsecond)
def test_erfa_astrom(): # I was having a pretty hard time in coming # up with a unit test only testing the astrom provider # that would not just test its implementation with its implementation # so we test a coordinate conversion using it location = EarthLocation( lon=-17.891105 * u.deg, lat=28.761584 * u.deg, height=2200 * u.m, ) obstime = Time('2020-01-01T18:00') + np.linspace(0, 1, 100) * u.hour altaz = AltAz(location=location, obstime=obstime) coord = SkyCoord(ra=83.63308333, dec=22.0145, unit=u.deg) # do the reference transformation, no interpolation ref = coord.transform_to(altaz) with erfa_astrom.set(ErfaAstromInterpolator(300 * u.s)): interp_300s = coord.transform_to(altaz) # make sure they are actually different assert np.any(ref.separation(interp_300s) > 0.005 * u.microarcsecond) # make sure the resolution is as good as we expect assert np.all(ref.separation(interp_300s) < 1 * u.microarcsecond)
def add_icrs_position_params(data, source_pos): """ Updating data with ICRS position values of reconstructed positions in RA DEC coordinates and add column on separation form true source position. """ reco_alt = data["reco_alt"] reco_az = data["reco_az"] time_utc = Time(data["dragon_time"], format="unix", scale="utc") reco_altaz = SkyCoord(alt=reco_alt, az=reco_az, frame=AltAz(obstime=time_utc, location=location)) with erfa_astrom.set(ErfaAstromInterpolator(300 * u.s)): reco_icrs = reco_altaz.transform_to(frame="icrs") data["RA"] = reco_icrs.ra.to(u.deg) data["Dec"] = reco_icrs.dec.to(u.deg) data["theta"] = reco_icrs.separation(source_pos).to(u.deg) return data
def create_event_list( data, run_number, source_name, source_pos, effective_time, elapsed_time ): """ Create the event_list BinTableHDUs from the given data Parameters ---------- Data: DL2 data file 'astropy.table.QTable' Run: Run number Int Source_name: Name of the source Str Source_pos: Ra/Dec position of the source 'astropy.coordinates.SkyCoord' Effective_time: Effective time of triggered events of the run Float Elapsed_time: Total elapsed time of triggered events of the run Float Returns ------- Events HDU: `astropy.io.fits.BinTableHDU` GTI HDU: `astropy.io.fits.BinTableHDU` Pointing HDU: `astropy.io.fits.BinTableHDU` """ tel_list = np.unique(data["tel_id"]) # Timing parameters t_start = data["dragon_time"].value[0] t_stop = data["dragon_time"].value[-1] time_utc = Time(data["dragon_time"], format="unix", scale="utc") t_start_iso = time_utc[0].to_value("iso", "date_hms") t_stop_iso = time_utc[-1].to_value("iso", "date_hms") date_obs = t_start_iso[:10] time_obs = t_start_iso[11:] date_end = t_stop_iso[:10] time_end = t_stop_iso[11:] MJDREF = Time("1970-01-01T00:00", scale="utc") # Position parameters reco_alt = data["reco_alt"] reco_az = data["reco_az"] pointing_alt = data["pointing_alt"] pointing_az = data["pointing_az"] reco_altaz = SkyCoord( alt=reco_alt, az=reco_az, frame=AltAz(obstime=time_utc, location=location) ) pnt_icrs = SkyCoord( alt=pointing_alt[0], az=pointing_az[0], frame=AltAz(obstime=time_utc[0], location=location), ).transform_to(frame="icrs") with erfa_astrom.set(ErfaAstromInterpolator(30 * u.s)): reco_icrs = reco_altaz.transform_to(frame="icrs") # Observation modes source_pointing_diff = source_pos.separation(pnt_icrs) if np.around(source_pointing_diff, 1) == wobble_offset: mode = "WOBBLE" elif np.around(source_pointing_diff, 1) > 1 * u.deg: mode = "OFF" elif np.around(source_pointing_diff, 1) == 0.0 * u.deg: mode = "ON" else: # Nomenclature is to be worked out or have a separate way to mark mispointings mode = "UNDETERMINED" log.info( "Source pointing difference with camera pointing" f" is {source_pointing_diff:.3f}" ) event_table = QTable( { "EVENT_ID": data["event_id"], "TIME": data["dragon_time"], "RA": reco_icrs.ra.to(u.deg), "DEC": reco_icrs.dec.to(u.deg), "ENERGY": data["reco_energy"], # Optional columns "GAMMANESS": data["gh_score"], "MULTIP": u.Quantity(np.repeat(len(tel_list), len(data)), dtype=int), "GLON": reco_icrs.galactic.l.to(u.deg), "GLAT": reco_icrs.galactic.b.to(u.deg), "ALT": reco_alt.to(u.deg), "AZ": reco_az.to(u.deg), } ) gti_table = QTable( { "START": u.Quantity(t_start, unit=u.s, ndmin=1), "STOP": u.Quantity(t_stop, unit=u.s, ndmin=1), } ) pnt_table = QTable( { "TIME": u.Quantity(t_start, unit=u.s, ndmin=1), "RA_PNT": u.Quantity(pnt_icrs.ra.to(u.deg), ndmin=1), "DEC_PNT": u.Quantity(pnt_icrs.dec.to(u.deg), ndmin=1), "ALT_PNT": u.Quantity(pointing_alt[0].to(u.deg), ndmin=1), "AZ_PNT": u.Quantity(pointing_az[0].to(u.deg), ndmin=1), } ) # Adding the meta data # Comments can be added later for relevant metadata # Event table metadata ev_header = DEFAULT_HEADER.copy() ev_header["CREATED"] = Time.now().utc.iso ev_header["HDUCLAS1"] = "EVENTS" ev_header["OBS_ID"] = run_number ev_header["DATE-OBS"] = date_obs ev_header["TIME-OBS"] = time_obs ev_header["DATE-END"] = date_end ev_header["TIME-END"] = time_end ev_header["TSTART"] = t_start ev_header["TSTOP"] = t_stop ev_header["MJDREFI"] = int(MJDREF.mjd) ev_header["MJDREFF"] = MJDREF.mjd - int(MJDREF.mjd) ev_header["TIMEUNIT"] = "s" ev_header["TIMESYS"] = "UTC" ev_header["TIMEREF"] = "TOPOCENTER" ev_header["ONTIME"] = elapsed_time ev_header["TELAPSE"] = t_stop - t_start ev_header["DEADC"] = effective_time / elapsed_time ev_header["LIVETIME"] = effective_time ev_header["OBJECT"] = source_name ev_header["OBS_MODE"] = mode ev_header["N_TELS"] = len(tel_list) ev_header["TELLIST"] = "LST-" + " ".join(map(str, tel_list)) ev_header["INSTRUME"] = f"{ev_header['TELLIST']}" ev_header["RA_PNT"] = pnt_icrs.ra.to_value() ev_header["DEC_PNT"] = pnt_icrs.dec.to_value() ev_header["ALT_PNT"] = data["pointing_alt"].mean().to_value(u.deg) ev_header["AZ_PNT"] = data["pointing_az"].mean().to_value(u.deg) ev_header["RA_OBJ"] = source_pos.ra.to_value() ev_header["DEC_OBJ"] = source_pos.dec.to_value() ev_header["FOVALIGN"] = "RADEC" # GTI table metadata gti_header = DEFAULT_HEADER.copy() gti_header["CREATED"] = Time.now().utc.iso gti_header["HDUCLAS1"] = "GTI" gti_header["OBS_ID"] = run_number gti_header["MJDREFI"] = ev_header["MJDREFI"] gti_header["MJDREFF"] = ev_header["MJDREFF"] gti_header["TIMESYS"] = ev_header["TIMESYS"] gti_header["TIMEUNIT"] = ev_header["TIMEUNIT"] gti_header["TIMEREF"] = ev_header["TIMEREF"] # Pointing table metadata pnt_header = DEFAULT_HEADER.copy() pnt_header["CREATED"] = Time.now().utc.iso pnt_header["HDUCLAS1"] = "POINTING" pnt_header["OBS_ID"] = run_number pnt_header["MJDREFI"] = ev_header["MJDREFI"] pnt_header["MJDREFF"] = ev_header["MJDREFF"] pnt_header["TIMEUNIT"] = ev_header["TIMEUNIT"] pnt_header["TIMESYS"] = ev_header["TIMESYS"] pnt_header["OBSGEO-L"] = ( location.lon.to_value(u.deg), "Geographic longitude of telescope (deg)", ) pnt_header["OBSGEO-B"] = ( location.lat.to_value(u.deg), "Geographic latitude of telescope (deg)", ) pnt_header["OBSGEO-H"] = ( round(location.height.to_value(u.m), 2), "Geographic latitude of telescope (m)", ) pnt_header["TIMEREF"] = ev_header["TIMEREF"] # Create HDUs event = fits.BinTableHDU(event_table, header=ev_header, name="EVENTS") gti = fits.BinTableHDU(gti_table, header=gti_header, name="GTI") pointing = fits.BinTableHDU(pnt_table, header=pnt_header, name="POINTING") return event, gti, pointing
from ..apply import predict_energy, predict_disp, predict_separator from ..parallel import parallelize_array_computation from ..io import ( read_telescope_data_chunked, copy_group, set_sample_fraction, load_model, ) from ..configuration import AICTConfig from ..feature_generation import feature_generation from ..preprocessing import calc_true_disp from ..logging import setup_logging # use interpolation for all coordinate transforms # 100x speed increase with no precision lost (~uas) erfa_astrom.set(ErfaAstromInterpolator(5 * u.min)) dl3_columns = [ "run_id", "event_num", "gamma_energy_prediction", "gamma_prediction", "disp_prediction", "theta_deg", "theta_deg_off_1", "theta_deg_off_2", "theta_deg_off_3", "theta_deg_off_4", "theta_deg_off_5", "pointing_position_az", "pointing_position_zd",
from time import perf_counter import numpy as np import astropy.units as u # array with 10000 obstimes obstime = Time('2010-01-01T20:00') + np.linspace(0, 6, 10000) * u.hour location = location = EarthLocation(lon=-17.89 * u.deg, lat=28.76 * u.deg, height=2200 * u.m) frame = AltAz(obstime=obstime, location=location) crab = SkyCoord(ra='05h34m31.94s', dec='22d00m52.2s') # transform with default transformation and print duration t0 = perf_counter() crab_altaz = crab.transform_to(frame) print(f'Transformation took {perf_counter() - t0:.2f} s') # transform with interpolating astrometric values t0 = perf_counter() with erfa_astrom.set(ErfaAstromInterpolator(300 * u.s)): crab_altaz_interpolated = crab.transform_to(frame) print(f'Transformation took {perf_counter() - t0:.2f} s') err = crab_altaz.separation(crab_altaz_interpolated) print(f'Mean error of interpolation: {err.to(u.microarcsecond).mean():.4f}') # To set erfa_astrom for a whole session, use it without context manager: erfa_astrom.set(ErfaAstromInterpolator(300 * u.s))
def test_warnings(): with pytest.warns(AstropyWarning): with erfa_astrom.set(ErfaAstromInterpolator(9 * u.us)): pass