Exemple #1
0
def tile_region(skymap_path, credzone=0.9, tile_area=1, log=None):
    if log is None:
        log = logging.getLogger(__name__)

    # Read the HEALPix sky map:
    try:
        prob, dist_mu, dist_sigma, dist_norm = hp.read_map(skymap_path,
                                                           field=None,
                                                           verbose=False)
    except Exception as e:
        log.error('Failed to read sky map!')
        send_mail(subject="[GW@Wise] Failed to read LVC sky map",
                  text='''FITS file: {}
                              Exception: {}'''.format(skymap_path, e),
                  log=log)

    sort_idx = np.flipud(np.argsort(prob, kind="stable"))
    sorted_credible_levels = np.cumsum(prob[sort_idx])
    credible_levels = np.empty_like(sorted_credible_levels)
    credible_levels[sort_idx] = sorted_credible_levels

    # pixels inside the credible zone
    good_pix = sort_idx[0:np.sum(credible_levels <= credzone)]
    npix = len(prob)
    nside = hp.npix2nside(npix)
    theta, phi = hp.pix2ang(nside, good_pix)

    sky_area = 4 * 180**2 / np.pi  # [deg^2]
    nside_obs = int(np.ceil(np.sqrt(sky_area / tile_area / 12)))
    obs_pix, unique_idx = np.unique(hp.ang2pix(nside_obs, theta, phi),
                                    return_inverse=True)
    probability = np.bincount(unique_idx, weights=prob[good_pix])

    # sort by descending probability
    sort_idx = np.flipud(np.argsort(probability, kind="stable"))
    probability = probability[sort_idx]
    obs_pix = obs_pix[sort_idx]

    theta, phi = hp.pix2ang(nside_obs, obs_pix)
    ra = Angle(np.rad2deg(phi) * u.deg)
    dec = Angle(np.rad2deg(0.5 * np.pi - theta) * u.deg)

    return ra, dec, probability
Exemple #2
0
def process_gcn(payload, root):
    alerts_path = config.get('ALERT FILES', 'PATH')  # event alert file path
    fits_path = config.get('EVENT FILES', 'PATH')  # event FITS file path
    is_test = config.getboolean('GENERAL', 'TEST') if config.has_option(
        'GENERAL', 'TEST') else False

    # Respond only to 'test'/'observation' events
    if is_test:
        role = 'test'
    else:
        role = 'observation'

    if root.attrib['role'] != role:
        logging.info('Not {}, aborting.'.format(role))
        return

    ivorn = root.attrib['ivorn']
    filename = ntpath.basename(ivorn).split('#')[1]
    log = init_log(filename)

    # Is retracted?
    if gcn.handlers.get_notice_type(root) == gcn.notice_types.LVC_RETRACTION:
        # Save alert to file
        with open(alerts_path + filename + '.xml', "wb") as f:
            f.write(payload)
        log.info("Event {} retracted, doing nothing.".format(ivorn))
        send_mail(
            subject="[GW@Wise] LVC event retracted",
            text="Attached GCN/LVC retraction {} received, doing nothing.".
            format(ivorn),
            files=[alerts_path + filename + '.xml'])
        return

    v = vp.loads(payload)

    # Read all of the VOEvent parameters from the "What" section
    params = {
        elem.attrib['name']: elem.attrib['value']
        for elem in v.iterfind('.//Param')
    }

    # Respond only to 'CBC' (compact binary coalescence candidates) events.
    # Change 'CBC' to 'Burst' to respond to only unmodeled burst events.
    if params['Group'] != 'CBC':
        log.info('Not CBC, aborting.')
        return

    # Save alert to file
    with open(alerts_path + filename + '.xml', "wb") as f:
        f.write(payload)
    log.info("GCN/LVC alert {} received, started processing.".format(ivorn))

    # Read VOEvent attributes
    keylist = ['ivorn', 'role', 'version']
    for key in keylist:
        params[key] = v.attrib[key]

    # Read Who
    params['author_ivorn'] = v.Who.Author.contactName
    params['date_ivorn'] = v.Who.Date

    # Read WhereWhen
    params[
        'observatorylocation_id'] = v.WhereWhen.ObsDataLocation.ObservatoryLocation.attrib[
            'id']
    params[
        'astrocoordsystem_id'] = v.WhereWhen.ObsDataLocation.ObservationLocation.AstroCoordSystem.attrib[
            'id']
    params[
        'isotime'] = v.WhereWhen.ObsDataLocation.ObservationLocation.AstroCoords.Time.TimeInstant.ISOTime

    # Read How
    description = ""
    for item in v.How.iterfind('Description'):
        description = description + ", " + item
    params['how_description'] = description

    # Insert VOEvent to the database
    mysql_update.insert_voevent('voevent_lvc', params, log)

    # Send alert email
    send_mail(
        subject="[GW@Wise] LVC alert received",
        text="Attached GCN/LVC alert {} received, started processing.".format(
            ivorn),
        files=[alerts_path + filename + '.xml'])

    # Download the HEALPix sky map FITS file.
    tmp_path = download_file(params['skymap_fits'])
    skymap_path = fits_path + filename + "_" + ntpath.basename(
        params['skymap_fits'])
    shutil.move(tmp_path, skymap_path)

    # Create the galaxy list
    galaxies, ra, dec = galaxy_list.find_galaxy_list(skymap_path, log=log)

    # Create Wise plan
    wise.process_galaxy_list(galaxies,
                             filename=ivorn.split('/')[-1],
                             ra_event=ra,
                             dec_event=dec,
                             log=log)

    # Finish and delete logger
    log.info("Done.")
    close_log(log)
Exemple #3
0
def find_galaxy_list(skymap_path, log=None, completeness=completenessp, credzone=0.99, relaxed_credzone=0.99995):
    if log is None:
        log = logging.getLogger(__name__)

    # Read the HEALPix sky map:
    try:
        prob, dist_mu, dist_sigma, dist_norm = hp.read_map(skymap_path, field=None, verbose=False)
    except Exception as e:
        log.error('Failed to read sky map!')
        send_mail(subject="[GW@Wise] Failed to read LVC sky map",
                  text='''FITS file: {}
                          Exception: {}'''.format(skymap_path, e))

    # Load the galaxy catalog (glade_id, RA, DEC, distance, Bmag):
    galaxy_cat = np.load(cat_file)
    galaxy_cat = Table(galaxy_cat, names=('ID', 'RA', 'Dec', 'Dist', 'Bmag'))
    galaxy_cat = galaxy_cat[np.where(galaxy_cat['Dist'] > 0)]  # remove entries with a negative distance
    galaxy_cat = galaxy_cat[np.where(~np.isnan(galaxy_cat['Bmag']))]  # remove entries with no Bmag

    # Skymap parameters:
    npix = len(prob)
    nside = hp.npix2nside(npix)

    # Convert galaxy WCS (RA, DEC) to spherical coordinates (theta, phi):
    theta = 0.5 * np.pi - np.deg2rad(galaxy_cat['Dec'])
    phi = np.deg2rad(galaxy_cat['RA'])
    d = np.array(galaxy_cat['Dist'])

    # Convert galaxy coordinates to skymap pixels:
    galaxy_pix = hp.ang2pix(nside, theta, phi)

    # Most probable sky location
    theta_maxprob, phi_maxprob = hp.pix2ang(nside, np.argmax(prob))
    ra_maxprob = np.rad2deg(phi_maxprob)
    dec_maxprob = np.rad2deg(0.5*np.pi - theta_maxprob)

    # Convert to coordinates
    ra_maxprob = Angle(ra_maxprob * u.deg)
    dec_maxprob = Angle(dec_maxprob * u.deg)

    # Find given percent probability zone (default is 99%):
    prob_cutoff = 1
    prob_sum = 0
    npix_credzone = 0

    prob_sorted = np.sort(prob, kind="stable")
    while prob_sum < credzone:
        prob_sum = prob_sum + prob_sorted[-1]
        prob_cutoff = prob_sorted[-1]
        prob_sorted = prob_sorted[:-1]
        npix_credzone = npix_credzone + 1

    # area = npix_credzone * hp.nside2pixarea(nside, degrees=True)

    ####################################################

    # calculate probability for galaxies by the localization map:
    p = prob[galaxy_pix]
    p_dist = dist_norm[galaxy_pix] * norm(dist_mu[galaxy_pix], dist_sigma[galaxy_pix]).pdf(d)

    # cutoffs - 99% of probability by angles and 3sigma by distance:
    within_dist_idx = np.where(np.abs(d - dist_mu[galaxy_pix]) < nsigmas_in_d*dist_sigma[galaxy_pix])
    within_credzone_idx = np.where(p >= prob_cutoff)
    within_idx = np.intersect1d(within_credzone_idx, within_dist_idx)

    do_mass_cutoff = True

    # Relax credzone limits if no galaxies are found:
    if within_idx.size == 0:
        while prob_sum < relaxed_credzone:
            if prob_sorted.size == 0:
                break
            prob_sum = prob_sum + prob_sorted[-1]
            prob_cutoff = prob_sorted[-1]
            prob_sorted = prob_sorted[:-1]
            npix_credzone = npix_credzone + 1
        within_dist_idx = np.where(np.abs(d - dist_mu[galaxy_pix]) < relaxed_nsigmas_in_d * dist_sigma[galaxy_pix])
        within_credzone_idx = np.where(p >= prob_cutoff)
        within_idx = np.intersect1d(within_credzone_idx, within_dist_idx)
        do_mass_cutoff = False

    p = p[within_idx]
    p = (p * (p_dist[within_idx]))  # d**2?

    galaxy_cat = galaxy_cat[within_idx]

    if len(galaxy_cat) == 0:
        log.warning("No galaxies in field!")
        log.warning("99.995% of probability is ", npix_credzone*hp.nside2pixarea(nside, degrees=True), "deg^2")
        log.warning("Peaking at (deg) RA = {}, Dec = {}".format(
            ra_maxprob.to_string(unit=u.hourangle, sep=':', precision=2, pad=True),
            dec_maxprob.to_string(sep=':', precision=2, alwayssign=True, pad=True)))
        return

    # Normalize luminosity to account for mass:
    luminosity = mag.L_nu_from_magAB(galaxy_cat['Bmag'] - 5 * np.log10(galaxy_cat['Dist'] * (10 ** 5)))
    luminosity_norm = luminosity / np.sum(luminosity)
    normalization = np.sum(p * luminosity_norm)
    score = p * luminosity_norm / normalization

    # Take 50% of mass:

    # The area under the Schechter function between L=inf and the brightest galaxy in the field:
    missing_piece = gammaincc(alpha + 2, 10 ** (-(min(galaxy_cat['Bmag'] - 5*np.log10(galaxy_cat['Dist']*(10**5))) - MB_star) / 2.5))
    # there are no galaxies brighter than this in the field, so don't count that part of the Schechter function

    while do_mass_cutoff:
        MB_max = MB_star + 2.5 * np.log10(gammaincinv(alpha + 2, completeness + missing_piece))

        if (min(galaxy_cat['Bmag'] - 5*np.log10(galaxy_cat['Dist']*(10**5))) - MB_star) > 0:
            MB_max = 100  # if the brightest galaxy in the field is fainter than the cutoff brightness - don't cut by brightness

        brightest = np.where(galaxy_cat['Bmag'] - 5*np.log10(galaxy_cat['Dist']*(10**5)) < MB_max)
        # print MB_max
        if len(brightest[0]) < min_galaxies:
            # Not enough galaxies, allowing fainter galaxies
            if completeness >= 0.9:  # Tried hard enough, just take all of them
                completeness = 1  # Just to be consistent
                do_mass_cutoff = False
            else:
                completeness = (completeness + (1. - completeness) / 2)
        else:  # got enough galaxies
            galaxy_cat = galaxy_cat[brightest]
            p = p[brightest]
            luminosity_norm = luminosity_norm[brightest]
            score = score[brightest]
            do_mass_cutoff = False

    # Account for the distance
    absolute_sensitivity = sensitivity - 5 * np.log10(galaxy_cat['Dist'] * (10 ** 5))

    absolute_sensitivity_lum = mag.f_nu_from_magAB(absolute_sensitivity)
    distance_factor = np.zeros(len(galaxy_cat))

    distance_factor[:] = ((maxL - absolute_sensitivity_lum) / (maxL - minL))
    distance_factor[min_dist_factor > (maxL - absolute_sensitivity_lum) / (maxL - minL)] = min_dist_factor
    distance_factor[absolute_sensitivity_lum < minL] = 1
    distance_factor[absolute_sensitivity > maxL] = min_dist_factor

    # Sort galaxies by probability
    ranking_idx = np.argsort(p*luminosity_norm*distance_factor, kind="stable")[::-1]

    # # Count galaxies that constitute 50% of the probability (~0.5*0.98)
    # sum = 0
    # galaxies50per = 0
    # sum_seen = 0
    # while sum < 0.5:
    #     if galaxies50per >= len(ranking_idx):
    #         break
    #     sum = sum + (p[ranking_idx[galaxies50per]] * luminosity_norm[ranking_idx[galaxies50per]]) / float(normalization)
    #     sum_seen = sum_seen + (p[ranking_idx[galaxies50per]] * luminosity_norm[ranking_idx[galaxies50per]] * distance_factor[ranking_idx[galaxies50per]]) / float(normalization)
    #     galaxies50per = galaxies50per + 1
    #
    # # Event statistics:
    # # Ngalaxies_50percent = the number of galaxies consisting 50% of probability (including luminosity but not distance factor)
    # # actual_percentage = usually around 50
    # # seen_percentage = if we include the distance factor - how much do the same galaxies worth
    # # 99percent_area = area of map in [deg^2] consisting 99% (using only the map from LIGO)
    # stats = {"Ngalaxies_50percent": galaxies50per, "actual_percentage": sum*100, "seen_percentage": sum_seen, "99percent_area": area}

    # Limit the maximal number of galaxies to use:
    if len(ranking_idx) > max_galaxies:
        n = max_galaxies
    else:
        n = len(ranking_idx)

    # Create sorted galaxy list (glade_id, RA, DEC, distance(Mpc), Bmag, score, distance factor (between 0-1))
    # The score is normalized so that all the galaxies in the field sum to 1 (before applying luminosity cutoff)
    galaxylist = np.ndarray((n, 7))
    for i in range(ranking_idx.shape[0])[:n]:
        ind = ranking_idx[i]
        galaxylist[i, :] = [galaxy_cat[ind]['ID'], galaxy_cat[ind]['RA'], galaxy_cat[ind]['Dec'], galaxy_cat[ind]['Dist'], galaxy_cat[ind]['Bmag'],
                            score[ind], distance_factor[ind]]

        # Update galaxy table in SQL database:
        lvc_galaxy_dict = {'voeventid': '(SELECT MAX(id) from voevent_lvc)',
                           'score': score[ind],
                           'gladeid': galaxy_cat[ind]['ID']}
        mysql_update.insert_values('lvc_galaxies', lvc_galaxy_dict)

    return galaxylist, ra_maxprob, dec_maxprob
Exemple #4
0
def process_gcn(payload, root):
    alerts_path = config.get('ALERT FILES', 'PATH')  # event alert file path
    fits_path = config.get('EVENT FILES', 'PATH')  # event FITS file path
    is_test = config.getboolean('GENERAL', 'TEST') if config.has_option(
        'GENERAL', 'TEST') else False

    # Respond only to 'test'/'observation' events
    if is_test:
        role = 'test'
    else:
        role = 'observation'

    if root.attrib['role'] != role:
        logging.info('Not {}, aborting.'.format(role))
        return

    ivorn = root.attrib['ivorn']
    filename = ntpath.basename(ivorn).split('#')[1]
    log = init_log(filename)

    # Is retracted?
    if gcn.handlers.get_notice_type(root) == gcn.notice_types.LVC_RETRACTION:
        # Save alert to file
        with open(alerts_path + filename + '.xml', "wb") as f:
            f.write(payload)
        log.info("Event {} retracted, doing nothing.".format(filename))
        send_mail(subject="[GW@Wise] {}".format(filename.split('-')[0]),
                  text="GCN/LVC retraction {} received, doing nothing.".format(
                      filename),
                  html=format_html("<b>Alert retracted.</b><br>"),
                  files=[alerts_path + filename + '.xml'])
        return

    v = vp.loads(payload)

    # Read all of the VOEvent parameters from the "What" section
    params = {
        elem.attrib['name']: elem.attrib['value']
        for elem in v.iterfind('.//Param')
    }

    # Respond only to 'CBC' (compact binary coalescence candidates) events.
    # Change 'CBC' to 'Burst' to respond to only unmodeled burst events.
    if params['Group'] != 'CBC':
        log.info('Not CBC, aborting.')
        return

    # Respond only to specific merger types
    if ((config.getfloat("GENERAL", "BNS_MIN") < float(params["BNS"])) |
            (config.getfloat("GENERAL", "NSBH_MIN") < float(params["NSBH"])) |
            (config.getfloat("GENERAL", "MASSGAP_MIN") < float(params["MassGap"])) |
            (config.getfloat("GENERAL", "BBH_MIN") < float(params["BBH"])) |
            (config.getfloat("GENERAL", "HASNS_MIN") < float(params["HasNS"])) |
            (config.getfloat("GENERAL", "HASREMNANT_MIN") < float(params["HasRemnant"]))) & \
            (config.getfloat("GENERAL", "TERRESTRIAL_MAX") >= float(params["Terrestrial"])) & \
            (config.getfloat("GENERAL", "FAR_MAX") >= float(params["FAR"])*60*60*24*365):
        pass
    else:
        log.info("Uninteresting alert, aborting.")
        return

    # Save alert to file
    with open(alerts_path + filename + '.xml', "wb") as f:
        f.write(payload)
    log.info("GCN/LVC alert {} received, started processing.".format(ivorn))

    # Read VOEvent attributes
    keylist = ['ivorn', 'role', 'version']
    for key in keylist:
        params[key] = v.attrib[key]

    # Read Who
    params['author_ivorn'] = v.Who.Author.contactName
    params['date_ivorn'] = v.Who.Date

    # Read WhereWhen
    params[
        'observatorylocation_id'] = v.WhereWhen.ObsDataLocation.ObservatoryLocation.attrib[
            'id']
    params[
        'astrocoordsystem_id'] = v.WhereWhen.ObsDataLocation.ObservationLocation.AstroCoordSystem.attrib[
            'id']
    params[
        'isotime'] = v.WhereWhen.ObsDataLocation.ObservationLocation.AstroCoords.Time.TimeInstant.ISOTime

    # Read How
    description = ""
    for item in v.How.iterfind('Description'):
        description = description + ", " + item
    params['how_description'] = description

    # Insert VOEvent to the database
    mysql_update.insert_voevent('voevent_lvc', params, log)

    # Download the HEALPix sky map FITS file.
    tmp_path = download_file(params['skymap_fits'], cache=False)
    skymap_path = fits_path + filename + "_" + ntpath.basename(
        params['skymap_fits'])
    shutil.move(tmp_path, skymap_path)

    # Respond only to alerts with reasonable localization
    credzones = [
        0.5, 0.9,
        config.getfloat("GENERAL", "AREA_CREDZONE"),
        config.getfloat("TILE", "CREDZONE")
    ]
    area = get_sky_area(skymap_path, credzone=credzones)
    if area[2] > config.getfloat("GENERAL", "AREA_MAX"):
        log.info(
            f"""{credzones[2]} area is {area[2]} > {config.get("GENERAL", "AREA_MAX")} deg^2, aborting."""
        )
        send_mail(
            subject="[GW@Wise] {}".format(params["GraceID"]),
            text=
            f"""Attached {filename} GCN/LVC alert received, but {credzones[2]} area is {area[2]} > \
                          {config.get("GENERAL", "AREA_MAX")} deg^2, aborting.""",
            html=format_alert(params, area[0:1]),
            files=[alerts_path + filename + '.xml'],
            log=log)
        return

    # Send alert email
    send_mail(
        subject="[GW@Wise] {}".format(params["GraceID"]),
        text="Attached {} GCN/LVC alert received, started processing.".format(
            filename),
        html=format_alert(params, area[0:2]),
        files=[alerts_path + filename + '.xml'],
        log=log)

    if area[3] > config.getfloat("TILE", "AREA_MAX"):
        # Create the galaxy list
        galaxies, ra, dec = galaxy_list.find_galaxy_list(skymap_path, log=log)
        # Save galaxy list to csv file and send it
        ascii.write(galaxies,
                    "galaxy_list.csv",
                    format="csv",
                    overwrite=True,
                    names=[
                        "GladeID", "RA", "Dec", "Dist", "Bmag", "Score",
                        "Distance factor"
                    ])
        send_mail(
            subject="[GW@Wise] {} Galaxy list".format(params["GraceID"]),
            text="{} GCN/LVC alert galaxy list is attached.".format(filename),
            files=["galaxy_list.csv"],
            log=log)

        # Create Wise plan
        wise.process_galaxy_list(galaxies,
                                 alertname=ivorn.split('/')[-1],
                                 ra_event=ra,
                                 dec_event=dec,
                                 log=log)
    else:
        # Tile the credible region
        wise.process_tiles(skymap_path,
                           alertname=ivorn.split('/')[-1],
                           log=log)

    # Finish and delete logger
    log.info("Done.")
    close_log(log)
Exemple #5
0
def process_galaxy_list(galaxies,
                        filename='galaxies',
                        ra_event=None,
                        dec_event=None,
                        log=None):
    """Get the full galaxy list, and find which are good to observe at Wise"""

    if log is None:
        log = logging.getLogger(__name__)

    log.info("Event most probable RA={}, Dec={}.".format(
        ra_event.to_string(unit=u.hourangle, sep=':', precision=2, pad=True),
        dec_event.to_string(sep=':', precision=2, alwayssign=True, pad=True)))

    t = Time.now()
    if not is_night(
            lat=config.getfloat('WISE', 'LAT') * u.deg,
            lon=config.getfloat('WISE', 'LON') * u.deg,
            alt=config.getfloat('WISE', 'ALT') * u.m,
            t=t,
            sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') *
            u.deg):
        log.info("Daytime at Wise! Preparing a plan for next sunset.")
        t = next_night(
            lat=config.getfloat('WISE', 'LAT') * u.deg,
            lon=config.getfloat('WISE', 'LON') * u.deg,
            alt=config.getfloat('WISE', 'ALT') * u.m,
            t=t,
            sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') *
            u.deg)
    else:
        log.info("It's nighttime at Wise! Preparing a plan for NOW.")

    telescopes = config.get('WISE', 'TELESCOPES').split(',')

    nothing_to_observe = True
    for tel in range(0, len(telescopes)):
        log.info("Writing a plan for the {}".format(telescopes[tel]))
        root = rtml.init(name=config.get('OBSERVING', 'USER'),
                         email=config.get('OBSERVING', 'EMAIL'))

        root = rtml.add_request(
            root,
            request_id=filename,
            bestefforts=config.get('OBSERVING', 'BESTEFFORTS'),
            user=config.get('OBSERVING', 'USER'),
            description=config.get('OBSERVING', 'DESCRIPTION'),
            project=config.get('OBSERVING', 'PROJECT'),
            airmass_min=config.get(telescopes[tel], 'AIRMASS_MIN'),
            airmass_max=config.get(telescopes[tel], 'AIRMASS_MAX'),
            hourangle_min=config.get(telescopes[tel], 'HOURANGLE_MIN'),
            hourangle_max=config.get(telescopes[tel], 'HOURANGLE_MAX'))

        log.debug(
            "Index\tGladeID\tRA\t\tDec\t\tAirmass\tHA\tDist\tBmag\tScore\t\tDist factor"
        )

        for i in range(tel, galaxies.shape[0], len(telescopes)):
            ra = Angle(galaxies[i, 1] * u.deg)
            dec = Angle(galaxies[i, 2] * u.deg)
            is_observe, airmass, ha = is_observable(
                ra=ra,
                dec=dec,
                lat=config.getfloat('WISE', 'LAT') * u.deg,
                lon=config.getfloat('WISE', 'LON') * u.deg,
                alt=config.getfloat('WISE', 'ALT') * u.m,
                t=t,
                ha_min=config.getfloat(telescopes[tel], 'HOURANGLE_MIN') *
                u.hourangle,
                ha_max=config.getfloat(telescopes[tel], 'HOURANGLE_MAX') *
                u.hourangle,
                airmass_min=config.getfloat(telescopes[tel], 'AIRMASS_MIN'),
                airmass_max=config.getfloat(telescopes[tel], 'AIRMASS_MAX'),
                return_values=True)

            if is_observe:
                nothing_to_observe = False
                log.debug(
                    "{}:\t{:.0f}\t{}\t{}\t{:+.2f}\t{:+.2f}\t{:.2f}\t{:.2f}\t{:.6g}\t\t{:.2f}\t\tadded to plan!"
                    .format(
                        i + 1, galaxies[i, 0],
                        ra.to_string(unit=u.hourangle,
                                     sep=':',
                                     precision=2,
                                     pad=True),
                        dec.to_string(sep=':',
                                      precision=2,
                                      alwayssign=True,
                                      pad=True), airmass, ha, galaxies[i, 3],
                        galaxies[i, 4], galaxies[i, 5], galaxies[i, 6]))

                rtml.add_target(root,
                                request_id=filename,
                                ra=ra.to_string(unit=u.degree, decimal=True),
                                dec=dec.to_string(unit=u.degree,
                                                  decimal=True,
                                                  alwayssign=True),
                                name="GladeID_{:.0f}".format(galaxies[i, 0]))

                rtml.add_picture(
                    root,
                    filt=config.get(telescopes[tel], 'FILTER'),
                    target_name="GladeID_{:.0f}".format(galaxies[i, 0]),
                    exptime=config.get(telescopes[tel], 'EXPTIME'),
                    binning=config.get(telescopes[tel], 'BINNING'))
            else:
                log.debug(
                    "{}:\t{:.0f}\t{}\t{}\t{:+.2f}\t{:+.2f}\t{:.2f}\t{:.2f}\t{:.6g}\t\t{:.2f}"
                    .format(
                        i + 1, galaxies[i, 0],
                        ra.to_string(unit=u.hourangle,
                                     sep=':',
                                     precision=2,
                                     pad=True),
                        dec.to_string(sep=':',
                                      precision=2,
                                      alwayssign=True,
                                      pad=True), airmass, ha, galaxies[i, 3],
                        galaxies[i, 4], galaxies[i, 5], galaxies[i, 6]))

        if nothing_to_observe:
            log.info("Nothing to observe.")
            send_mail(
                subject="[GW@Wise] Nothing to observe",
                text=
                "Nothing to observe for alert {}.\nEvent most probable at RA={}, Dec={}."
                .format(
                    filename,
                    ra_event.to_string(unit=u.hourangle,
                                       sep=':',
                                       precision=2,
                                       pad=True),
                    dec_event.to_string(sep=':',
                                        precision=2,
                                        alwayssign=True,
                                        pad=True)))

        else:
            rtml_filename = config.get(
                'WISE', 'PATH') + filename + '_' + telescopes[tel] + '.xml'
            rtml.write(root, rtml_filename)

            log.info("Created observing plan for alert {}.".format(filename))
            send_mail(
                subject="[GW@Wise] {} observing plan".format(telescopes[tel]),
                text=
                "{} observing plan for alert {}.\nEvent most probable at RA={}, Dec={}."
                .format(
                    telescopes[tel], filename,
                    ra_event.to_string(unit=u.hourangle,
                                       sep=':',
                                       precision=2,
                                       pad=True),
                    dec_event.to_string(sep=':',
                                        precision=2,
                                        alwayssign=True,
                                        pad=True)),
                files=[rtml_filename])

    return
Exemple #6
0
def process_tiles(skymap_path, alertname='GW', log=None):
    if log is None:
        log = logging.getLogger(__name__)

    eventname = alertname.split('#')[1]
    eventname = eventname.split('-')[0]

    t = Time.now()
    if not is_night(
            lat=config.getfloat('WISE', 'LAT') * u.deg,
            lon=config.getfloat('WISE', 'LON') * u.deg,
            alt=config.getfloat('WISE', 'ALT') * u.m,
            t=t,
            sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') *
            u.deg):
        log.info("Daytime at Wise! Preparing a plan for next sunset.")
        t = next_sunset(
            lat=config.getfloat('WISE', 'LAT') * u.deg,
            lon=config.getfloat('WISE', 'LON') * u.deg,
            alt=config.getfloat('WISE', 'ALT') * u.m,
            t=t,
            sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') *
            u.deg)
    else:
        log.info("It's nighttime at Wise! Preparing a plan for NOW.")

    t_sunrise = next_sunrise(
        lat=config.getfloat('WISE', 'LAT') * u.deg,
        lon=config.getfloat('WISE', 'LON') * u.deg,
        alt=config.getfloat('WISE', 'ALT') * u.m,
        t=t,
        sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') * u.deg)
    log.debug("Now/sunset = {}, sunrise = {}".format(t, t_sunrise))

    telescopes = config.get('WISE', 'TELESCOPES').split(', ')

    # change IERS table URL (to fix URL timeout problems)
    change_iers_url(url=config.get('IERS', 'URL'))

    nothing_to_observe = True
    for tel in range(0, len(telescopes)):
        log.info("Writing a plan for the {}".format(telescopes[tel]))
        root = rtml.init(name=config.get('OBSERVING', 'USER'),
                         email=config.get('OBSERVING', 'EMAIL'))

        # Tile the credible region
        ra, dec, probability = tile.tile_region(
            skymap_path,
            credzone=config.getfloat("TILE", "CREDZONE"),
            tile_area=config.getfloat("TILE", "SIZE") *
            config.getfloat(telescopes[tel], "FOV"),
            log=log)

        log.debug("Index\tRA\t\tDec\tAirmass\tHA\tLunarDist\tProbability")

        csv_filename = f"{telescopes[tel]}_TileList.csv"
        fid = open(csv_filename, "w")
        fid.write("Index,RA,Dec,Airmass,HA,LunarDist,Probability\n")

        for i in range(len(ra)):
            is_observe, airmass, ha, lunar_dist = is_observable_in_interval(
                ra=ra[i],
                dec=dec[i],
                lat=config.getfloat('WISE', 'LAT') * u.deg,
                lon=config.getfloat('WISE', 'LON') * u.deg,
                alt=config.getfloat('WISE', 'ALT') * u.m,
                t1=t,
                t2=t_sunrise,
                ha_min=config.getfloat(telescopes[tel], 'HOURANGLE_MIN') *
                u.hourangle,
                ha_max=config.getfloat(telescopes[tel], 'HOURANGLE_MAX') *
                u.hourangle,
                airmass_min=config.getfloat(telescopes[tel], 'AIRMASS_MIN'),
                airmass_max=config.getfloat(telescopes[tel], 'AIRMASS_MAX'),
                min_lunar_distance=config.getfloat(telescopes[tel],
                                                   'MIN_LUNAR_DIST') * u.deg,
                return_values=True)

            if is_observe:
                nothing_to_observe = False
                log.debug(
                    "{}:\t{}\t{}\t{:+.2f}\t{:+.2f}\t{:.2f}\t{:.6g}\t\tadded to plan!"
                    .format(
                        i + 1, ra[i].to_string(unit=u.hourangle,
                                               sep=':',
                                               precision=2,
                                               pad=True),
                        dec[i].to_string(sep=':',
                                         precision=2,
                                         alwayssign=True,
                                         pad=True), airmass, ha, lunar_dist,
                        probability[i]))
                fid.write("{},{},{},{:+.2f},{:+.2f},{:.2f},{:.6g}\n".format(
                    i + 1, ra[i].to_string(unit=u.hourangle,
                                           sep=':',
                                           precision=2,
                                           pad=True),
                    dec[i].to_string(sep=':',
                                     precision=2,
                                     alwayssign=True,
                                     pad=True), airmass, ha, lunar_dist,
                    probability[i]))

                root = rtml.add_request(
                    root,
                    request_id="Tile_{:.0f}".format(i + 1),
                    bestefforts=config.get('OBSERVING', 'BESTEFFORTS'),
                    user=config.get('OBSERVING', 'USER'),
                    description=config.get('OBSERVING', 'DESCRIPTION'),
                    project=alertname,
                    airmass_min=config.get(telescopes[tel], 'AIRMASS_MIN'),
                    airmass_max=config.get(telescopes[tel], 'AIRMASS_MAX'),
                    hourangle_min=config.get(telescopes[tel], 'HOURANGLE_MIN'),
                    hourangle_max=config.get(telescopes[tel], 'HOURANGLE_MAX'),
                    priority=str(len(ra) - i))

                rtml.add_target(root,
                                request_id="Tile_{:.0f}".format(i + 1),
                                ra=ra[i].to_string(unit=u.degree,
                                                   decimal=True),
                                dec=dec[i].to_string(unit=u.degree,
                                                     decimal=True,
                                                     alwayssign=True),
                                name="Tile_{:.0f}".format(i + 1))

                rtml.add_picture(root,
                                 filt=config.get(telescopes[tel], 'FILTER'),
                                 target_name="Tile_{:.0f}".format(i + 1),
                                 exptime=config.get(telescopes[tel],
                                                    'EXPTIME'),
                                 binning=config.get(telescopes[tel],
                                                    'BINNING'))
            else:
                log.debug(
                    "{}:\t{}\t{}\t{:+.2f}\t{:+.2f}\t{:+.2f}\t{:.6g}".format(
                        i + 1,
                        ra.to_string(unit=u.hourangle,
                                     sep=':',
                                     precision=2,
                                     pad=True),
                        dec.to_string(sep=':',
                                      precision=2,
                                      alwayssign=True,
                                      pad=True), airmass, ha, lunar_dist,
                        probability[i]))

        if nothing_to_observe:
            log.info("Nothing to observe.")
            send_mail(
                subject=
                f"[GW@Wise] {eventname} {telescopes[tel]} observing plan",
                text=f"Nothing to observe for alert {alertname}.")

        else:
            rtml_filename = config.get(
                'WISE', 'PATH') + alertname + '_' + telescopes[tel] + '.xml'
            rtml.write(root, rtml_filename)

            fid.close()

            log.info(f"Created observing plan for alert {alertname}.")
            send_mail(
                subject=
                f"[GW@Wise] {eventname} {telescopes[tel]} observing plan",
                text="{} observing plan for alert {}.".format(
                    telescopes[tel], alertname),
                files=[rtml_filename, csv_filename])

            # upload to remote Scheduler
            if not config.get(telescopes[tel], 'HOST'):
                log.info("No host name was provided, skipping plan upload.")
            else:
                result = rtml.import_to_remote_scheduler(
                    rtml_filename,
                    username=config.get(telescopes[tel], 'USER'),
                    remote_host=config.get(telescopes[tel], 'HOST'),
                    remote_path=config.get(telescopes[tel], 'PATH'),
                    cygwin_path=config.get(telescopes[tel], 'CYGWIN_PATH'))
                log.info(result)

    return
Exemple #7
0
def process_galaxy_list(galaxies,
                        alertname='GW',
                        ra_event=None,
                        dec_event=None,
                        log=None):
    """Get the full galaxy list, and find which are good to observe at Wise"""

    if log is None:
        log = logging.getLogger(__name__)

    log.info("Event most probable RA={}, Dec={}.".format(
        ra_event.to_string(unit=u.hourangle, sep=':', precision=2, pad=True),
        dec_event.to_string(sep=':', precision=2, alwayssign=True, pad=True)))

    eventname = alertname.split('#')[1]
    eventname = eventname.split('-')[0]

    t = Time.now()
    if not is_night(
            lat=config.getfloat('WISE', 'LAT') * u.deg,
            lon=config.getfloat('WISE', 'LON') * u.deg,
            alt=config.getfloat('WISE', 'ALT') * u.m,
            t=t,
            sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') *
            u.deg):
        log.info("Daytime at Wise! Preparing a plan for next sunset.")
        t = next_sunset(
            lat=config.getfloat('WISE', 'LAT') * u.deg,
            lon=config.getfloat('WISE', 'LON') * u.deg,
            alt=config.getfloat('WISE', 'ALT') * u.m,
            t=t,
            sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') *
            u.deg)
    else:
        log.info("It's nighttime at Wise! Preparing a plan for NOW.")

    t_sunrise = next_sunrise(
        lat=config.getfloat('WISE', 'LAT') * u.deg,
        lon=config.getfloat('WISE', 'LON') * u.deg,
        alt=config.getfloat('WISE', 'ALT') * u.m,
        t=t,
        sun_alt_twilight=config.getfloat('OBSERVING', 'SUN_ALT_MAX') * u.deg)
    log.debug("Now/sunset = {}, sunrise = {}".format(t, t_sunrise))

    telescopes = config.get('WISE', 'TELESCOPES').split(',')
    max_galaxies = config.getint(
        'GALAXIES', 'MAXGALAXIESPLAN'
    )  # maximal number of galaxies to use in observation plan

    # change IERS table URL (to fix URL timeout problems)
    change_iers_url(url=config.get('IERS', 'URL'))

    nothing_to_observe = True
    for tel in range(0, len(telescopes)):
        log.info("Writing a plan for the {}".format(telescopes[tel]))
        root = rtml.init(name=config.get('OBSERVING', 'USER'),
                         email=config.get('OBSERVING', 'EMAIL'))

        log.debug(
            "Index\tGladeID\tRA\t\tDec\t\tAirmass\tHA\tLunarDist\tDist\tBmag\tScore\t\tDist factor"
        )

        csv_filename = f"{telescopes[tel]}_GalaxyList.csv"
        fid = open(csv_filename, "w")
        fid.write(
            "Index,GladeID,RA,Dec,Airmass,HA,LunarDist,Dist,Bmag,Score,Dist factor\n"
        )

        n_galaxies_in_plan = 0
        for i in range(tel, galaxies.shape[0], len(telescopes)):

            ra = Angle(galaxies[i, 1] * u.deg)
            dec = Angle(galaxies[i, 2] * u.deg)
            is_observe, airmass, ha, lunar_dist = is_observable_in_interval(
                ra=ra,
                dec=dec,
                lat=config.getfloat('WISE', 'LAT') * u.deg,
                lon=config.getfloat('WISE', 'LON') * u.deg,
                alt=config.getfloat('WISE', 'ALT') * u.m,
                t1=t,
                t2=t_sunrise,
                ha_min=config.getfloat(telescopes[tel], 'HOURANGLE_MIN') *
                u.hourangle,
                ha_max=config.getfloat(telescopes[tel], 'HOURANGLE_MAX') *
                u.hourangle,
                airmass_min=config.getfloat(telescopes[tel], 'AIRMASS_MIN'),
                airmass_max=config.getfloat(telescopes[tel], 'AIRMASS_MAX'),
                min_lunar_distance=config.getfloat(telescopes[tel],
                                                   'MIN_LUNAR_DIST') * u.deg,
                return_values=True)

            if is_observe:
                nothing_to_observe = False
                n_galaxies_in_plan += 1
                log.debug(
                    "{}:\t{:.0f}\t{}\t{}\t{:+.2f}\t{:+.2f}\t{:.2f}\t{:.2f}\t{:.2f}\t{:.6g}\t\t{:.2f}\t\tadded to plan!"
                    .format(
                        i + 1, galaxies[i, 0],
                        ra.to_string(unit=u.hourangle,
                                     sep=':',
                                     precision=2,
                                     pad=True),
                        dec.to_string(sep=':',
                                      precision=2,
                                      alwayssign=True,
                                      pad=True), airmass, ha, lunar_dist,
                        galaxies[i, 3], galaxies[i, 4], galaxies[i, 5],
                        galaxies[i, 6]))
                fid.write(
                    "{},{:.0f},{},{},{:+.2f},{:+.2f},{:.2f},{:.2f},{:.2f},{:.6g},{:.2f}\n"
                    .format(
                        i + 1, galaxies[i, 0],
                        ra.to_string(unit=u.hourangle,
                                     sep=':',
                                     precision=2,
                                     pad=True),
                        dec.to_string(sep=':',
                                      precision=2,
                                      alwayssign=True,
                                      pad=True), airmass, ha, lunar_dist,
                        galaxies[i, 3], galaxies[i, 4], galaxies[i, 5],
                        galaxies[i, 6]))

                root = rtml.add_request(
                    root,
                    request_id="GladeID_{:.0f}".format(galaxies[i, 0]),
                    bestefforts=config.get('OBSERVING', 'BESTEFFORTS'),
                    user=config.get('OBSERVING', 'USER'),
                    description=config.get('OBSERVING', 'DESCRIPTION'),
                    project=alertname,
                    airmass_min=config.get(telescopes[tel], 'AIRMASS_MIN'),
                    airmass_max=config.get(telescopes[tel], 'AIRMASS_MAX'),
                    hourangle_min=config.get(telescopes[tel], 'HOURANGLE_MIN'),
                    hourangle_max=config.get(telescopes[tel], 'HOURANGLE_MAX'),
                    priority=str(
                        min(max_galaxies, galaxies.shape[0]) -
                        n_galaxies_in_plan + 1))

                rtml.add_target(root,
                                request_id="GladeID_{:.0f}".format(
                                    galaxies[i, 0]),
                                ra=ra.to_string(unit=u.degree, decimal=True),
                                dec=dec.to_string(unit=u.degree,
                                                  decimal=True,
                                                  alwayssign=True),
                                name="GladeID_{:.0f}".format(galaxies[i, 0]))

                rtml.add_picture(
                    root,
                    filt=config.get(telescopes[tel], 'FILTER'),
                    target_name="GladeID_{:.0f}".format(galaxies[i, 0]),
                    exptime=config.get(telescopes[tel], 'EXPTIME'),
                    binning=config.get(telescopes[tel], 'BINNING'))
            else:
                log.debug(
                    "{}:\t{:.0f}\t{}\t{}\t{:+.2f}\t{:+.2f}\t{:+.2f}\t{:.2f}\t{:.2f}\t{:.6g}\t\t{:.2f}"
                    .format(
                        i + 1, galaxies[i, 0],
                        ra.to_string(unit=u.hourangle,
                                     sep=':',
                                     precision=2,
                                     pad=True),
                        dec.to_string(sep=':',
                                      precision=2,
                                      alwayssign=True,
                                      pad=True), airmass, ha, lunar_dist,
                        galaxies[i, 3], galaxies[i, 4], galaxies[i, 5],
                        galaxies[i, 6]))

            if n_galaxies_in_plan >= max_galaxies:
                # maximal number of galaxies per plan has been reached
                break

        if nothing_to_observe:
            log.info("Nothing to observe.")
            send_mail(
                subject=
                f"[GW@Wise] {eventname} {telescopes[tel]} observing plan",
                text=
                "Nothing to observe for alert {}.\nEvent most probable at RA={}, Dec={}."
                .format(
                    alertname,
                    ra_event.to_string(unit=u.hourangle,
                                       sep=':',
                                       precision=2,
                                       pad=True),
                    dec_event.to_string(sep=':',
                                        precision=2,
                                        alwayssign=True,
                                        pad=True)))

        else:
            rtml_filename = config.get(
                'WISE', 'PATH') + alertname + '_' + telescopes[tel] + '.xml'
            rtml.write(root, rtml_filename)

            fid.close()

            log.info(f"Created observing plan for alert {alertname}.")
            send_mail(
                subject=
                f"[GW@Wise] {eventname} {telescopes[tel]} observing plan",
                text=
                "{} observing plan for alert {}.\nEvent most probable at RA={}, Dec={}."
                .format(
                    telescopes[tel], alertname,
                    ra_event.to_string(unit=u.hourangle,
                                       sep=':',
                                       precision=2,
                                       pad=True),
                    dec_event.to_string(sep=':',
                                        precision=2,
                                        alwayssign=True,
                                        pad=True)),
                files=[rtml_filename, csv_filename])

            # upload to remote Scheduler
            if not config.get(telescopes[tel], 'HOST'):
                log.info("No host name was provided, skipping plan upload.")
            else:
                result = rtml.import_to_remote_scheduler(
                    rtml_filename,
                    username=config.get(telescopes[tel], 'USER'),
                    remote_host=config.get(telescopes[tel], 'HOST'),
                    remote_path=config.get(telescopes[tel], 'PATH'),
                    cygwin_path=config.get(telescopes[tel], 'CYGWIN_PATH'))
                log.info(result)

    return