Commit f8690fda authored by kberry's avatar kberry
Browse files

re-added in ISIS Serial Number

parent 78d15759
Loading
Loading
Loading
Loading
+290 −0
Original line number Diff line number Diff line
%% Cell type:code id: tags:

``` python
import os
import sys
print(os.path.abspath('../'))
sys.path.insert(0, os.path.abspath('../'))

from functools import reduce
import glob
import re

from autocnet.graph import network
from autocnet.fileio.sqlalchemy_json.alchemy import NestedJsonObject
from autocnet.utils.utils import find_in_dict

import sqlalchemy
from sqlalchemy.ext import declarative
from sqlalchemy import orm

import json
import warnings


import pvl
from pvl._collections import PVLModule
```

%% Output

    /Users/jlaura/github/autocnet

%% Cell type:markdown id: tags:

## Generate the data
The next three cells take a directory of cleaned `.trn` files (extra values like AUTO or OPTIONAL removed) and generate a `data.db` database of ISIS serial number translations.

%% Cell type:code id: tags:

``` python
# Database population and a declared class

Base = declarative.declarative_base()

class Translations(Base):
    __tablename__ = 'isis_translations'
    id = sqlalchemy.Column(sqlalchemy.INTEGER, primary_key=True)
    mission = sqlalchemy.Column(sqlalchemy.String)
    instrument = sqlalchemy.Column(sqlalchemy.String)
    translation = sqlalchemy.Column(NestedJsonObject)

    def __init__(self, mission, instrument, translation):
        self.mission = mission
        self.instrument = instrument
        self.translation = translation

class StringToMission(Base):
    __tablename__ = 'isis_mission_to_standard'
    id = sqlalchemy.Column(sqlalchemy.INTEGER, primary_key=True)
    key = sqlalchemy.Column(sqlalchemy.String)
    value = sqlalchemy.Column(sqlalchemy.String)

    def __init__(self, key, value):
        self.key = key
        self.value = value

engine = sqlalchemy.create_engine('sqlite:///data.db')
Base.metadata.bind = engine
Base.metadata.create_all()
session = orm.sessionmaker(bind=engine)()
```

%% Cell type:code id: tags:

``` python
files = glob.glob('../autocnet/examples/serial_number_translations/*.trn')
for f in files:
    p = pvl.load(f)
    name = os.path.basename(f[:-16])
    try:
        v = re.findall("([a-z, 0-9]*)([A-Z, a-z, 0-9]*)", name)[0]
        mission, instrument = v
    except:
        v = re.findall("[a-z, 0-9]*", name)
        mission = v[0]
        instrument = None
    r = Translations(mission, instrument, p)
    session.add(r)
session.commit()
```

%% Cell type:code id: tags:

``` python
# Build the mission names lookup table
v = """
Group = MissionName
  InputKey      = SpacecraftName
  InputGroup    = "IsisCube,Instrument"
  InputPosition = (IsisCube, Instrument)
  Translation   = (Aircraft, "Aircraft")
  Translation   = (Apollo15, "APOLLO 15")
  Translation   = (Apollo15, "APOLLO15")
  Translation   = (Apollo16, "APOLLO 16")
  Translation   = (Apollo16, "APOLLO16")
  Translation   = (Apollo17, "APOLLO 17")
  Translation   = (Apollo17, "APOLLO17")
  Translation   = (Cassini, Cassini-Huygens)
#  Translation   = (Chan1, "CHANDRAYAAN-1 ORBITER")
#  Translation   = (Chan1, CHANDRAYAAN1_ORBITER)
#  Translation   = (Chan1, CHANDRAYAAN-1)
  Translation   = (Chandrayaan1, "CHANDRAYAAN-1 ORBITER")
  Translation   = (Chandrayaan1, CHANDRAYAAN1_ORBITER)
  Translation   = (Chandrayaan1, CHANDRAYAAN-1)
  Translation   = (Clementine1, CLEMENTINE_1)
  Translation   = (Clementine1, "CLEMENTINE 1")
  Translation   = (Dawn, "DAWN")
  Translation   = (Galileo, "Galileo Orbiter")
  Translation   = (Hayabusa, HAYABUSA)
  Translation   = (Ideal, IdealSpacecraft)
  Translation   = (Kaguya, KAGUYA)
  Translation   = (Kaguya, SELENE-M)
  Translation   = (Lo, "Lunar Orbiter 3")
  Translation   = (Lo, "Lunar Orbiter 4")
  Translation   = (Lo, "Lunar Orbiter 5")
  Translation   = (Lro, "LUNAR RECONNAISSANCE ORBITER")
  Translation   = (Lro, "Lunar Reconnaissance Orbiter")
  Translation   = (Mariner10, Mariner_10)
  Translation   = (Mariner10, MARINER_10)
  Translation   = (Mer, "MARS EXPLORATION ROVER 1")
  Translation   = (Mer, MARS_EXPLORATION_ROVER_1)
  Translation   = (Mer, "MARS EXPLORATION ROVER 2")
  Translation   = (Mer, "SIMULATED MARS EXPLORATION ROVER 1")
  Translation   = (Mer, "SIMULATED MARS EXPLORATION ROVER 2")
  Translation   = (Messenger, MESSENGER)
  Translation   = (Messenger, Messenger)
  Translation   = (Mex, "MARS EXPRESS")
  Translation   = (Mex, "Mars Express")
    Translation   = (Mgs, MARSGLOBALSURVEYOR)
  Translation   = (Mgs, "MARS GLOBAL SURVEYOR")
  Translation   = (Mro, "MARS RECONNAISSANCE ORBITER")
  Translation   = (Mro, Mars_Reconnaissance_Orbiter)
  Translation   = (NewHorizons, "NEW HORIZONS")
  Translation   = (Near, NEAR)
  Translation   = (Near, "NEAR EARTH ASTEROID RENDEZVOUS")
  Translation   = (Odyssey, MARS_ODYSSEY)
  Translation   = (OsirisRex, OSIRIS-REX)
  Translation   = (Smart1, SMART1)
  Translation   = (Viking1, VIKING_ORBITER_1)
  Translation   = (Viking2, VIKING_ORBITER_2)
  Translation   = (Voyager1, VOYAGER_1)
  Translation   = (Voyager2, VOYAGER_2)
End_Group
End
"""
p = pvl.loads(v)

for k, v in p['MissionName'].items():
    if k == 'Translation':
        r = StringToMission(v[1], v[0])
        session.add(r)
session.commit()
```

%% Cell type:markdown id: tags:

## Sample Query

%% Cell type:code id: tags:

``` python
# Sample querying the database
for i, j, t in session.query(Translations.mission, Translations.instrument, Translations.translation):
    print(i,j)
    d = PVLModule(t)
    print(d)
    break
```

%% Cell type:markdown id: tags:

## Testing code to prototype the functionality now in autocnet

%% Cell type:code id: tags:

``` python
 class SerialNumberDecoder(pvl.decoder.PVLDecoder):
     """
     A PVL Decoder class to handle cube label parsing for the purpose of creating a valid ISIS
     serial number. Inherits from the PVLDecoder in planetarypy's pvl module.
     """
     def cast_unquoated_string(self, value):
         """
         Overrides the parent class's method so that any un-quoted string type value found in the
         parsed pvl will just return the original value. This is needed so that keyword values
         are not re-formatted from what is originally in the ISIS cube label.

         Note: This affects value types that are recognized as null, boolean, number, datetime,
         et at.
         """
         return value.decode('utf-8')


def get_isis_translation(label):
    """
    Compute the ISIS serial number for a given image using
    the input cube or the label extracted from the cube.

    Parameters
    ----------
    label : dict or str
            A PVL dict object or file name to extract
            the PVL object from

    Returns
    -------
    translation : dict
                  A PVLModule object containing the extracted
                  translation file
    """

    if not isinstance(label, PVLModule):
        label = pvl.load(label)

    cube_obj = find_in_dict(label, 'Instrument')

    # Grab the spacecraft name and run it through the ISIS lookup
    spacecraft_name = find_in_dict(cube_obj, 'SpacecraftName')
    for row in session.query(StringToMission).filter(StringToMission.key==spacecraft_name):
        spacecraft_name = row.value.lower()

    #Try and pull an instrument identifier
    try:
        instrumentid = find_in_dict(cube_obj, 'InstrumentId').capitalize()
    except:
        instrumentid = None

    # Grab the translation PVL object using the lookup
    for row in session.query(Translations).filter(Translations.mission==spacecraft_name,
                                                  Translations.instrument==instrumentid):
        # Convert the JSON back to a PVL object
        translation = PVLModule(row.translation)

    return translation

def extract_subgroup(data, key_list):
    return reduce(lambda d, k: d[k], key_list, data)

def generate_serial_number(label):

    if not isinstance(label, PVLModule):
        label = pvl.load(label, cls=SerialNumberDecoder)

    # Get the translation information
    translation = get_isis_translation(label)
    serial_number = []

    # Sort the keys to ensure proper iteration order
    keys = sorted(translation.keys())
    for k in keys:
        group = translation[k]
        search_key = group['InputKey']
        search_position = group['InputPosition']
        search_translation = {group['Translation'][1]:group['Translation'][0]}
        print(search_key, search_position, search_translation)

        sub_group = extract_subgroup(label, search_position)
        serial_entry = sub_group[search_key]
        if serial_entry in search_translation.keys():
            serial_entry = search_translation[serial_entry]
        elif '*' in search_translation.keys() and search_translation['*'] != '*':
            serial_entry = search_translation['*']

        serial_number.append(serial_entry)

    return '/'.join(serial_number)




serial = generate_serial_number('/Users/jlaura/Desktop/Apollo15/AS15-M-0296_sub4.cub')
print(serial)
```

%% Output

    SpacecraftName ['IsisCube', 'Instrument'] {'*': 'APOLLO15'}
    InstrumentId ['IsisCube', 'Instrument'] {'*': '*'}
    StartTime ['IsisCube', 'Instrument'] {'*': '*'}
    APOLLO15/METRIC/1971-07-31T01:24:36.970