def moon_angle_var(fobj, ext): #getting RA and DEC sampling = fobj[0].header #FINDING INTERPLATE SKY TIME fin_mean = [ ] #time for each moon sky observation interplate, used for moon angle h_beg = [] h_end = [] mean_per = [] #time for each moon sky observation intraplate h = ext.header h_beg.append( h['TAI-BEG']) #ONLY VARIES WITH PLATE NUMBER, different for k's h_end.append( h['TAI-END']) #ONLY VARIES WITH PLATE NUMBER, different for k's ttime = (h['TAI-BEG'] + h['TAI-END']) / 2 #TAI TO MJD time_MJD = ttime / (86400.) t = Time(time_MJD, format='mjd') moon = get_moon(t, aplEL) moonaltaz = moon.transform_to(AltAz(location=aplEL, obstime=t)) alt = h['ALT'] az = h['AZ'] myaltaz = AltAz(alt=alt * u.deg, az=az * u.deg, location=aplEL, obstime=t) #moon_coords=SkyCoord(ra=moon_coords.ra, dec=moon_coords.dec) #MOON-SKY ANGLE CALCULATIONS moon_sky_angle = myaltaz.separation(moonaltaz) #setting up MJD format date_of_ob = t.datetime #calculating moon phase moon_phase = apl.moon_phase(date=date_of_ob) #0=New moon #7=First quarter #14=Full moon #21=Last quarter #there are only four moon phases available #in astropy error possible here phase = 0.5 * (1 - np.cos(moon_phase * np.pi * 2 / 28.)) var = np.cos(moon_sky_angle.radian) * phase return var
def test_moon_altaz(self): """Verify moon (alt,az) for first week of 2020""" ephem = get_ephem() location = get_location() for i, jd in enumerate(self.table['jd']): t = Time(jd, format='jd') night = ephem.get_night(t) f_moon = get_object_interpolator(night, 'moon', altaz=True) alt, az = f_moon(t.mjd) truth = AltAz(alt=self.table['alt'][i] * u.deg, az=self.table['az'][i] * u.deg, obstime=t, location=location, pressure=0) calc = AltAz(alt=alt * u.deg, az=az * u.deg, obstime=t, location=location, pressure=0) sep = truth.separation(calc) self.assertTrue(abs(sep.to(u.deg).value) < 0.3)
def generate_ddf(ddf_name, nyears=10, space=2): previous_ddf = generate_dd_surveys() survey_names = np.array([survey.survey_name for survey in previous_ddf]) survey_indx = np.where(survey_names == ddf_name)[0].max() ddf_ra = previous_ddf[survey_indx].ra * u.rad ddf_dec = previous_ddf[survey_indx].dec * u.rad site = Site('LSST') location = EarthLocation(lat=site.latitude, lon=site.longitude, height=site.height) mjd = np.arange(59853.5, 59853.5 + 365.25 * nyears, 20. / 60 / 24.) times = Time(mjd, format='mjd', location=location) airmass_limit = 2.5 # demand airmass lower than this twilight_limit = -18. # Sun below this altitude in degrees dist_to_moon_limit = 30. # minimum distance to keep from moon degrees zenith_limit = 10. # Need to be this far away from zenith to start (20 min = 5 deg) g_m5_limit = 23.5 # mags season_gap = 20. # days. Count any gap longer than this as it's own season season_length_limit = 80 # Days. Demand at least this many days in a season # How long to keep attempting a DDF expire_dict = {1: 36. / 24., 2: 0.5} sun_coords = get_sun(times) moon_coords = get_moon(times) sched_downtime_data = ScheduledDowntimeData(Time(mjd[0], format='mjd')) observatory_up = np.ones(mjd.size, dtype=bool) for dt in sched_downtime_data(): indx = np.where((mjd >= dt['start'].mjd) & (mjd <= dt['end'].mjd))[0] observatory_up[indx] = False lst = times.sidereal_time('mean') sun_altaz = sun_coords.transform_to(AltAz(location=location)) # generate a night label for each timestep sun_rise = np.where((sun_altaz.alt[0:-1] < 0) & (sun_altaz.alt[1:] > 0))[0] night = np.zeros(mjd.size, dtype=int) night[sun_rise] = 1 night = np.cumsum(night) + 1 # 1-index for night sun_down = np.where(sun_altaz.alt < twilight_limit * u.deg)[0] ddf_coord = SkyCoord(ra=ddf_ra, dec=ddf_dec) ddf_altaz = ddf_coord.transform_to(AltAz(location=location, obstime=times)) ddf_airmass = 1. / np.cos(np.radians(90. - ddf_altaz.az.deg)) zenith = AltAz(alt=90. * u.deg, az=0. * u.deg) ddf_zenth_dist = zenith.separation(ddf_altaz) nside = 32 ddf_indx = raDec2Hpid(nside, ddf_coord.ra.deg, ddf_coord.dec.deg) sm = SkyModelPre() g_sb = mjd * 0 + np.nan indices = np.where((sun_altaz.alt < twilight_limit * u.deg) & (ddf_airmass > airmass_limit))[0] # In theory, one could reach into the sky brightness model and do a much faster interpolation # There might be an airmass limit on the sky brightness. for indx in sun_down: g_sb[indx] = sm.returnMags(mjd[indx], indx=[ddf_indx], filters='g', badval=np.nan)['g'] dist_to_moon = ddf_coord.separation(moon_coords) seeing_model = SeeingModel() ddf_approx_fwhmEff = seeing_model(0.7, ddf_airmass) # I think this should pluck out the g-filter. Really should be labled ddf_approx_fwhmEff = ddf_approx_fwhmEff['fwhmEff'][1].ravel() ddf_m5 = m5_flat_sed('g', g_sb, ddf_approx_fwhmEff, 30., ddf_airmass, nexp=1.) # demand sun down past twilight, ddf is up, and observatory is open, and not too close to the moon good = np.where((ddf_airmass < airmass_limit) & (sun_altaz.alt < twilight_limit * u.deg) & (ddf_airmass > 0) & (observatory_up == True) & (dist_to_moon > dist_to_moon_limit * u.deg) & (ddf_zenth_dist > zenith_limit * u.deg) & (ddf_m5 > g_m5_limit)) potential_nights = np.unique(night[good]) night_gap = potential_nights[1:] - potential_nights[0:-1] big_gap = np.where(night_gap > season_gap)[0] + 1 season = potential_nights * 0 season[big_gap] = 1 season = np.cumsum(season) u_seasons = np.unique(season) season_lengths = [] for se in u_seasons: in_se = np.where(season == se) season_lengths.append( np.max(potential_nights[in_se]) - np.min(potential_nights[in_se])) season_lengths = np.array(season_lengths) good_seasons = u_seasons[np.where(season_lengths > season_length_limit)[0]] gn = np.isin(season, good_seasons) potential_nights = potential_nights[gn] season = season[gn] obs_attempts = [] for sea in np.unique(season): night_indx = np.where(season == sea) obs_attempts.append( place_obs(potential_nights[night_indx], space=space)) obs_attempts = np.concatenate(obs_attempts) mjd_observe = [] m5_approx = [] for indx in np.where(obs_attempts > 0)[0]: in_night_indx = np.where(night == potential_nights[indx])[0] best_depth_indx = np.min( np.where( ddf_m5[in_night_indx] == np.nanmax(ddf_m5[in_night_indx]))[0]) mjd_start = mjd[in_night_indx[best_depth_indx]] m5_approx.append(ddf_m5[in_night_indx[best_depth_indx]]) mjd_end = mjd_start + expire_dict[obs_attempts[indx]] mjd_observe.append((mjd_start, mjd_end)) result = np.zeros(len(mjd_observe), dtype=[('mjd_start', '<f8'), ('mjd_end', '<f8'), ('label', '<U10')]) mjd_observe = np.array(mjd_observe) result['mjd_start'] = mjd_observe[:, 0] result['mjd_end'] = mjd_observe[:, 1] result['label'] = ddf_name return result #, ddf_ra, ddf_dec #, previous_ddf[survey_indx].observations, m5_approx
def correct_altitudes(firetable, cut_cata, station): ''' correct altitude information based on correlated residuals on the global astrometric fit firetable: table to correct cut_cata: meaningful reference catalog station: Observer location ''' # TODO FIXME calculate the pixscale pixscale = (120 * u.arcsec).to(u.deg).value # Default error default_error = np.nan default_error = 0.1 # fit alt_residuals_fit = np.polyfit(cut_cata[alt_cata_col_], cut_cata[delta_alt_cata_col_], 3) alt_residuals_poly = np.poly1d(alt_residuals_fit) #firetable.show_in_browser(jsviewer=True) firetable['altitude'] = firetable['altitude'] - alt_residuals_poly(firetable['altitude']) cut_cata['corrected_delta_altitude'] = cut_cata[delta_alt_cata_col_] - alt_residuals_poly(cut_cata[alt_fitted_col_]) times = Time(Time(cut_cata['jd_mid_obs'], format='jd', scale='utc').isot) #print(cut_cata[az_cata_col_]) reference_altaz = AltAz(az=cut_cata[az_cata_col_].data*u.deg,alt=cut_cata[alt_cata_col_].data*u.deg, location=station, obstime=times) for i in range(len(firetable)): # choose reference data @ +-30 degrees cut = 30.*u.deg firepoint = firetable[i] firepoint_coord = AltAz(az=firepoint['azimuth']*u.deg, alt=firepoint['altitude']*u.deg, location=station, obstime=Time(firepoint['datetime'])) ref_subset_az = cut_cata[firepoint_coord.separation(reference_altaz) < cut] if len(ref_subset_az) < 5: firepoint['err_minus_altitude'] = default_error firepoint['err_plus_altitude'] = default_error firepoint['err_minus_azimuth'] = default_error firepoint['err_plus_azimuth'] = default_error else: err_alt = np.std(ref_subset_az['corrected_delta_altitude']) + pixscale * firepoint['err_minus_x_image'] firepoint['err_minus_altitude'] = err_alt firepoint['err_plus_altitude'] = err_alt err_az = np.std(ref_subset_az[delta_az_cata_col_]) + pixscale * firepoint['err_minus_x_image'] firepoint['err_minus_azimuth'] = err_az firepoint['err_plus_azimuth'] = err_az #firetable.show_in_browser(jsviewer=True) return firetable