Example #1
0
def define_constraints(minAltitude, earliestObs, latestObs):
    """
    Define various constraints to define 'observability'.

    Format for times: YYYY-MM-DD

    Parameters
    ----------
    minAltitude : int
        minimum local elevation in degree
    earliestObs : str
        Earliest time of observation
    latestObs : str
        Latest time of observation

    Returns
    -------
    constraints : list
        list of constraints
    earliestObs : Time object
        Earliest time of observation
    latestObs : Time object
        Latest time of observation
    """
    constraints = [AtNightConstraint.twilight_astronomical(),
                   AltitudeConstraint(min=minAltitude*u.deg)]
    return constraints, Time(earliestObs), Time(latestObs)
Example #2
0
def run_months(observers, nameList, args):
    targets = [FixedTarget(coord=lookuptarget(name),name=name) for name in nameList]
    targetLabelList, ylabelsize = makeTargetLabels(nameList,args)

    constraints = [
        AltitudeConstraint(min=args.minAlt*u.deg),
        AtNightConstraint.twilight_astronomical(),
    ]
    
    outfn = args.outFileNameBase+"_monthly.pdf"
    with PdfPages(outfn) as pdf:
        for observer in observers:
            observability_months_table = months_observable(constraints,observer,targets,time_grid_resolution=1*u.hour)

            observability_months_grid = numpy.zeros((len(targets),12))
            for i, observable in enumerate(observability_months_table):
                for jMonth in range(1,13):
                    observability_months_grid[i,jMonth-1] = jMonth in observable

            observable_targets = targets
            observable_target_labels = targetLabelList
            ever_observability_months_grid = observability_months_grid
            if args.onlyEverObservable:
                target_is_observable = numpy.zeros(len(targets))
                for iMonth in range(observability_months_grid.shape[1]):
                    target_is_observable += observability_months_grid[:,iMonth]
                target_is_observable = target_is_observable > 0. # change to boolean numpy array
                observable_targets = [x for x, o in zip(targets,target_is_observable) if o]
                observable_target_labels = [x for x, o in zip(targetLabelList,target_is_observable) if o]
                ever_observability_months_grid = observability_months_grid[target_is_observable,:]

            fig, ax = mpl.subplots(
                figsize=(8.5,11),
                gridspec_kw={
                    "top":0.92,
                    "bottom":0.03,
                    "left":0.13,
                    "right":0.98,
                },
                tight_layout=False,constrained_layout=False
            )
            extent = [-0.5, -0.5+12, -0.5, len(observable_targets)-0.5]
            ax.imshow(ever_observability_months_grid, extent=extent, origin="lower", aspect="auto", cmap=mpl.get_cmap("Greens"))
            ax.xaxis.tick_top()
            ax.invert_yaxis()
            ax.set_yticks(range(0,len(observable_targets)))
            ax.set_yticklabels(observable_target_labels, fontsize=ylabelsize)
            ax.set_xticks(range(12))
            ax.set_xticklabels(["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"])
            ax.set_xticks(numpy.arange(extent[0], extent[1]), minor=True)
            ax.set_yticks(numpy.arange(extent[2], extent[3]), minor=True)
            ax.grid(which="minor",color="black",ls="-", linewidth=1)
            ax.tick_params(axis='y', which='minor', left=False, right=False)
            ax.tick_params(axis='x', which='minor', bottom=False, top=False)
        
            fig.suptitle(f"Monthly Observability at {observer.name}")
            fig.text(1.0,0.0,"Constraints: Astronomical Twilight, Altitude $\geq {:.0f}^\circ$".format(args.minAlt),ha="right",va="bottom")
            pdf.savefig(fig)
        print(f"Writing out file: {outfn}")
Example #3
0
def compute_is_up(name, time):
    '''
    Computes what V<11 objects in a catalog are up right now.

    args:
        name (str): one in: ['messier', 'ngc']
        time (str): in 24hr format, e.g. "2017-04-17 21:00:00"

    returns:
        catalog with is_up calculated, sorted by v_mag.
    '''

    import datetime
    from astropy.time import Time
    from astroplan import FixedTarget
    from astropy.coordinates import SkyCoord
    from astroplan import Observer, FixedTarget, AltitudeConstraint, \
        AtNightConstraint, is_observable, is_always_observable, \
        months_observable

    assert name in ['messier', 'ngc']

    if name == 'messier':
        data_path = '../data/catalogs/messier.csv'
    elif name == 'ngc':
        data_path = '../data/catalogs/ngc.csv'

    df = pd.read_csv(data_path)
    # The search & target creation is slow for >~thousands of FixedTargets. NGC
    # catalog is 13226 objects. Take those with v_mag<11, since from Peyton we
    # likely won't go fainter.
    df = df.sort_values('v_mag')
    df = df[df['v_mag']<11]

    peyton = Observer(longitude=74.65139*u.deg, latitude=40.34661*u.deg,
        elevation=62*u.m, name='Peyton', timezone='US/Eastern')

    if name == 'ngc':
        ras = np.array(df['ra'])*u.hourangle
        decs = np.array(df['dec'])*u.degree
        names = np.array(df['ngc_id'])
    elif name == 'messier':
        ras = np.array(df['ra'])*u.hourangle
        decs = np.array(df['dec'])*u.degree
        names = np.array(df['messier_id'])

    targets = [FixedTarget(SkyCoord(ra=r, dec=d), name=n) for r, d, n in
            tuple(zip(ras, decs, names))]

    constraints = [AltitudeConstraint(10*u.deg, 82*u.deg),
            AtNightConstraint(max_solar_altitude=-3.*u.deg)]

    t_obs = Time(time)
    is_up = is_observable(constraints, peyton, targets, times=t_obs)

    df['is_up'] = is_up

    return df
Example #4
0
def minimal_example():
    apo = Observer.at_site('APO', timezone='US/Mountain')
    target = FixedTarget.from_name("HD 209458")

    primary_eclipse_time = Time(2452826.628514, format='jd')
    orbital_period = 3.52474859 * u.day
    eclipse_duration = 0.1277 * u.day

    hd209458 = EclipsingSystem(primary_eclipse_time=primary_eclipse_time,
                               orbital_period=orbital_period,
                               duration=eclipse_duration,
                               name='HD 209458 b')

    n_transits = 100  # This is the roughly number of transits per year

    obs_time = Time('2017-01-01 12:00')
    midtransit_times = hd209458.next_primary_eclipse_time(
        obs_time, n_eclipses=n_transits)

    import astropy.units as u
    min_local_time = dt.time(18, 0)  # 18:00 local time at APO (7pm)
    max_local_time = dt.time(8, 0)  # 08:00 local time at APO (5am)
    constraints = [
        AtNightConstraint.twilight_civil(),
        AltitudeConstraint(min=30 * u.deg),
        LocalTimeConstraint(min=min_local_time, max=max_local_time)
    ]

    # just at midtime
    b = is_event_observable(constraints, apo, target, times=midtransit_times)

    # completely observable transits
    observing_time = Time('2016-01-01 00:00')

    ing_egr = hd209458.next_primary_ingress_egress_time(observing_time,
                                                        n_eclipses=n_transits)

    ibe = is_event_observable(constraints,
                              apo,
                              target,
                              times_ingress_egress=ing_egr)

    oot_duration = 30 * u.minute
    oot_ing_egr = np.concatenate(
        (np.array(ing_egr[:, 0] - oot_duration)[:, None],
         np.array(ing_egr[:, 1] + oot_duration)[:, None]),
        axis=1)

    oibeo = is_event_observable(constraints,
                                apo,
                                target,
                                times_ingress_egress=oot_ing_egr)
Example #5
0
def make_airmass_chart(name="WASP 4"):

    target = FixedTarget.from_name(name)
    observer = Observer.at_site('keck')

    constraints = [
        AltitudeConstraint(min=20 * u.deg, max=85 * u.deg),
        AtNightConstraint.twilight_civil()
    ]

    best_months = months_observable(constraints, observer, [target])

    # computed observability on "best_months" grid of 0.5 hr
    print('for {}, got best-months on 0.5 hour grid:'.format(name))
    print(best_months)
    print('where 1 = Jan, 2 = Feb, etc.')
Example #6
0
def get_observability_fraction(name="WASP 4", site='keck', ra=None, dec=None,
                               start_time=Time('2019-09-13 20:00:00'),
                               end_time=Time('2020-07-31 20:00:00')):

    if isinstance(name,str) and ra is None and dec is None:
        target = FixedTarget.from_name(name)
    elif isinstance(ra,float) and isinstance(dec,float):
        target_coord = SkyCoord(ra=ra*u.deg, dec=dec*u.deg)
        target = FixedTarget(coord=target_coord, name=name)
    else:
        raise NotImplementedError('failed to make target')

    observer = Observer.at_site(site)

    constraints = [AltitudeConstraint(min=20*u.deg, max=85*u.deg),
                   AirmassConstraint(3),
                   AtNightConstraint.twilight_civil()]

    # over every day between start and end time, check if the observing
    # constraints are meetable.
    days = Time(
        np.arange(start_time.decimalyear, end_time.decimalyear,
                  1/(365.25)),
        format='decimalyear'
    )

    frac, ever_observable = [], []

    for day in days:

        table = observability_table(constraints, observer, [target],
                                    time_range=day)
        frac.append(float(table['fraction of time observable']))
        ever_observable.append(bool(table['ever observable']))

    ever_observable = np.array(ever_observable)
    frac = np.array(frac)

    return frac, ever_observable, days
def make_obs_table(obs_info, source_list, save=True, min_uptime=10):

    tab = Table.read(source_list, format="ascii.csv")
    targets = [
        FixedTarget(coord=SkyCoord(ra=ra, dec=dec, unit=(u.hourangle, u.deg)),
                    name=source) for source, ra, dec, _ in tab
    ]

    # Some arecibo specific settings
    arecibo_site = E.from_geocentric(x=2390490.0,
                                     y=-5564764.0,
                                     z=1994727.0,
                                     unit=u.meter)
    arecibo = Observer(location=arecibo_site, name="AO")
    constraints = [
        AltitudeConstraint((90 - 19.7) * u.deg, (90 - 1.06) * u.deg)
    ]
    min_alt = (90 - 19.7) * u.deg
    max_alt = (90 - 1.06) * u.deg
    utc_offset = 4 * u.hour
    ast_to_utc_offset = TimezoneInfo(utc_offset=utc_offset)

    months = [
        'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct',
        'Nov', 'Dec'
    ]

    tstarts = []
    tends = []
    for index, row in obs_info.iterrows():
        obs_month = row['Month']
        for i, month in enumerate(months):
            if month == obs_month:
                break
        i = i + 1
        if row['End_time(AST)'] == '24:00':
            row['End_time(AST)'] = '23:59'
        tstarts.append(
            f"{row['Year']}-{i:02d}-{row['Start_date']} {row['Start_time(AST)']}"
        )
        tends.append(
            f"{row['Year']}-{i:02d}-{row['End_date']} {row['End_time(AST)']}")

    ots = []
    for st, et in zip(tstarts, tends):

        #setting up for altitude constraints
        tstart_obs = Time(st) + utc_offset
        tobs_len = (Time(et) - Time(st)).sec / (60 * 60)  #hours
        delta_t = np.linspace(0, tobs_len, 100) * u.hour
        frame_obs = AltAz(obstime=tstart_obs + delta_t, location=arecibo_site)

        #setting up for astroplan observability table
        st_utc = str(Time(st).to_datetime(timezone=ast_to_utc_offset))[:-6]
        et_utc = str(Time(et).to_datetime(timezone=ast_to_utc_offset))[:-6]

        time_range = Time([st_utc, et_utc], scale='utc')

        print(f'Making observability table for {st}')
        ot = observability_table(constraints,
                                 arecibo,
                                 targets,
                                 times=time_grid_from_range(
                                     time_range, 5 * u.min)).to_pandas()

        ot['ever obs'] = ot['ever observable']

        ot = ot.drop([
            'fraction of time observable', 'ever observable',
            'always observable'
        ],
                     axis=1)
        ot_obs = ot[ot['ever obs']]

        ra = []
        dec = []
        set_time = []
        up_time = []
        rise_time = []
        tstart_observable = []
        tend_observable = []

        print(f'Processing observability table for {st}')
        for i, row in ot_obs.iterrows():
            ra.append(targets[i].ra.deg)
            dec.append(targets[i].dec.deg)

            # manual altitude constraints
            target = SkyCoord(ra=targets[i].ra, dec=targets[i].dec)
            frame_obs_altaz = target.transform_to(frame_obs)

            times_observable = tstart_obs + delta_t[
                (frame_obs_altaz.alt > min_alt)
                & (frame_obs_altaz.alt < max_alt)]

            tstart_observable.append(times_observable.min() - utc_offset)

            if Time(times_observable.max()) < Time(et_utc):
                tend_observable.append(times_observable.max() - utc_offset)
                up_time.append((Time(times_observable.max()) -
                                Time(times_observable.min())).sec / 60)
            else:
                tend_observable.append(Time(et_utc) - utc_offset)
                up_time.append(
                    (Time(et_utc) - Time(times_observable.min())).sec / 60)

        ot_obs['RA'] = ra
        ot_obs['DEC'] = dec
        ot_obs['uptime (min)'] = up_time

        ot_obs['tstart_obs (AST)'] = tstart_observable
        ot_obs['tend_obs (AST)'] = tend_observable

        ot_obs = ot_obs[ot_obs['uptime (min)'] > min_uptime]
        ot_obs = ot_obs.drop(['ever obs'], axis=1)
        ots.append(ot_obs)

        if save:
            fname = str(Time(st_utc) - utc_offset)
            f = open(fname.replace(' ', '_') + '.tab', 'w')
            f.write(
                f'Observations from {str(Time(st_utc) - utc_offset)} to {str(Time(et_utc) - utc_offset)}\n'
            )
            f.write(f'Length of observations: {tobs_len:.2f}hr \n')
            f.write(
                tabulate(ot_obs,
                         headers='keys',
                         tablefmt='psql',
                         showindex="never"))
            f.close()
Example #8
0
def vis(date, objects, obj_tab):

    #This tool is designed for the Magellan Telescope @ Las Camapanas Observatory, in Chile
    las = Observer.at_site('LCO')
    #both las and los are the locations of MagAO, but one is used for the plot and the other for the time
    lco = EarthLocation.of_site('Las Campanas Observatory')

    userEntered_list = list(objects.split(","))
    target_list = userEntered_list

    targets = []
    for i in range(1, len(obj_tab)):
        ra = (obj_tab.iloc[i, 2])[1:] + ' hours'
        dec = (obj_tab.iloc[i, 3])[1:] + ' degrees'
        print(ra + ',' + dec)
        targets.append(
            FixedTarget(coord=SkyCoord(ra=ra, dec=dec),
                        name=target_list[i - 1]))

    constraints = [
        AltitudeConstraint(10 * u.deg, 80 * u.deg),
        AirmassConstraint(5),
        AtNightConstraint.twilight_civil()
    ]

    start_time = las.sun_set_time(Time(date), which='nearest')
    end_time = las.sun_rise_time(Time(date), which='nearest')
    date = start_time.iso[:10] + ' to ' + end_time.iso[:10]

    time_range = Time([start_time, end_time])

    # In[ ]:

    delta_t = end_time - start_time
    observe_time = start_time + delta_t * np.linspace(0, 1, 75)

    # In[ ]:

    # Are targets *ever* observable in the time range?
    ever_observable = is_observable(constraints,
                                    las,
                                    targets,
                                    time_range=time_range)

    # Are targets *always* observable in the time range?
    always_observable = is_always_observable(constraints,
                                             las,
                                             targets,
                                             time_range=time_range)

    # During what months are the targets ever observable?
    best_months = months_observable(constraints, las, targets)

    # In[ ]:

    table = observability_table(constraints,
                                las,
                                targets,
                                time_range=time_range)
    print(table)

    table = table.to_pandas()

    np.savetxt(
        'static/data/visibility.txt',
        table,
        fmt="%-30s",
        header=
        'Target name                  ever observable                always observable              fraction of time observable'
    )
Example #9
0
def construct_plan(data,
                   site,
                   start_time,
                   end_time,
                   constraints=None,
                   max_priority=3):
    if constraints is None:
        constraints = [
            AltitudeConstraint(10 * u.deg, 80 * u.deg),
            AirmassConstraint(5),
            AtNightConstraint.twilight_civil()
        ]

    data = data.sort_values(by=["Add. Data Priority", "RA"], ascending=[1, 1])

    time_range = Time([start_time, end_time])

    # targets.lis format:
    # NAME
    # <RA hh:mm:ss.ss> <DEC dd:mm:ss.s>
    # <HMJD/BMJD T0 err P err
    #
    # NAME...
    # ENTRY = "{}\n{} {}\n{} linear {} {} {} {}\n\n"
    targets_list = ""
    targets_prg = ""
    targets_notes = ""
    for name, row in data.iterrows():
        row['RA'], row['Dec'] = row['RA'].replace(" ",
                                                  ":"), row['Dec'].replace(
                                                      " ", ":")

        target = FixedTarget(coord=SkyCoord(ra=Angle(row['RA'],
                                                     unit='hourangle'),
                                            dec=Angle(row['Dec'],
                                                      unit='degree')),
                             name=name)

        # Does the target rise above the horizon?
        ever_observable = is_observable(constraints,
                                        site,
                                        target,
                                        time_range=time_range)

        # Parse the ephemeris data
        try:
            T0, T0_err = row['T(0) +/- (d)'].replace(" ", "").split("(")
            calendar, T0 = T0.split("=")
            T0_err = T0_err.replace(")", "")

            N = len(T0.split(".")[1]) - len(T0_err)
            T0_err = "0.{}{}".format(("0" * N), T0_err)

            P, P_err = row['P +/- (d)'].split("(")
            P_err = P_err.replace(")", "")

            M = len(P.split(".")[1]) - len(P_err)
            P_err = "0.{}{}".format(("0" * M), P_err)
        except ValueError:
            print("Failed to extract row! {}".format(name))
            continue

        # Get the priority of this system
        try:
            priority = int(row['Add. Data Priority'])
        except ValueError:
            continue

        # Logic about if we want to use this target
        writeme = ever_observable[0] and (priority <= max_priority)

        # If true, add to the list
        if writeme:
            # Output data formats
            line = "{}\n{} {}\n{} linear {} {} {} {}\n\n".format(
                name, row['RA'], row['Dec'], calendar, T0, T0_err, P, P_err)
            prgline = "{}\n0.7 1.3 3 8\n\n".format(name)
            notesline = '{}: "{}"\n\n\n'.format(name, row['Target Notes'])

            targets_list += line
            targets_prg += prgline
            targets_notes += notesline

    # Write out files
    with open(os.path.join('OUTPUT', 'targets.lis'), 'w') as f:
        f.write(targets_list)
    with open(os.path.join('OUTPUT', 'targets.prg'), 'w') as f:
        f.write(targets_prg)
    with open(os.path.join('OUTPUT', 'targets.txt'), 'w') as f:
        f.write(targets_notes)
Example #10
0
def observability_objects(data):
    """
    Test the observability of a list of objects for a single date

    Parameters
    ----------
    data : POST data format

    data = {
        'observatory' : 'OT',
        'altitude_lower_limit' : '30',
        'altitude_higher_limit' : '90',
        'objects' : [{
                'name' : 'Kelt 8b',
                'RA' : 283.30551667 ,
                'Dec' : 24.12738139,
                'dates' : [
                        ['2020-06-11 00:16:30', '2020-06-11 03:44:26'],
                        ['2020-06-14 06:07:56', '2020-06-14 09:35:53']
                    ]
                },
                {
                    'name' : 'TIC 123456789',
                    'RA' : 13.13055667 ,
                    'Dec' : 24.13912738,
                    'dates' : [
                        ['2020-06-11 23:59:59']
                    ]
                }
            ]
        }

    Returns
    -------
    observability : dict
        Dictionary with the observability and moon distance for all objects

        {'V0879 Cas' : {
                'observability' : 'True', 'moon_separation' : 30.4
            },
        'RU Scl' : {
            'observability' : 'True', 'moon_separation' : 10.8
            }
        }

    """

    import astropy.units as u
    from astroplan import FixedTarget
    from astroplan import (AltitudeConstraint, AtNightConstraint)
    from astroplan import is_observable, is_always_observable

    # Site location
    location = get_location(data['observatory'])

    # dict of observability for each target
    observabilities = {}

    if 'twilight_type' not in data.keys():
        data['twilight_type'] = 'astronomical'

    if data['twilight_type'] == 'civil':
        twilight_constraint = AtNightConstraint.twilight_civil()
    elif data['twilight_type'] == 'nautical':
        twilight_constraint = AtNightConstraint.twilight_nautical()
    else:
        twilight_constraint = AtNightConstraint.twilight_astronomical()

    # Observation constraints
    constraints = [
        AltitudeConstraint(
            float(data['altitude_lower_limit']) * u.deg,
            float(data['altitude_higher_limit']) * u.deg), twilight_constraint
    ]

    for target in data['objects']:

        coords = SkyCoord(ra=target['RA'] * u.deg, dec=target['Dec'] * u.deg)
        fixed_target = [FixedTarget(coord=coords, name=target['name'])]

        observabilities[target['name']] = []

        for date in target['dates']:

            # time range for transits
            # Always observable for time range
            if len(date) > 1:
                # If exoplanet transit, test observability always during transit,
                # if not, test observability *ever* during night
                time_range = Time([date[0], date[1]])

                # Are targets *always* observable in the time range?
                observable = is_always_observable(constraints,
                                                  location,
                                                  fixed_target,
                                                  time_range=time_range)

            # No time range, *ever* observabable during the night
            # Observability is test from sunset to sunrise
            # Default time resolution is 0.5h
            else:
                sunset = location.sun_set_time(Time(date[0]))
                sunrise = location.sun_rise_time(Time(date[0]), 'next')
                time_range = Time([sunset, sunrise])
                observable = is_observable(constraints,
                                           location,
                                           fixed_target,
                                           time_range=time_range)

            # Moon location for the observation date
            moon = location.moon_altaz(Time(date[0]))
            moon_separation = moon.separation(coords)

            observabilities[target['name']].append({
                'observable':
                str(observable[0]),
                'moon_separation':
                moon_separation.degree
            })

    return observabilities
Example #11
0
def observability_dates(data):
    """
    Test the observability of a single objects for several nights

    If the first element of 'dates' contains a single date, then
    the observability is test as *ever* for the night. 
    If a time range is given, observability is test as *always* for the time range

    Parameters
    ----------
    data : POST data format

        # data for transiting planet, time range constrained
        data = {
            'name' : 'Kelt 8b',
            'RA' : 283.30551667 ,
            'Dec' : 24.12738139,
            'observatory' : 'OT',
            'altitude_lower_limit' : '30',
            'altitude_higher_limit' : '90',
            'twilight_type' : 'astronomical',
            'dates' : [
                    ['2020-06-11 00:16:30', '2020-06-11 03:44:26'],
                    ['2020-06-14 06:07:56', '2020-06-14 09:35:53']
                ]
            }
        
        # data for ordinary target, twilight constrained
        # single date list

        data = {
            'name' : 'KIC8012732',
            'RA' : 284.72949583 ,
            'Dec' : 43.86421667,
            'observatory' : 'OT',
            'altitude_lower_limit' : '30',
            'altitude_higher_limit' : '90',
            'dates' : [
                        ['2020-06-11 23:00:00']
                    ]
            }

    Returns
    -------
    observability : dict
        Dictionary with the observability and moon distance for all objects

        {'V0879 Cas' : {
                'observability' : 'True', 'moon_separation' : 30.4
            },
        'RU Scl' : {
                'observability' : 'True', 'moon_separation' : 10.8
            }
        }

    """

    import astropy.units as u
    from astroplan import FixedTarget
    from astroplan import (AltitudeConstraint, AtNightConstraint)
    from astroplan import is_observable, is_always_observable

    # Site location
    location = get_location(data['observatory'])

    coords = SkyCoord(ra=data['RA'] * u.deg, dec=data['Dec'] * u.deg)
    fixed_target = [FixedTarget(coord=coords, name=data['name'])]

    # List of dates of observability
    observabilities = []

    if 'twilight_type' not in data.keys():
        data['twilight_type'] = 'astronomical'

    if data['twilight_type'] == 'civil':
        twilight_constraint = AtNightConstraint.twilight_civil()
    elif data['twilight_type'] == 'nautical':
        twilight_constraint = AtNightConstraint.twilight_nautical()
    else:
        twilight_constraint = AtNightConstraint.twilight_astronomical()

    # Observation constraints
    constraints = [
        AltitudeConstraint(
            float(data['altitude_lower_limit']) * u.deg,
            float(data['altitude_higher_limit']) * u.deg), twilight_constraint
    ]

    for date in data['dates']:

        # time range for transits
        # Always observable for time range
        if len(data['dates'][0]) > 0:

            # If exoplanet transits, check for observability always during transit,
            # if not, check observability *ever* during night
            time_range = Time([date[0], date[1]])

            # Are targets *always* observable in the time range?
            observable = is_always_observable(constraints,
                                              location,
                                              fixed_target,
                                              time_range=time_range)

        # No time range, *ever* observabable during the night
        else:
            observable = is_observable(constraints,
                                       location,
                                       fixed_target,
                                       times=Time(date[0]))

        # Moon location for the observation date
        moon = location.moon_altaz(Time(date[0]))
        moon_separation = moon.separation(coords)

        observabilities.append({
            'observable': str(observable[0]),
            'moon_separation': moon_separation.degree
        })

    return observabilities
Example #12
0
def run_nights(observers, nameList, args):
    # Define range of times to observe between
    startDate = datetime.datetime.strptime(args.startDate,"%Y-%m-%d")
    beginTimeFirstNight = datetime.datetime(startDate.year,startDate.month,startDate.day,hour=16)
    endTimeFirstNight = beginTimeFirstNight + datetime.timedelta(hours=16)
    t_datetimes_nights_list = []
    for iDay in range(args.nNights):
        beginTime = beginTimeFirstNight + datetime.timedelta(days=iDay)
        endTime = endTimeFirstNight + datetime.timedelta(days=iDay)
        currTime = beginTime
        t_datetime = []
        while currTime <= endTime:
            t_datetime.append(currTime)
            currTime += datetime.timedelta(hours=1)
        t_datetimes_nights_list.append(t_datetime)

    targets = [FixedTarget(coord=lookuptarget(name),name=name) for name in nameList]
    targetLabelList, ylabelsize = makeTargetLabels(nameList,args)

    constraints = [
        AltitudeConstraint(min=args.minAlt*u.deg),
        AtNightConstraint.twilight_astronomical(),
        MoonSeparationConstraint(min=args.minMoonSep*u.deg),
        MoonIlluminationConstraint(max=args.maxMoonIllum),
    ]

    outfn = args.outFileNameBase+"_nightly.pdf"
    with PdfPages(outfn) as pdf:
        for observer in observers:
            fig, axes = mpl.subplots(
                figsize=(8.5,11),
                ncols=args.nNights,
                sharex="col",
                gridspec_kw={
                    "top":0.92,
                    "bottom":0.03,
                    "left":0.13,
                    "right":0.98,
                    "hspace":0,
                    "wspace":0
                },
                tight_layout=False,constrained_layout=False
            )

            observability_grids = []
            for iNight in range(args.nNights):
                t_datetime = t_datetimes_nights_list[iNight]
                time_grid = [Time(observer.timezone.localize(t)) for t in t_datetime]
                
                observability_grid = numpy.zeros((len(targets),len(time_grid)-1))
                for i in range(len(time_grid)-1):
                    tmp = is_always_observable(constraints, observer, targets, times=[time_grid[i],time_grid[i+1]])
                    observability_grid[:, i] = tmp
                observability_grids.append(observability_grid)

            observable_targets = targets
            observable_target_labels = targetLabelList
            ever_observability_grids = observability_grids
            if args.onlyEverObservable:
                target_is_observable = numpy.zeros(len(targets))
                for observability_grid in observability_grids:
                    for iTime in range(observability_grid.shape[1]):
                        target_is_observable += observability_grid[:,iTime]
                target_is_observable = target_is_observable > 0. # change to boolean numpy array
                observable_targets = [x for x, o in zip(targets,target_is_observable) if o]
                observable_target_labels = [x for x, o in zip(targetLabelList,target_is_observable) if o]
                ever_observability_grids = []
                for observability_grid in observability_grids:
                    ever_observability_grid = observability_grid[target_is_observable,:]
                    ever_observability_grids.append(ever_observability_grid)

            for iNight in range(args.nNights):
                ax = axes[iNight]
                t_datetime = t_datetimes_nights_list[iNight]
                extent = [0, len(t_datetime)-1, -0.5, len(observable_targets)-0.5]
                ax.imshow(ever_observability_grids[iNight], extent=extent, origin="lower", aspect="auto", cmap=mpl.get_cmap("Greens"))
                ax.xaxis.tick_top()
                ax.xaxis.set_label_position("top")
                ax.invert_yaxis()

                if iNight == 0:
                    ax.set_yticks(range(0,len(observable_targets)))
                    ax.set_yticklabels(observable_target_labels, fontsize=ylabelsize)
                else:
                    ax.set_yticks([])

                ax.set_xticks(range(0,len(t_datetime)-1,4))
                ax.set_xticks(range(0,len(t_datetime)),minor=True)
                ax.set_xticklabels([t_datetime[i].strftime("%Hh") for i in range(0,len(t_datetime)-1,4)])

                ax.set_xlabel(t_datetime[0].strftime("%a %b %d"))

                ax.set_yticks(numpy.arange(extent[2], extent[3]), minor=True)

                ax.grid(axis="x",which="minor",color="0.7",ls="-", linewidth=0.5)
                ax.grid(axis="x",which="major",color="0.7",ls="-", linewidth=1)
                ax.grid(axis="y",which="minor",color="0.7",ls="-", linewidth=0.5)

                ax.tick_params(axis='y', which='minor', left=False, right=False)
                ax.tick_params(axis='x', which='minor', bottom=False, top=False)
        
            fig.suptitle(f"Observability at {observer.name} in {startDate.year}")
            fig.text(1.0,0.0,"Constraints: Astronomical Twilight, Altitude $\geq {:.0f}^\circ$, Moon Seperation $\geq {:.0f}^\circ$, Moon Illumination $\leq {:.2f}$".format(args.minAlt,args.minMoonSep,args.maxMoonIllum),ha="right",va="bottom")
            pdf.savefig(fig)
        print(f"Writing out file: {outfn}")
Example #13
0
def get_obs_data(target, observers, current_time, alt_limit=30):
    """Compile infomation about the target's visibility from the given observers."""
    all_data = {}
    if target is None:
        return all_data

    for observer in observers:
        data = {}
        data['observer'] = observer
        data['current_time'] = current_time

        # Get midnight and astronomical twilight times
        midnight = observer.midnight(current_time, which='next')
        sun_set = observer.twilight_evening_astronomical(midnight,
                                                         which='previous')
        sun_rise = observer.twilight_morning_astronomical(midnight,
                                                          which='next')
        dark_time = Time([sun_set, sun_rise])
        data['midnight'] = midnight
        data['sun_set'] = sun_set
        data['sun_rise'] = sun_rise

        # Apply a constraint on altitude
        min_alt = alt_limit * u.deg
        alt_constraint = AltitudeConstraint(min=min_alt, max=None)
        alt_observable = is_observable(alt_constraint,
                                       observer,
                                       target,
                                       time_range=dark_time)[0]
        data['alt_constraint'] = alt_constraint
        data['alt_observable'] = alt_observable

        # Get target rise and set times
        if alt_observable:
            with warnings.catch_warnings():
                warnings.simplefilter('ignore')
                target_rise = observer.target_rise_time(midnight,
                                                        target,
                                                        which='nearest',
                                                        horizon=min_alt)
                target_set = observer.target_set_time(target_rise,
                                                      target,
                                                      which='next',
                                                      horizon=min_alt)

            # Get observation times
            observation_start = target_rise
            observation_end = target_set
            if target_rise.jd < 0 or target_set.jd < 0:
                # target is always above the horizon, so visible all night
                observation_start = sun_set
                observation_end = sun_rise
            if target_rise < sun_set:
                # target is already up when the sun sets
                observation_start = sun_set
            if target_set > sun_rise:
                # target sets after the sun rises
                observation_end = sun_rise

            data['target_rise'] = target_rise
            data['target_set'] = target_set
            data['observation_start'] = observation_start
            data['observation_end'] = observation_end
        else:
            data['target_rise'] = None
            data['target_set'] = None
            data['observation_start'] = None
            data['observation_end'] = None

        # Apply a constraint on distance from the Moon
        min_moon = 5 * u.deg
        moon_constraint = MoonSeparationConstraint(min=min_moon, max=None)
        moon_observable = is_observable(moon_constraint,
                                        observer,
                                        target,
                                        time_range=dark_time)[0]
        data['moon_constraint'] = moon_constraint
        data['moon_observable'] = moon_observable

        all_data[observer.name] = data

    return all_data
Example #14
0
def observability(self, json_exoplanet_array, longitude, latitude, elevation, start_date, end_date, min_altitude, max_altitude, resolution):
    '''background task to (slowly) find planet observabilities'''
    
    # create Observer instance
    if elevation is None: elevation = 0
    custom_location = Observer(longitude=longitude*u.deg, latitude=latitude*u.deg, elevation=elevation*u.m)

    # time range
    if start_date is not None: start_date = Time(datetime.combine(datetime.fromisoformat(start_date), datetime.min.time()), out_subfmt='date')
    else: start_date = Time(datetime.combine(datetime.now(), datetime.min.time()), out_subfmt='date')
    if end_date is not None: end_date = Time(datetime.combine(datetime.fromisoformat(end_date), datetime.min.time()), out_subfmt='date')
    else: end_date = start_date + 30*u.day
    time_range = Time([start_date, end_date])

    # altitude and night time constraints
    if min_altitude is None: min_altitude = 0
    if max_altitude is None: max_altitude = 90
    constraints = [AltitudeConstraint(min_altitude*u.deg, max_altitude*u.deg), AtNightConstraint.twilight_astronomical()]
    
    # calculate if observable within lookahead time from now
    if resolution is None: resolution = 0.5
    
    # since we had to use a json string as argument, recreate the custom_exoplanet_array from the json
    custom_exoplanet_array = []
    json_unload = json.loads(json_exoplanet_array) # unpack json to make a dictionary
    for dict_ in json_unload:
        planet = Exoplanet()
        # copy properties back over from dictionary
        for prop, val in dict_.items(): functions.rsetattr(planet, prop, val)
        custom_exoplanet_array.append(planet)

    # trying to split array into chunks so we can say the task has been completed to the nearest percent
    num_chunks = round(len(custom_exoplanet_array)/800 * (resolution/0.5)**-1 * ((end_date-start_date).jd/30)**2 * 10)
    if num_chunks == 0: num_chunks = 1
    exoplanet_array_chunks = np.array_split(custom_exoplanet_array, num_chunks) # split exoplanet array into num_chunk parts

    planets_done = 0 # planets calculated for so far
    planets_lost = 0 # planets removed so far

    recombined_chunks = []
    for chunk in exoplanet_array_chunks:
        # make an array of FixedTarget instances
        target_table = []
        for planet in chunk:
            target_table.append((planet.name, planet.host.ra, planet.host.dec))
        targets = [FixedTarget(coord=SkyCoord(ra=ra*u.deg, dec=dec*u.deg), name=name)
                   for name, ra, dec in target_table]

        # calculate
        ever_observable = is_observable(constraints, custom_location, targets, time_range=time_range, time_grid_resolution=resolution*u.hour)

        # note unobservables
        to_pop = []
        for i in range(len(chunk)):
            chunk[i].observable = bool(ever_observable[i])
            if chunk[i].observable == False:
                to_pop.append(i)
        # remove unobservables
        chunk = np.delete(chunk, to_pop)

        # record numbers
        planets_done += len(targets)
        planets_lost += len(targets) - len(chunk)

        # write json
        recombined_chunks += chunk.tolist()
        observable_exoplanet_array = [planet for planet in recombined_chunks if planet.observable]
        json_exoplanet_array = functions.planet_array_to_json_array(observable_exoplanet_array, 'host_')

        # graph of decision metric vs rank
        tooltip_dict = {
            'name'            : [],
            'mass'            : [],
            'radius'          : [],
            'orbital_period'  : [],
            'semi_major_axis' : [],
            'temp_calculated' : [],
            'detection_type'  : [],
            'decision_metric' : [],
            'filter'          : [],
            't_exp'           : [],
        }
        graph = functions.metric_rank_bar_graph(observable_exoplanet_array, tooltip_dict)

        # update status
        self.update_state(state='PROGRESS',
                          meta={'current'         : planets_done,
                                'removed'         : planets_lost,
                                'total'           : len(custom_exoplanet_array),
                                'exoplanet_array' : json_exoplanet_array,
                                'graph'           : graph,
                                'finished'        : 'n'})
    
    return {'current': planets_done, 'removed': planets_lost, 'total': len(custom_exoplanet_array), 'exoplanet_array': json_exoplanet_array, 'graph': graph, 'finished': 'y'}
def get_event_observability(
    eventclass,
    site, ra, dec, name, t_mid_0, period, duration, n_transits=100,
    obs_start_time=Time(dt.datetime.today().isoformat()),
    min_altitude = None,
    oot_duration = 30*u.minute,
    minokmoonsep = 30*u.deg,
    max_airmass = None,
    twilight_limit = 'nautical'):
    """
    note: barycentric corrections not yet implemented. (could do this myself!)
    -> 16 minutes of imprecision is baked into this observability calculator!

    args:

        eventclass: e.g., "OIBE". Function does NOT return longer events.

        site (astroplan.observer.Observer)

        ra, dec (units u.deg), e.g.:
            ra=101.28715533*u.deg, dec=16.71611586*u.deg,
        or can also accept
            ra="17 56 35.51", dec="-29 32 21.5"

        name (str), e.g., "Sirius"

        t_mid_0 (float): in BJD_TDB, preferably (but see note above).

        period (astropy quantity, units time)

        duration (astropy quantity, units time)

        n_transits (int): number of transits forward extrapolated to

        obs_start_time (astropy.Time object): when to start calculation from

        min_altitude (astropy quantity, units deg): 20 degrees is the more
        relevant constraint.

        max_airmass: e.g., 2.5. One of max_airmass or min_altitude is required.

        oot_duration (astropy quantity, units time): with which to brack
        transit observations, to get an OOT baseline.

        twilight_limit: 'astronomical', 'nautical', 'civil' for -18, -12, -6
        deg.
    """
    if eventclass not in [
        'OIBEO', 'OIBE', 'IBEO', 'IBE', 'BEO', 'OIB', 'OI', 'EO'
    ]:
        raise AssertionError

    if (isinstance(ra, u.quantity.Quantity) and
        isinstance(dec, u.quantity.Quantity)
    ):
        target_coord = SkyCoord(ra=ra, dec=dec)
    elif (isinstance(ra, str) and
          isinstance(dec, str)
    ):
        target_coord = SkyCoord(ra=ra, dec=dec, unit=(u.hourangle, u.deg))
    else:
        raise NotImplementedError

    if (
        not isinstance(max_airmass, float)
        or isinstance(min_altitude, u.quantity.Quantity)
    ):
        raise NotImplementedError

    target = FixedTarget(coord=target_coord, name=name)

    primary_eclipse_time = Time(t_mid_0, format='jd')

    system = EclipsingSystem(primary_eclipse_time=primary_eclipse_time,
                             orbital_period=period, duration=duration,
                             name=name)

    midtransit_times = system.next_primary_eclipse_time(
        obs_start_time, n_eclipses=n_transits)

    # for the time being, omit any local time constraints.
    if twilight_limit == 'astronomical':
        twilight_constraint = AtNightConstraint.twilight_astronomical()
    elif twilight_limit == 'nautical':
        twilight_constraint = AtNightConstraint.twilight_nautical()
    else:
        raise NotImplementedError('civil twilight is janky.')

    constraints = [twilight_constraint,
                   AltitudeConstraint(min=min_altitude),
                   AirmassConstraint(max=max_airmass),
                   MoonSeparationConstraint(min=minokmoonsep)]

    # tabulate ingress and egress times.
    ing_egr = system.next_primary_ingress_egress_time(
        obs_start_time, n_eclipses=n_transits
    )

    oibeo_window = np.concatenate(
        (np.array(ing_egr[:,0] - oot_duration)[:,None],
         np.array(ing_egr[:,1] + oot_duration)[:,None]),
        axis=1)
    oibe_window = np.concatenate(
        (np.array(ing_egr[:,0] - oot_duration)[:,None],
         np.array(ing_egr[:,1])[:,None]),
        axis=1)
    ibeo_window = np.concatenate(
        (np.array(ing_egr[:,0])[:,None],
         np.array(ing_egr[:,1] + oot_duration)[:,None]),
        axis=1)
    oib_window = np.concatenate(
        (np.array(ing_egr[:,0] - oot_duration)[:,None],
         np.array(midtransit_times)[:,None]),
        axis=1)
    beo_window = np.concatenate(
        (np.array(midtransit_times)[:,None],
         np.array(ing_egr[:,1] + oot_duration)[:,None]),
        axis=1)
    ibe_window = ing_egr
    oi_window = np.concatenate(
        (np.array(ing_egr[:,0] - oot_duration)[:,None],
        np.array(ing_egr[:,0])[:,None]),
        axis=1)
    eo_window = np.concatenate(
        (np.array(ing_egr[:,1])[:,None],
        np.array(ing_egr[:,1] + oot_duration)[:,None]),
        axis=1)

    keys = ['oibeo','oibe','ibeo','oib','beo','ibe','oi','eo']
    windows = [oibeo_window, oibe_window, ibeo_window,
               oib_window, beo_window, ibe_window, oi_window, eo_window]
    is_obs_dict = {}
    for key, window in zip(keys, windows):
        is_obs_dict[key] = np.array(
            is_event_observable(constraints, site, target,
                                times_ingress_egress=window)
        ).flatten()

    is_obs_df = pd.DataFrame(is_obs_dict)

    is_obs_df['ing'] = ing_egr[:,0]
    is_obs_df['egr'] = ing_egr[:,1]
    is_obs_df['isoing'] = Time(ing_egr[:,0], format='iso')
    is_obs_df['isoegr'] = Time(ing_egr[:,1], format='iso')

    # this function returns the observable events that are LONGEST. e.g.,
    # during an OIBEO transit you COULD observe just OIB, but why would you?

    if eventclass == 'OIBEO':
        event_ind = np.array(is_obs_df[eventclass.lower()])[None,:]
    elif eventclass in ['IBEO', 'OIBE']:
        event_ind = np.array(
            is_obs_df[eventclass.lower()] & ~is_obs_df['oibeo']
        )[None,:]
    elif eventclass in ['IBE', 'OIB', 'BEO']:
        event_ind = np.array(
            is_obs_df[eventclass.lower()]
            & ~is_obs_df['oibeo']
            & ~is_obs_df['oibe']
            & ~is_obs_df['ibeo']
        )[None,:]
    elif eventclass in ['OI', 'EO']:
        event_ind = np.array(
            is_obs_df[eventclass.lower()]
            & ~is_obs_df['oibeo']
            & ~is_obs_df['oibe']
            & ~is_obs_df['ibeo']
            & ~is_obs_df['oib']
            & ~is_obs_df['ibe']
            & ~is_obs_df['beo']
        )[None,:]

    # get moon separation over each transit. take minimum moon sep at
    # ing/tmid/egr as the moon separation.
    moon_tmid = get_moon(midtransit_times, location=site.location)
    moon_separation_tmid = moon_tmid.separation(target_coord)

    moon_ing = get_moon(ing_egr[:,0], location=site.location)
    moon_separation_ing = moon_ing.separation(target_coord)

    moon_egr = get_moon(ing_egr[:,1], location=site.location)
    moon_separation_egr = moon_egr.separation(target_coord)

    moon_separation = np.round(np.array(
        [moon_separation_tmid, moon_separation_ing,
         moon_separation_egr]).min(axis=0),0).astype(int)

    moon_illumination = np.round(
        100*moon.moon_illumination(midtransit_times),0).astype(int)

    # completely observable transits (OOT, ingress, bottom, egress, OOT)
    oibeo = is_event_observable(constraints, site, target,
                                times_ingress_egress=oibeo_window)

    ing_tmid_egr = np.concatenate(
        (np.array(ing_egr[:,0])[:,None],
         np.array(midtransit_times)[:,None],
         np.array(ing_egr[:,1])[:,None]),
        axis=1)

    target_window = np.array(windows)[
        int(np.argwhere(np.array(keys)==eventclass.lower())), :, :
    ]

    return (
        event_ind, oibeo, ing_tmid_egr, target_window,
        moon_separation, moon_illumination
    )
Example #16
0
    """
    Constraint requiring 3hrs setup for MUSTANG
    """
    def compute_constraint(self, times, observer, targets):

        # we want the time since the sun went below 5 deg,
        # which is enough to start cooling the dish
        sunset = observer.sun_set_time(times, horizon=5 * u.deg)

        mask = times > sunset + astropy.time.TimeDelta(3 * u.hour)

        return mask


constraints = [
    AltitudeConstraint(20 * u.deg, 80 * u.deg), GBTNight,
    GBT3hoursAfterSunset()
]

targets = [
    coordinates.SkyCoord(glon, 0, frame='galactic', unit='deg')
    for glon in range(-5, 56)
]

assert len(targets) < 65

# observability tables take _forever_
# first do a fast one to make sure things work...
#obstab_quick = observability_table(constraints, observer, targets[0:2],
#                                   time_range=time_range,
#                                   time_grid_resolution=1*u.hour)
Example #17
0
def send_database_report(event):
    """Send a message to Slack with details of the database pointings and visibility."""
    title = ['*Visibility for event {}*'.format(event.name)]

    # Basic details
    details = []
    filepath = None
    with db.open_session() as session:
        # Query Event table entries
        db_events = session.query(
            db.Event).filter(db.Event.name == event.name).all()

        details += [
            'Number of entries in the events table: {}'.format(len(db_events))
        ]

        if len(db_events) == 0:
            # Uh-oh
            details += ['*ERROR: Nothing found in database*']
        else:
            # This event should be the latest added
            db_event = db_events[-1]

            # Get Mpointings
            db_mpointings = db_event.mpointings

            details += [
                'Number of targets for this event: {}'.format(
                    len(db_mpointings))
            ]

            if len(db_mpointings) == 0:
                # It might be because it's a retraction, so we've removed the previous pointings
                if event.type == 'GW_RETRACTION':
                    details += ['- Previous targets removed successfully']
                # Or it might be because no tiles passed the filter
                elif (event.strategy['on_grid']
                      and event.strategy['prob_limit'] > 0
                      and max(event.full_table['prob']) <
                      event.strategy['prob_limit']):
                    details += [
                        '- No tiles passed the probability limit ' +
                        '({:.1f}%, '.format(event.strategy['prob_limit'] * 100)
                        + 'highest had {:.1f}%)'.format(
                            max(event.full_table['prob']) * 100),
                    ]
                else:
                    # Uh-oh
                    details += ['- *ERROR: No Mpointings found in database*']

            else:
                # Get the Mpointing coordinates
                ras = [mpointing.ra for mpointing in db_mpointings]
                decs = [mpointing.dec for mpointing in db_mpointings]
                coords = SkyCoord(ras, decs, unit='deg')

                for site in ['La Palma']:  # TODO: should be in params
                    details += ['Predicted visibility from {}:'.format(site)]

                    # Create Astroplan Observer
                    observer = Observer.at_site(site.lower().replace(' ', ''))

                    # Create visibility constraints
                    min_alt = float(
                        event.strategy['constraints_dict']['min_alt']) * u.deg
                    max_sunalt = float(event.strategy['constraints_dict']
                                       ['max_sunalt']) * u.deg
                    alt_constraint = AltitudeConstraint(min=min_alt)
                    night_constraint = AtNightConstraint(
                        max_solar_altitude=max_sunalt)
                    constraints = [alt_constraint, night_constraint]

                    # Check visibility until the stop time
                    start_time = event.strategy['start_time']
                    stop_time = event.strategy['stop_time']
                    details += [
                        '- Valid dates: {} to {}'.format(
                            start_time.datetime.strftime('%Y-%m-%d'),
                            stop_time.datetime.strftime('%Y-%m-%d'))
                    ]

                    if event.strategy['stop_time'] < Time.now():
                        # The Event pointings will have expired
                        delta = Time.now() - event.strategy['stop_time']
                        details[-1] += ' _(expired {:.1f} days ago)_'.format(
                            delta.to('day').value)

                    mps_visible_mask = is_observable(
                        constraints,
                        observer,
                        coords,
                        time_range=[start_time, stop_time])
                    details += [
                        '- Targets visible during valid period: {}/{}'.format(
                            sum(mps_visible_mask), len(db_mpointings))
                    ]

                    if event.strategy['on_grid']:
                        # Find the total probibility for all tiles
                        mp_tiles = np.array(
                            [mp.grid_tile.name for mp in db_mpointings])
                        total_prob = event.grid.get_probability(
                            list(mp_tiles)) * 100
                        details += [
                            '- Total probability in all tiles: {:.1f}%'.format(
                                total_prob)
                        ]

                        # Get visible mp tile names
                        mp_tiles_visible = mp_tiles[mps_visible_mask]
                        visible_prob = event.grid.get_probability(
                            list(mp_tiles_visible)) * 100
                        details += [
                            '- Probability in visible tiles: {:.1f}%'.format(
                                visible_prob)
                        ]

                        # Get non-visible mp tile names
                        mps_notvisible_tonight_mask = np.invert(
                            mps_visible_mask)
                        mp_tiles_notvisible = mp_tiles[
                            mps_notvisible_tonight_mask]

                        # Get all non-visible tiles
                        tiles_visible_mask = is_observable(
                            constraints,
                            observer,
                            event.grid.coords,
                            time_range=[start_time, stop_time])
                        tiles_notvisible_mask = np.invert(tiles_visible_mask)
                        tiles_notvisible = np.array(
                            event.grid.tilenames)[tiles_notvisible_mask]

                        # Create a plot of the tiles, showing visibility tonight
                        # TODO: multiple sites? Need multiple plots or one combined?
                        filename = event.name + '_tiles.png'
                        filepath = os.path.join(params.FILE_PATH, filename)
                        event.grid.plot(
                            filename=filepath,
                            plot_skymap=True,
                            highlight=[mp_tiles_visible, mp_tiles_notvisible],
                            highlight_color=['blue', 'red'],
                            color={
                                tilename: '0.5'
                                for tilename in tiles_notvisible
                            },
                        )

    message_text = '\n'.join(title + details)

    # Send the message, with the plot attached if one was generated
    send_slack_msg(message_text, filepath=filepath)
Example #18
0
def plan_when_transits_will_occur(
        filename='targets.txt',
        observatory='Southern African Large Telescope',
        start='2017-06-22',
        end='2017-06-28',
        airmass_limit=2.5,
        moon_distance=10,
        do_secondary=True,
        method='by_night'):
    '''
    Plan when targets will be visibile and transiting from a site. 
    
    Inputs
    ------
    filename : str
        A plain text file with the following columns:
            target : The name of the target (e.g. J0555-57).
            RA     : The right ascension of the target (e.g. 05h55m32.62s).
            DEC    : The declination of the target (e.g. -57d17m26.1s).
            epoch* : The epoch of the transit. Youc can either use:
                         epoch_HJD-2400000 : HJD - 24500000
                         epoch_BJD-2455000 : MJD
            Period : The period of the system (days).
            Secondary : can be True or False depending on whether you want
                        to see when the secondary transits will be.
    observatory : str
        The observatory you are observing from. See later for list of available
        observatories (accepted by astropy).    
    start : str
        The first night of observation (e.g. 2017-08-31).
    end : str
        The last night of observation (e.g. 2017-09-10).
    airmass_limit : float
        The maximum airmass you want to observe through. 
    moon_distance : float
        The closest the target can be t the moon in arcmins.
    do_secondary = True:
        Look for secondary eclipses assuming circularised orbits. 
        
    Available observator names are:
         'ALMA',
         'Anglo-Australian Observatory',
         'Apache Point',
         'Apache Point Observatory',
         'Atacama Large Millimeter Array',
         'BAO',
         'Beijing XingLong Observatory',
         'Black Moshannon Observatory',
         'CHARA',
         'Canada-France-Hawaii Telescope',
         'Catalina Observatory',
         'Cerro Pachon',
         'Cerro Paranal',
         'Cerro Tololo',
         'Cerro Tololo Interamerican Observatory',
         'DCT',
         'Discovery Channel Telescope',
         'Dominion Astrophysical Observatory',
         'Gemini South',
         'Hale Telescope',
         'Haleakala Observatories',
         'Happy Jack',
         'Jansky Very Large Array',
         'Keck Observatory',
         'Kitt Peak',
         'Kitt Peak National Observatory',
         'La Silla Observatory',
         'Large Binocular Telescope',
         'Las Campanas Observatory',
         'Lick Observatory',
         'Lowell Observatory',
         'Manastash Ridge Observatory',
         'McDonald Observatory',
         'Medicina',
         'Medicina Dish',
         'Michigan-Dartmouth-MIT Observatory',
         'Mount Graham International Observatory',
         'Mt Graham',
         'Mt. Ekar 182 cm. Telescope',
         'Mt. Stromlo Observatory',
         'Multiple Mirror Telescope',
         'NOV',
         'National Observatory of Venezuela',
         'Noto',
         'Observatorio Astronomico Nacional, San Pedro Martir',
         'Observatorio Astronomico Nacional, Tonantzintla',
         'Palomar',
         'Paranal Observatory',
         'Roque de los Muchachos',
         'SAAO',
         'SALT',
         'SRT',
         'Siding Spring Observatory',
         'Southern African Large Telescope',
         'Subaru',
         'Subaru Telescope',
         'Sutherland',
         'Vainu Bappu Observatory',
         'Very Large Array',
         'W. M. Keck Observatory',
         'Whipple',
         'Whipple Observatory',
         'aao',
         'alma',
         'apo',
         'bmo',
         'cfht',
         'ctio',
         'dao',
         'dct',
         'ekar',
         'example_site',
         'flwo',
         'gemini_north',
         'gemini_south',
         'gemn',
         'gems',
         'greenwich',
         'haleakala',
         'irtf',
         'keck',
         'kpno',
         'lapalma',
         'lasilla',
         'lbt',
         'lco',
         'lick',
         'lowell',
         'mcdonald',
         'mdm',
         'medicina',
         'mmt',
         'mro',
         'mso',
         'mtbigelow',
         'mwo',
         'noto',
         'ohp',
         'paranal',
         'salt',
         'sirene',
         'spm',
         'srt',
         'sso',
         'tona',
         'vbo',
         'vla'.
    '''
    ###################
    # Try reading table
    ###################
    try:
        target_table = Table.read(filename, format='ascii')
    except:
        raise ValueError(
            'I cant open the target file (make sure its ascii with the following first line:\ntarget		RA		DEC		epoch_HJD-2400000	Period		Secondary'
        )

##############################
# try reading observation site
##############################
    try:
        observation_site = coord.EarthLocation.of_site(observatory)
        observation_handle = Observer(location=observation_site)
        observation_handle1 = Observer.at_site(observatory)
    except:
        print(coord.EarthLocation.get_site_names())
        raise ValueError('The site is not understood')

###################################
# Try reading start and end times
###################################
    try:
        start_time = Time(start + ' 12:01:00', location=observation_site)
        end_time = Time(end + ' 12:01:00', location=observation_site)
        number_of_nights = int(end_time.jd - start_time.jd)
        time_range = Time([start + ' 12:01:00', end + ' 12:01:00'])
        print('Number of nights: {}'.format(number_of_nights))
    except:
        raise ValueError('Start and end times not understood')

#####################
# Now do constraints
#####################
#try:

    constraints = [
        AltitudeConstraint(0 * u.deg, 90 * u.deg),
        AirmassConstraint(3),
        AtNightConstraint.twilight_civil()
    ]
    #except:
    #	raise ValueError('Unable to get set constraints')

    if method == 'by_night':
        for i in range(number_of_nights):
            start_time_tmp = start_time + TimeDelta(
                i,
                format='jd')  #  get start time (doesent need to be accurate)
            end_time_tmp = start_time + TimeDelta(
                i + 1,
                format='jd')  #  get start time (doesent need to be accurate)
            print('#' * 80)
            start_time_tmpss = start_time_tmp.datetime.ctime().split(
            )  # ['Fri', 'Dec', '24', '12:00:00', '2010']
            print('Night {} - {} {} {} {}'.format(i + 1, start_time_tmpss[0],
                                                  start_time_tmpss[2],
                                                  start_time_tmpss[1],
                                                  start_time_tmpss[-1]))
            print('#' * 80)

            # Now print Almnac information (sunset and end of evening twilight
            print('Almnac:')
            sun_set = observation_handle.sun_set_time(start_time_tmp,
                                                      which='next')
            print('Sunset:\t\t\t\t\t\t\t' + sun_set.utc.datetime.ctime())

            twilight_evening_astronomical = observation_handle.twilight_evening_astronomical(
                start_time_tmp, which='next')  # -18
            twilight_evening_nautical = observation_handle.twilight_evening_nautical(
                start_time_tmp, which='next')  # -12
            twilight_evening_civil = observation_handle.twilight_evening_civil(
                start_time_tmp, which='next')  # -6 deg
            print('Civil evening twilight (-6 deg) (U.T.C):\t\t' +
                  twilight_evening_civil.utc.datetime.ctime())
            print('Nautical evening twilight (-12 deg) (U.T.C):\t\t' +
                  twilight_evening_nautical.utc.datetime.ctime())
            print('Astronomical evening twilight (-18 deg) (U.T.C):\t' +
                  twilight_evening_astronomical.utc.datetime.ctime())
            print('\n')

            twilight_morning_astronomical = observation_handle.twilight_morning_astronomical(
                start_time_tmp, which='next')  # -18
            twilight_morning_nautical = observation_handle.twilight_morning_nautical(
                start_time_tmp, which='next')  # -12
            twilight_morning_civil = observation_handle.twilight_morning_civil(
                start_time_tmp, which='next')  # -6 deg
            print('Astronomical morning twilight (-18 deg) (U.T.C):\t' +
                  twilight_morning_astronomical.utc.datetime.ctime())
            print('Nautical morning twilight (-12 deg) (U.T.C):\t\t' +
                  twilight_morning_nautical.utc.datetime.ctime())
            print('Civil morning twilight (-6 deg) (U.T.C):\t\t' +
                  twilight_morning_civil.utc.datetime.ctime())
            sun_rise = observation_handle.sun_rise_time(start_time_tmp,
                                                        which='next')
            print('Sunrise:\t\t\t\t\t\t' + sun_rise.utc.datetime.ctime())
            print('\n')

            # stuff for creating plot
            plot_mids = []
            plot_names = []
            plot_widths = []

            for j in range(len(target_table)):
                # Extract information
                star_coordinates = coord.SkyCoord('{} {}'.format(
                    target_table['RA'][j], target_table['DEC'][j]),
                                                  unit=(u.hourangle, u.deg),
                                                  frame='icrs')
                star_fixed_coord = FixedTarget(coord=star_coordinates,
                                               name=target_table['target'][j])

                ####################
                # Get finder image
                ####################
                '''
                plt.close()
                try:
                finder_image = plot_finder_image(star_fixed_coord,reticle=True,fov_radius=10*u.arcmin)
                except:
                pass
                plt.savefig(target_table['target'][j]+'_finder_chart.eps')
                '''

                P = target_table['Period'][j]
                Secondary_transit = target_table['Secondary'][j]
                transit_half_width = TimeDelta(
                    target_table['width'][j] * 60 * 60 / 2,
                    format='sec')  # in seconds for a TimeDelta

                # now convert T0 to HJD -> JD -> BJD so we can cout period
                if 'epoch_HJD-2400000' in target_table.colnames:
                    #print('Using HJD-2400000')
                    T0 = target_table['epoch_HJD-2400000'][j]
                    T0 = Time(T0 + 2400000, format='jd')  # HJD given by WASP
                    ltt_helio = T0.light_travel_time(star_coordinates,
                                                     'heliocentric',
                                                     location=observation_site)
                    T0 = T0 - ltt_helio  # HJD -> JD
                    ltt_bary = T0.light_travel_time(star_coordinates,
                                                    'barycentric',
                                                    location=observation_site)
                    T0 = T0 + ltt_bary  # JD -> BJD
                elif 'epoch_BJD-2455000' in target_table.colnames:
                    #print('Using BJD-2455000')
                    T0 = target_table['epoch_BJD-2455000'][j] + 2455000
                    T0 = Time(T0, format='jd')  # BJD
                else:
                    print('\n\n\n\n FAILE\n\n\n\n')
                    continue

                ##########################################################
                # Now start from T0 and count in periods to find transits
                ##########################################################
                # convert star and end time to BJD
                ltt_bary_start_time = start_time_tmp.light_travel_time(
                    star_coordinates, 'barycentric',
                    location=observation_site)  # + TimeDelta(i,format='jd')
                start_time_bary = start_time_tmp + ltt_bary_start_time  # + TimeDelta(i,format='jd') #  convert start time to BJD

                ltt_bary_end_time_tmp = end_time_tmp.light_travel_time(
                    star_coordinates, 'barycentric',
                    location=observation_site)  # + TimeDelta(i,format='jd')
                end_time_bary = end_time_tmp + ltt_bary_start_time  #+ TimeDelta(i+1,format='jd') #  convert end time to BJD and add 1 day 12pm -> 12pm the next day

                elapsed = end_time_bary - start_time_bary  # now this is 24 hours from the start day 12:00 pm

                # now count transits
                time = Time(T0.jd, format='jd')  # make a temporary copy
                transits = []
                primary_count, secondary_count = 0, 0
                while time.jd < end_time_bary.jd:
                    if (time.jd > start_time_bary.jd) and (time.jd <
                                                           end_time_bary.jd):
                        if is_observable(constraints,
                                         observation_handle,
                                         [star_fixed_coord],
                                         times=[time])[0] == True:
                            transits.append(time)
                            primary_count += 1
                    if Secondary_transit == 'yes':
                        timesecondary = time + TimeDelta(P / 2, format='jd')
                        if (timesecondary.jd > start_time_bary.jd) and (
                                timesecondary.jd < end_time_bary.jd):
                            if is_observable(constraints,
                                             observation_handle,
                                             [star_fixed_coord],
                                             times=[timesecondary])[0] == True:
                                transits.append(timesecondary)
                                secondary_count += 1

                    time = time + TimeDelta(P,
                                            format='jd')  # add another P to T0

                # Now find visible transits
                transits = [
                    i for i in transits
                    if is_observable(constraints,
                                     observation_handle, [star_fixed_coord],
                                     times=[i])[0] == True
                ]

                if len(transits) == 0:
                    message = '{} has no transits.'.format(
                        target_table['target'][j])
                    print('-' * len(message))
                    print(message)
                    print('-' * len(message))
                    print('\n')
                    plt.close()
                    continue
                else:
                    message = '{} has {} primary transits and {} secondary transits.'.format(
                        target_table['target'][j], primary_count,
                        secondary_count)
                    print('-' * len(message))
                    print(message)
                    print('RA: {}'.format(target_table['RA'][j]))
                    print('DEC: {}'.format(target_table['DEC'][j]))
                    print('Epoch: 2000')
                    print('T0 (BJD): {}'.format(T0.jd))
                    print('Period: {}'.format(P))
                    print('Transit width (hr): {}'.format(
                        target_table['width'][j]))
                    print('-' * len(message))
                    print('\n')

                for i in transits:
                    # currently transit times are in BJD (need to convert to HJD to check
                    ltt_helio = i.light_travel_time(star_coordinates,
                                                    'barycentric',
                                                    location=observation_site)
                    ii = i - ltt_helio
                    ltt_helio = ii.light_travel_time(star_coordinates,
                                                     'heliocentric',
                                                     location=observation_site)
                    ii = ii + ltt_helio

                    transit_1 = i - transit_half_width - TimeDelta(
                        7200, format='sec')  # ingress - 2 hr
                    transit_2 = i - transit_half_width - TimeDelta(
                        3600, format='sec')  # ingress - 2 hr
                    transit_3 = i - transit_half_width  # ingress
                    transit_4 = i + transit_half_width  # egress
                    transit_5 = i + transit_half_width + TimeDelta(
                        3600, format='sec')  # ingress - 2 hr
                    transit_6 = i + transit_half_width + TimeDelta(
                        7200, format='sec')  # ingress - 2 hr

                    if (((i.jd - time.jd) / P) - np.floor(
                        (i.jd - time.jd) / P) < 0.1) or ((
                            (i.jd - time.jd) / P) - np.floor(
                                (i.jd - time.jd) / P) > 0.9):
                        print('Primary Transit:')
                        print('-' * len('Primary Transit'))
                    if 0.4 < ((i.jd - time.jd) / P) - np.floor(
                        (i.jd - time.jd) / P) < 0.6:
                        print('Secondary Transit')
                        print('-' * len('Secondary Transit'))

                    ##################
                    # now get sirmass
                    ##################
                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=transit_1, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        transit_1, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Ingress - 2hr (U.T.C):\t\t\t\t\t' +
                          transit_1.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))

                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=transit_2, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        transit_2, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Ingress - 1hr (U.T.C):\t\t\t\t\t' +
                          transit_2.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))

                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=transit_3, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        transit_3, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Ingress (U.T.C):\t\t\t\t\t' +
                          transit_3.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))

                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=i, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        i, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Mid transit (U.T.C):\t\t\t\t\t' +
                          i.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))

                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=transit_4, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        transit_4, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Egress (U.T.C):\t\t\t\t\t\t' +
                          transit_4.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))

                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=transit_5, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        transit_5, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Egress + 1hr (U.T.C):\t\t\t\t\t' +
                          transit_5.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))

                    altaz = star_coordinates.transform_to(
                        AltAz(obstime=transit_6, location=observation_site))
                    hourangle = observation_handle1.target_hour_angle(
                        transit_6, star_coordinates)
                    hourangle = 24 * hourangle.degree / 360
                    if hourangle > 12:
                        hourangle -= 24
                    print('Egress + 2hr (U.T.C):\t\t\t\t\t' +
                          transit_6.utc.datetime.ctime() +
                          '\tAirmass: {:.2f}\tHA:{:.2f}'.format(
                              altaz.secz, hourangle))
                    print('HJD {} (to check with http://var2.astro.cz/)\n'.
                          format(ii.jd))

                    # append stuff for plots
                    plot_mids.append(i)  # astropy Time
                    plot_names.append(target_table['target'][j])
                    plot_widths.append(target_table['width'][j])

            # Now plot

            plt.close()
            if len(plot_mids) == 0:
                continue
            date_formatter = dates.DateFormatter('%H:%M')
            #ax.xaxis.set_major_formatter(date_formatter)

            # now load dummy transit lightcurves
            xp, yp = np.load('lc.npy')
            xs, ys = np.load('lcs.npy')

            # x = np.linspace(0, 2*np.pi, 400)
            # y = np.sin(x**2)

            subplots_adjust(hspace=0.000)
            number_of_subplots = len(
                plot_names)  # number of targets transiting that night

            time = sun_set + np.linspace(-1, 14,
                                         100) * u.hour  # take us to sunset
            for i, v in enumerate(xrange(number_of_subplots)):
                # exctract params
                width = plot_widths[v]
                name = plot_names[v]
                mid = plot_mids[v]

                # now set up dummy lc plot
                x_tmp = mid + xp * (width /
                                    2) * u.hour  # get right width in hours

                # now set up axis
                v = v + 1
                ax1 = subplot(number_of_subplots, 1, v)
                ax1.xaxis.set_major_formatter(date_formatter)

                if v == 1:
                    ax1.set_title(start)

                # plot transit model
                ax1.plot_date(x_tmp.plot_date, ys, 'k-')

                # plot continuum
                #xx  =time.plot_date
                #xx = [uu for uu in xx if (uu<min(x_tmp.plot_date)) or (uu>max(x_tmp.plot_date))]

                #ax1.plot_date(xx, np.ones(len(xx)),'k--', alpha=0.3)
                ax1.set_xlim(min(time.plot_date), max(time.plot_date))
                #ax1.plot_date(mid.plot_date, 0.5, 'ro')
                plt.setp(ax1.get_xticklabels(), rotation=30, ha='right')
                ax1.set_ylabel(name, rotation=45, labelpad=20)

                twilights = [
                    (sun_set.datetime, 0.0),
                    (twilight_evening_civil.datetime, 0.1),
                    (twilight_evening_nautical.datetime, 0.2),
                    (twilight_evening_astronomical.datetime, 0.3),
                    (twilight_morning_astronomical.datetime, 0.4),
                    (twilight_morning_nautical.datetime, 0.3),
                    (twilight_morning_civil.datetime, 0.2),
                    (sun_rise.datetime, 0.1),
                ]

                for ii, twii in enumerate(twilights[1:], 1):
                    ax1.axvspan(twilights[ii - 1][0],
                                twilights[ii][0],
                                ymin=0,
                                ymax=1,
                                color='grey',
                                alpha=twii[1])

                ax1.grid(alpha=0.5)
                ax1.get_yaxis().set_ticks([])
                if v != number_of_subplots:
                    ax1.get_xaxis().set_ticks([])

            plt.xlabel('Time [U.T.C]')
            #plt.tight_layout()
            #plt.savefig('test.eps',format='eps')
            plt.show()
Example #19
0
    def __init__(self,
                 t0=None,
                 period=None,
                 perr=None,
                 duration=None,
                 loc='Siding Spring Observatory',
                 timezone='Australia/NSW',
                 ra=None,
                 dec=None,
                 startdate=None,
                 starttime='0:00',
                 run_length=180,
                 el_limit=30,
                 toi=None):

        if toi is not None:
            self.set_params_from_toi(toi)

        else:

            self.epoch = Time(t0 + 2457000, format='jd')
            self.period = period * u.d
            if perr is not None:
                self.period_err = perr * u.d
            else:
                self.period_err = None

            self.duration = duration / 24 * u.d
            self.coords = [ra * u.deg, dec * u.deg]

        self.alt_limit = el_limit

        self.observatory = loc
        self.timezone = timezone

        self.obs_mid_times_utc = None
        self.obs_mid_uncerts = None
        self.obs_mid_times_local = None

        coord = SkyCoord(ra=self.coords[0], dec=self.coords[1])
        target = FixedTarget(coord, name='Target')

        SSO = Observer.at_site(self.observatory, timezone=self.timezone)

        planet = EclipsingSystem(primary_eclipse_time=self.epoch,
                                 orbital_period=self.period,
                                 duration=self.duration)

        starttime = startdate + ' ' + starttime
        self.start = Time(starttime)
        self.run_length = run_length * u.d

        n_transits = np.ceil(self.run_length / self.period)

        self.all_transit_times = planet.next_primary_eclipse_time(
            self.start, n_eclipses=n_transits)

        diff = self.all_transit_times - self.start - self.run_length
        real_trans = diff.value < 0
        if np.sum(real_trans) < 0.5:
            self.all_transit_times = None
            return
        else:
            self.all_transit_times = self.all_transit_times[real_trans]

        if self.period_err is not None:
            self.uncert_vals = (self.all_transit_times - self.epoch
                                ) * self.period_err / self.period * 1440

        constraints = [
            AtNightConstraint.twilight_nautical(),
            AltitudeConstraint(min=self.alt_limit * u.deg)
        ]

        obs_mid = is_event_observable(constraints,
                                      SSO,
                                      target,
                                      times=self.all_transit_times)[0]
        obs_start = is_event_observable(constraints,
                                        SSO,
                                        target,
                                        times=self.all_transit_times -
                                        0.5 * self.duration)[0]
        obs_end = is_event_observable(constraints,
                                      SSO,
                                      target,
                                      times=self.all_transit_times +
                                      0.5 * self.duration)[0]

        if np.sum(obs_mid * obs_start * obs_end) > 0:

            self.obs_airmass = np.zeros(
                (np.sum(obs_mid * obs_start * obs_end), 3))

            self.obs_mid_times_utc = self.all_transit_times[obs_mid *
                                                            obs_start *
                                                            obs_end]
            if self.period_err is not None:
                self.obs_mid_uncerts = self.uncert_vals[obs_mid * obs_start *
                                                        obs_end]

            for i in range(np.sum(obs_mid * obs_start * obs_end)):
                obs_airmass_mid = SSO.altaz(self.obs_mid_times_utc[i],
                                            coord).secz
                obs_airmass_start = SSO.altaz(
                    self.obs_mid_times_utc[i] - self.duration / 2, coord).secz
                obs_airmass_end = SSO.altaz(
                    self.obs_mid_times_utc[i] + self.duration / 2, coord).secz

                self.obs_airmass[i] = [
                    obs_airmass_start, obs_airmass_mid, obs_airmass_end
                ]

            # NEED A BARYCENTRIC CORRECTION

            tz = pytz.timezone('utc')

            dtime = self.obs_mid_times_utc.to_datetime()

            self.obs_mid_times_local = np.array([])

            for i in range(len(self.obs_mid_times_utc)):
                inoz = tz.localize(dtime[i])
                if self.period_err is not None:
                    indiv_uncert = self.obs_mid_uncerts[i]
                val = inoz.astimezone(pytz.timezone(self.timezone))
                self.obs_mid_times_local = np.append(
                    self.obs_mid_times_local,
                    val.strftime('%Y-%m-%d %H:%M:%S'))
Example #20
0
# Create astroplan.FixedTarget objects for each one in the table.
from astropy.coordinates import SkyCoord
import astropy.units as u
targets = [(FixedTarget(coord=ra=ra*u.deg, dec=dec*u.deg), name=name)
            for name, ra, dec in target_table]

# Build a bulleted list of constrains:
# 1. Only observe btwn altitudes of 10-80 deg, with AltitudeConstraint class.
# 2. Put an upper limit on the airmass of each target with AirmassConstraint
# class.
# 3. Use the AtNightConstraint class too, to see things at night. We can define 
# night to be "between civil twilights" with the class method twilight_civil,
# but there are also other ways to define the observing window.

from astroplan import (AltitudeConstraint, AirmassConstraint,
        AtNightConstraint)
constraints = [AltitudeConstraint(10*u.deg, 80*u.deg), AirmassConstraint(5),
        AtNightConstraint.twilight_civil()]

from astroplan import is_observable, is_always_observable, months_observable
# Are targets *ever* observable in the time range?
ever_observable = is_observable(constraints, subaru, targets,
        time_range=time_range)
# Are targets *always* observable in the time range?
always_observable = is_always_observable(constraints, subaru, targets,
        time_range=time_range)
# During what months are the targets ever observable?
best_months = months_observable(constraints, subaru, targets)


Example #21
0
from django.test import TestCase

from mop.toolbox.obs_details import all_night_moon_sep, calculate_visibility
from mop.toolbox.LCO_obs_locs import choose_loc

OGG = choose_loc('OGG')
v_test_target = ['Sirius', 100.7362500 * u.deg, -16.6459444 * u.deg]
v_date = Time("2019-12-25 00:00:00", scale='utc')
v_coords = SkyCoord(v_test_target[1], v_test_target[2], frame='icrs')
v_obs_begin = OGG.twilight_evening_astronomical(v_date, which='nearest')
v_obs_end = OGG.twilight_morning_astronomical(v_date, which='next')
v_observing_range = [v_obs_begin, v_obs_end]
constraints = [
    AirmassConstraint(2.0),
    AltitudeConstraint(20 * u.deg, 85 * u.deg),
    AtNightConstraint.twilight_astronomical()
]
ever_observable = is_observable(constraints,
                                OGG,
                                v_coords,
                                time_range=v_observing_range)

v_fail_start = Time("2019-12-24 10:00:00", scale='utc')
v_fail_end = Time("2019-12-25 10:00:00", scale='utc')


class TestVisibilityCalc(TestCase):
    def test_timeobj(self):
        self.assertEqual(v_date.scale, 'utc')
        self.assertEqual(v_date.value, '2019-12-25 00:00:00.000')
Example #22
0
def find_observability(exoplanet_array, default_lookahead, longitude, latitude,
                       elevation, start_date, end_date, min_altitude,
                       max_altitude, resolution, flash, display):
    '''Function to calculate'''
    '''# find timezone
    timezone_name = tf.timezone_at(lng=longitude, lat=latitude)
    delta_degree = 1
    while timezone_name is None:
        delta_degree += 1
        timezone_name = tf.closest_timezone_at(lng=longitude, lat=latitude, delta_degree=delta_degree)
    if flash: flash.append('Timezone   : ' + timezone_name)
    print(timezone_name)'''

    # create Observer instance
    if elevation is None: elevation = 0
    custom_location = Observer(longitude=longitude * u.deg,
                               latitude=latitude * u.deg,
                               elevation=elevation * u.m)

    # make an array of FixedTarget instances
    target_table = []
    for planet in exoplanet_array:
        target_table.append((planet.name, planet.host.ra, planet.host.dec))
    targets = [
        FixedTarget(coord=SkyCoord(ra=ra * u.deg, dec=dec * u.deg), name=name)
        for name, ra, dec in target_table
    ]

    # time range
    if start_date is not None:
        start_date = Time(datetime.combine(start_date, datetime.min.time()),
                          out_subfmt='date')
    else:
        start_date = Time(datetime.combine(datetime.now(),
                                           datetime.min.time()),
                          out_subfmt='date')
    if end_date is not None:
        end_date = Time(datetime.combine(end_date, datetime.min.time()),
                        out_subfmt='date')
    else:
        end_date = start_date + default_lookahead * u.day
    time_range = Time([start_date, end_date])
    #time_range_int = # no. days as an int
    if display:
        flash.append('Start date : ' + str(start_date.iso))
        flash.append('End date   : ' + str(end_date.iso))

    # altitude and night time constraints
    if min_altitude is None: min_altitude = 0
    if max_altitude is None: max_altitude = 90
    constraints = [
        AltitudeConstraint(min_altitude * u.deg, max_altitude * u.deg),
        AtNightConstraint.twilight_astronomical()
    ]

    # calculate if observable within lookahead time from now
    if resolution is None: resolution = 0.5

    # new route, faster by not bothering to recheck planets already found to be observable
    # UPDATE, ASTROPY IS ALREADY OPTIMISED FOR THIS, THIS TAKES 10 TIMES LONGER, LEAVING IN FOR DEMONSTRATION PURPOSES ONLY (commented out lines in 'old route' are also only for demonstrating the difference)
    # start = time.perf_counter()
    # ever_observable = [False] * len(exoplanet_array)
    # day = 0
    # while start_date + day*u.day != end_date:
    #     print(str(start_date + day*u.day) + ', ' + str(end_date))
    #     for i in range(len(ever_observable)):
    #         if ever_observable[i] == False:
    #             ever_observable[i] = is_observable(constraints, custom_location, [targets[i]], time_range=Time([start_date+day*u.day, start_date+(day+1)*u.day]), time_grid_resolution=resolution*u.hour)[0]
    #             print(str(day) + ', ' + str(i) + ', ' + targets[i].name + ', ' + str(ever_observable[i]))
    #     day += 1
    # end = time.perf_counter()
    # print(str(end - start) + ' seconds fast')

    # new route, faster by not bothering to recheck planets already found to be observable
    # UPDATE, ASTROPY IS ALREADY OPTIMISED FOR THIS, THIS TAKES 10 TIMES LONGER, LEAVING IN FOR DEMONSTRATION PURPOSES ONLY (commented out lines in 'old route' are also only for demonstrating the difference)
    # start = time.perf_counter()
    # ever_observable = [False] * len(exoplanet_array)
    # day = 0
    # for i in range(len(ever_observable)):
    #     for day in range(30):
    #         print(str(start_date + day*u.day) + ', ' + str(end_date))

    #         if ever_observable[i] == False:
    #             ever_observable[i] = is_observable(constraints, custom_location, [targets[i]], time_range=Time([start_date+day*u.day, start_date+(day+1)*u.day]), time_grid_resolution=resolution*u.hour)[0]
    #             print(str(day) + ', ' + str(i) + ', ' + targets[i].name + ', ' + str(ever_observable[i]))
    #         else: break
    # end = time.perf_counter()
    # print(str(end - start) + ' seconds fast')

    # trying to split array into chunks so we can say the task has been completed to the nearest percent
    # tosplit_target_array = copy.deepcopy(targets)
    # start = time.perf_counter()
    # target_chunks = np.array_split(tosplit_target_array, 10) # split targets into 10 parts (not 100, this makes the calculation time too long)
    # for i in range(len(target_chunks)):
    #     is_observable(constraints, custom_location, target_chunks[i].tolist(), time_range=time_range, time_grid_resolution=resolution*u.hour)
    #     #print('%i calculated' %i)
    # end = time.perf_counter()
    # print(str(end - start) + ' seconds fast')

    # old route, slow, commented out lines are for demonstrating that it is better than a manual method by a factor of 10
    start = time.perf_counter()
    ever_observable = is_observable(constraints,
                                    custom_location,
                                    targets,
                                    time_range=time_range,
                                    time_grid_resolution=resolution * u.hour)
    end = time.perf_counter()
    print(str(end - start) + ' seconds slow')

    for i in range(len(exoplanet_array)):
        exoplanet_array[i].observable = ever_observable[i]
    if display: flash.append('Timing resolution = {} hrs'.format(resolution))
Example #23
0
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
Example #24
0
targets = [
    FixedTarget(coord=SkyCoord(ra=ra * u.deg, dec=dec * u.deg), name=name)
    for name, ra, dec in target_table
]

from astroplan import (AltitudeConstraint, AirmassConstraint,
                       AtNightConstraint)

for target in targets:
    print("Target: ", target.name)
    #if False:
    #print("Posang: ", target.posang)

constraints = [
    AltitudeConstraint(10 * u.deg, 80 * u.deg),
    AirmassConstraint(5),
    AtNightConstraint.twilight_civil()
]

#from astroplan import is_observable, is_always_observable, months_observable
## Are targets *ever* observable in the time range?
#ever_observable = is_observable(constraints, subaru, targets, time_range=time_range)

## Are targets *always* observable in the time range?
#always_observable = is_always_observable(constraints, subaru, targets, time_range=time_range)

## During what months are the targets ever observable?
## best_months = months_observable(constraints, subaru, targets)

#import numpy as np
Example #25
0
    # TODO select proper coordinates: load from params_star.csv
    # TODO select proper observer place (ground, space)
    coords = "1:12:43.2 +1:12:43"
    target = FixedTarget(SkyCoord(coords, unit=(u.deg, u.deg)))
    # TODO select proper time
    n_transits = 100  # This is the roughly number of transits per year
    obs_time = Time('2017-01-01 12:00')
    # TODO bulk to file
    midtransit_times = system.next_primary_eclipse_time(obs_time,
                                                        n_eclipses=n_transits)
    ingress_egress_times = system.next_primary_ingress_egress_time(
        obs_time, n_eclipses=n_transits)
    # TODO select local times somehow
    min_local_time = dt.time(19, 0)  # 19:00 local time at APO (7pm)
    max_local_time = dt.time(0, 0)  # 00:00 local time at APO (midnight)
    constraints = [
        AtNightConstraint.twilight_civil(),
        AltitudeConstraint(min=30 * u.deg),
        LocalTimeConstraint(min=min_local_time, max=max_local_time)
    ]
    midtime_observable = astroplan.is_event_observable(constraints,
                                                       observer_site,
                                                       target,
                                                       times=midtransit_times)
    entire_observable = astroplan.is_event_observable(
        constraints,
        observer_site,
        target,
        times=midtransit_times,
        times_ingress_egress=ingress_egress_times)
Example #26
0
def observability(data):
    """
    Test the observability of a list of objects for a single date

    Parameters
    ----------
    data : POST data format

        Observatory, date, limits and objects
        data = {
            'observatory' : 'OT',
            'date' : '2020-06-11 00:16:30',
            'date_end' : '2020-06-11 03:44:26',
            'altitude_lower_limit' : '30',
            'altitude_higher_limit' : '90',
            'twilight_type' : 'astronomical',
            'objects' : [{
                    'name' : 'Kelt 8b',
                    'RA' : 283.30551667 ,
                    'Dec' : 24.12738139
                    },
                    (more objects...)
                ]
            }

    Returns
    -------
    observability : dict
        Dictionary with the observability and moon distance for all objects
        {
            'V0879 Cas' : {
                'observability' : 'True', 'moon_separation' : 30.4
            },
            'RU Scl' : {
                'observability' : 'True', 'moon_separation' : 10.8
            }
        }

    """

    import astropy.units as u
    from astroplan import FixedTarget
    from astroplan import (AltitudeConstraint, AtNightConstraint)
    from astroplan import is_observable, is_always_observable

    # Site location
    location = get_location(data['observatory'])

    time_range = Time([data['date'], data['date_end']])

    if 'twilight_type' not in data.keys():
        data['twilight_type'] = 'astronomical'

    if data['twilight_type'] == 'civil':
        twilight_constraint = AtNightConstraint.twilight_civil()
    elif data['twilight_type'] == 'nautical':
        twilight_constraint = AtNightConstraint.twilight_nautical()
    else:
        twilight_constraint = AtNightConstraint.twilight_astronomical()

    # Observation constraints
    constraints = [
        AltitudeConstraint(
            int(data['altitude_lower_limit']) * u.deg,
            int(data['altitude_higher_limit']) * u.deg), twilight_constraint
    ]

    # Dictionary with star name and observability (bool str)
    result = {}

    # Moon location for the observation date
    middle_observing_time = time_range[-1] - (time_range[-1] -
                                              time_range[0]) / 2
    moon = location.moon_altaz(middle_observing_time)

    for target in data['objects']:
        # Object coordinates
        coords = SkyCoord(ra=target['RA'] * u.deg, dec=target['Dec'] * u.deg)
        fixed_target = [FixedTarget(coord=coords, name=target['name'])]

        if 'transit' in target.keys():
            time_range = Time(
                [target['transit']['t_early'], target['transit']['t_late']])
            # Are targets *always* observable in the time range?
            observable = is_always_observable(constraints,
                                              location,
                                              fixed_target,
                                              time_range=time_range)
        else:
            time_range = Time([data['date'], data['date_end']])
            # Are targets *ever* observable in the time range?
            observable = is_observable(constraints,
                                       location,
                                       fixed_target,
                                       time_range=time_range)

        moon_separation = moon.separation(coords)

        result[target['name']] = {
            'observable': str(observable[0]),
            'moon_separation': moon_separation.degree
        }

    return result
Example #27
0
def get_transit_observability(site,
                              ra,
                              dec,
                              name,
                              t_mid_0,
                              period,
                              duration,
                              n_transits=100,
                              obs_start_time=Time(
                                  dt.datetime.today().isoformat()),
                              min_local_time=dt.time(16, 0),
                              max_local_time=dt.time(9, 0),
                              min_altitude=20 * u.deg,
                              oot_duration=30 * u.minute,
                              minokmoonsep=30 * u.deg):
    """
    note: barycentric corrections not yet implemented. (could do this myself!)
    -> 16 minutes of imprecision is baked into this observability calculator!

    args:

        site (astroplan.observer.Observer)

        ra, dec (units u.deg), e.g.:
            ra=101.28715533*u.deg, dec=16.71611586*u.deg,
        or can also accept
            ra="17 56 35.51", dec="-29 32 21.5"

        name (str), e.g., "Sirius"

        t_mid_0 (float): in BJD_TDB, preferably (but see note above).

        period (astropy quantity, units time)

        duration (astropy quantity, units time)

        n_transits (int): number of transits forward extrapolated to

        obs_start_time (astropy.Time object): when to start calculation from

        min_local_time, max_local_time: earliest time when you think observing
        is OK. E.g., 16:00 local and 09:00 local are earliest and latest. Note
        this constraint is a bit silly, since the astroplan "AtNightConstraint"
        is imposed automatically. As implemented, these are ignored.

        min_altitude (astropy quantity, units deg): 20 degrees is the more
        relevant constraint.

        oot_duration (astropy quantity, units time): with which to brack
        transit observations, to get an OOT baseline.
    """

    if (isinstance(ra, u.quantity.Quantity)
            and isinstance(dec, u.quantity.Quantity)):
        target_coord = SkyCoord(ra=ra, dec=dec)
    elif (isinstance(ra, str) and isinstance(dec, str)):
        target_coord = SkyCoord(ra=ra, dec=dec, unit=(u.hourangle, u.deg))
    else:
        raise NotImplementedError

    target = FixedTarget(coord=target_coord, name=name)

    primary_eclipse_time = Time(t_mid_0, format='jd')

    system = EclipsingSystem(primary_eclipse_time=primary_eclipse_time,
                             orbital_period=period,
                             duration=duration,
                             name=name)

    midtransit_times = system.next_primary_eclipse_time(obs_start_time,
                                                        n_eclipses=n_transits)

    # for the time being, omit any local time constraints.
    constraints = [
        AtNightConstraint.twilight_civil(),
        AltitudeConstraint(min=min_altitude),
        MoonSeparationConstraint(min=minokmoonsep)
    ]
    #constraints = [AtNightConstraint.twilight_civil(),
    #               AltitudeConstraint(min=min_altitude),
    #               LocalTimeConstraint(min=min_local_time, max=max_local_time)]

    # observable just at midtime (bottom)
    b = is_event_observable(constraints, site, target, times=midtransit_times)

    # observable full transits (ingress, bottom, egress)
    ing_egr = system.next_primary_ingress_egress_time(obs_start_time,
                                                      n_eclipses=n_transits)

    ibe = is_event_observable(constraints,
                              site,
                              target,
                              times_ingress_egress=ing_egr)

    # get moon separation over each transit. take minimum moon sep at
    # ing/tmid/egr as the moon separation.
    moon_tmid = get_moon(midtransit_times, location=site.location)
    moon_separation_tmid = moon_tmid.separation(target_coord)

    moon_ing = get_moon(ing_egr[:, 0], location=site.location)
    moon_separation_ing = moon_ing.separation(target_coord)

    moon_egr = get_moon(ing_egr[:, 1], location=site.location)
    moon_separation_egr = moon_egr.separation(target_coord)

    moon_separation = np.round(
        np.array(
            [moon_separation_tmid, moon_separation_ing,
             moon_separation_egr]).min(axis=0), 0).astype(int)

    moon_illumination = np.round(
        100 * moon.moon_illumination(midtransit_times), 0).astype(int)

    # completely observable transits (OOT, ingress, bottom, egress, OOT)
    oot_ing_egr = np.concatenate(
        (np.array(ing_egr[:, 0] - oot_duration)[:, None],
         np.array(ing_egr[:, 1] + oot_duration)[:, None]),
        axis=1)

    oibeo = is_event_observable(constraints,
                                site,
                                target,
                                times_ingress_egress=oot_ing_egr)

    ing_tmid_egr = np.concatenate(
        (np.array(ing_egr[:, 0])[:, None], np.array(midtransit_times)[:, None],
         np.array(ing_egr[:, 1])[:, None]),
        axis=1)

    return ibe, oibeo, ing_tmid_egr, moon_separation, moon_illumination
Example #28
0
def create_selection_coumpound_list(session_plan, schedule_form, observer, observation_time, time_from, time_to, tz_info,
                                    page, offset, per_page, sort_by, mag_scale, sort_def):

    global rise_set_cache

    if session_plan.is_anonymous and (schedule_form.obj_source.data is None or schedule_form.obj_source.data == 'WL'):
        schedule_form.obj_source.data = 'M'  # set Messier

    if schedule_form.obj_source.data is None or schedule_form.obj_source.data == 'WL':
        wishlist_subquery = db.session.query(WishListItem.dso_id) \
            .join(WishListItem.wish_list) \
            .filter(WishList.user_id==current_user.id)

        dso_query = DeepskyObject.query \
            .filter(DeepskyObject.id.in_(wishlist_subquery))

    elif schedule_form.obj_source.data.startswith('DL_'):
        dso_list_id = int(schedule_form.obj_source.data[3:])

        dsolist_subquery = db.session.query(DsoListItem.dso_id) \
            .join(DsoListItem.dso_list) \
            .filter(DsoList.id==dso_list_id)

        dso_query = DeepskyObject.query \
            .filter(DeepskyObject.id.in_(dsolist_subquery))
    else:
        dso_query = DeepskyObject.query
        cat_id = Catalogue.get_catalogue_id_by_cat_code(schedule_form.obj_source.data)
        if cat_id:
            dso_query = dso_query.filter_by(catalogue_id=cat_id)

    scheduled_subquery = db.session.query(SessionPlanItem.dso_id) \
        .filter(SessionPlanItem.session_plan_id==session_plan.id)

    # Subtract already scheduled dsos
    dso_query = dso_query.filter(DeepskyObject.id.notin_(scheduled_subquery))

    # Subtract observed dsos
    if not session_plan.is_anonymous and schedule_form.not_observed.data:
        observed_subquery = db.session.query(ObservedListItem.dso_id) \
            .join(ObservedListItem.observed_list) \
            .filter(ObservedList.user_id==current_user.id)
        dso_query = dso_query.filter(DeepskyObject.id.notin_(observed_subquery))
        dso_query = dso_query.filter(or_(DeepskyObject.master_id.is_(None), DeepskyObject.master_id.notin_(observed_subquery)))


    # filter by type
    if schedule_form.dso_type.data and schedule_form.dso_type.data != 'All':
        dso_query = dso_query.filter(DeepskyObject.type==schedule_form.dso_type.data)

    # filter by magnitude limit
    if schedule_form.maglim.data is not None and schedule_form.maglim.data < mag_scale[1]:
        dso_query = dso_query.filter(DeepskyObject.mag<schedule_form.maglim.data)

    # filter by constellation
    if schedule_form.constellation_id.data is not None:
        dso_query = dso_query.filter(DeepskyObject.constellation_id==schedule_form.constellation_id.data)

    order_by_field = None
    if sort_by:
        desc = sort_by[0] == '-'
        sort_by_name = sort_by[1:] if desc else sort_by
        order_by_field = sort_def.get(sort_by_name)
        if order_by_field and desc:
            order_by_field = order_by_field.desc()

    if order_by_field is None:
        order_by_field = DeepskyObject.id

    all_count = dso_query.count()

    if all_count > 500:
        selection_list = dso_query.order_by(order_by_field).limit(per_page).offset(offset).all().copy()
        use_time_filter = False
    else:
        selection_list = dso_query.order_by(order_by_field).all().copy()
        use_time_filter = True

    # filter by rise-set time
    if use_time_filter:
        key_suffix = '/' + str(observer.location.lat) + '/' + str(observer.location.lon) + '/' + observation_time.strftime('%Y-%m-%d')
        index_table = []
        i = 0
        composed_selection_rms_list = []
        to_process_list = []
        for x in selection_list:
            key = str(x.id) + key_suffix
            cached = rise_set_cache.get(key, None)
            if cached is None:
                index_table.append(i)
                composed_selection_rms_list.append(None)
                to_process_list.append((x.ra, x.dec))
            else:
                composed_selection_rms_list.append(cached)
            i += 1

        if to_process_list:
            selection_rms_list = rise_merid_set_up(time_from, time_to, observer, to_process_list)
            for i in range(len(selection_rms_list)):
                index = index_table[i]
                val = selection_rms_list[i]
                composed_selection_rms_list[index] = val
                key = str(selection_list[index].id) + key_suffix
                rise_set_cache[key] = val

        time_filtered_list = []
        i = 0
        for rise_t, merid_t, set_t, is_up in composed_selection_rms_list:
            if is_up or rise_t < time_to or set_t>time_from:
                time_filtered_list.append((selection_list[i], _to_HM_format(rise_t, tz_info), _to_HM_format(merid_t, tz_info), _to_HM_format(set_t, tz_info)))
            i += 1

        # filter by altitude
        if len(time_filtered_list) > 0 and schedule_form.min_altitude.data is not None and schedule_form.min_altitude.data > 0:
            constraints = [AltitudeConstraint(schedule_form.min_altitude.data*u.deg)]
            targets = []
            for item in time_filtered_list:
                dso = item[0]
                target = FixedTarget(coord=SkyCoord(ra=dso.ra * u.rad, dec=dso.dec * u.rad), name=dso.name)
                targets.append(target)
            time_range = Time([time_from, time_to])
            observable_list = is_observable(constraints, observer, targets, time_range=time_range)
            time_filtered_list = [ time_filtered_list[i] for i in range(len(time_filtered_list)) if observable_list[i] ]

        all_count = len(time_filtered_list)
        if offset>=all_count:
            offset = 0
            page = 1
        selection_compound_list = time_filtered_list[offset:offset+per_page]
    else:
        selection_rms_list = rise_merid_set_time_str(observation_time, observer, [ (x.ra, x.dec) for x in selection_list], tz_info)
        selection_compound_list = [ (selection_list[i], *selection_rms_list[i]) for i in range(len(selection_list))]

    return selection_compound_list, page, all_count