def compute_constraint(self, times, observer, targets): """ Computes the observability of the moon given a minimum distance to the moon between self.min_dist (for illumination = 0) and self.max_dist (for illumination = 1) by interpolating an intermediate distance from those two values following a linear regression. @param times: the times to compute the constraint for @param observer: the observer to compute the constraint for @param targets: the list of targets to compute the constraint for @return: the positive mask for target being observable for the given times and observer given the constraint is matched """ # removed the location argument here, which causes small <1 deg # inaccuracies, but it is needed until astropy PR #5897 is released # which should be astropy 1.3.2 moon = get_moon(times) # note to future editors - the order matters here # moon.separation(targets) is NOT the same as targets.separation(moon) # the former calculates the separation in the frame of the moon coord # which is GCRS, and that is what we want. moon_separation = moon.separation(targets) illumination = moon_illumination(times) min_dist = self.min_dist.value + (self.max_dist.value - self.min_dist.value) * illumination mask = min_dist <= moon_separation.degree return mask
def moonlight_veto(self, dt, debug=False): """ Check if the Moon period defined by the rise and set time correspond to a situation where the moon is too bright or too close from the source. If this is the case (too bright or too close), returns True (the veto is confirmed). """ too_bright = False too_close = False # Check moon illumination for t in dt: moonlight = moon_illumination(Df(t)) if (moonlight >= self.moon_maxlight): too_bright = True if (debug): print("Moonlight :", moonlight, " too bright ! -> confirmed") break # Check distance to source at rise and set for t in dt: moon_radec = get_moon(Df(t), self.site) dist = moon_radec.separation(self.target.coord) if dist <= self.moon_mindist: too_close = True if (debug): print(" Moon Distance : ", dist, "too close !") break return (too_bright, too_close)
def get_moon_illumination(time): """ Get moon illumination (number from 0 to 1) at a given time INPUT: time - astropy.time.Time object OUTPUT: moon illumination from 0 to 1 """ return moon_illumination(time)
def previous_obs_func(illum_min, illum_max): filt = [] for p in previous_obs: if p.obs_mjd: mjd_prev = p.obs_mjd elif p.mjd_requested: mjd_prev = p.mjd_requested t_prev = Time(mjd_prev, format='mjd') illum_prev = moon_illumination(t_prev) if illum_prev >= illum_min and illum_prev <= illum_max: filt += [p.photometric_band.name] if len(filt) == 2: return filt return None
def moon_vis(target): day_range = 30 times = Time([ str(datetime.datetime.utcnow() + datetime.timedelta(days=delta)) for delta in np.arange(0, day_range, 0.2) ], format='iso', scale='utc') obj_pos = SkyCoord(target.ra, target.dec, unit=u.deg) moon_pos = get_moon(times) separations = moon_pos.separation(obj_pos).deg phases = moon_illumination(times) distance_color = 'rgb(0, 0, 255)' phase_color = 'rgb(255, 0, 0)' plot_data = [ go.Scatter(x=times.mjd - times[0].mjd, y=separations, mode='lines', name='Moon distance (degrees)', line=dict(color=distance_color)), go.Scatter(x=times.mjd - times[0].mjd, y=phases, mode='lines', name='Moon phase', yaxis='y2', line=dict(color=phase_color)) ] layout = go.Layout( xaxis=dict(title='Days from now'), yaxis=dict(range=[0., 180.], tick0=0., dtick=45., tickfont=dict(color=distance_color)), yaxis2=dict(range=[0., 1.], tick0=0., dtick=0.25, overlaying='y', side='right', tickfont=dict(color=phase_color)), margin=dict(l=20, r=10, b=30, t=40), #hovermode='compare', width=600, height=300, autosize=True) figure = offline.plot(go.Figure(data=plot_data, layout=layout), output_type='div', show_link=False) return {'plot': figure}
def moon_distance(target, day_range=30): """ Renders plot for lunar distance from sidereal target. Adapted from Jamison Frost Burke's moon visibility code in Supernova Exchange 2.0, as seen here: https://github.com/jfrostburke/snex2/blob/0c1eb184c942cb10f7d54084e081d8ac11700edf/custom_code/templatetags/custom_code_tags.py#L196 :param target: Target object for which moon distance is calculated :type target: tom_targets.models.Target :param day_range: Number of days to plot lunar distance :type day_range: int """ if target.type != 'SIDEREAL': return {'plot': None} day_range = 30 times = Time( [str(datetime.utcnow() + timedelta(days=delta)) for delta in np.arange(0, day_range, 0.2)], format='iso', scale='utc' ) obj_pos = SkyCoord(target.ra, target.dec, unit=u.deg) moon_pos = get_moon(times) separations = moon_pos.separation(obj_pos).deg phases = moon_illumination(times) distance_color = 'rgb(0, 0, 255)' phase_color = 'rgb(255, 0, 0)' plot_data = [ go.Scatter(x=times.mjd-times[0].mjd, y=separations, mode='lines', name='Moon distance (degrees)', line=dict(color=distance_color)), go.Scatter(x=times.mjd-times[0].mjd, y=phases, mode='lines', name='Moon phase', yaxis='y2', line=dict(color=phase_color)) ] layout = go.Layout( xaxis={'title': 'Days from now'}, yaxis={'range': [0, 180], 'tick0': 0, 'dtick': 45, 'tickfont': {'color': distance_color}}, yaxis2={'range': [0, 1], 'tick0': 0, 'dtick': 0.25, 'overlaying': 'y', 'side': 'right', 'tickfont': {'color': phase_color}}, margin={'l': 20, 'r': 10, 'b': 30, 't': 40}, width=600, height=300, autosize=True ) moon_distance_plot = offline.plot( go.Figure(data=plot_data, layout=layout), output_type='div', show_link=False ) return {'plot': moon_distance_plot}
def moonlight_plot(vis, times, ax=None, color="tab:orange"): if (ax == None): fig, ax = plt.subplots(figsize=(21, 5)) with quantity_support(): ax.plot(times.datetime, moon_illumination(times), color=color, label="Illumination") ax.axhline(y=vis.moon_maxlight, color=color, ls=":", label="Max. illumination") ax.set_ylabel("Illumination") ax.set_ylim(ymin=0, ymax=1.) ax.legend(loc="lower right") return ax
def eop(self): IERS_A_in_cache() # astroplan.get_IERS_A_or_workaround() iers.conf.auto_download = False iers.conf.auto_max_age = None now = Time.now() longitude = '78d57m53s' latitude = '32d46m44s' elevation = 4500 * u.m location = EarthLocation.from_geodetic(longitude, latitude, elevation) iaohanle = Observer(location=location, timezone='Asia/Kolkata', name="IAO", description="IAO Hanle telescopes") iaohanle # Calculating the sunset, midnight and sunrise times for our observatory sunset_iao = iaohanle.sun_set_time(now, which='nearest') eve_twil_iao = iaohanle.twilight_evening_astronomical(now, which='nearest') midnight_iao = iaohanle.midnight(now, which='next') morn_twil_iao = iaohanle.twilight_morning_astronomical(now, which='next') sunrise_iao = iaohanle.sun_rise_time(now, which='next') moon_rise = iaohanle.moon_rise_time(eve_twil_iao, which='nearest') moon_set = iaohanle.moon_set_time(now, which='nearest') # moon_alt = iaohanle.moon_altaz(now).alt # moon_az = iaohanle.moon_altaz(now).az #lst_now = iaohanle.local_sidereal_time(now) #lst_mid = iaohanle.local_sidereal_time(midnight_iao) #print("LST at IAO now is {0:.2f}".format(lst_now)) #print("LST at IAO at local midnight will be {0:.2f}".format(lst_mid)) Automation.moon_strength = moon_illumination(midnight_iao) observing_time = (morn_twil_iao - eve_twil_iao).to(u.h) #print("Total Night hours at IAO tonight {0:.1f} ".format(observing_time)) img = Image.new('RGB', (850, 320), color=(0, 0, 0)) fnt = ImageFont.truetype( '/var/lib/defoma/gs.d/dirs/fonts/DejaVuSerif.ttf', 15) d = ImageDraw.Draw(img) d.text((10, 11), "IAO Hanle Coordinates: " + str(iaohanle), font=fnt, fill=(255, 255, 255)) d.text((10, 71), "Moon Illumination Strength : " + str(moon_illumination(midnight_iao)), font=fnt, fill=(255, 255, 255)) d.text((10, 101), "Sunset : " + Time(sunset_iao, out_subfmt='date_hms').iso + " UTC", font=fnt, fill=(255, 255, 255)) d.text((10, 131), "Astronomical evening twilight : " + Time(eve_twil_iao, out_subfmt='date_hms').iso + " UTC", font=fnt, fill=(255, 255, 255)) d.text((10, 161), "Astronomical morning twilight : " + Time(morn_twil_iao, out_subfmt='date_hms').iso + " UTC", font=fnt, fill=(255, 255, 255)) d.text((10, 191), "Sunrise : " + Time(sunrise_iao, out_subfmt='date_hms').iso + " UTC", font=fnt, fill=(255, 255, 255)) d.text((10, 221), "Moon Rise : " + Time(moon_rise, out_subfmt='date_hms').iso + " UTC", font=fnt, fill=(255, 255, 255)) d.text((10, 251), "Moon Set : " + Time(moon_set, out_subfmt='date_hms').iso + " UTC", font=fnt, fill=(255, 255, 255)) d.text((10, 281), "Total Astronomical hours tonight : " + str(observing_time), font=fnt, fill=(255, 255, 255)) img.save('tonight.png') img.close() t_start = eve_twil_iao t_end = morn_twil_iao # We can turn solar system objects into 'pseudo-fixed' targets to plan observations mercury_midnight = FixedTarget(name='Mercury', coord=get_body('mercury', midnight_iao)) mercury_midnight.coord venus_midnight = FixedTarget(name='Venus', coord=get_body('venus', midnight_iao)) venus_midnight.coord uranus_midnight = FixedTarget(name='Uranus', coord=get_body('uranus', midnight_iao)) uranus_midnight.coord neptune_midnight = FixedTarget(name='Neptune', coord=get_body('neptune', midnight_iao)) neptune_midnight.coord saturn_midnight = FixedTarget(name='Saturn', coord=get_body('saturn', midnight_iao)) saturn_midnight.coord jupiter_midnight = FixedTarget(name='Jupiter', coord=get_body('jupiter', midnight_iao)) jupiter_midnight.coord mars_midnight = FixedTarget(name='Mars', coord=get_body('mars', midnight_iao)) mars_midnight.coord targets = [ mercury_midnight, venus_midnight, mars_midnight, jupiter_midnight, saturn_midnight, uranus_midnight, neptune_midnight ] targets #for target in targets: #print(iaohanle.target_rise_time(now, target, which='next', horizon=10 * u.deg).iso) # iaohanle.altaz(now, targets[0]) # print(iaohanle.target_rise_time(now, target, which='next', horizon=10 * u.deg).iso) # iaohanle.altaz(now, targets[0]) times = (t_start - 0.5 * u.h) + (t_end - t_start + 1 * u.h) * np.linspace(0.0, 1.0, 20) for target in targets: plot_sky(target, iaohanle, times) plt.legend(loc=[1.0, 0]) plt.xlabel('Planets motion tonight') # plt.ylim(4,0.5) # plt.legend() plt.savefig('planets_motion.png') plt.close() # plt.legend(loc=[1.1,0]) coords1 = SkyCoord( '15h58m3s', '-18d10m0.0s', frame='icrs') # coordinates of Andromeda Galaxy (M32) tt1 = FixedTarget(name='Moon', coord=coords1) tt1.coord t_observe = t_start + (t_end - t_start) * np.linspace(0.0, 1.0, 20) plot_sky(tt1, iaohanle, t_observe) plt.xlabel('Moon motion tonight') plt.savefig('moon_motion.png') plt.close() if (eve_twil_iao <= now): Automation.eve_twilight_flag = 1 Automation.mor_twilight_flag = 0 Automation.moon_setting_flag = 0 elif (morn_twil_iao <= now): Automation.eve_twilight_flag = 0 Automation.mor_twilight_flag = 1 Automation.moon_setting_flag = 0 elif (Automation.moon_strength > 0.30): if (moon_rise <= now): Automation.eve_twilight_flag = 0 Automation.mor_twilight_flag = 0 Automation.moon_setting_flag = 1 elif (moon_set <= now): Automation.eve_twilight_flag = 1 Automation.mor_twilight_flag = 0 Automation.moon_setting_flag = 0
def form_valid(self, form): response = super(AddSurveyObsFormView, self).form_valid(form) if 'hi': #self.request.is_ajax(): instance = form.save(commit=False) telescope = Telescope.objects.get(name='Pan-STARRS1') location = EarthLocation.from_geodetic(telescope.longitude * u.deg, telescope.latitude * u.deg, telescope.elevation * u.m) tel = Observer(location=location, timezone="US/Hawaii") m = date_to_mjd(form.cleaned_data['survey_obs_date']) time = Time(m, format='mjd') sunset_forobs = mjd_to_date(tel.sun_set_time(time, which="next")) survey_field_blocks = SurveyFieldMSB.objects.filter( name__in=form.cleaned_data['ztf_field_id']) #survey_field = SurveyField.objects.filter(ztf_field_id__in=form.cleaned_data['ztf_field_id']) for sb in survey_field_blocks: for s in sb.survey_fields.all(): t = Time(m, format='mjd') illum = moon_illumination(t) # need to see what was observed in the previous obs w/ the same moon illumination # first have to grab the MSB associated with this observation, if it exists # otherwise it's gonna schedule different filters for different pointings previous_msb = SurveyFieldMSB.objects.filter( survey_fields__in=[s]) if len(previous_msb): previous_field = previous_msb[0].survey_fields.all()[0] previous_obs = SurveyObservation.objects.filter(survey_field=previous_field).\ filter(Q(obs_mjd__lt=m) | Q(mjd_requested__lt=m)).order_by('-obs_mjd').\ order_by('-mjd_requested').select_related() else: previous_obs = SurveyObservation.objects.filter(survey_field=s).\ filter(Q(obs_mjd__lt=m) | Q(mjd_requested__lt=m)).order_by('-obs_mjd').\ order_by('-mjd_requested').select_related() def previous_obs_func(illum_min, illum_max): filt = [] for p in previous_obs: if p.obs_mjd: mjd_prev = p.obs_mjd elif p.mjd_requested: mjd_prev = p.mjd_requested t_prev = Time(mjd_prev, format='mjd') illum_prev = moon_illumination(t_prev) if illum_prev >= illum_min and illum_prev <= illum_max: filt += [p.photometric_band.name] if len(filt) == 2: return filt return None if s.field_id.lower().startswith('virgo'): if illum < 0.66: filt = previous_obs_func(0, 0.66) if filt is None: band1name, band2name = 'g', 'r' elif 'r' in filt: band1name, band2name = 'g', 'i' elif 'i' in filt: band1name, band2name = 'g', 'z' else: band1name, band2name = 'g', 'r' else: filt = previous_obs_func(0.66, 1) if filt is None or 'z' in filt: band1name, band2name = 'r', 'i' else: band1name, band2name = 'r', 'z' else: if illum < 0.33: filt = previous_obs_func(0, 0.33) if filt is None or 'i' in filt: band1name, band2name = 'g', 'r' else: band1name, band2name = 'g', 'i' elif illum < 0.66: filt = previous_obs_func(0.33, 0.66) if filt is None or 'z' in filt: band1name, band2name = 'g', 'i' else: band1name, band2name = 'g', 'z' else: filt = previous_obs_func(0.66, 1) if filt is None or 'z' in filt: band1name, band2name = 'r', 'i' else: band1name, band2name = 'r', 'z' band1 = PhotometricBand.objects.filter( name=band1name, instrument__name=s.instrument.name)[0] band2 = PhotometricBand.objects.filter( name=band2name, instrument__name=s.instrument.name)[0] SurveyObservation.objects.create( mjd_requested=date_to_mjd(sunset_forobs), survey_field=s, status=TaskStatus.objects.get(name='Requested'), exposure_time=27, photometric_band=band1, created_by=self.request.user, modified_by=self.request.user) SurveyObservation.objects.create( mjd_requested=date_to_mjd(sunset_forobs), survey_field=s, status=TaskStatus.objects.get(name='Requested'), exposure_time=27, photometric_band=band2, created_by=self.request.user, modified_by=self.request.user) # for key,value in form.cleaned_data.items(): data = { 'message': "Successfully submitted form data.", } return JsonResponse(data) else: return response
def form_valid(self, form): response = super(AddSurveyFieldFormView, self).form_valid(form) if self.request.is_ajax(): instance = form.save(commit=False) instance.created_by = self.request.user instance.modified_by = self.request.user instance.obs_group = ObservationGroup.objects.get(name='YSE') instance.width_deg = 3.3 instance.height_deg = 3.3 instance.first_mjd = date_to_mjd(form.cleaned_data['valid_start']) instance.last_mjd = date_to_mjd(form.cleaned_data['valid_stop']) instance.ra_cen, instance.dec_cen = coordstr_to_decimal( form.cleaned_data['coord']) instance.save() #update_fields=['created_by','modified_by'] print(form.cleaned_data) # clear out the conflicting SurveyObservationTasks # danger! obs_requests = SurveyObservation.objects.\ filter(survey_field__field_id=instance.field_id).\ filter(mjd_requested__range=(instance.first_mjd, instance.last_mjd)) obs_requests.delete() # use the SurveyField to populate the SurveyObservationTask list # rules: follow cad #import pdb; pdb.set_trace() mjd = np.arange(instance.first_mjd, instance.last_mjd, instance.cadence) #if len(mjd) > 1: import pdb; pdb.set_trace() for i, m in enumerate(mjd): t = Time(m, format='mjd') illum = moon_illumination(t) if illum < 0.33: if i % 2: band1name, band2name = 'g', 'r' else: band1name, band2name = 'g', 'i' elif illum < 0.66: if i % 2: band1name, band2name = 'g', 'i' else: band1name, band2name = 'g', 'z' else: if i % 2: band1name, band2name = 'r', 'i' else: band1name, band2name = 'r', 'z' band1 = PhotometricBand.objects.filter( name=band1name, instrument__name=instance.instrument.name)[0] band2 = PhotometricBand.objects.filter( name=band2name, instrument__name=instance.instrument.name)[0] SurveyObservation.objects.create( mjd_requested=m, survey_field=instance, status=TaskStatus.objects.get(name='Requested'), exposure_time=27, photometric_band=band1, created_by=self.request.user, modified_by=self.request.user) SurveyObservation.objects.create( mjd_requested=m, survey_field=instance, status=TaskStatus.objects.get(name='Requested'), exposure_time=27, photometric_band=band2, created_by=self.request.user, modified_by=self.request.user) # for key,value in form.cleaned_data.items(): data = { 'message': "Successfully submitted form data.", } return JsonResponse(data) else: return response
def airmass(ra=0., dec=0., obs='apo', date='2019-10-01', name='object', plot=False, tz='US/Mountain'): """ Get airmass table for specified object position, observatory, date """ # set the site site = Observer.at_site(obs, timezone=tz) # set the objects if type(ra) is float: obj = FixedTarget(name=name, coord=SkyCoord(str(ra) + 'd', str(dec) + 'd')) else: obj = FixedTarget(name=name, coord=SkyCoord(ra + 'h', dec + 'd')) time = Time('{:s} 00:00:00'.format(date), scale='utc', location=(site.location.lon, site.location.lat), precision=0) sunset = site.sun_set_time(time) civil = site.twilight_evening_civil(time) nautical = site.twilight_evening_nautical(time) astronomical = site.twilight_evening_astronomical(time) for t in [sunset, civil, nautical, astronomical]: t.format = 'isot' t.precision = 0 print('Observatory: ', obs) print('Sunset: ', sunset) print('Civil twilight: ', civil) print('Nautical twilight: ', nautical) print('Astronomical twilight: ', astronomical) # loop over all UTC hours for this date (would prefer local!) print('{:8s}{:8s}{:8s}{:8s}{:8s}{:9s}{:8s}{:8s} {:16s}{:20s}'.format( 'Local', 'UT', 'LST', 'HA', 'Airmass', 'ParAng', 'Phase', 'Moon Alt', 'Moon RA', 'Moon DEC')) for hr in np.arange(24): time = Time('{:s} {:d}:00:00'.format(date, hr), scale='utc', location=(site.location.lon, site.location.lat), precision=0) sun = get_sun(time) if site.sun_altaz(time).alt.value > 10: continue moon = get_moon(time) val = site.altaz(time, obj).secz if val < 0: airmass = ' ...' else: airmass = '{:8.2f}'.format(val) val = site.moon_altaz(time).alt.value if val < 0: moonalt = ' ...' else: moonalt = '{:8.2f}'.format(val) lst = time.sidereal_time('mean').hms ha = site.target_hour_angle(time, obj) ha.wrap_angle = 180 * units.deg local = site.astropy_time_to_datetime(time) print( '{:02d}:{:02d} {:02d}:{:02d} {:02d}:{:02d} {:3d}:{:02d} {:8s} {:8.2f} {:8.2f} {:8s} {:s} {:s}' .format( local.hour, local.minute, time.datetime.hour, time.datetime.minute, int(round(lst[0])), int(round(lst[1])), int(round(ha.hms[0])), int(abs(round(ha.hms[1]))), airmass, #site.altaz(time,obj).secz, site.parallactic_angle(time, obj).deg, astroplan.moon_illumination(time), moonalt, str(moon.ra.to_string(units.hour)), str(moon.dec))) if plot: fig, ax = plt.subplots(2, 1) fig.subplots_adjust(hspace=0.001) plot_airmass(obj, site, time, ax=ax[0]) plot_parallactic(obj, site, time, ax=ax[1])
dec=those_ten[i][1], unit=(u.hourangle, u.deg)))) newOutput = observability_table( cons, kitt, newFixedTargs, time_range=Time(["2018-05-15 00:01", "2018-05-31 23:59"])) return [output, newOutput] print(most_obs(10)[0]) print("\n ------------------ \n") print(most_obs(10)[1]) # We can change it to whatever, obviously moon_ang1 = moon_illumination(Time(['2018-04-15'])) moon_ang2 = moon_illumination(Time(['2018-04-30'])) # I changed the function here so now the variables are poorly named but I'm leaving it to build character mrt1 = Time(kitt.moon_rise_time(Time(['2018-04-15']), 'nearest'), format='iso')[0] mst1 = Time(kitt.moon_set_time(Time(['2018-04-15']), 'nearest'), format='iso')[0] mrt2 = Time(kitt.moon_rise_time(Time(['2018-04-30']), 'nearest'), format='iso')[0] mst2 = Time(kitt.moon_set_time(Time(['2018-04-30']), 'nearest'), format='iso')[0] #print("moon illumination begins at: " + str(moon_ang1) + " and ends with: " + str(moon_ang2)) #print("In the middle of the month, the moon rises at " + str(mrt1) + " and sets at " + str(mst1) + ". At the end of the month, the moon rises at " + str(mrt2) + " and sets at " + str(mst2) + ".")
def create_observation_observables(object_id, object_dir, since, name, epoch, epoch_low_err, epoch_up_err, period, period_low_err, period_up_err, duration, observatories_file, timezone, latitude, longitude, altitude, max_days, min_altitude, moon_min_dist, moon_max_dist, transit_fraction, baseline, error_alert=True): """ @param object_id: the candidate id @param object_dir: the candidate directory @param since: starting plan date @param name: the name given to the candidate @param epoch: the candidate epoch @param epoch_low_err: the candidate epoch's lower error @param epoch_up_err: the candidate epoch's upper error @param period: the candidate period @param period_low_err: the candidate period's lower error @param period_up_err: the candidate period's upper error @param duration: the candidate duration @param observatories_file: the file containing the observatories file (csv format) @param timezone: the timezone of the observatory (if observatories_file=None) @param latitude: the latitude of the observatory (if observatories_file=None) @param longitude: the longitude of the observatory (if observatories_file=None) @param altitude: the altitude of the observatory (if observatories_file=None) @param max_days: the maximum number of days to compute the observables @param min_altitude: the minimum altitude of the target above the horizon @param moon_min_dist: the minimum moon distance for moon illumination = 0 @param moon_max_dist: the minimum moon distance for moon illumination = 1 @param transit_fraction: the minimum transit observability (0.25 for at least ingress/egress, 0.5 for ingress/egress + midtime, 1 for ingress, egress and midtime). @param baseline: the required baseline in hours. @param: error_alert: whether to create the alert date to signal imprecise observations @return: the generated data and target folders """ if observatories_file is not None: observatories_df = pd.read_csv(observatories_file, comment='#') else: observatories_df = pd.DataFrame( columns=['name', 'tz', 'lat', 'long', 'alt']) observatories_df = observatories_df.append("Obs-1", timezone, latitude, longitude, altitude) # TODO probably convert epoch to proper JD mission, mission_prefix, id_int = LcBuilder().parse_object_info(object_id) if mission == "TESS": primary_eclipse_time = Time(epoch, format='btjd', scale="tdb") elif mission == "Kepler" or mission == "K2": primary_eclipse_time = Time(epoch, format='bkjd', scale="tdb") else: primary_eclipse_time = Time(epoch, format='jd') target = FixedTarget(SkyCoord(coords, unit=(u.deg, u.deg))) n_transits = int(max_days // period) system = EclipsingSystem(primary_eclipse_time=primary_eclipse_time, orbital_period=u.Quantity(period, unit="d"), duration=u.Quantity(duration, unit="h"), name=name) observables_df = pd.DataFrame(columns=[ 'observatory', 'timezone', 'start_obs', 'end_obs', 'ingress', 'egress', 'midtime', "midtime_up_err_h", "midtime_low_err_h", 'twilight_evening', 'twilight_morning', 'observable', 'moon_phase', 'moon_dist' ]) plan_dir = object_dir + "/plan" images_dir = plan_dir + "/images" if os.path.exists(plan_dir): shutil.rmtree(plan_dir, ignore_errors=True) os.mkdir(plan_dir) if os.path.exists(images_dir): shutil.rmtree(images_dir, ignore_errors=True) os.mkdir(images_dir) alert_date = None for index, observatory_row in observatories_df.iterrows(): observer_site = Observer(latitude=observatory_row["lat"], longitude=observatory_row["lon"], elevation=u.Quantity(observatory_row["alt"], unit="m")) midtransit_times = system.next_primary_eclipse_time( since, n_eclipses=n_transits) ingress_egress_times = system.next_primary_ingress_egress_time( since, n_eclipses=n_transits) constraints = [ AtNightConstraint.twilight_nautical(), AltitudeConstraint(min=min_altitude * u.deg), MoonIlluminationSeparationConstraint( min_dist=moon_min_dist * u.deg, max_dist=moon_max_dist * u.deg) ] moon_for_midtransit_times = get_moon(midtransit_times) moon_dist_midtransit_times = moon_for_midtransit_times.separation( SkyCoord(star_df.iloc[0]["ra"], star_df.iloc[0]["dec"], unit="deg")) moon_phase_midtransit_times = np.round( astroplan.moon_illumination(midtransit_times), 2) transits_since_epoch = np.round( (midtransit_times - primary_eclipse_time).jd / period) midtransit_time_low_err = np.round( (((transits_since_epoch * period_low_err)**2 + epoch_low_err**2) **(1 / 2)) * 24, 2) midtransit_time_up_err = np.round( (((transits_since_epoch * period_up_err)**2 + epoch_up_err**2) **(1 / 2)) * 24, 2) low_err_delta = TimeDelta(midtransit_time_low_err * 3600, format='sec') up_err_delta = TimeDelta(midtransit_time_up_err * 3600, format='sec') i = 0 for midtransit_time in midtransit_times: twilight_evening = observer_site.twilight_evening_nautical( midtransit_time) twilight_morning = observer_site.twilight_morning_nautical( midtransit_time) ingress = ingress_egress_times[i][0] egress = ingress_egress_times[i][1] lowest_ingress = ingress - low_err_delta[i] highest_egress = egress + up_err_delta[i] if error_alert and (highest_egress - lowest_ingress).jd > 0.33: alert_date = midtransit_time if (alert_date is None) or ( alert_date is not None and alert_date >= midtransit_time) else alert_date break else: baseline_low = lowest_ingress - baseline * u.hour baseline_up = highest_egress + baseline * u.hour transit_times = baseline_low + ( baseline_up - baseline_low) * np.linspace(0, 1, 100) observable_transit_times = astroplan.is_event_observable( constraints, observer_site, target, times=transit_times)[0] observable_transit_times_true = np.argwhere( observable_transit_times) observable = len(observable_transit_times_true) / 100 if observable < transit_fraction: i = i + 1 continue start_obs = transit_times[observable_transit_times_true[0]][0] end_obs = transit_times[observable_transit_times_true[ len(observable_transit_times_true) - 1]][0] start_plot = baseline_low end_plot = baseline_up if twilight_evening > start_obs: start_obs = twilight_evening if twilight_morning < end_obs: end_obs = twilight_morning moon_dist = round(moon_dist_midtransit_times[i].degree) moon_phase = moon_phase_midtransit_times[i] # TODO get is_event_observable for several parts of the transit (ideally each 5 mins) to get the proper observable percent. Also with baseline if observatory_row["tz"] is not None and not np.isnan( observatory_row["tz"]): observer_timezone = observatory_row["tz"] else: observer_timezone = get_offset(observatory_row["lat"], observatory_row["lon"], midtransit_time.datetime) observables_df = observables_df.append( { "observatory": observatory_row["name"], "timezone": observer_timezone, "ingress": ingress.isot, "start_obs": start_obs.isot, "end_obs": end_obs.isot, "egress": egress.isot, "midtime": midtransit_time.isot, "midtime_up_err_h": str(int(midtransit_time_up_err[i] // 1)) + ":" + str(int(midtransit_time_up_err[i] % 1 * 60)).zfill(2), "midtime_low_err_h": str(int(midtransit_time_low_err[i] // 1)) + ":" + str(int(midtransit_time_low_err[i] % 1 * 60)).zfill(2), "twilight_evening": twilight_evening.isot, "twilight_morning": twilight_morning.isot, "observable": observable, "moon_phase": moon_phase, "moon_dist": moon_dist }, ignore_index=True) plot_time = start_plot + (end_plot - start_plot) * np.linspace( 0, 1, 100) plt.tick_params(labelsize=6) airmass_ax = plot_airmass(target, observer_site, plot_time, brightness_shading=False, altitude_yaxis=True) airmass_ax.axvspan(twilight_morning.plot_date, end_plot.plot_date, color='white') airmass_ax.axvspan(start_plot.plot_date, twilight_evening.plot_date, color='white') airmass_ax.axvspan(twilight_evening.plot_date, twilight_morning.plot_date, color='gray') airmass_ax.axhspan(1. / np.cos(np.radians(90 - min_altitude)), 5.0, color='green') airmass_ax.get_figure().gca().set_title("") airmass_ax.get_figure().gca().set_xlabel("") airmass_ax.get_figure().gca().set_ylabel("") airmass_ax.set_xlabel("") airmass_ax.set_ylabel("") xticks = [] xticks_labels = [] xticks.append(start_obs.plot_date) hour_min_sec_arr = start_obs.isot.split("T")[1].split(":") xticks_labels.append("T1_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=start_obs.plot_date, color="violet") xticks.append(end_obs.plot_date) hour_min_sec_arr = end_obs.isot.split("T")[1].split(":") xticks_labels.append("T1_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=end_obs.plot_date, color="violet") if start_plot < lowest_ingress < end_plot: xticks.append(lowest_ingress.plot_date) hour_min_sec_arr = lowest_ingress.isot.split("T")[1].split(":") xticks_labels.append("T1_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=lowest_ingress.plot_date, color="red") if start_plot < ingress < end_plot: xticks.append(ingress.plot_date) hour_min_sec_arr = ingress.isot.split("T")[1].split(":") xticks_labels.append("T1_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=ingress.plot_date, color="orange") if start_plot < midtransit_time < end_plot: xticks.append(midtransit_time.plot_date) hour_min_sec_arr = midtransit_time.isot.split("T")[1].split( ":") xticks_labels.append("T0_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=midtransit_time.plot_date, color="black") if start_plot < egress < end_plot: xticks.append(egress.plot_date) hour_min_sec_arr = egress.isot.split("T")[1].split(":") xticks_labels.append("T4_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=egress.plot_date, color="orange") if start_plot < highest_egress < end_plot: xticks.append(highest_egress.plot_date) hour_min_sec_arr = highest_egress.isot.split("T")[1].split(":") xticks_labels.append("T4_" + hour_min_sec_arr[0] + ":" + hour_min_sec_arr[1]) plt.axvline(x=highest_egress.plot_date, color="red") airmass_ax.xaxis.set_tick_params(labelsize=5) airmass_ax.set_xticks([]) airmass_ax.set_xticklabels([]) degrees_ax = get_twin(airmass_ax) degrees_ax.yaxis.set_tick_params(labelsize=6) degrees_ax.set_yticks([1., 1.55572383, 2.]) degrees_ax.set_yticklabels([90, 50, 30]) fig = matplotlib.pyplot.gcf() fig.set_size_inches(1.25, 0.75) plt.savefig(plan_dir + "/images/" + observatory_row["name"] + "_" + str(midtransit_time.isot)[:-4] + ".png", bbox_inches='tight') plt.close() i = i + 1 observables_df = observables_df.sort_values(["midtime", "observatory"], ascending=True) observables_df.to_csv(plan_dir + "/observation_plan.csv", index=False) print("Observation plan created in directory: " + object_dir) return observatories_df, observables_df, alert_date, plan_dir, images_dir
def plot_target_radecs_and_moon(ras, decs, names, time, savename=None, savefolder=""): """ Plot and RA DEC plot of targets and Moon INPUT: ras - ras (degrees) of target stars decs - decs (degrees) of target stars names - names of target stars time - astropy time savename - output name of .png file to save the plot. EXAMPLE: time = Time("2018-02-25 00:00:00") plot_target_radecs_and_moon(ras,decs,df_all.SIMBADNAME.values,time) """ mcd = Observer.at_site('McDonald Observatory') sun_rise = mcd.sun_rise_time(time, which="nearest") sun_set = mcd.sun_set_time(time, which="nearest") times = sun_set + (sun_rise - sun_set) * np.linspace(0, 1, 20) moon = get_moon(times) illum = moon_illumination( times[10]) # get moon illumination at middle of the time array fig, ax = plt.subplots(figsize=(12, 8), dpi=200) ax.plot(ras, decs, "k.") ax.plot(moon.ra.value, moon.dec.value, label="Moon") ax.plot(moon.ra.value[0], moon.dec.value[0], color="red", marker="o", label="Moon: Sunset", lw=0) ax.plot(moon.ra.value[-1], moon.dec.value[-1], color="orange", marker="o", label="Moon: Sunrise", lw=0) for i, name in enumerate(names): ax.text(ras[i], decs[i], name) ax.legend(loc="upper left") ax.minorticks_on() ax.grid(lw=0.5, alpha=0.3) ax.set_xlabel("RA (deg)") ax.set_ylabel("Dec (deg)") title = "Targets and Moon on {} UT".format(str(time)[0:10]) title += "\n Sunset: {}".format(str(sun_set.iso)) title += "\n Sunrise: {}".format(str(sun_rise.iso)) title += "\n Moon illumination: {:0.3}%".format(illum * 100) ax.set_title(title) if savename is None: savename = "moondistance_" + str(time)[0:10] + ".png" savename = savefolder + savename fig.savefig(savename) print("saved to {}".format(savename))
def analyze_day(search_around, obs, FO, localtz, args, verbose=True): sunset = obs.sun_set_time(search_around, which='nearest') delta = (search_around.to_datetime() - sunset.to_datetime()).total_seconds() if abs(delta) > 12*60*60: sunset = obs.sun_set_time(search_around+TimeDelta(1800, format='sec'), which='nearest') delta = (search_around.to_datetime() - sunset.to_datetime()).total_seconds() if abs(delta) > 12*60*60: print('WARNING Delta = {:.0f} seconds'.format(delta)) local_sunset = sunset.to_datetime(localtz) dusk = obs.twilight_evening_astronomical(sunset, which='next') local_dusk = dusk.to_datetime(localtz) description = [f"Sunset @ {local_sunset.strftime('%I:%M %p')}", f"18 deg Twilight @ {local_dusk.strftime('%I:%M %p')}"] # Moon from astroplan illum = moon_illumination(sunset) mooncoord = moon.get_moon(sunset).transform_to(FK5()) mooncoord.location = obs.location moonalt = mooncoord.transform_to(AltAz()).alt moon_down = moonalt.value < 0. moon_rise = obs.moon_rise_time(sunset) moon_set = obs.moon_set_time(sunset) ttup = local_sunset.timetuple() endtime = dt(ttup.tm_year, ttup.tm_mon, ttup.tm_mday, 23, 59, 00, 0, localtz) print(f"Sunset at {local_sunset.strftime('%Y/%m/%d %H:%M')}")#\ # f" (Moon down: {moon_down} {moonalt:.1f} {illum*100:.1f}%)") if illum > 0.9: print(f" Moon is bright ({illum*100:.0f}%)") elif illum < 0.1: title = f"Moon is dark ({illum*100:.0f}%)" description.append(f"Moon is dark ({illum*100:.0f}%)") ics_entry(FO, title, local_sunset-2*tdelta(seconds=60.*60.*1.), endtime, description, verbose=True) elif moon_down is True: local_moon_rise = moon_rise.to_datetime(localtz) time_to_rise = moon_rise - dusk if time_to_rise.sec < 0: print(' Moon rises during twilight') if time_to_rise.sec*u.second > args.dark_time*u.hour: title = f"Dark until {local_moon_rise.strftime('%I:%M %p')} ({time_to_rise.sec/3600:.1f} hr)" description.append(f"{illum*100:.0f}% Moon Rises @ {local_moon_rise.strftime('%I:%M %p')}") ics_entry(FO, title, local_sunset-2*tdelta(seconds=60.*60.*1.), endtime, description, verbose=True) elif time_to_rise.sec > 0: print(f" Moon rises at {local_moon_rise.strftime('%Y/%m/%d %H:%M')},"\ f" only {time_to_rise.sec/3600:.1f} hours after dusk.") else: local_moon_set = moon_set.to_datetime(localtz) time_to_wait = moon_set - dusk if time_to_wait.sec < 0: print(" Moon sets during dusk.") title = f'Dark ({illum*100.:.0f}% moon)' ics_entry(FO, title, local_sunset-2*tdelta(seconds=60.*60.*1.), endtime, description, verbose=True) elif time_to_wait.sec*u.second < args.wait_time*u.hour: title = f"Dark after {local_moon_set.strftime('%I:%M %p')}" description.append(f"{illum*100:.0f}% Moon Sets @ {local_moon_set.strftime('%I:%M %p')}") ics_entry(FO, title, local_sunset-2*tdelta(seconds=60.*60.*1.), endtime, description, verbose=True) else: print(f" {illum*100:.0f}% Moon is up in the evening") return sunset
def moon_distance(target, day_range=30, width=600, height=400, background=None, label_color=None, grid=True): """ Renders plot for lunar distance from sidereal target. Adapted from Jamison Frost Burke's moon visibility code in Supernova Exchange 2.0, as seen here: https://github.com/jfrostburke/snex2/blob/0c1eb184c942cb10f7d54084e081d8ac11700edf/custom_code/templatetags/custom_code_tags.py#L196 :param target: Target object for which moon distance is calculated :type target: tom_targets.models.Target :param day_range: Number of days to plot lunar distance :type day_range: int :param width: Width of generated plot :type width: int :param height: Height of generated plot :type width: int :param background: Color of the background of generated plot. Can be rgba or hex string. :type background: str :param label_color: Color of labels/tick labels. Can be rgba or hex string. :type label_color: str :param grid: Whether to show grid lines. :type grid: bool """ if target.type != 'SIDEREAL': return {'plot': None} day_range = 30 times = Time([ str(datetime.utcnow() + timedelta(days=delta)) for delta in np.arange(0, day_range, 0.2) ], format='iso', scale='utc') obj_pos = SkyCoord(target.ra, target.dec, unit=u.deg) moon_pos = get_moon(times) separations = moon_pos.separation(obj_pos).deg phases = moon_illumination(times) distance_color = 'rgb(0, 0, 255)' phase_color = 'rgb(255, 0, 0)' plot_data = [ go.Scatter(x=times.mjd - times[0].mjd, y=separations, mode='lines', name='Moon distance (degrees)', line=dict(color=distance_color)), go.Scatter(x=times.mjd - times[0].mjd, y=phases, mode='lines', name='Moon phase', yaxis='y2', line=dict(color=phase_color)) ] layout = go.Layout(xaxis={'title': 'Days from now'}, yaxis={ 'range': [0, 180], 'tick0': 0, 'dtick': 45, 'tickfont': { 'color': distance_color } }, yaxis2={ 'range': [0, 1], 'tick0': 0, 'dtick': 0.25, 'overlaying': 'y', 'side': 'right', 'tickfont': { 'color': phase_color } }, margin={ 'l': 20, 'r': 10, 'b': 30, 't': 40 }, width=width, height=height, autosize=True, paper_bgcolor=background, plot_bgcolor=background) layout.legend.font.color = label_color fig = go.Figure(data=plot_data, layout=layout) fig.update_yaxes(showgrid=grid, color=label_color, showline=True, linecolor=label_color, mirror=True) fig.update_xaxes(showgrid=grid, color=label_color, showline=True, linecolor=label_color, mirror=True) moon_distance_plot = offline.plot(fig, output_type='div', show_link=False) return {'plot': moon_distance_plot}