Skip to content
Snippets Groups Projects
Commit 4c7ad530 authored by Kelvin's avatar Kelvin
Browse files

added Kaguya TC driver

parent da2c6e20
No related branches found
No related tags found
No related merge requests found
......@@ -22,6 +22,22 @@ __driver_modules__ = [importlib.import_module('.'+m, package='ale.drivers') for
drivers = dict(chain.from_iterable(inspect.getmembers(dmod, lambda x: inspect.isclass(x) and "_driver" in x.__module__) for dmod in __driver_modules__))
class JsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.ndarray):
return obj.tolist()
if isinstance(obj, np.int64):
return int(obj)
if isinstance(obj, datetime.datetime):
return obj.__str__()
if isinstance(obj, bytes):
return obj.decode("utf-8")
if isinstance(obj, pvl.PVLModule):
return pvl.dumps(obj)
if isinstance(obj, set):
return list(obj)
return json.JSONEncoder.default(self, obj)
def load(label):
"""
......@@ -35,7 +51,7 @@ def load(label):
for name, driver in drivers.items():
print("Trying:", name)
try:
res = driver(label, *args, **kwargs)
res = driver(label)
if res.is_valid():
with res as r:
return res.to_dict()
......@@ -47,15 +63,5 @@ def load(label):
def loads(label):
class JsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, np.ndarray):
return obj.tolist()
if isinstance(obj, np.int64):
return int(obj)
if isinstance(obj, datetime.datetime):
return obj.__str__()
return json.JSONEncoder.default(self, obj)
res = load(label)
return json.dumps(res, cls=JsonEncoder)
......@@ -480,10 +480,7 @@ class PDS3():
@property
def line_exposure_duration(self):
try:
return self.label['LINE_EXPOSURE_DURATION'].value * 0.001 # Scale to seconds
except:
return np.nan
@property
def instrument_id(self):
......@@ -531,13 +528,6 @@ class PDS3():
self._starting_ephemeris_time = spice.scs2e(self.spacecraft_id, sclock)
return self._starting_ephemeris_time
@property
def exposure_duration(self):
try:
return self.label['EXPOSURE_DURATION'].value * 0.001 # Scale to seconds
except:
return np.nan
@property
def spacecraft_clock_stop_count(self):
sc = self.label.get('SPACECRAFT_CLOCK_STOP_COUNT', None)
......@@ -818,10 +808,6 @@ class Isis3():
"""
return self.label['IsisCube']['Core']['Dimensions']['Samples']
@property
def _exposure_duration(self):
return self.label['IsisCube']['Instrument']['ExposureDuration'].value * 0.001 # Scale to seconds
@property
def target_name(self):
"""
......@@ -1283,3 +1269,13 @@ class RadialDistortion():
"coefficients" : self._odtk
}
}
class TransverseDistortion():
@property
def optical_distortion(self):
return {
"Transverse": {
"x" : self._odtx,
"y" : self._odty
}
}
import spiceypy as spice
import os
import pvl
import ale
import numpy as np
from ale.drivers.base import Driver, LineScanner, PDS3, Spice, TransverseDistortion
class TcPds3Driver(Driver, LineScanner, PDS3, Spice, TransverseDistortion):
@property
def instrument_id(self):
instrument = self.label.get("INSTRUMENT_ID")
if instrument == "TC1":
return "LISM_TC1"
elif instrument == "TC2":
return "LISM_TC2"
@property
def metakernel(self):
self._metakernels = 'mk_kaguyatc.tm'
return self._metakernels
@property
def starting_ephemeris_time(self):
if not hasattr(self, '_starting_ephemeris_time'):
self._starting_ephemeris_time = self.label.get('CORRECTED_SC_CLOCK_START_COUNT').value
self._starting_ephemeris_time = spice.sct2e(self.spacecraft_id, self._starting_ephemeris_time)
return self._starting_ephemeris_time
@property
def _detector_center_line(self):
return 1
@property
def _detector_center_sample(self):
return spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[0]
@property
def _sensor_orientation(self):
if not hasattr(self, '_orientation'):
current_et = self.starting_ephemeris_time
qua = np.empty((self.number_of_quaternions, 4))
for i in range(self.number_of_quaternions):
# Find the rotation matrix
camera2bodyfixed = spice.pxform("J2000",
self.reference_frame,
current_et)
q = spice.m2q(camera2bodyfixed)
qua[i,:3] = q[1:]
qua[i,3] = q[0]
current_et += getattr(self, 'dt_quaternion', 0)
self._orientation = qua
return self._orientation.tolist()
@property
def focal2pixel_lines(self):
"""
Calculated using pixel pitch and 1/pixel pitch
"""
return [0, 0, 142.857142857]
@property
def focal2pixel_samples(self):
"""
Calculated using pixel pitch and 1/pixel pitch
"""
return [0, 142.857142857, 0]
@property
def _odtx(self):
"""
Returns
-------
: list
Optical distortion x coefficients
"""
return spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist()
@property
def _odty(self):
"""
Returns
-------
: list
Optical distortion y coefficients
"""
return spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist()
......@@ -109,6 +109,9 @@ class MdisPDS3Driver(PDS3, MdisSpice):
"""
return self.id_lookup[self.label['INSTRUMENT_ID']]
@property
def line_exposure_duration(self):
return self.label["EXPOSURE_DURATION"].value * 0.001
class MdisIsis3Driver(Isis3, MdisSpice):
"""
......
......@@ -23,6 +23,8 @@ class SimpleSpice():
return np.asarray([1,2,3,4])
def bodn2c(self, *args):
return "SPACE"
def sct2e(self, *args):
return 0.1
def get_mockkernels(self, *args):
return "some_metakernel"
import pytest
from ale.drivers import kaguya_driver
from ale.drivers.kaguya_driver import TcPds3Driver
# 'Mock' the spice module where it is imported
from conftest import SimpleSpice, get_mockkernels
simplespice = SimpleSpice()
kaguya_driver.spice = simplespice
TcPds3Driver.metakernel = get_mockkernels
@pytest.fixture
def kaguya_tclabel():
return """
PDS_VERSION_ID = "PDS3"
/*** FILE FORMAT ***/
RECORD_TYPE = "UNDEFINED"
FILE_NAME = "TC1W2B0_01_00296N081E2387.img"
PRODUCT_ID = "TC1W2B0_01_00296N081E2387"
DATA_FORMAT = "PDS"
/*** POINTERS TO START BYTE OFFSET OF OBJECTS IN FILE ***/
^IMAGE = 7609 <BYTES>
/*** GENERAL DATA DESCRIPTION PARAMETERS ***/
SOFTWARE_NAME = "RGC_TC_w_Level2B0 (based on RGC_TC_MI version 2.10.1)"
SOFTWARE_VERSION = "1.0.0"
PROCESS_VERSION_ID = "L2B"
PRODUCT_CREATION_TIME = 2013-07-16T20:12:53Z
PROGRAM_START_TIME = 2013-07-16T20:08:01Z
PRODUCER_ID = "LISM"
PRODUCT_SET_ID = "TC_w_Level2B0"
PRODUCT_VERSION_ID = "01"
REGISTERED_PRODUCT = "Y"
ILLUMINATION_CONDITION = "MORNING"
LEVEL2A_FILE_NAME = "TC1W2A0_02TSF00296_001_0022.img"
SPICE_METAKERNEL_FILE_NAME = "RGC_INF_TCv401IK_MIv200IK_SPv105IK_RISE100h_02_LongCK_D_V02_de421_110706.mk"
/*** SCENE RELATED PARAMETERS ***/
MISSION_NAME = "SELENE"
SPACECRAFT_NAME = "SELENE-M"
DATA_SET_ID = "TC1_Level2B"
INSTRUMENT_NAME = "Terrain Camera 1"
INSTRUMENT_ID = "TC1"
MISSION_PHASE_NAME = "InitialCheckout"
REVOLUTION_NUMBER = 296
STRIP_SEQUENCE_NUMBER = 1
SCENE_SEQUENCE_NUMBER = 22
UPPER_LEFT_DAYTIME_FLAG = "Day"
UPPER_RIGHT_DAYTIME_FLAG = "Day"
LOWER_LEFT_DAYTIME_FLAG = "Day"
LOWER_RIGHT_DAYTIME_FLAG = "Day"
TARGET_NAME = "MOON"
OBSERVATION_MODE_ID = "NORMAL"
SENSOR_DESCRIPTION = "Imagery type:Pushbroom. ImageryMode:Mono,Stereo. ExposureTimeMode:Long,Middle,Short. CompressionMode:NonComp,DCT. Q-table:32 patterns. H-table:4 patterns. SwathMode:F(Full),N(Nominal),H(Half). First pixel number:1(F),297(N),1172(H)."
SENSOR_DESCRIPTION2 = "Pixel size:7x7[micron^2](TC1/TC2). Wavelength range:430-850[nm](TC1/TC2). A/D rate:10[bit](TC1/TC2). Slant angle:+/-15[degree] (from nadir to +x of S/C)(TC1/TC2). Focal length:72.45/72.63[mm](TC1/TC2). F number:3.97/3.98(TC1/TC2)."
DETECTOR_STATUS = {"TC1:ON","TC2:ON","MV:OFF","MN:OFF","SP:ON"}
EXPOSURE_MODE_ID = "SHORT"
LINE_EXPOSURE_DURATION = 1.625000 <msec>
SPACECRAFT_CLOCK_START_COUNT = 878074165.1875 <sec>
SPACECRAFT_CLOCK_STOP_COUNT = 878074195.4450 <sec>
CORRECTED_SC_CLOCK_START_COUNT = 878074165.186621 <sec>
CORRECTED_SC_CLOCK_STOP_COUNT = 878074195.443901 <sec>
START_TIME = 2007-11-02T21:29:27.123714Z
STOP_TIME = 2007-11-02T21:29:57.381214Z
CORRECTED_START_TIME = 2007-11-02T21:29:27.122835Z
CORRECTED_STOP_TIME = 2007-11-02T21:29:57.380115Z
LINE_SAMPLING_INTERVAL = 6.500000 <msec>
CORRECTED_SAMPLING_INTERVAL = 6.499953 <msec>
UPPER_LEFT_LATITUDE = 7.290785 <deg>
UPPER_LEFT_LONGITUDE = 238.410490 <deg>
UPPER_RIGHT_LATITUDE = 7.288232 <deg>
UPPER_RIGHT_LONGITUDE = 238.991705 <deg>
LOWER_LEFT_LATITUDE = 8.820028 <deg>
LOWER_LEFT_LONGITUDE = 238.417311 <deg>
LOWER_RIGHT_LATITUDE = 8.817605 <deg>
LOWER_RIGHT_LONGITUDE = 238.999370 <deg>
LOCATION_FLAG = "A"
ROLL_CANT = "NO"
SCENE_CENTER_LATITUDE = 8.053752 <deg>
SCENE_CENTER_LONGITUDE = 238.704621 <deg>
INCIDENCE_ANGLE = 28.687 <deg>
EMISSION_ANGLE = 17.950 <deg>
PHASE_ANGLE = 31.600 <deg>
SOLAR_AZIMUTH_ANGLE = 108.126 <deg>
FOCAL_PLANE_TEMPERATURE = 18.85 <degC>
TELESCOPE_TEMPERATURE = 18.59 <degC>
SATELLITE_MOVING_DIRECTION = "-1"
FIRST_SAMPLED_LINE_POSITION = "UPPERMOST"
FIRST_DETECTOR_ELEMENT_POSITION = "LEFT"
A_AXIS_RADIUS = 1737.400 <km>
B_AXIS_RADIUS = 1737.400 <km>
C_AXIS_RADIUS = 1737.400 <km>
DEFECT_PIXEL_POSITION = "N/A"
/*** CAMERA RELATED PARAMETERS ***/
SWATH_MODE_ID = "FULL"
FIRST_PIXEL_NUMBER = 1
LAST_PIXEL_NUMBER = 1600
SPACECRAFT_ALTITUDE = 108.719 <km>
SPACECRAFT_GROUND_SPEED = 1.530 <km/sec>
TC1_TELESCOPE_TEMPERATURE = 18.70 <degC>
TC2_TELESCOPE_TEMPERATURE = 18.70 <degC>
DPU_TEMPERATURE = 14.60 <degC>
TM_TEMPERATURE = 18.01 <degC>
TM_RADIATOR_TEMPERATURE = 17.67 <degC>
Q_TABLE_ID = "N/A"
HUFFMAN_TABLE_ID = "N/A"
DATA_COMPRESSION_PERCENT_MEAN = 100.0
DATA_COMPRESSION_PERCENT_MAX = 100.0
DATA_COMPRESSION_PERCENT_MIN = 100.0
/*** DESCRIPTION OF OBJECTS CONTAINED IN THE FILE ***/
OBJECT = IMAGE
ENCODING_TYPE = "N/A"
ENCODING_COMPRESSION_PERCENT = 100.0
NOMINAL_LINE_NUMBER = 4088
NOMINAL_OVERLAP_LINE_NUMBER = 568
OVERLAP_LINE_NUMBER = 568
LINES = 4656
LINE_SAMPLES = 1600
SAMPLE_TYPE = "MSB_INTEGER"
SAMPLE_BITS = 16
IMAGE_VALUE_TYPE = "RADIANCE"
UNIT = "W/m**2/micron/sr"
SCALING_FACTOR = 1.30000e-02
OFFSET = 0.00000e+00
MIN_FOR_STATISTICAL_EVALUATION = 0
MAX_FOR_STATISTICAL_EVALUATION = 32767
SCENE_MAXIMUM_DN = 7602
SCENE_MINIMUM_DN = 1993
SCENE_AVERAGE_DN = 2888.6
SCENE_STDEV_DN = 370.2
SCENE_MODE_DN = 2682
SHADOWED_AREA_MINIMUM = 0
SHADOWED_AREA_MAXIMUM = 0
SHADOWED_AREA_PERCENTAGE = 0
INVALID_TYPE = ("SATURATION" , "MINUS" , "DUMMY_DEFECT" , "OTHER")
INVALID_VALUE = (-20000 , -21000 , -22000 , -23000)
INVALID_PIXELS = (0 , 0 , 0 , 0)
END_OBJECT = IMAGE
OBJECT = PROCESSING_PARAMETERS
DARK_FILE_NAME = "TC1_DRK_00293_02951_S_N_b05.csv"
FLAT_FILE_NAME = "TC1_FLT_00293_04739_N_N_b05.csv"
EFFIC_FILE_NAME = "TC1_EFF_PRFLT_N_N_v01.csv"
NONLIN_FILE_NAME = "TC1_NLT_PRFLT_N_N_v01.csv"
RAD_CNV_COEF = 3.790009 <W/m**2/micron/sr>
L2A_DEAD_PIXEL_THRESHOLD = 30
L2A_SATURATION_THRESHOLD = 1023
DARK_VALID_MINIMUM = -5
RADIANCE_SATURATION_THRESHOLD = 425.971000 <W/m**2/micron/sr>
END_OBJECT = PROCESSING_PARAMETERS
END
"""
def test_kaguya_creation(kaguya_tclabel):
with TcPds3Driver(kaguya_tclabel) as m:
d = m.to_dict()
assert isinstance(d, dict)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment