def azel2radec(az_deg, el_deg, lat_deg, lon_deg, dtime): obs = EarthLocation(lat=lat_deg * u.deg, lon=lon_deg * u.deg) direc = AltAz(location=obs, obstime=Time(dtime), az=az_deg * u.deg, alt=el_deg * u.deg) sky = SkyCoord(direc.transform_to(ICRS())) return sky.ra.deg, sky.dec.deg
def RunAstrometryCalibration(InputImage,Outputfile=None): """ Does Astrometry calibration of input fits image InputImage. Returns True if calibration succeded.""" # Following lines are TIRSPEC specific for formating the time from fits header obs_timehdr = fits.getval(InputImage,'OBSTIME') obs_datehdr = fits.getval(InputImage,'OBSDATE') time_str = '{0} {1}'.format('-'.join(obs_datehdr.split('.')),obs_timehdr) time = Time(time_str,format='iso',scale='utc') hct_hanle = EarthLocation(lat=32.77944*u.deg, lon=78.9641*u.deg, height=4500*u.m) zenith = AltAz(location=hct_hanle, obstime=time, az=0*u.deg, alt=90*u.deg) ZenithRaDec = zenith.transform_to(ICRS) # Finally call astrometry.net software to calibrate fits image Z_ra = '{0.ra}'.format(ZenithRaDec).split()[0] Z_dec = '{0.dec}'.format(ZenithRaDec).split()[0] ret = subprocess.call(['solve-field','--no-plots', '--ra',Z_ra, '--dec',Z_dec, '--radius','85', '--scale-units','arcsecperpix', '--scale-low','0.28', '--scale-high','0.32', InputImage]) print(ret) if ret == 0: if Outputfile is not None: print('Copying {0} to {1}'.format(os.path.splitext(InputImage)[0]+'.new',Outputfile)) shutil.copy(os.path.splitext(InputImage)[0]+'.new',Outputfile) return True else: return False
def azel2radec(az_deg, el_deg, lat_deg, lon_deg, dtime): if usevallado: ra_deg, dec_deg = azel2radecvallado( az_deg,el_deg,lat_deg,lon_deg,dtime) else: #use astropy v1.0 + obs = EarthLocation(lat=lat_deg*u.deg, lon=lon_deg*u.deg) direc = AltAz(location=obs, obstime=Time(dtime), az=az_deg*u.deg, alt=el_deg*u.deg) sky = SkyCoord(direc.transform_to(ICRS())) return sky.ra.deg, sky.dec.deg
def azel2radec(az_deg: float, el_deg: float, lat_deg: float, lon_deg: float, time: datetime, usevallado: bool = False) -> Tuple[float, float]: """ viewing angle (az, el) to sky coordinates (ra, dec) Parameters ---------- az_deg : float or numpy.ndarray of float azimuth [degrees clockwize from North] el_deg : float or numpy.ndarray of float elevation [degrees above horizon (neglecting aberration)] lat_deg : float observer latitude [-90, 90] lon_deg : float observer longitude [-180, 180] (degrees) time : datetime.datetime or str time of observation usevallado : bool, optional default use astropy. If true, use Vallado algorithm Returns ------- ra_deg : float or numpy.ndarray of float ecliptic right ascension (degress) dec_deg : float or numpy.ndarray of float ecliptic declination (degrees) """ if usevallado or Time is None: # non-AstroPy method, less accurate return vazel2radec(az_deg, el_deg, lat_deg, lon_deg, time) obs = EarthLocation(lat=lat_deg * u.deg, lon=lon_deg * u.deg) direc = AltAz(location=obs, obstime=Time(str2dt(time)), az=az_deg * u.deg, alt=el_deg * u.deg) sky = SkyCoord(direc.transform_to(ICRS())) return sky.ra.deg, sky.dec.deg
def altaz_to_radec(alt=35, az=90, location=None, obstime=None, *args, **kwargs): """ Convert alt/az degrees to RA/Dec SkyCoord Args: alt (int, optional): Altitude, defaults to 35 az (int, optional): Azimute, defaults to 90 (east) location (None, required): A ~astropy.coordinates.EarthLocation location must be passed. obstime (None, optional): Time for object, defaults to `current_time` Returns: `astropy.coordinates.SkyCoord: FK5 SkyCoord """ assert location is not None if obstime is None: obstime = current_time() verbose = kwargs.get('verbose', False) if verbose: print("Getting coordinates for Alt {} Az {}, from {} at {}".format(alt, az, location, obstime)) altaz = AltAz(obstime=obstime, location=location, alt=alt * u.deg, az=az * u.deg) return SkyCoord(altaz.transform_to(ICRS))
def SUN_POS(): """ Finds sun position in RA and DEC at sunrise and sunset to find which parts of the sky are viewable """ LIST = [] loc = coord.EarthLocation(lon=28.7134 * u.deg, lat=17.9058 * u.deg) start = Time(datetime.utcnow(), format='datetime', scale='utc') - TimeDelta(1, format='jd') for i in range(0, 384): T = start + TimeDelta(i * 225, format='sec') LST = T.sidereal_time('apparent', '28.7134d') TMP1 = str(LST).split('h') TMP2 = TMP1[1].split('m') TMP3 = TMP2[1].split('s') LST = (15 * float(TMP1[0]) + 0.0166667 * float(TMP2[0]) + 0.000277778 * float(TMP3[0])) altazframe = AltAz(obstime=T, location=loc) sunaltaz = coord.get_sun(T).transform_to(altazframe) if sunaltaz.alt.value <= -47 and len(LIST) == 0: LIST.append(str(coord.get_sun(T).ra).split('d')[0]) print('Sunset') print(T) elif sunaltaz.alt.value >= 48 and len(LIST) == 1: LIST.append(str(coord.get_sun(T).ra).split('d')[0]) print('Sunrise') print(T) break UP = 30 + (float(LIST[0]) + float(LIST[1])) / 2 LOW = (float(LIST[0]) + float(LIST[1])) / 2 - 30 return ([UP, LOW])
def test_gcrs_altaz(): """ Check GCRS<->AltAz transforms for round-tripping. Has multiple paths """ from astropy.coordinates import EarthLocation ra, dec, _ = randomly_sample_sphere(1) gcrs = GCRS(ra=ra[0], dec=dec[0], obstime='J2000') # check array times sure N-d arrays work times = Time(np.linspace(2456293.25, 2456657.25, 51) * u.day, format='jd') loc = EarthLocation(lon=10 * u.deg, lat=80. * u.deg) aaframe = AltAz(obstime=times, location=loc) aa1 = gcrs.transform_to(aaframe) aa2 = gcrs.transform_to(ICRS()).transform_to(CIRS()).transform_to(aaframe) aa3 = gcrs.transform_to(ITRS()).transform_to(CIRS()).transform_to(aaframe) # make sure they're all consistent assert_allclose(aa1.alt, aa2.alt) assert_allclose(aa1.az, aa2.az) assert_allclose(aa1.alt, aa3.alt) assert_allclose(aa1.az, aa3.az)
def airmass(self, ra, dec, lat_input, lon_input, height_input, time_input, AIRMASS_MIN, AIRMASS_MAX): """ Airmass calculation at a given time in a particular site.""" # Geodetic coordinates of observatory observatory = astropy.coordinates.EarthLocation(lat=lat_input * u.deg, lon=lon_input * u.deg, height=height_input * u.m) max_prob_p = SkyCoord(ra=ra * u.deg, dec=dec * u.deg, frame='icrs') # ipix sky coordinates time = Time(time_input) # Time object altaz = max_prob_p.transform_to( AltAz(obstime=time, location=observatory)) # Altitude-Azimuth system #--> Horizontal coordinates airmass_value = altaz.secz # 1/cos(altaz) if airmass_value <= AIRMASS_MIN or airmass_value >= AIRMASS_MAX: airmass_value = "nan" else: airmass_value = round(airmass_value, 2) return airmass_value
def put_radec(fitsfile,skycoo): """Put RA,DEC coordinates into a fits file. Parameters ---------- fitsfile : string Fits file name to update. skycoo : astropy.coordinates.SkyCoord Object Sky coordinates of the object. """ comm = {'OBJCTRA':'Nominal Right Ascension of center of image', 'OBJCTDEC':'Nominal Declination of center of image'} hdulist = fits.open(fitsfile) hdu = hdulist[0] data = hdu.data try: target_name = hdu.header['OBJECT'].strip() except: msg = '*** FATAL ERROR: target '+target_name+' not found' t120.log.error(msg) raiseValueError(msg) hdu.header['OBJECT'] = (target_name.upper().replace(' ',''),'Target name') t120.log.info('target_name='+target_name) time = Time(hdu.header['DATE-OBS']) site = EarthLocation(lat=hdu.header['SITELAT'], lon=hdu.header['SITELONG']) altazframe = AltAz(obstime=time, location=site) altaz = skycoo.transform_to(altazframe) hdu.header['OBJCTRA'] = (skycoo.ra.to('deg').value,comm['OBJCTRA']) hdu.header['OBJCTDEC'] = (skycoo.dec.to('deg').value,comm['OBJCTDEC']) hdu.header['CRVAL1'] = (skycoo.ra.to('deg').value ,'Reference Right ascencion in decimal deg') hdu.header['CRVAL2'] = (skycoo.dec.to('deg').value,'Reference Declination in decimal deg') hdu.header['HISTORY'] = 'RA,DEC values inserted with py routine.' hdu.writeto(fitsfile,overwrite=True) t120.log.info('File '+fitsfile+' successfully updated with RADEC info') return
def get_pointing_meridian_scan(time, alt, az, location, x_position, y_position, altaz=False): ''' estimate the pointing RA Dec accoriding obs time and init Dec for drift scan pointing at meridian time: obs time ''' c0 = SkyCoord(alt=alt, az=az, frame='altaz', location=location, obstime=time) c0 = c0.transform_to('icrs') separation = np.sqrt(x_position ** 2 + y_position ** 2) * u.arcmin position_angle = np.arctan2(x_position, -y_position) * u.rad _c = offset_by(c0[:, None], position_angle[None, :], separation[None, :]) #return _c.ra.deg, _c.dec.deg if altaz: _altaz = _c.transform_to(AltAz(obstime=time, location=location)).altaz return _altaz.alt.deg, _altaz.az.deg else: return _c.ra.deg, _c.dec.deg
def hx_aer_astropy(x_gcrs, time, observer_lla=None, trans_matrix=None, observer_itrs=None): """ desc: measurement function - convert state into a measurement where measurements are [azimuth, elevation] :param x_gcrs: :param time: :param observer_lla: :param trans_matrix: :param observer_itrs: Observer coordinates in itrs (meters) :return: array[azimuth, elevation, slant] """ object = SkyCoord(x=x_gcrs[0] * u.m, y=x_gcrs[1] * u.m, z=x_gcrs[2] * u.m, frame='gcrs', representation_type='cartesian', obstime=time) if observer_itrs is None: obs = EarthLocation.from_geodetic(lat=observer_lla[0] * u.rad, lon=observer_lla[1] * u.rad, height=observer_lla[2] * u.m) else: obs = EarthLocation.from_geocentric(x=observer_itrs[0] * u.m, y=observer_itrs[1] * u.m, z=observer_itrs[2] * u.m) AltAz_frame = AltAz(obstime=time, location=obs) results = object.transform_to(AltAz_frame) az = results.az.to_value(u.rad) alt = results.alt.to_value(u.rad) sr = results.distance.to_value(u.m) aer = np.array([az, alt, sr]) return aer
def plot2D_runs(runs, names, source, threshold, ax=None): for i, df in enumerate(runs): ax = ax or plt.gca() df_selected = df.query(f'gammaness > {threshold}') crab = SkyCoord.from_name(source) altaz = AltAz( location = EarthLocation.of_site('Roque de los Muchachos'), obstime = Time(df_selected.dragon_time, format='unix') ) telescope_pointing = SkyCoord( alt = u.Quantity(df_selected.alt_tel.to_numpy(), u.rad, copy=False), az = u.Quantity(df_selected.az_tel.to_numpy(), u.rad, copy=False), frame = altaz ) camera_frame = CameraFrame( focal_length = u.Quantity(df_selected.focal_length.to_numpy(), u.m, copy=False), telescope_pointing = telescope_pointing, location = EarthLocation.of_site('Roque de los Muchachos'), obstime = Time(df_selected.dragon_time, format='unix') ) crab_cf = crab.transform_to(camera_frame) crab_tf = crab_cf.transform_to(TelescopeFrame()) ax.scatter( crab_tf.fov_lon.to_value(u.deg), crab_tf.fov_lat.to_value(u.deg), color = f'C{i}', marker = ',', label = names[i] ) ax.legend() ax.set_xlabel(r'fov_lon$ \,/\, \mathrm{deg}$') ax.set_ylabel(r'fov_lat$ \,/\, \mathrm{deg}$') return ax
def hx2(x, t, obs_lat=observer_lat, obs_lon=observer_lon, obs_height=observer_alt): # measurement function - convert state into a measurement # where measurements are [azimuth, elevation] object = SkyCoord(x=x[0] * u.km, y=x[1] * u.km, z=x[2] * u.km, frame='gcrs', representation_type='cartesian', obstime=t) obs = EarthLocation.from_geodetic(lon=obs_lon * u.rad, lat=obs_lat * u.rad, height=obs_height * u.m) AltAz_frame = AltAz(obstime=t, location=obs) results = object.transform_to(AltAz_frame) az = results.az.to_value(u.rad) alt = results.alt.to_value(u.rad) sr = results.distance.to_value(u.km) aer = np.array([az, alt, sr]) return aer
def horizontal_to_camera_cta_simtel(alt, az, alt_pointing, az_pointing, focal_length): with warnings.catch_warnings(): warnings.simplefilter('ignore', MissingFrameAttributeWarning) altaz = AltAz() source_altaz = SkyCoord( alt=u.Quantity(alt, u.deg, copy=False), az=u.Quantity(az, u.deg, copy=False), frame=altaz, ) tel_pointing = SkyCoord( alt=u.Quantity(alt_pointing, u.deg, copy=False), az=u.Quantity(az_pointing, u.deg, copy=False), frame=altaz, ) camera_frame = CameraFrame( focal_length=u.Quantity(focal_length, u.m, copy=False), telescope_pointing=tel_pointing, ) cam_coords = source_altaz.transform_to(camera_frame) return cam_coords.x.to_value(u.m), cam_coords.y.to_value(u.m)
def makeTableElevConstrains(year, month): day = 1 t0 = Time("%d-%02d-%02d 00:00:00" % (year, month, day), format = 'iso', scale = 'utc') titer = t0 while titer.datetime.month == month: moonpos = astropy.coordinates.get_moon(titer, location=IAR) moonHA = observer.target_hour_angle(target = moonpos, time = titer) moonHA = moonHA.deg moonAltAz = moonpos.transform_to(AltAz(obstime = titer, location = IAR)) if 180 < moonHA < 360: moonHA = moonHA - 360. if (-29 <= moonHA <= -27) or (27 <= moonHA <= 29): print "%s,%02.02f,%0.03f,%0.02f,%0.02f" % (titer.datetime, moonHA, moonpos.dec.deg, moonAltAz.az.deg, moonAltAz.alt.deg) titer += fiveMins
def itrs2horizon(station, ts, positions, coord_type): """ Convert cartesian coordinates of targets in ITRF to spherical coordinates in topocentric reference frame for a specific station. Usage: az,alt,rho = itrs2horizon(station,ts,ts_quasi_mjd,positions,coord_type) Inputs: station -> [numercial array or list with 3 elements] coordinates of station. It can either be geocentric(x, y, z) coordinates or geodetic(lon, lat, height) coordinates. Unit for (x, y, z) are meter, and for (lon, lat, height) are degree and meter. ts -> [str array] isot-formatted UTC for interpolated prediction positions -> [2d float array] target positions in cartesian coordinates in meters w.r.t. ITRF for interpolated prediction. coord_type -> [str] coordinates type for coordinates of station; it can either be 'geocentric' or 'geodetic'. Outputs: az -> [float array] Azimuth for interpolated prediction in degrees alt -> [float array] Altitude for interpolated prediction in degrees rho -> [float array] Range for interpolated prediction in meters """ if coord_type == 'geocentric': x, y, z = station site = EarthLocation.from_geocentric(x, y, z, unit='m') elif coord_type == 'geodetic': lat, lon, height = station site = EarthLocation.from_geodetic(lon, lat, height) coords = SkyCoord(positions, unit='m', representation_type='cartesian', frame='itrs', obstime=Time(ts)) horizon = coords.transform_to(AltAz(obstime=Time(ts), location=site)) az, alt, rho = horizon.az.deg, horizon.alt.deg, horizon.distance.m return az, alt, rho
def get_altaz_in_rotated_frame( self, time: Time, location: EarthLocation, altaz: SkyCoord, ) -> SkyCoord: """Rotates the given coordinates to the frame defined by given the altitude and azimuth offsets for the given time and observing_location. Parameters ---------- time : `Time` The Time for which the AltAz coordinates are valid location : `EarthLocation` The observing_location for which the AltAz coordinates are valid altaz : `SkyCoord` The altitude and azimuth to rotate. Returns ------- telescope_altaz: `SkyCoord` The altitude and azimuth rotated to the new frame. """ telescope_altaz = AltAz(alt=self.delta_alt, az=self.delta_az, obstime=time, location=location) telescope_frame = altaz.transform_to( SkyOffsetFrame(origin=telescope_altaz)) return SkyCoord( alt=Angle(telescope_frame.lon.deg * u.deg), az=Angle(telescope_frame.lat.deg * u.deg), frame="altaz", obstime=time, location=location, )
def test_separation_is_the_same(): from ctapipe.coordinates import TelescopeFrame obstime = Time('2013-11-01T03:00') location = EarthLocation.of_site('Roque de los Muchachos') horizon_frame = AltAz(location=location, obstime=obstime) crab = SkyCoord(ra='05h34m31.94s', dec='22d00m52.2s') ceta_tauri = SkyCoord(ra='5h37m38.6854231s', dec='21d08m33.158804s') # simulate crab "on" observations telescope_pointing = crab.transform_to(horizon_frame) telescope_frame = TelescopeFrame( telescope_pointing=telescope_pointing, location=location, obstime=obstime, ) ceta_tauri_telescope = ceta_tauri.transform_to(telescope_frame) crab_telescope = crab.transform_to(telescope_frame) sep = ceta_tauri_telescope.separation(crab_telescope).to_value(u.deg) assert ceta_tauri.separation(crab).to_value(u.deg) == approx(sep, rel=1e-4)
def _orientation(location, time='now'): """ Return the orientation angle for the Sun from a specified Earth location and time. The orientation angle is the angle between local zenith and solar north, measured eastward from local zenith. Parameters ---------- location : `~astropy.coordinates.EarthLocation` Observer location on Earth time : {parse_time_types} Time to use in a parse_time-compatible format Returns ------- out : `~astropy.coordinates.Angle` The orientation of the Sun """ obstime = parse_time(time) # Define the frame where its Z axis is aligned with local zenith local_frame = AltAz(obstime=obstime, location=location) return _sun_north_angle_to_z(local_frame)
def test_regression_5133(): N = 1000 np.random.seed(12345) lon = np.random.uniform(-10, 10, N) * u.deg lat = np.random.uniform(50, 52, N) * u.deg alt = np.random.uniform(0, 10., N) * u.km time = Time('2010-1-1') objects = EarthLocation.from_geodetic(lon, lat, height=alt) itrs_coo = objects.get_itrs(time) homes = [ EarthLocation.from_geodetic(lon=-1 * u.deg, lat=52 * u.deg, height=h) for h in (0, 1000, 10000) * u.km ] altaz_frames = [AltAz(obstime=time, location=h) for h in homes] altaz_coos = [itrs_coo.transform_to(f) for f in altaz_frames] # they should all be different for coo in altaz_coos[1:]: assert not quantity_allclose(coo.az, coo.az[0]) assert not quantity_allclose(coo.alt, coo.alt[0])
def astropy_parallactic_angles(times, antenna_positions, field_centre): """ Computes parallactic angles per timestep for the given reference antenna position and field centre. """ ap = antenna_positions fc = field_centre # Convert from MJD second to MJD times = Time(times / 86400.00, format='mjd', scale='utc') ap = EarthLocation.from_geocentric( ap[:, 0], ap[:, 1], ap[:, 2], unit='m') fc = SkyCoord(ra=fc[0], dec=fc[1], unit=units.rad, frame='fk5') pole = SkyCoord(ra=0, dec=90, unit=units.deg, frame='fk5') cirs_frame = CIRS(obstime=times) pole_cirs = pole.transform_to(cirs_frame) fc_cirs = fc.transform_to(cirs_frame) altaz_frame = AltAz(location=ap[None, :], obstime=times[:, None]) pole_altaz = pole_cirs[:, None].transform_to(altaz_frame) fc_altaz = fc_cirs[:, None].transform_to(altaz_frame) return fc_altaz.position_angle(pole_altaz)
def save_png(self, figname: str, beam_contours: bool = True, show_sources: bool = True, **kwargs): """ """ image_center = altaz_to_radec( SkyCoord( self.analog_pointing.az, self.analog_pointing.alt, frame=AltAz( obstime=self.tv_image.time[0], location=nenufar_position ) ) ) #kwargs = {} if show_sources: src_names = [] src_position = [] with open(join(dirname(__file__), "nenufar_tv_sources.json")) as src_file: sources = json.load(src_file) for name in sources["FixedSources"]: src = FixedTarget.from_name(name, time=self.tv_image.time[0]) if src.coordinates.separation(image_center) <= 0.8*self.fov_radius: src_names.append(name) src_position.append(src.coordinates) for name in sources["SolarSystemSources"]: src = SolarSystemTarget.from_name(name, time=self.tv_image.time[0]) if src.coordinates.separation(image_center) <= 0.8*self.fov_radius: src_names.append(name) src_position.append(src.coordinates) if len(src_position) != 0: kwargs["text"] = (SkyCoord(src_position), src_names, "white") if beam_contours: # Simulate the array factor ma = MiniArray() af_sky = ma.array_factor( sky=HpxSky( resolution=0.2*u.deg, time=self.tv_image.time[0], frequency=self.tv_image.frequency[0] ), pointing=Pointing( coordinates=image_center, time=self.tv_image.time[0] ) ) # Normalize the array factor af = af_sky[0, 0, 0].compute() af_normalized = af/af.max() kwargs["contour"] = (af_normalized, np.arange(0.5, 1, 0.2), "copper") # Plot self.tv_image[0, 0, 0].plot( center=image_center, radius=self.fov_radius - 2.5*u.deg, figname=figname, colorbar_label=f"Stokes {self.tv_image.polarization[0]}", **kwargs ) return
def rephase_visibilities(self, phase_center, uvw): """ """ # Compute the zenith original phase center zenith = SkyCoord( np.zeros(self.time.size), np.ones(self.time.size)*90, unit="deg", frame=AltAz( obstime=self.time, location=nenufar_position ) ) zenith_phase_center = altaz_to_radec(zenith) # Define the rotation matrix def rotation_matrix(skycoord): """ """ ra_rad = skycoord.ra.rad dec_rad = skycoord.dec.rad if np.isscalar(ra_rad): ra_rad = np.array([ra_rad]) dec_rad = np.array([dec_rad]) cos_ra = np.cos(ra_rad) sin_ra = np.sin(ra_rad) cos_dec = np.cos(dec_rad) sin_dec = np.sin(dec_rad) return np.array([ [cos_ra, -sin_ra, np.zeros(ra_rad.size)], [-sin_ra*sin_dec, -cos_ra*sin_dec, cos_dec], [sin_ra*cos_dec, cos_ra*cos_dec, sin_dec], ]) # Transformation matrices to_origin = rotation_matrix(zenith_phase_center) # (3, 3, ntimes) to_new_center = rotation_matrix(phase_center) # (3, 3, 1) total_transformation = np.matmul( np.transpose( to_new_center, (2, 0, 1) ), to_origin ) # (3, 3, ntimes) rotUVW = np.matmul( np.expand_dims( (to_origin[2, :] - to_new_center[2, :]).T, axis=1 ), np.transpose( to_origin, (2, 1, 0) ) ) # (ntimes, 1, 3) phase = np.matmul( rotUVW, np.transpose(uvw, (0, 2, 1)) ) # (ntimes, 1, nvis) rotate_visibilities = np.exp( 2.j*np.pi*phase/wavelength(self.frequency).to(u.m).value[None, :, None] ) # (ntimes, nfreqs, nvis) new_uvw = np.matmul( uvw, # (ntimes, nvis, 3) np.transpose(total_transformation, (2, 0, 1)) ) return rotate_visibilities, new_uvw
def coordinate_calc(self, x_list, y_list, time_list, coord, off_az, off_el, hosei, lamda, press, temp, humi, limit=True, rotation=True): """ x_list and y_list == [deg] """ if coord == "planet": planet_flag = True coord = "altaz" else: planet_flag = False pass # coordinate check len(x_list)=len(y_list)=len(time_list) frame = self.coord_list[coord.lower()] az_list = [] el_list = [] if frame == "altaz": az_list = list(map(lambda k: k + off_az, x_list)) el_list = list(map(lambda k: k + off_el, y_list)) if planet_flag == True: tmp_az_list = [] tmp_el_list = [] for i in range(len(az_list)): azel_list = self.kisa_calc2(az_list[i], el_list[i], hosei) tmp_az_list.append(azel_list[0] + off_az) tmp_el_list.append(azel_list[1] + off_el) az_list = tmp_az_list el_list = tmp_el_list else: pass else: on_coord = SkyCoord( x_list, y_list, frame=frame, unit='arcsec', ) # convert_azel nanten2 = EarthLocation(lat=self.latitude * u.deg, lon=self.longitude * u.deg, height=self.height * u.m) on_coord.location = nanten2 on_coord.pressure = press * u.hPa #weather correction on_coord.temperature = temp * u.deg_C #weather correction on_coord.relative_humidity = humi #weather correction on_coord.obswl = lamda * u.um #weather correction altaz_list = on_coord.transform_to(AltAz(obstime=time_list)) for i in range(len(altaz_list)): azel_list = self.kisa_calc(altaz_list[i], hosei) az_list.append(azel_list[0] + off_az) el_list.append(azel_list[1] + off_el) #az_list.append(altaz_list[i].az.arcsec+off_az) #no_kisa #el_list.append(altaz_list[i].alt.arcsec+off_el) #no_kisa pass if rotation == False: az_list = [ i - 360 * 3600. if i > 180 * 3600. else i for i in az_list ] az_list = [ i + 360 * 3600. if i < -180 * 3600. else i for i in az_list ] #print("az :",az_list[0]/3600.,"el :", el_list[0]/3600.) return [az_list, el_list]
def analyze_muon_event(event): """ Generic muon event analyzer. Parameters ---------- event : ctapipe dl1 event container Returns ------- muonringparam, muonintensityparam : MuonRingParameter and MuonIntensityParameter container event """ names = [ 'LST_LST_LSTCam', 'MST_MST_NectarCam', 'MST_MST_FlashCam', 'MST_SCT_SCTCam', 'SST_1M_DigiCam', 'SST_GCT_CHEC', 'SST_ASTRI_ASTRICam', 'SST_ASTRI_CHEC' ] tail_cuts = [(5, 7), (5, 7), (10, 12), (5, 7), (5, 7), (5, 7), (5, 7), (5, 7)] # 10, 12? impact = [(0.2, 0.9), (0.1, 0.95), (0.2, 0.9), (0.2, 0.9), (0.1, 0.95), (0.1, 0.95), (0.1, 0.95), (0.1, 0.95)] * u.m ringwidth = [(0.04, 0.08), (0.02, 0.1), (0.01, 0.1), (0.02, 0.1), (0.01, 0.5), (0.02, 0.2), (0.02, 0.2), (0.02, 0.2)] * u.deg total_pix = [1855., 1855., 1764., 11328., 1296., 2048., 2368., 2048] # 8% (or 6%) as limit min_pix = [148., 148., 141., 680., 104., 164., 142., 164] # Need to either convert from the pixel area in m^2 or check the camera specs ang_pixel_width = [0.1, 0.2, 0.18, 0.067, 0.24, 0.2, 0.17, 0.2, 0.163 ] * u.deg # Found from TDRs (or the pixel area) hole_rad = [ 0.308 * u.m, 0.244 * u.m, 0.244 * u.m, 4.3866 * u.m, 0.160 * u.m, 0.130 * u.m, 0.171 * u.m, 0.171 * u.m ] # Assuming approximately spherical hole cam_rad = [2.26, 3.96, 3.87, 4., 4.45, 2.86, 5.25, 2.86] * u.deg # Above found from the field of view calculation sec_rad = [ 0. * u.m, 0. * u.m, 0. * u.m, 2.7 * u.m, 0. * u.m, 1. * u.m, 1.8 * u.m, 1.8 * u.m ] sct = [False, False, False, True, False, True, True, True] # Added cleaning here. All these options should go to an input card cleaning = True muon_cuts = { 'Name': names, 'tail_cuts': tail_cuts, 'Impact': impact, 'RingWidth': ringwidth, 'total_pix': total_pix, 'min_pix': min_pix, 'CamRad': cam_rad, 'SecRad': sec_rad, 'SCT': sct, 'AngPixW': ang_pixel_width, 'HoleRad': hole_rad } logger.debug(muon_cuts) muonringlist = [] # [None] * len(event.dl0.tels_with_data) muonintensitylist = [] # [None] * len(event.dl0.tels_with_data) tellist = [] muon_event_param = { 'TelIds': tellist, 'MuonRingParams': muonringlist, 'MuonIntensityParams': muonintensitylist } for telid in event.dl0.tels_with_data: logger.debug("Analysing muon event for tel %d", telid) image = event.dl1.tel[telid].image # Get geometry teldes = event.inst.subarray.tel[telid] geom = teldes.camera x, y = geom.pix_x, geom.pix_y dict_index = muon_cuts['Name'].index(str(teldes)) logger.debug('found an index of %d for camera %d', dict_index, geom.cam_id) tailcuts = muon_cuts['tail_cuts'][dict_index] logger.debug("Tailcuts are %s", tailcuts) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) # TODO: correct this hack for values over 90 altval = event.mcheader.run_array_direction[1] if altval > Angle(90, unit=u.deg): warnings.warn('Altitude over 90 degrees') altval = Angle(90, unit=u.deg) telescope_pointing = SkyCoord(alt=altval, az=event.mcheader.run_array_direction[0], frame=AltAz()) camera_coord = SkyCoord( x=x, y=y, frame=CameraFrame( focal_length=teldes.optics.equivalent_focal_length, rotation=geom.pix_rotation, telescope_pointing=telescope_pointing, )) nom_coord = camera_coord.transform_to( NominalFrame(origin=telescope_pointing)) x = nom_coord.delta_az.to(u.deg) y = nom_coord.delta_alt.to(u.deg) if (cleaning): img = image * clean_mask else: img = image muonring = ChaudhuriKunduRingFitter(None) logger.debug("img: %s mask: %s, x=%s y= %s", np.sum(image), np.sum(clean_mask), x, y) if not sum(img): # Nothing left after tail cuts continue muonringparam = muonring.fit(x, y, image * clean_mask) dist = np.sqrt( np.power(x - muonringparam.ring_center_x, 2) + np.power(y - muonringparam.ring_center_y, 2)) ring_dist = np.abs(dist - muonringparam.ring_radius) muonringparam = muonring.fit( x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)) dist = np.sqrt( np.power(x - muonringparam.ring_center_x, 2) + np.power(y - muonringparam.ring_center_y, 2)) ring_dist = np.abs(dist - muonringparam.ring_radius) muonringparam = muonring.fit( x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)) muonringparam.tel_id = telid muonringparam.obs_id = event.dl0.obs_id muonringparam.event_id = event.dl0.event_id dist_mask = np.abs( dist - muonringparam.ring_radius) < muonringparam.ring_radius * 0.4 pix_im = image * dist_mask nom_dist = np.sqrt( np.power(muonringparam.ring_center_x, 2) + np.power(muonringparam.ring_center_y, 2)) minpix = muon_cuts['min_pix'][dict_index] # 0.06*numpix #or 8% mir_rad = np.sqrt(teldes.optics.mirror_area.to("m2") / np.pi) # Camera containment radius - better than nothing - guess pixel # diameter of 0.11, all cameras are perfectly circular cam_rad = # np.sqrt(numpix*0.11/(2.*np.pi)) if (npix_above_threshold(pix_im, tailcuts[0]) > 0.1 * minpix and npix_composing_ring(pix_im) > minpix and nom_dist < muon_cuts['CamRad'][dict_index] and muonringparam.ring_radius < 1.5 * u.deg and muonringparam.ring_radius > 1. * u.deg): muonringparam.ring_containment = ring_containment( muonringparam.ring_radius, muon_cuts['CamRad'][dict_index], muonringparam.ring_center_x, muonringparam.ring_center_y) # Guess HESS is 0.16 # sec_rad = 0.*u.m # sct = False # if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m: # sec_rad = 1.*u.m # sct = True # # Store muon ring parameters (passing cuts stage 1) # muonringlist[idx] = muonringparam tellist.append(telid) muonringlist.append(muonringparam) muonintensitylist.append(None) ctel = MuonLineIntegrate( mir_rad, hole_radius=muon_cuts['HoleRad'][dict_index], pixel_width=muon_cuts['AngPixW'][dict_index], sct_flag=muon_cuts['SCT'][dict_index], secondary_radius=muon_cuts['SecRad'][dict_index]) if image.shape[0] == muon_cuts['total_pix'][dict_index]: muonintensityoutput = ctel.fit_muon( muonringparam.ring_center_x, muonringparam.ring_center_y, muonringparam.ring_radius, x[dist_mask], y[dist_mask], image[dist_mask]) muonintensityoutput.tel_id = telid muonintensityoutput.obs_id = event.dl0.obs_id muonintensityoutput.event_id = event.dl0.event_id muonintensityoutput.mask = dist_mask idx_ring = np.nonzero(pix_im) muonintensityoutput.ring_completeness = ring_completeness( x[idx_ring], y[idx_ring], pix_im[idx_ring], muonringparam.ring_radius, muonringparam.ring_center_x, muonringparam.ring_center_y, threshold=30, bins=30) muonintensityoutput.ring_size = np.sum(pix_im) dist_ringwidth_mask = np.abs( dist - muonringparam.ring_radius) < ( muonintensityoutput.ring_width) pix_ringwidth_im = image * dist_ringwidth_mask idx_ringwidth = np.nonzero(pix_ringwidth_im) muonintensityoutput.ring_pix_completeness = npix_above_threshold( pix_ringwidth_im[idx_ringwidth], tailcuts[0]) / len( pix_im[idx_ringwidth]) logger.debug( "Tel %d Impact parameter = %s mir_rad=%s " "ring_width=%s", telid, muonintensityoutput.impact_parameter, mir_rad, muonintensityoutput.ring_width) conditions = [ muonintensityoutput.impact_parameter * u.m < muon_cuts['Impact'][dict_index][1] * mir_rad, muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][0], muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][1], muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][0] ] if all(conditions): muonintensityparam = muonintensityoutput idx = tellist.index(telid) muonintensitylist[idx] = muonintensityparam logger.debug("Muon found in tel %d, tels in event=%d", telid, len(event.dl0.tels_with_data)) else: continue return muon_event_param
def pwv(location, Ra=None, Dec=None, P_min=300, P_max=750, line_of_site='zenith', plot=False): """ Compute the precipitable water vapor at ``location`` in direction of ``line_of_site``. Parameters ---------- location : `~fyodor.Location` Location of observatory. Ra : float Right ascension of target Dec : float Declination of target P_min : float Minimum pressure (hPa) P_max : float Maximum pressure (hPa) line_of_site : str, {"target", "zenith"} Either compute line of sight to the target or to the zenith. plot : bool Generate a plot of the PWV at each time. Returns ------- dates : list PWV : `~numpy.ndarray` """ params = load_files() times, day, epoch, date, nc_filesT, nc_filesM, h, e, r_pol = params[:9] r_eq, P, H, lon_origin, g16_data_file = params[9:] # Pressure level boundaries P_min = np.abs(P - P_min).argmin() P_max = np.abs(P - P_max).argmin() # Convert from radian to degrees: Ra = float(Ra) Dec = float(Dec) Sky = SkyCoord(ra=Ra * u.degree, dec=Dec * u.degree) Aa = Sky.transform_to( AltAz(obstime=times, location=location.to_EarthLocation())) latt = Dec lont = Ra # Computes PWV along line of sight if line_of_site == 'target': INDEX = np.ravel(np.where(Aa.alt.degree < 30)) INDEXP = np.ravel(np.where(Aa.alt.degree > 30)) # Keep time values corresponding to Alt above 30 degrees EPOCH = epoch for index in sorted(INDEX, reverse=True): del EPOCH[index] DATE = [] for i in range(0, len(epoch)): DATEt = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(EPOCH[i])) DATE.append(DATEt) Alt = Aa.alt.rad Az = Aa.az.rad # Compute distance from location to projection point delta_x = [] d_lat = [] d_lon = [] for i in range(0, len(Alt)): delta_xi = [] for j in h: delta_xt = j / np.tan(Alt[i]) delta_xt = delta_xt * u.m**-1 delta_xi.append(delta_xt) delta_x.append(delta_xi) delta_x = np.array(delta_x) for i in range(0, len(Az)): d_latt = delta_x[i, ] * np.cos(Az[i]) d_lont = delta_x[i, ] * np.sin(Az[i]) d_lat.append(d_latt) d_lon.append(d_lont) d_lat = np.array(d_lat) d_lon = np.array(d_lon) # Compute latitude and longitude of projection points lat_proj = [] lon_proj = [] for i in range(0, len(Alt)): obs_latt = ( location.latdeg + np.degrees(np.arctan(d_lat[i, ] * u.m / R_earth)).value) obs_lont = ( location.londeg + np.degrees(np.arctan(d_lon[i, ] * u.m / R_earth)).value) lat_proj.append(obs_latt) lon_proj.append(obs_lont) lat_proj = np.array(lat_proj) lon_proj = np.array(lon_proj) lat_proj_rad = np.radians(lat_proj) lon_proj_rad = np.radians(lon_proj) lambda_0 = np.radians(lon_origin) # Transform into scan angles lat_origin = np.arctan(r_pol**2 / r_eq**2 * np.tan(lat_proj_rad)) r_c = r_pol / np.sqrt(1 - (e**2) * np.cos(lat_origin)**2) x, y = geodetic_to_cartesian(lat_origin, lon_proj_rad, lambda_0, r_c, H) g16_data_fileT = [] xscanT = [] yscanT = [] XT = [] YT = [] LVT = [] # Retrieve Temperature data for i in INDEXP: g16_data = nc_filesT[i] g16_data_fileT.append(g16_data) g16 = Dataset(nc_filesT[i], 'r') xtemp = g16.variables['x'][:] xscanT.append(xtemp) ytemp = g16.variables['y'][:] yscanT.append(ytemp) LVTi = [] Xi = [] Yi = [] for j in range(P_min, P_max + 1): Xtemp = np.abs(xtemp - x[i, j]).argmin() Xi.append(Xtemp) Ytemp = np.abs(ytemp - y[i, j]).argmin() Yi.append(Ytemp) LVTtemp = g16.variables['LVT'][Ytemp, Xtemp, j] LVTi.append(LVTtemp) LVT.append(LVTi) XT.append(Xi) YT.append(Yi) LVT = np.array(LVT) # Retrieve Relative humidity data g16_data_fileM = [] xscanM = [] yscanM = [] XM = [] YM = [] LVM = [] for i in INDEXP: g16_dataM = nc_filesM[i] g16_data_fileM.append(g16_dataM) g16M = Dataset(nc_filesM[i], 'r') xtempM = g16M.variables['x'][:] xscanM.append(xtempM) ytempM = g16M.variables['y'][:] yscanM.append(ytempM) LVMi = [] Xi = [] Yi = [] for j in range(P_min, P_max + 1): XtempM = np.abs(xtempM - x[i, j]).argmin() Xi.append(XtempM) YtempM = np.abs(ytempM - y[i, j]).argmin() Yi.append(YtempM) LVMtemp = g16M.variables['LVM'][YtempM, XtempM, j] LVMi.append(LVMtemp) LVM.append(LVMi) XM.append(Xi) YM.append(Yi) LVM = np.array(LVM) P = 100 * P LVT = LVT - 273.15 Pi = P[P_min:P_max + 1] PWV = pwv_integral(LVT, LVM, Pi) if plot: # Plot and save data fig = plt.figure(figsize=(8, 5)) ax = fig.add_subplot(111) ax.plot(DATE, PWV, 'bo', ms=4) plt.title('Precipitable Water Vapor along line of sight, {} on {}'. format(location.site, day[0]), fontsize=20) plt.xticks(rotation='vertical', fontsize=16) plt.yticks(fontsize=16) ax.set_xlabel("Date", color="C0", fontsize=18) ax.set_ylabel("PWV (mm)", color="C0", fontsize=18) RA_patch = mpatches.Patch(color='white', label='RA: {} degrees'.format(Ra)) Dec_patch = mpatches.Patch(color='white', label='Dec: {} degrees'.format(Dec)) every_nth = 4 for n, label in enumerate(ax.xaxis.get_ticklabels()): if n % every_nth != 0: label.set_visible(False) for n, label in enumerate(ax.xaxis.get_ticklines()): if n % every_nth != 0: label.set_visible(False) plt.tight_layout() plt.legend(handles=[RA_patch, Dec_patch], loc='lower right', fontsize=18) out_date = DATE # Computes PWV at zenith elif line_of_site == 'zenith': # Transform latitude and longitude into scan angles lambda_0 = np.radians(lon_origin) obs_lat_rad = np.radians(latt) obs_lon_rad = np.radians(lont) lat_origin = np.arctan(r_pol**2 / r_eq**2 * np.tan(obs_lat_rad)) r_c = r_pol / (np.sqrt(1 - (e**2) * (np.cos(lat_origin))**2)) x, y = geodetic_to_cartesian(lat_origin, obs_lon_rad, lambda_0, r_c, H) xscanT = [] yscanT = [] # Retrieve Temperature data LVT = [] for i in range(0, len(nc_filesT)): g16_data = nc_filesT[i] g16_data_file.append(g16_data) g16 = Dataset(g16_data_file[i], 'r') xtemp = g16.variables['x'][:] xscanT.append(xtemp) ytemp = g16.variables['y'][:] yscanT.append(ytemp) XT = [] YT = [] LVTi = [] for j in range(0, len(P)): Xtemp = np.abs(xtemp - x).argmin() XT.append(Xtemp) Ytemp = np.abs(ytemp - y).argmin() YT.append(Ytemp) LVTtemp = g16.variables['LVT'][Ytemp, Xtemp, j] LVTi.append(LVTtemp) LVT.append(LVTi) LVT = np.array(LVT) # Retrieve Relative humidity data g16_data_fileM = [] xscanM = [] yscanM = [] LVM = [] for i in range(0, len(nc_filesM)): g16_dataM = nc_filesM[i] g16_data_fileM.append(g16_dataM) g16M = Dataset(g16_data_fileM[i], 'r') xtempM = g16M.variables['x'][:] xscanM.append(xtempM) ytempM = g16M.variables['y'][:] yscanM.append(ytempM) XM = [] YM = [] LVMi = [] for j in range(0, len(P)): XtempM = np.abs(xtempM - x).argmin() XM.append(XtempM) YtempM = np.abs(ytempM - y).argmin() YM.append(YtempM) LVMtemp = g16M.variables['LVM'][YtempM, XtempM, j] LVMi.append(LVMtemp) LVM.append(LVMi) LVM = np.array(LVM) # Change pressure units to Pa and Temperature to K P = 100 * P LVT = LVT - 273.15 PWV = pwv_integral(LVT, LVM, P) if plot: fig = plt.figure(figsize=(8, 5)) ax = fig.add_subplot(111) ax.plot(date, PWV, 'bo', ms=4) plt.title('Precipitable Water Vapor at zenith, {} on {}'.format( location.site, day[0]), fontsize=20) plt.xticks(rotation='vertical', fontsize=16) plt.yticks(fontsize=16) ax.set_xlabel("Date", color="C0", fontsize=18) ax.set_ylabel("PWV (mm)", color="C0", fontsize=18) every_nth = 4 for n, label in enumerate(ax.xaxis.get_ticklabels()): if n % every_nth != 0: label.set_visible(False) for n, label in enumerate(ax.xaxis.get_ticklines()): if n % every_nth != 0: label.set_visible(False) plt.tight_layout() out_date = date return out_date, PWV
def showPfsDesign(pfsDesigns, date=None, timerange=8, showTime=None, showDesignId=True): """Show the altitude at Subaru of the available pfsDesigns as a function of time. pfsDesigns: array of `pfs.datamodel.PfsDesign` The available designs date: `str` or ``None`` The desired date; if None use today (in HST) If None, also show the current time unless showTime is False timerange: `int` Total number of hours to show, centred at midnight showTime: `bool` or `None` If False don't show the current time even if known showDesignId: `bool` Include the pfsDesignId in the labels """ if date is None: now = datetime.datetime.now(pytz.timezone('US/Hawaii')) date = now.date() now += datetime.timedelta(utcoffset / 24) # all times are actually kept in UTC else: now = None midnight = Time(f'{date} 00:00:00') # UTC, damn astropy time = midnight + np.linspace(24 - timerange / 2, 24 + timerange / 2, 100) * u.hour global subaru if subaru is None: subaru = EarthLocation.of_site('Subaru') telstate = AltAz(obstime=time - utcoffset * u.hour, location=subaru) # AltAz needs UTC xformatter = mdates.DateFormatter('%H:%M') plt.gca().xaxis.set_major_formatter(xformatter) for pfsDesign in pfsDesigns: boresight = SkyCoord(ra=pfsDesign.raBoresight * u.degree, dec=pfsDesign.decBoresight * u.degree, frame='icrs') label = showDesignId plt.plot(time.datetime, boresight.transform_to(telstate).alt, label=f"0x{pfsDesign.pfsDesignId:x} {pfsDesign.designName}" if showDesignId else pfsDesign.designName) plt.gcf().autofmt_xdate() plt.legend(prop={"family": "monospace"} if showDesignId else {}) if now is not None and showTime is not False: plt.axvline(now, ls='-', color='black', alpha=0.5) plt.ylim(max([-1, plt.ylim()[0]]), None) plt.xlabel("Local Time") plt.ylabel("Altitude (deg)") plt.title(f"{date}")
def altaz2radec(altaz, location, obstime=None, epoch_RA=2000.0, time_type=None): """ ---------------------------------------------------------------------------- Convert Alt-Az to RA-Dec with accurate ephemeris Inputs: altaz [numpy array] Altitude and Azimuth as a Nx2 numpy array. All units in degrees location [instance of class astropy.coordinates.EarthLocation] Location of the observer provided as an instance of class astropy.coordinates.EarthLocation obstime [scalar, string, or instance of class astropy.time.Time] The time or epoch which applies to input altaz. It can be a scalar (in JD or JYear), string (JYear string prefixed with 'J' or ISO or ISOT), or an instance of class astropy.time.Time. The appropriate format must be specified in input time_type. If set to None (default), it will be set equal to epoch_RA. epoch_RA [scalar, string, or instance of class astropy.time.Time] The time or epoch which applies to output radec. It can be a scalar (in JD or JYear), string (JYear string prefixed with 'J' or ISO or ISOT), or an instance of class astropy.time.Time. The appropriate format must be specified in input time_type. It must be in the same format as the one obstime is specified in. If set to 2000.0 (default), it is assumed to be in 'jyear' format. If set to None, it will be set equal to default of 2000.0 in 'jyear' format. time_type [string] Specifies the format in which obstime and epoch_RA are provided. Accepted values are 'jd' (Julian Day), 'jyear' (Julian year), 'iso' or 'isot'. If set to None (default) and if obstime and/or epoch_RA is a scalar, the corresponding scalar entries are assumed to be in Julian Year. Output: The output radec as a numpy array of shape (N,2) in units of degrees is returned at the epoch specified in epoch_RA. ---------------------------------------------------------------------------- """ if isinstance(altaz, NP.ndarray): if altaz.size == 2: altaz = altaz.reshape(1,-1) if altaz.ndim != 2: raise ValueError('Input altaz must be a numpy array of shape (N,2)') if altaz.shape[1] != 2: raise ValueError('Input altaz must be a numpy array of shape (N,2)') elif not isinstance(altaz, AltAz): raise TypeError('Input altaz must be a numpy array or an instance of class astropy.coordinates.AltAz') if not isinstance(location, EarthLocation): raise TypeError('Input location must be an instance of class astropy.coordinates.EarthLocation') if epoch_RA is not None: if isinstance(epoch_RA, (int,float)): if (time_type is None) or (time_type.lower() == 'jyear'): equinox_RA = Time(epoch_RA, scale='utc', format='jyear') elif time_type.lower() == 'jd': equinox_RA = Time(epoch_RA, scale='utc', format='jd') elif isinstance(epoch_RA, str): if time_type.lower() == 'jyear': equinox_RA = Time('J{0:.9f}'.format(epoch_RA), scale='utc', format='jyear_str') elif (time_type.lower() == 'iso') or (time_type.lower() == 'isot'): equinox_RA = Time(epoch_RA, scale='utc', format=time_type.lower()) elif isinstance(epoch_RA, Time): equinox_RA = copy.copy(epoch_RA) else: raise TypeError('Input epoch_RA is invalid or currently not accepted') else: equinox_RA = Time(2000.0, format='jyear', scale='utc') warnings.warn('No epoch_RA provided. Setting epoch to {0}'.format(equinox_RA.jyear_str)) if obstime is not None: if isinstance(obstime, (int,float)): if (time_type is None) or (time_type.lower() == 'jyear'): equinox_altaz = Time(obstime, scale='utc', format='jyear') elif time_type.lower() == 'jd': equinox_altaz = Time(obstime, scale='utc', format='jd') elif isinstance(obstime, str): if time_type.lower() == 'jyear': equinox_altaz = Time('J{0:.9f}'.format(obstime), scale='utc', format='jyear_str') if (time_type.lower() == 'iso') or (time_type.lower() == 'isot'): equinox_altaz = Time(obstime, scale='utc', format=time_type.lower()) elif isinstance(obstime, Time): equinox_altaz = copy.copy(obstime) else: raise TypeError('Input obstime is invalid or currently not accepted') else: if isinstance(altaz, AltAz): equinox_altaz = copy.deepcopy(altaz.obstime) else: equinox_altaz = copy.copy(equinox_RA) warnings.warn('No obstime provided. Setting obstime to {0}'.format(equinox_altaz.jyear_str)) if isinstance(altaz, AltAz): elaz = copy.deepcopy(altaz) else: elaz = AltAz(alt=altaz[:,0]*U.deg, az=altaz[:,1]*U.deg, obstime=equinox_altaz, location=location) coords_radec = elaz.transform_to(FK5(equinox=equinox_RA)) radec = NP.hstack((coords_radec.ra.deg.reshape(-1,1), coords_radec.dec.deg.reshape(-1,1))) return radec
observation_time = ephem.Date('2018/3/30 03:00:00.00') for i in xrange(len(data)): observer = ephem.Observer() observer.lon = np.radians(mandi_lon) observer.lat = np.radians(mandi_lat) observer.elevation = 1000 observer.date = observation_time output_alt, output_az = [], [] for l in xrange(5): names = ['Star1', 'Star2', 'Star3', 'Star4', 'Star5'] ra, dec = observer.radec_of(np.radians(stars_az[l]), np.radians(stars_alt[l])) ab = data[i] lato, lono = ab['latitude'], ab['longitude'] new_location = EarthLocation(lat=lato, lon=lono, height=100 * u.m) new_time = Time('2018-3-30 12:00:00') aa = AltAz(location=new_location, obstime=new_time) coord = SkyCoord(str(ra), str(dec), unit='deg') g = coord.transform_to(aa) az, alt = boring_function(str(g.az)), boring_function(str(g.alt)) output_az.append(az) output_alt.append(alt) wb = load_workbook('output.xlsx') sheet = wb.get_sheet_by_name('N-W') sheet[putter_string[l] + str(i + 2)] = "alt=" + str(alt) + ", az=" + str(az) wb.save(filename='output.xlsx')
def run(obs, method, h5parmFilename, maxdtec=0.5, maxvtec=50, alphaIon=11 / 3, hIon=250e3, vIon=20, seed=0, fitsFilename=None, stepname='tec', angRes=60, expfolder='', ncpu=0): """ Simulate TEC values and store them to a h5parm. Parameters ---------- method : str Method to use: "fits": read TEC values from the FITS cube specified by fitsFilename "tid": generate a traveling ionospheric disturbance (TID) wave "turbulence": generate a turbulent ionosphere h5parmFilename : str Filename of output h5parm file. maxdtec : float, optional. Default = 0.5 Maximum screen dTEC per timestep in TECU. maxvtec: float, optional. Default = 50. Highest vTEC in daily modulation in TECU. alphaIon: float, optional. Default = 11/3. Ionosphere power spectrum exponent. Is 11/3 for Kolmogorov, de Gasperin and Mevius found 3.89 for LOFAR. hIon : float, optional. Default = 250 km Height of thin layer ionoshpere. vIono : float, optional. Default = 20 m/s Velocity of tecscreen. This controls the tec variation frequency. seed: int, optional. Random screen seed. Use for reproducibility. fitsFilename : str, optional Filename of input FITS cube with dTEC solutions. stepname _ str, optional Name of step to use in DPPP parset angRes : float, optional. Default = 60. Angular resolution of the screen [arcsec]. Only for turbulent model. expfolder : str, optional. Default = None Export the tecscreen data to this folder for plotting. Depending on system memory, this will not work for very large/highres screens. Only for 'turbulence' method. ncpu : int, optional Number of cores to use, by default all available. """ # TODO : Test TID and polynomial method for multi-ms usage method = method.lower() if ncpu == 0: ncpu = mp.cpu_count() # Get sky model properties ras, decs = obs.get_patch_coords() source_names = obs.get_patch_names() ants = obs.stations sp = obs.stationpositions times = obs.get_times() tecvals = np.zeros((len(times), len(ants), len(ras))) weights = np.ones_like(tecvals) if method == 'turbulence': directions = np.array([ras, decs]).T tecvals = comoving_tecscreen(sp, directions, times, alpha=alphaIon, angRes=angRes, hIon=hIon, vIon=vIon, maxvtec=maxvtec, maxdtec=maxdtec, ncpu=ncpu, expfolder=expfolder, seed=seed) elif method == 'fits': # Load solutions from FITS cube hdu = pyfits.open(fitsFilename, memmap=False) data = hdu[0].data header = hdu[0].header w = wcs.WCS(header) ntimes, _, nstations, ny, nx = data.shape # Check that number of stations in input FITS cube matches MS if nstations != len(ants): logger.error('Number of stations in input FITS cube does not ' 'match that in the input MS') return 1 # Get solutions at the source coords for d, (ra_deg, dec_deg) in enumerate(zip(ras, decs)): ra_dec = np.array([[ra_deg, dec_deg, 0, 0, 0]]) x = int(w.wcs_world2pix(ra_dec, 0)[0][0]) y = int(w.wcs_world2pix(ra_dec, 0)[0][1]) if x < 0 or x > nx or y < 0 or y > ny: tecvals[:, :, d, :] = 0.0 weights[:, :, d, :] = 0.0 continue for t in range(ntimes): for s in range(nstations): tecvals[t, s, d] = data[t, 0, s, y, x] tecvals = daytime_tec_modulation(times)[:, np.newaxis, np.newaxis] * ( tecvals + maxvtec) elif method == 'tid': # Properties of TID wave tidLen = 200e3 tidVel = 500e3 / 3600, tid_prop = [maxdtec, tidLen, tidVel] # Generate solutions for TID wave A12 = EarthLocation(lat=52.91 * u.deg, lon=6.87 * u.deg, height=1 * u.m) mjd = Time(times / (3600.0 * 24.0), format="mjd") aa = AltAz(location=A12, obstime=mjd) altazcoord = [] pool = mp.Pool(processes=ncpu) radec = [(r, d, aa) for r, d in zip(ras, decs)] altazcoord = pool.map(_getaltaz, radec) gettec_args = [(a, sp, A12, times, *tid_prop) for a in altazcoord] alltec = pool.map(_gettec, gettec_args) pool.close() pool.join() alltec = np.array(alltec) # Fill the axis arrays tecvals = alltec[:, :, 0, :].transpose([2, 1, 0]) # [:,:,:,0] # convert to vTEC tecvals = daytime_tec_modulation(times)[:, np.newaxis, np.newaxis] * ( tecvals + maxvtec) else: logger.error('method "{}" not understood'.format(method)) return 1 # Write tec values to h5parm file as DPPP input ho = h5parm(h5parmFilename, readonly=False) if 'sol000' in ho.getSolsetNames(): solset = ho.getSolset('sol000') else: solset = ho.makeSolset(solsetName='sol000') if 'tec000' in solset.getSoltabNames(): logger.info('''Solution-table tec000 is already present in {}. It will be overwritten.'''.format(h5parmFilename + '/sol000')) solset.getSoltab('tec000').delete() st = solset.makeSoltab('tec', 'tec000', axesNames=['time', 'ant', 'dir'], axesVals=[times, ants, source_names], vals=tecvals, weights=weights) antennaTable = solset.obj._f_get_child('antenna') antennaTable.append(list(zip(*(ants, sp)))) sourceTable = solset.obj._f_get_child('source') vals = [[ra, dec] for ra, dec in zip(ras, decs)] sourceTable.append(list(zip(*(source_names, vals)))) # Add CREATE entry to history soltabs = solset.getSoltabs() for st in soltabs: st.addHistory('CREATE (by TEC operation of LoSiTo from obs {0} ' 'and method="{{1}}")'.format(h5parmFilename, method)) ho.close() # Update predict parset parameters for the obs obs.add_to_parset(stepname, 'tec000', h5parmFilename) return 0
def get_observation_site_location(): current_time = get_current_time() observation_site = get_current_location() observation_site_frame = AltAz(obstime=current_time, location=observation_site) return observation_site_frame
Greenland = EarthLocation( lat=Angle(72.5796, 'deg'), lon=Angle(-38.4592, 'deg'), height=3200 * u.m), Tibet = EarthLocation( lat=Angle(32.3166667, 'deg'), lon=Angle(80.0166666667, 'deg'), height=5100 * u.m), ) location = locations[LOCATION] start_time = Time(datetime.datetime(2015, 8, 1), scale='ut1') sampling_interval = TimeDelta(SAMPLING, format="sec") time = start_time + sampling_interval * np.arange(0., HOURS*3600/SAMPLING) # zenith altaz = AltAz(az=Angle(0., unit=u.degree), alt=ELEVATION, obstime=time, location=location) radec = altaz.transform_to(ICRS) ra_zenith = radec.ra.radian dec_zenith = radec.dec.radian # local north altaz = AltAz(az=Angle(0., unit=u.degree), alt=Angle(0., unit=u.degree), obstime=time, location=location) radec = altaz.transform_to(ICRS) ra_north = radec.ra.radian dec_north = radec.dec.radian import pandas as pd pd.DataFrame({"ra_zenith_rad":ra_zenith, "dec_zenith_rad":dec_zenith, "ra_north_rad":ra_north, "dec_north_rad":dec_north}, index=time.datetime).to_hdf("zenith_pointing_" + LOCATION.lower() + ".h5", "data")
def execute(self, command): t = Time(Time.now(), location=self.location) altaz = SkyCoord(self.STATE['az'], self.STATE['alt'], unit=(u.hour, u.deg), frame=AltAz(obstime=t, location=self.location)) # Apply state changes based on the command. if command == 'Abort': self.STATE['status'].slewing = 0 self.STATE['status'].tracking = 0 elif command == 'Park': self.STATE['alt'] = 50 self.STATE['az'] = 90 self.STATE['status'].parked = 1 elif command == 'UnPark': self.STATE['status'].parked = 0 elif command.startswith('GoToAltAz'): command, az, alt = command.split(' ') altaz = SkyCoord(az, alt, unit=u.deg, frame=AltAz(obstime=t, location=self.location)) self.STATE['destination']['alt'] = altaz.alt.deg self.STATE['destination']['az'] = altaz.az.deg # Slew to the given alt/az, updating current alt and az as we go. # TODO: threading.Thread(target=self._slew_altaz).start() self.STATE['alt'] = altaz.alt.deg self.STATE['az'] = altaz.az.deg elif command.startswith('GoTo'): command, ra, dec, equinox = command.split(' ') radec = SkyCoord(ra, dec, unit=(u.hour, u.deg), equinox='J2000', obstime=t, location=self.location) self.STATE['destination']['ra'] = radec.ra.hour self.STATE['destination']['dec'] = radec.dec.deg self.STATE['destination']['equinox'] = str(equinox) self.STATE['destination']['alt'] = radec.altaz.alt.deg self.STATE['destination']['az'] = radec.altaz.az.deg # Slew to the given ra/dec, updating current ra and dec as we go. # TODO: threading.Thread(target=self._slew_radec).start() self.STATE['ra'] = radec.ra.hour self.STATE['dec'] = radec.dec.deg self.STATE['status'].tracking = 1 elif command.startswith('SetTrackMode'): command, tracking, track_type, ra_rate, dec_rate = command.split( ' ') self.STATE['status'].tracking = int(tracking) self.STATE['status'].non_sidereal_tracking = int(track_type) self.STATE.update({ 'tracking': { 'enabled': int(tracking), 'ra_rate': float(ra_rate), 'dec_rate': float(dec_rate), }, }) elif command.startswith('SyncToAltAz'): command, az, alt = command.split(' ') self.STATE['alt'] = float(alt) self.STATE['az'] = float(az) elif command.startswith('Sync'): command, ra, dec, type_, equinox = command.split(' ') self.STATE['ra'] = float(ra) self.STATE['dec'] = float(dec) self.STATE['equinox'] = equinox elif command.startswith('PulseGuide'): pass # TODO elif command == 'MotorsToBlinky': self.STATE['status'].manual = 1 elif command == 'MotorsToAuto': self.STATE['status'].manual = 0 elif command.startswith('CookCoordinates'): pass # TODO elif command.startswith('UnCookCoordinates'): pass # TODO elif command.startswith('JogArcSeconds'): command, direction, arcsec = command.split(' ') arcsec = float(arcsec) * u.arcsec if direction == 'N': self.STATE['dec'] = (Angle(self.STATE['dec'] * u.deg) + arcsec).value elif direction == 'S': self.STATE['dec'] = (Angle(self.STATE['dec'] * u.deg) - arcsec).value elif direction == 'E': self.STATE['ra'] = (Angle(self.STATE['ra'] * u.hour) + arcsec).value elif direction == 'W': self.STATE['ra'] = (Angle(self.STATE['ra'] * u.hour) - arcsec).value # Construct a response based on the issued command. if command == 'ReadScopeDestination': response = '{};{};{};{};{};{};{};{};{};{};{};_'.format( self.STATE['status'].value, self.STATE['destination']['ra'], self.STATE['destination']['dec'], self.STATE['destination']['alt'], self.STATE['destination']['az'], self.STATE['secondary_axis_angle'], self.STATE['primary_axis_angle'], t.sidereal_time(kind='apparent').hour, t.jd, self.STATE['time'], altaz.secz, ) elif command == 'RotatorComms': response = '{};{};{};{};{};{};{};{};{};{};{};_'.format( self.STATE['status'].value, self.STATE['ra'], self.STATE['dec'], self.STATE['alt'], self.STATE['az'], self.STATE['derotator'][ self.STATE['instrument']]['parallactic_angle'], self.STATE['derotator'][ self.STATE['instrument']]['parallactic_rate'], self.STATE['derotator'][ self.STATE['instrument']]['camera_solved_angle'], self.STATE['derotator'][self.STATE['instrument']] ['destination_position'], self.STATE['time'], altaz.secz, ) elif command == 'SiteLocations': response = '{};{};{};_SiteLocations'.format( self.location.lat.value, self.location.lon.value, self.location.height.value) else: response = '{};{};{};{};{};{};{};{};{};{};{};_'.format( self.STATE['status'].value, self.STATE['ra'], self.STATE['dec'], self.STATE['alt'], self.STATE['az'], self.STATE['secondary_axis_angle'], self.STATE['primary_axis_angle'], t.sidereal_time(kind='apparent').hour, t.jd, self.STATE['time'], altaz.secz, ) return response + Driver.TERMINATOR
def get_instrumental_mags(data, coords, obsname, ext): ''' Takes a hipercam data object, and exctracts the instrumental magnitude of each aperture in each CCD If Coords and an observatory are supplied, also correct for airmass, using supplied extinction coeffiecients Arguments: ---------- data: hipercam.Hlog The data to analyse. tseries will be extracted from here. coords: str Ra, Dec of the data. Must be readable by Astropy. obsname: str Observing location name of the data. ext: iterable Extinction corrections to apply, given in CCD order. i.e. [<CCD1 ext>, <CCD2 ext>, ...] Returns: -------- all_mags: dict Dict, with the keys corresponding to the CCD numbers. Each entry is a numpy array of the instrumental magnitudes, in the order they're found in the aperture list. ''' logger.printer("------- Getting instrumental magnitude -------") logger.printer(" I'm correcting for airmass, using the following:") logger.printer(" Extinction: {} mags/airmass".format(ext)) logger.printer(" Ra, Dec: {}".format(coords)) logger.printer(" Observatory: {}".format(obsname)) # Where are we? try: observatory = coord.EarthLocation.of_site(obsname) logger.printer("Observatory successfully retrieved from site name") except: obsname = obsname.split(',') if len(obsname) != 2: logger.printer(" The (lat, lon) MUST!!! be comma separated!") exit() lat, lon = obsname logger.printer( " Earth location from latitude, longitude: {}, {}".format( lat, lon)) observatory = coord.EarthLocation.from_geodetic(lat=lat, lon=lon) star_loc = coord.SkyCoord(coords, unit=(u.hourangle, u.deg)) # I want altitude converted to zenith angle. obs_T = data.tseries('1', '1').t obs_T = time.Time(obs_T, format='mjd') # Define the altAz frame, containing the time and location altAz_frame = AltAz(obstime=obs_T, location=observatory) star_loc_AltAz = star_loc.transform_to(altAz_frame) # Compute the airmass, at the time of the first frame zenith_angle = 90 - star_loc_AltAz.alt.deg zenith_angle_rad = np.deg2rad(zenith_angle) airmass = 1. / np.cos(zenith_angle_rad) logger.printer( " For the observations starting at {} and ending at {}...".format( obs_T[0].iso, obs_T[-1].iso)) logger.printer( " -> Zenith angle starts at {:.3f}, and ends at {:.3f}".format( zenith_angle[0], zenith_angle[-1])) logger.printer(" -> Airmass starts at {:.3f}, ends at {:.3f}".format( airmass[0], airmass[-1])) # I'll use the mean for reporting. mean_airmass = np.mean(airmass) logger.printer("Mean airmass: {:.3f}".format(mean_airmass)) if np.any(airmass) <= 0: logger.printer("Airmass is negative!! We have a problem there!") logger.printer("EarthLocation (constructed from {}):".format(obsname)) logger.printer(str(observatory)) logger.printer(str(observatory.lat), str(observatory.lon)) logger.printer("Star location:") logger.printer(str(star_loc)) input("Hit enter to continue... ") logger.printer( "\nGetting the INSTRUMENTAL (electron flux) magnitudes for the log file" ) all_mags = {} aps = data.apnames CCDs = [str(i + 1) for i, key in enumerate(aps)] if ext is None: logger.printer("NOT applying extinction corrections!!!") ext = [0.0 for i in CCDs] ext = np.array(ext) # Data masking stuff FLAG = np.uint32(0) for f in FLAGS_TO_IGNORE: FLAG = FLAG | f if FLAG: logger.printer(" Ignoring bad data flags: {}".format(FLAGS_TO_IGNORE)) logger.printer("List of keys:") logger.printer(hcam.FLAGS) for CCD in CCDs: logger.printer("\n---> Doing CCD {} <---".format(CCD)) # information gathering ap = sorted(aps[CCD]) ex = ext[int(CCD) - 1] exptime = data[CCD]['Exptim'] # star magnitudes mags = [] for comp in ap: logger.printer("") star = data.tseries(CCD, comp) ### AIRMASSES ### # I want altitude converted to zenith angle. obs_T = star.t obs_T = time.Time(obs_T, format='mjd') # Define the altAz frame, containing the time and location altAz_frame = AltAz(obstime=obs_T, location=observatory) star_loc_AltAz = star_loc.transform_to(altAz_frame) # Compute the airmass, at the time of the first frame zenith_angle = 90 - star_loc_AltAz.alt.deg zenith_angle_rad = np.deg2rad(zenith_angle) airmass = 1. / np.cos(zenith_angle_rad) # Mask out data that has flags # Filter out flags I don't care about. star.mask = star.mask & (~FLAG) mask = star.mask != 0 # First and last data are never good mask[0] = True mask[-1] = True if np.any(star.mask): removed = np.sum(star.mask != 0) logger.printer("Bad data detected!") logger.printer( "The mask will remove {}/{} data points.".format( removed, len(star.y))) # star counts/s fl = star.y / exptime # Get magnitudes, and apply atmospheric extinction correction to each frame. aperture_mags = -2.5 * np.log10(fl) aperture_mags -= (ex * airmass) # Take a clipped mean mag, mag_median, mag_sigma = sigma_clipped_stats(aperture_mags, mask=mask, sigma=3.0) # Just for reporting counts_per_frame = np.mean(star.y[np.where(mask == False)]) counts_per_frame_err = np.std(star.y[np.where(mask == False)]) logger.printer( "Aperture {} had a clipped mean counts per frame of {:.2f}+/-{:.2f}" .format(comp, counts_per_frame, counts_per_frame_err)) logger.printer(" and a mean exposure time of {:.3f}s".format( np.mean(exptime))) # logger.printer(" Pre-ext correct: CCD {}, Ap {}, mag: {:.3f}+/-{:.3f}".format(CCD, comp, -2.5*np.log10(fl), mag_sigma)) mags.append(mag) mags = np.array(mags) logger.printer(" CCD {} extinction: {:.3f} mags".format( CCD, ex * mean_airmass)) logger.printer(" Post-ext correct:") for i, mag in enumerate(mags): logger.printer(" Ap {}: {:.3f} mags".format(i, mag)) logger.printer("\n\n") all_mags[CCD] = np.array(mags) return all_mags
def enu_to_enu(from_coo, to_frame): # for now we just implement this through AltAz to make sure we get everything # covered return from_coo.transform_to( AltAz(obstime=from_coo.obstime)).transform_to(to_frame)
def altaz_frame(self): """ALT / AZ frame (`~astropy.coordinates.AltAz`).""" return AltAz(obstime=self.time, location=self.location)
def plot(self, date): """ Produce plot of the object visability for date Modified from https://docs.astropy.org/en/stable/generated/examples/coordinates/plot_obs-planning.html """ import matplotlib.pyplot as plt from astropy.visualization import astropy_mpl_style plt.style.use(astropy_mpl_style) midnight = self.observer.midnight(date, which='next') delta_midnight = np.linspace(-2, 10, 100) * u.hour frame_night = AltAz(obstime=midnight + delta_midnight, location=self.location) targetaltazs_night = self.target.transform_to(frame_night) # Use `~astropy.coordinates.get_sun` to find the location of the Sun at 1000 from astropy.coordinates import get_sun delta_midnight = np.linspace(-12, 12, 1000) * u.hour times = midnight + delta_midnight frame = AltAz(obstime=times, location=self.location) sunaltazs = get_sun(times).transform_to(frame) # Do the same with `~astropy.coordinates.get_moon` to find when the moon is # up. Be aware that this will need to download a 10MB file from the internet # to get a precise location of the moon. from astropy.coordinates import get_moon moon = get_moon(times) moonaltazs = moon.transform_to(frame) ############################################################################## # Find the alt,az coordinates of M33 at those same times: targetaltazs = self.target.transform_to(frame) ############################################################################## # Make a beautiful figure illustrating nighttime and the altitudes of M33 and # the Sun over that time: plt.plot(delta_midnight, sunaltazs.alt, color='r', label='Sun') plt.plot(delta_midnight, moonaltazs.alt, color=[0.75] * 3, ls='--', label='Moon') plt.scatter(delta_midnight, targetaltazs.alt, c=targetaltazs.az, label='Target', lw=0, s=8, cmap='viridis') plt.fill_between(delta_midnight.to('hr').value, 0, 90, sunaltazs.alt < -0 * u.deg, color='0.5', zorder=0) plt.fill_between(delta_midnight.to('hr').value, 0, 90, sunaltazs.alt < -18 * u.deg, color='k', zorder=0) plt.hlines(self.altConstraint, -12, 12, colors='red', linestyles='dotted', lw=1) plt.colorbar().set_label('Azimuth [deg]') plt.legend(loc='upper left') plt.xlim(-12, 12) plt.xticks(np.arange(13) * 2 - 12) plt.ylim(0, 90) plt.xlabel('Hours from Local Midnight') plt.ylabel('Altitude [deg]') plt.show()
def make_test_observation_table(observatory_name='HESS', n_obs=10, datestart=None, dateend=None, use_abs_time=False, random_state='random-seed'): """Make a test observation table. For the moment, only random observation tables are created. If `datestart` and `dateend` are specified, the starting time of the observations will be restricted to the specified interval. These parameters are interpreted as date, the precise hour of the day is ignored, unless the end date is closer than 1 day to the starting date, in which case, the precise time of the day is also considered. Parameters ---------- observatory_name : str Name of the observatory; a list of choices is given in `~gammapy.obs.observatory_locations`. n_obs : int Number of observations for the obs table. datestart : `~astropy.time.Time`, optional Starting date for random generation of observation start time. dateend : `~astropy.time.Time`, optional Ending date for random generation of observation start time. use_abs_time : bool, optional Use absolute UTC times instead of [MET]_ seconds after the reference. random_state : {int, 'random-seed', 'global-rng', `~numpy.random.RandomState`}, optional Defines random number generator initialisation. Passed to `~gammapy.utils.random.get_random_state`. Returns ------- obs_table : `~gammapy.obs.ObservationTable` Observation table. """ random_state = get_random_state(random_state) n_obs_start = 1 obs_table = ObservationTable() # build a time reference as the start of 2010 dateref = Time('2010-01-01T00:00:00', format='isot', scale='utc') dateref_mjd_fra, dateref_mjd_int = np.modf(dateref.mjd) # define table header obs_table.meta['OBSERVATORY_NAME'] = observatory_name obs_table.meta['MJDREFI'] = dateref_mjd_int obs_table.meta['MJDREFF'] = dateref_mjd_fra if use_abs_time: # show the observation times in UTC obs_table.meta['TIME_FORMAT'] = 'absolute' else: # show the observation times in seconds after the reference obs_table.meta['TIME_FORMAT'] = 'relative' header = obs_table.meta # obs id obs_id = np.arange(n_obs_start, n_obs_start + n_obs) obs_table['OBS_ID'] = obs_id # obs time: 30 min time_observation = Quantity(30. * np.ones_like(obs_id), 'minute').to('second') obs_table['TIME_OBSERVATION'] = time_observation # livetime: 25 min time_live = Quantity(25. * np.ones_like(obs_id), 'minute').to('second') obs_table['TIME_LIVE'] = time_live # start time # - random points between the start of 2010 and the end of 2014 (unless # otherwise specified) # - using the start of 2010 as a reference time for the header of the table # - observations restrict to night time (only if specified time interval is # more than 1 day) # - considering start of astronomical day at midday: implicit in setting # the start of the night, when generating random night hours if datestart == None: datestart = Time('2010-01-01T00:00:00', format='isot', scale='utc') if dateend == None: dateend = Time('2015-01-01T00:00:00', format='isot', scale='utc') time_start = random_state.uniform(datestart.mjd, dateend.mjd, len(obs_id)) time_start = Time(time_start, format='mjd', scale='utc') # check if time interval selected is more than 1 day if (dateend - datestart).jd > 1.: # keep only the integer part (i.e. the day, not the fraction of the day) time_start_f, time_start_i = np.modf(time_start.mjd) time_start = Time(time_start_i, format='mjd', scale='utc') # random generation of night hours: 6 h (from 22 h to 4 h), leaving 1/2 h # time for the last run to finish night_start = Quantity(22., 'hour') night_duration = Quantity(5.5, 'hour') hour_start = random_state.uniform(night_start.value, night_start.value + night_duration.value, len(obs_id)) hour_start = Quantity(hour_start, 'hour') # add night hour to integer part of MJD time_start += hour_start if use_abs_time: # show the observation times in UTC time_start = Time(time_start.isot) else: # show the observation times in seconds after the reference time_start = time_relative_to_ref(time_start, header) # converting to quantity (better treatment of units) time_start = Quantity(time_start.sec, 'second') obs_table['TIME_START'] = time_start # stop time # calculated as TIME_START + TIME_OBSERVATION if use_abs_time: time_stop = Time(obs_table['TIME_START']) time_stop += TimeDelta(obs_table['TIME_OBSERVATION']) else: time_stop = TimeDelta(obs_table['TIME_START']) time_stop += TimeDelta(obs_table['TIME_OBSERVATION']) # converting to quantity (better treatment of units) time_stop = Quantity(time_stop.sec, 'second') obs_table['TIME_STOP'] = time_stop # az, alt # random points in a sphere above 45 deg altitude az, alt = sample_sphere(size=len(obs_id), lon_range=Angle([0, 360], 'degree'), lat_range=Angle([45, 90], 'degree'), random_state=random_state) az = Angle(az, 'degree') alt = Angle(alt, 'degree') obs_table['AZ'] = az obs_table['ALT'] = alt # RA, dec # derive from az, alt taking into account that alt, az represent the values # at the middle of the observation, i.e. at time_ref + (TIME_START + TIME_STOP)/2 # (or better: time_ref + TIME_START + (TIME_OBSERVATION/2)) # in use_abs_time mode, the time_ref should not be added, since it's already included # in TIME_START and TIME_STOP az = Angle(obs_table['AZ']) alt = Angle(obs_table['ALT']) if use_abs_time: obstime = Time(obs_table['TIME_START']) obstime += TimeDelta(obs_table['TIME_OBSERVATION']) / 2. else: obstime = time_ref_from_dict(obs_table.meta) obstime += TimeDelta(obs_table['TIME_START']) obstime += TimeDelta(obs_table['TIME_OBSERVATION']) / 2. location = observatory_locations[observatory_name] alt_az_coord = AltAz(az=az, alt=alt, obstime=obstime, location=location) sky_coord = alt_az_coord.transform_to(FK5) obs_table['RA'] = sky_coord.ra obs_table['DEC'] = sky_coord.dec # positions # number of telescopes # random integers between 3 and 4 n_tels_min = 3 n_tels_max = 4 n_tels = random_state.randint(n_tels_min, n_tels_max + 1, len(obs_id)) obs_table['N_TELS'] = n_tels # muon efficiency # random between 0.6 and 1.0 muon_efficiency = random_state.uniform(low=0.6, high=1.0, size=len(obs_id)) obs_table['MUON_EFFICIENCY'] = muon_efficiency return obs_table