def test_crossmatching(self):

        # SETUP ALL DATABASE CONNECTIONS
        from sherlock import database
        db = database(log=log, settings=settings)
        dbConns, dbVersions = db.connect()
        transientsDbConn = dbConns["transients"]
        cataloguesDbConn = dbConns["catalogues"]
        pmDbConn = dbConns["marshall"]

        from sherlock.commonutils import get_crossmatch_catalogues_column_map
        colMaps = get_crossmatch_catalogues_column_map(log=log,
                                                       dbConn=cataloguesDbConn)

        from sherlock import transient_classifier
        classifier = transient_classifier(log=log, settings=settings)
        transientsMetadataList = classifier._get_transient_metadata_from_database_list(
        )
        crossmatches = classifier._crossmatch_transients_against_catalogues(
            colMaps=colMaps, transientsMetadataList=transientsMetadataList)

        classifications, crossmatches = classifier._rank_classifications(
            colMaps=colMaps, crossmatches=crossmatches)

        classifier._update_transient_database(
            classifications=classifications,
            transientsMetadataList=transientsMetadataList,
            colMaps=colMaps,
            crossmatches=crossmatches)
    def test_get_transient_metadata_from_database_list(self):

        from sherlock import transient_classifier
        classifier = transient_classifier(log=log,
                                          settings=settings,
                                          updateNed=False)
        transientsMetadataList = classifier._get_transient_metadata_from_database_list(
        )
    def test_get_transient_metadata_from_database_list(self):

        from sherlock import transient_classifier
        classifier = transient_classifier(log=log, settings=settings)
        transientsMetadataList = classifier._get_transient_metadata_from_database_list(
        )
        classifier._update_ned_stream(
            transientsMetadataList=transientsMetadataList)
    def test_transient_classifier_function(self):

        from sherlock import transient_classifier
        this = transient_classifier(log=log,
                                    settings=settings,
                                    update=True,
                                    updateNed=False,
                                    oneRun=True)
        this.classify()
    def test_transient_update_classified_annotations_function(self):

        from sherlock import transient_classifier
        this = transient_classifier(log=log,
                                    settings=settings,
                                    update=True,
                                    fast=True)
        # this.update_peak_magnitudes()
        this.update_classification_annotations_and_summaries()
    def test_full_classifier(self):

        from sherlock import transient_classifier
        classifier = transient_classifier(log=log,
                                          settings=settings,
                                          verbose=2,
                                          update=True,
                                          updateNed=False,
                                          updatePeakMags=True)
        classifier.classify()
    def test_transient_classifier_single_source_function(self):

        from sherlock import transient_classifier
        this = transient_classifier(log=log,
                                    settings=settings,
                                    ra="08:57:57.19",
                                    dec="+43:25:44.1",
                                    name="PS17gx",
                                    verbose=0)
        classifications, crossmatches = this.classify()
    def test_transient_classifier_function_exception(self):

        from sherlock import transient_classifier
        try:
            this = transient_classifier(log=log,
                                        settings=settings,
                                        fakeKey="break the code")
            this.get()
            assert False
        except Exception as e:
            assert True
            print(str(e))
示例#9
0
def classify(name, ra, dec, lite=False):
    with open(conf['sherlock_settings'], "r") as f:
        sherlock_settings = yaml.safe_load(f)
        classifier = transient_classifier(log=app.logger,
                                          settings=sherlock_settings,
                                          ra=ra,
                                          dec=dec,
                                          name=name,
                                          verbose=1,
                                          updateNed=False,
                                          lite=lite)
        classifications, crossmatches = classifier.classify()
        return classifications, crossmatches
    def test_classification_annotations(self):

        from sherlock import database
        db = database(log=log, settings=settings)
        dbConns, dbVersions = db.connect()
        transientsDbConn = dbConns["transients"]
        cataloguesDbConn = dbConns["catalogues"]

        from sherlock.commonutils import get_crossmatch_catalogues_column_map
        colMaps = get_crossmatch_catalogues_column_map(log=log,
                                                       dbConn=cataloguesDbConn)

        from sherlock import transient_classifier
        classifier = transient_classifier(log=log, settings=settings)
        classifier.classification_annotations()
示例#11
0
def classify(conf, log, alerts):
    "send a batch of alerts to sherlock and add the responses to the alerts, return the number of alerts classified"
    
    #global alerts

    log.debug('called classify with config: ' + str(conf))
  
    # read Sherlock settings file
    sherlock_settings = {}
    try:
        with open(conf['sherlock_settings'], "r") as f:
            sherlock_settings = yaml.safe_load(f)
    except IOError as e:
        log.error(e)

    # look up objects in cache
    annotations = {}
    if conf['cache_db']:
        names = []
        for alert in alerts:
            name = alert.get('objectId', alert.get('candid'))
            names.append(name)
        query = "SELECT * FROM cache WHERE name IN ('{}');".format("','".join(names))
        url = urlparse(conf['cache_db'])
        connection = pymysql.connect(
                host=url.hostname,
                user=url.username,
                password=url.password,
                db=url.path.lstrip('/'),
                charset='utf8mb4',
                cursorclass=pymysql.cursors.DictCursor)        
        try:
            with connection.cursor() as cursor:
                cursor.execute(query)
                for result in cursor.fetchall():
                    try:
                        match = json.loads(result.get('crossmatch'))
                        annotations[result['name']] = {
                            'classification': result['class']
                            }
                        for key,value in match.items():
                            annotations[result['name']][key] = value
                        log.debug("Got crossmatch from cache:\n" + json.dumps(match, indent=2))
                    except ValueError:
                        log.info("Ignoring cache entry with malformed or missing crossmatch: {}".format(result['name']))
                        continue

        except TypeError:
            log.debug("Got TypeError reading cache. Entry probably present, but incomplete or malformed. Ignoring.")
        finally:
            connection.close()
    if len(annotations)>0:
        log.info("got {:d} annotations from cache".format(len(annotations)))

    # make lists of names, ra, dec
    names = []
    ra = []
    dec = []
    for alert in alerts:
        name = alert.get('objectId', alert.get('candid'))
        # ignore SS alerts
        ssnamenr = alert['candidate'].get('ssnamenr', "null")
        if ssnamenr != "null":
            log.debug("Skipping classification for solar system alert {}".format(name))
            continue
        if not name in annotations:
            if not name in names:
                names.append(name)
                ra.append(alert['candidate']['ra'])
                dec.append(alert['candidate']['dec'])

    # set up sherlock
    classifier = transient_classifier(
        log=log,
        settings=sherlock_settings,
        ra=ra,
        dec=dec,
        name=names,
        verbose=0,
        updateNed=False,
        lite=True
    )

    # run sherlock
    cm_by_name = {}
    if len(names) > 0:
        log.log(logging.INFO_, "running Sherlock classifier on {:d} objects".format(len(names)))
        classifications, crossmatches = classifier.classify()
        log.log(logging.INFO_, "got {:d} classifications".format(len(classifications)))
        log.log(logging.INFO_, "got {:d} crossmatches".format(len(crossmatches)))
        # process classfications
        for name in names:
            if name in classifications:
                annotations[name] = { 'classification': classifications[name][0] }
                if len(classifications[name]) > 1:
                    annotations[name]['description'] = classifications[name][1]
        # process crossmatches
        for cm in crossmatches:
            name = cm['transient_object_id']
            if name in cm_by_name:
                cm_by_name[name].append(cm)
            else:
                cm_by_name[name] = [cm]
        for name in names:
            if name in cm_by_name:
                cm = cm_by_name[name]
                if len(cm) > 0:
                    match = cm[0]
                    log.debug("got crossmatch:\n {}".format(json.dumps(match, indent=2)))
                    for key, value in match.items():
                        if key != 'rank':
                            annotations[name][key] = value
    else:
        log.log(logging.INFO_, "not running Sherlock as no remaining alerts to process")

    # update cache database
    if conf['cache_db'] and len(names)>0:
        connection = pymysql.connect(
                host=url.hostname,
                user=url.username,
                password=url.password,
                db=url.path.lstrip('/'),
                charset='utf8mb4',
                cursorclass=pymysql.cursors.DictCursor)
        values = []
        crossmatches = []
        for name in names:
            classification = annotations[name]['classification']
            cm = cm_by_name.get(name, [])
            crossmatch = "{}".format(json.dumps(cm[0])) if len(cm) > 0 else "NULL"
            values.append("\n ('{}','{}',%s)".format(name, classification))
            crossmatches.append(crossmatch)
        # Syntax for ON DUPLICATE KEY appears to differ between MySQL and MariaDB :(
        ##query = "INSERT INTO cache VALUES {} AS new ON DUPLICATE KEY UPDATE class=new.class, crossmatch=new.crossmatch".format(",".join(values))
        query = "INSERT INTO cache VALUES {} ON DUPLICATE KEY UPDATE class=VALUES(class), crossmatch=VALUES(crossmatch)".format(",".join(values))
        log.info("update cache: {}".format(query))
        try:
            with connection.cursor() as cursor:
                # make deprecation warning non-fatal
                with warnings.catch_warnings():
                    warnings.simplefilter('default')
                    cursor.execute(query, crossmatches)
        finally:
            connection.commit()
            connection.close()

    # add the annotations to the alerts
    n = 0
    for alert in alerts:
        name = alert.get('objectId', alert.get('candid'))
        if name in annotations:
            annotations[name]['annotator'] = "https://github.com/thespacedoctor/sherlock"
            annotations[name]['additional_output'] = "http://lasair.lsst.ac.uk/api/sherlock/object/" + name
            # placeholders until sherlock returns these
            #annotations[name]['summary']  = 'Placeholder'
            if 'annotations' not in alert:
                alert['annotations'] = {}
            alert['annotations']['sherlock'] = []
            alert['annotations']['sherlock'].append(annotations[name])
            n += 1

    return n