Skip to content
Snippets Groups Projects
Commit d6740b6a authored by Kelvin Rodriguez's avatar Kelvin Rodriguez Committed by Jesse Mapel
Browse files

Updated load interface (#253)

* kernel list support added

* simple spice as fixture

* removed abstractmethod tags

* added property tags

* addressed comments

* removed config, combined kernel and metakernel methods, added test for metakerenl queries

* added test to env var

* Add short name test for dawn

* added sorted driver list

* i don't remmeber

* updated tests to only need one reload for ale

* removed uneeded header

* removed cpp load notebook

* removed vis module

* updated write_metakernel code to use abspaths

* updated tests, removed json from repo and now is conda installed from conda-forge

* removed redundant json conversion in load func

* addressed commnets

* updated tests as per comments
parent 2fe89e3f
No related branches found
No related tags found
No related merge requests found
Showing
with 492 additions and 20587 deletions
...@@ -17,8 +17,15 @@ class Driver(): ...@@ -17,8 +17,15 @@ class Driver():
file : str file : str
path to file to be parsed path to file to be parsed
""" """
if not props:
self._props = {}
elif isinstance(props, dict):
self._props = props self._props = props
elif isinstance(props, str):
self._props = json.loads(props)
else:
raise Exception(f'Invalid props arg: {props}')
self._num_quaternions = num_quats self._num_quaternions = num_quats
self._num_ephem = num_ephem self._num_ephem = num_ephem
self._file = file self._file = file
......
import spiceypy as spice import spiceypy as spice
import numpy as np import numpy as np
import ale
from ale.base.type_sensor import Framer from ale.base.type_sensor import Framer
from ale.transformation import FrameChain from ale.transformation import FrameChain
from ale.rotation import TimeDependentRotation from ale.rotation import TimeDependentRotation
...@@ -31,7 +32,13 @@ class NaifSpice(): ...@@ -31,7 +32,13 @@ class NaifSpice():
if 'kernels' in self._props.keys(): if 'kernels' in self._props.keys():
self._kernels = self._props['kernels'] self._kernels = self._props['kernels']
else: else:
search_results = util.get_metakernels(missions=self.short_mission_name, years=self.utc_start_time.year, versions='latest') if not ale.spice_root:
raise EnvironmentError(f'ale.spice_root is not set, cannot search for metakernels. ale.spice_root = "{ale.spice_root}"')
search_results = util.get_metakernels(ale.spice_root, missions=self.short_mission_name, years=self.utc_start_time.year, versions='latest')
if search_results['count'] == 0:
raise ValueError(f'Failed to find metakernels. mission: {self.short_mission_name}, year:{self.utc_start_time.year}, versions="latest" spice root = "{ale.spice_root}"')
self._kernels = [search_results['data'][0]['path']] self._kernels = [search_results['data'][0]['path']]
return self._kernels return self._kernels
......
...@@ -12,9 +12,11 @@ import numpy as np ...@@ -12,9 +12,11 @@ import numpy as np
import datetime import datetime
from datetime import datetime, date from datetime import datetime, date
import traceback import traceback
from collections import OrderedDict
from ale.formatters.usgscsm_formatter import to_usgscsm from ale.formatters.usgscsm_formatter import to_usgscsm
from ale.formatters.isis_formatter import to_isis from ale.formatters.isis_formatter import to_isis
from ale.base.data_isis import IsisSpice
from abc import ABC from abc import ABC
...@@ -25,28 +27,24 @@ __driver_modules__ = [importlib.import_module('.'+m, package='ale.drivers') for ...@@ -25,28 +27,24 @@ __driver_modules__ = [importlib.import_module('.'+m, package='ale.drivers') for
__formatters__ = {'usgscsm': to_usgscsm, __formatters__ = {'usgscsm': to_usgscsm,
'isis': to_isis} 'isis': to_isis}
drivers = dict(chain.from_iterable(inspect.getmembers(dmod, lambda x: inspect.isclass(x) and "_driver" in x.__module__) for dmod in __driver_modules__)) def sort_drivers(drivers=[]):
return list(sorted(drivers, key=lambda x:IsisSpice in x.__bases__, reverse=True))
class JsonEncoder(json.JSONEncoder): class AleJsonEncoder(json.JSONEncoder):
def default(self, obj): 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): if isinstance(obj, set):
return list(obj) return list(obj)
if isinstance(obj, np.nan): if isinstance(obj, np.integer):
return None return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, datetime.date):
return obj.isoformat()
return json.JSONEncoder.default(self, obj) return json.JSONEncoder.default(self, obj)
def load(label, props={}, formatter='usgscsm', verbose=False):
def load(file_path, formatter='usgscsm'):
""" """
Attempt to load a given label from all possible drivers Attempt to load a given label from all possible drivers
...@@ -58,18 +56,25 @@ def load(file_path, formatter='usgscsm'): ...@@ -58,18 +56,25 @@ def load(file_path, formatter='usgscsm'):
if isinstance(formatter, str): if isinstance(formatter, str):
formatter = __formatters__[formatter] formatter = __formatters__[formatter]
for name, driver in drivers.items(): drivers = chain.from_iterable(inspect.getmembers(dmod, lambda x: inspect.isclass(x) and "_driver" in x.__module__) for dmod in __driver_modules__)
print(f'Trying {name}') drivers = sort_drivers([d[1] for d in drivers])
for driver in drivers:
if verbose:
print(f'Trying {driver}')
try: try:
res = driver(label) res = driver(label, props=props)
# get instrument_id to force early failure
res.instrument_id
with res as driver: with res as driver:
return formatter(driver) return formatter(driver)
except Exception as e: except Exception as e:
if verbose:
print(f'Failed: {e}\n') print(f'Failed: {e}\n')
traceback.print_exc() traceback.print_exc()
raise Exception('No Such Driver for Label') raise Exception('No Such Driver for Label')
def loads(label, props='', formatter='usgscsm'):
def loads(label, formatter='usgscsm'): res = load(label, props, formatter)
res = load(label, formatter) return json.dumps(res, cls=AleJsonEncoder)
return json.dumps(res, cls=JsonEncoder)
import json
import numpy as np
import datetime
class NumpyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return list(obj)
if isinstance(obj, np.integer):
return int(obj)
elif isinstance(obj, np.floating):
return float(obj)
elif isinstance(obj, np.ndarray):
return obj.tolist()
elif isinstance(obj, datetime.date):
return obj.isoformat()
return json.JSONEncoder.default(self, obj)
import json import json
from ale.rotation import ConstantRotation, TimeDependentRotation from ale.rotation import ConstantRotation, TimeDependentRotation
from ale.encoders import NumpyEncoder
from networkx.algorithms.shortest_paths.generic import shortest_path from networkx.algorithms.shortest_paths.generic import shortest_path
...@@ -93,4 +92,4 @@ def to_isis(driver): ...@@ -93,4 +92,4 @@ def to_isis(driver):
sun_position['Velocities'] = velocities sun_position['Velocities'] = velocities
meta_data['SunPosition'] = sun_position meta_data['SunPosition'] = sun_position
return json.dumps(meta_data, cls=NumpyEncoder) return meta_data
...@@ -5,7 +5,6 @@ from scipy.interpolate import interp1d, BPoly ...@@ -5,7 +5,6 @@ from scipy.interpolate import interp1d, BPoly
from ale.transformation import FrameChain from ale.transformation import FrameChain
from ale.base.type_sensor import LineScanner, Framer from ale.base.type_sensor import LineScanner, Framer
from ale.encoders import NumpyEncoder
from ale.rotation import ConstantRotation, TimeDependentRotation from ale.rotation import ConstantRotation, TimeDependentRotation
def to_usgscsm(driver): def to_usgscsm(driver):
...@@ -147,4 +146,4 @@ def to_usgscsm(driver): ...@@ -147,4 +146,4 @@ def to_usgscsm(driver):
raise Exception('No CSM sensor model name found!') raise Exception('No CSM sensor model name found!')
# Convert to JSON object # Convert to JSON object
return json.dumps(isd_data, cls=NumpyEncoder) return isd_data
...@@ -8,6 +8,7 @@ dependencies: ...@@ -8,6 +8,7 @@ dependencies:
- eigen - eigen
- gsl - gsl
- jupyter - jupyter
- nlohmann_json
- numba - numba
- numpy - numpy
- openblas>=0.3.0 - openblas>=0.3.0
......
#ifndef ALE_INCLUDE_ALE_H #ifndef ALE_INCLUDE_ALE_H
#define ALE_INCLUDE_ALE_H #define ALE_INCLUDE_ALE_H
#include <json.hpp> #include <nlohmann/json.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
...@@ -116,7 +116,7 @@ namespace ale { ...@@ -116,7 +116,7 @@ namespace ale {
*@return *@return
*/ */
double interpolate(std::vector<double> points, std::vector<double> times, double time, interpolation interp, int d); double interpolate(std::vector<double> points, std::vector<double> times, double time, interpolation interp, int d);
std::string load(std::string filename); std::string load(std::string filename, std::string props="", std::string formatter="usgscsm");
} }
#endif // ALE_H #endif // ALE_H
JSON for Modern C++ is licensed under the MIT License
<http://opensource.org/licenses/MIT>:
Copyright (c) 2013-2017 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Source diff could not be displayed: it is too large. Options to address this: view the blob.
%% Cell type:code id: tags:
``` C++11
#pragma cling add_include_path("/home/krodriguez/repos/ale/include/")
#pragma cling add_include_path("/home/krodriguez/repos/ale/include/json")
#pragma cling add_include_path("/data/big/anaconda3/envs/ale/include/python3.7m")
#pragma cling load("/home/krodriguez/repos/ale/build/libale.so")
```
%% Cell type:code id: tags:
``` C++11
#include "Python.h"
#include "ale.h"
#include <iostream>
#include <string.h>
std::string test_lro_label =
"PDS_VERSION_ID = PDS3\n"
"\n"
"/*FILE CHARACTERISTICS*/\n"
"RECORD_TYPE = FIXED_LENGTH\n"
"RECORD_BYTES = 5064\n"
"FILE_RECORDS = 13313\n"
"LABEL_RECORDS = 1\n"
"^IMAGE = 2\n"
"\n"
"/*DATA IDENTIFICATION*/\n"
"DATA_SET_ID = \"LRO-L-LROC-2-EDR-V1.0\"\n"
"ORIGINAL_PRODUCT_ID = nacl0002fc60\n"
"PRODUCT_ID = M128963531LE\n"
"MISSION_NAME = \"LUNAR RECONNAISSANCE ORBITER\"\n"
"MISSION_PHASE_NAME = \"NOMINAL MISSION\"\n"
"INSTRUMENT_HOST_NAME = \"LUNAR RECONNAISSANCE ORBITER\"\n"
"INSTRUMENT_HOST_ID = LRO\n"
"INSTRUMENT_NAME = \"LUNAR RECONNAISSANCE ORBITER CAMERA\"\n"
"INSTRUMENT_ID = LROC\n"
"LRO:PREROLL_TIME = 2010-05-20T02:57:44.373\n"
"START_TIME = 2010-05-20T02:57:44.720\n"
"STOP_TIME = 2010-05-20T02:57:49.235\n"
"LRO:SPACECRAFT_CLOCK_PREROLL_COUNT = \"1/296017064:22937\"\n"
"SPACECRAFT_CLOCK_START_COUNT = \"1/296017064:45694\"\n"
"SPACECRAFT_CLOCK_STOP_COUNT = \"1/296017069:13866\"\n"
"ORBIT_NUMBER = 4138\n"
"PRODUCER_ID = LRO_LROC_TEAM\n"
"PRODUCT_CREATION_TIME = 2013-09-16T19:57:12\n"
"PRODUCER_INSTITUTION_NAME = \"ARIZONA STATE UNIVERSITY\"\n"
"PRODUCT_TYPE = EDR\n"
"PRODUCT_VERSION_ID = \"v1.8\"\n"
"UPLOAD_ID = \"SC_2010140_0000_A_V01.txt\"\n"
"\n"
"/*DATA DESCRIPTION*/\n"
"TARGET_NAME = \"MOON\"\n"
"RATIONALE_DESC = \"TARGET OF OPPORTUNITY\"\n"
"FRAME_ID = LEFT\n"
"DATA_QUALITY_ID = \"0\"\n"
"DATA_QUALITY_DESC = \"The DATA_QUALITY_ID is set to an 8-bit\n"
" value that encodes the following data quality information for the\n"
" observation. For each bit a value of 0 means FALSE and a value of 1 means\n"
" TRUE. More information about the data quality ID can be found in the LROC\n"
" EDR/CDR SIS, section 3.3 'Label and Header Descriptions'.\n"
" Bit 1: Temperature of focal plane array is out of bounds.\n"
" Bit 2: Threshold for saturated pixels is reached.\n"
" Bit 3: Threshold for under-saturated pixels is reached.\n"
" Bit 4: Observation is missing telemetry packets.\n"
" Bit 5: SPICE information is bad or missing.\n"
" Bit 6: Observation or housekeeping information is bad or missing.\n"
" Bit 7: Spare.\n"
" Bit 8: Spare.\"\n"
"\n"
"/*ENVIRONMENT*/\n"
"LRO:TEMPERATURE_SCS = 4.51 <degC>\n"
"LRO:TEMPERATURE_FPA = 17.88 <degC>\n"
"LRO:TEMPERATURE_FPGA = -12.33 <degC>\n"
"LRO:TEMPERATURE_TELESCOPE = 5.91 <degC>\n"
"LRO:TEMPERATURE_SCS_RAW = 2740\n"
"LRO:TEMPERATURE_FPA_RAW = 2107\n"
"LRO:TEMPERATURE_FPGA_RAW = 3418\n"
"LRO:TEMPERATURE_TELESCOPE_RAW = 2675\n"
"\n"
"/*IMAGING PARAMETERS*/\n"
"CROSSTRACK_SUMMING = 1\n"
"BANDWIDTH = 300 <nm>\n"
"CENTER_FILTER_WAVELENGTH = 600 <nm>\n"
"LINE_EXPOSURE_DURATION = 0.337600 <ms>\n"
"LRO:LINE_EXPOSURE_CODE = 0\n"
"LRO:DAC_RESET_LEVEL = 198\n"
"LRO:CHANNEL_A_OFFSET = 60\n"
"LRO:CHANNEL_B_OFFSET = 123\n"
"LRO:COMPAND_CODE = 3\n"
"LRO:LINE_CODE = 13\n"
"LRO:BTERM = (0,16,69,103,128)\n"
"LRO:MTERM = (0.5,0.25,0.125,0.0625,0.03125)\n"
"LRO:XTERM = (0,64,424,536,800)\n"
"LRO:COMPRESSION_FLAG = 1\n"
"LRO:MODE = 7\n"
"\n"
"/*DATA OBJECT*/\n"
"OBJECT = IMAGE\n"
" LINES = 13312\n"
" LINE_SAMPLES = 5064\n"
" SAMPLE_BITS = 8\n"
" SAMPLE_TYPE = LSB_INTEGER\n"
" UNIT = \"RAW_INSTRUMENT_COUNT\"\n"
" MD5_CHECKSUM = \"0fe91f4b2e93083ee0093e7c8d05f3bc\"\n"
"END_OBJECT = IMAGE\n"
"END\n";
```
%% Cell type:code id: tags:
``` C++11
std::string label;
```
%% Cell type:code id: tags:
``` C++11
label = load(test_lro_label);
```
%% Cell type:code id: tags:
``` C++11
// label
```
%% Cell type:code id: tags:
``` C++11
using json = nlohmann::json;
json jlabel = json::parse(label)
```
%% Cell type:code id: tags:
``` C++11
std::vector<double> orientations = jlabel.at("sensor_orientation").at(0).get<std::vector<double>>()
```
%% Cell type:code id: tags:
``` C++11
orientations
```
%% Output
{ 0.622216, 0.274174, -0.668159, 0.30206 }
%% Cell type:code id: tags:
``` C++11
```
#include "ale.h" #include "ale.h"
#include <json.hpp> #include <nlohmann/json.hpp>
#include <gsl/gsl_interp.h> #include <gsl/gsl_interp.h>
#include <gsl/gsl_spline.h> #include <gsl/gsl_spline.h>
...@@ -337,7 +337,7 @@ namespace ale { ...@@ -337,7 +337,7 @@ namespace ale {
return ""; return "";
} }
std::string load(std::string filename) { std::string load(std::string filename, std::string props, std::string formatter) {
static bool first_run = true; static bool first_run = true;
if(first_run) { if(first_run) {
// Initialize the Python interpreter but only once. // Initialize the Python interpreter but only once.
...@@ -359,25 +359,35 @@ namespace ale { ...@@ -359,25 +359,35 @@ namespace ale {
if(!pFunc) { if(!pFunc) {
// import errors do not set a PyError flag, need to use a custom // import errors do not set a PyError flag, need to use a custom
// error message instead. // error message instead.
throw runtime_error("Failed to import ale.load function from Python." throw runtime_error("Failed to import ale.loads function from Python."
"This Usually indicates an error in the Ale Python Library." "This Usually indicates an error in the Ale Python Library."
"Check if Installed correctly and the function ale.loads exists."); "Check if Installed correctly and the function ale.loads exists.");
} }
// Create a Python tuple to hold the arguments to the method. // Create a Python tuple to hold the arguments to the method.
PyObject *pArgs = PyTuple_New(1); PyObject *pArgs = PyTuple_New(3);
if(!pArgs) { if(!pArgs) {
throw runtime_error(getPyTraceback()); throw runtime_error(getPyTraceback());
} }
// Set the Python int as the first and second arguments to the method. // Set the Python int as the first and second arguments to the method.
PyObject *pString = PyUnicode_FromString(filename.c_str()); PyObject *pStringFileName = PyUnicode_FromString(filename.c_str());
PyTuple_SetItem(pArgs, 0, pString); PyTuple_SetItem(pArgs, 0, pStringFileName);
PyObject *pStringProps = PyUnicode_FromString(props.c_str());
PyTuple_SetItem(pArgs, 1, pStringProps);
PyObject *pStringFormatter = PyUnicode_FromString(formatter.c_str());
PyTuple_SetItem(pArgs, 2, pStringFormatter);
// Call the function with the arguments. // Call the function with the arguments.
PyObject* pResult = PyObject_CallObject(pFunc, pArgs); PyObject* pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs); Py_DECREF(pArgs);
Py_DECREF(pString); Py_DECREF(pStringFileName);
Py_DECREF(pStringProps);
Py_DECREF(pStringFormatter);
if(!pResult) { if(!pResult) {
throw invalid_argument(getPyTraceback()); throw invalid_argument(getPyTraceback());
} }
......
...@@ -3,6 +3,8 @@ import os ...@@ -3,6 +3,8 @@ import os
import numpy as np import numpy as np
import ale import ale
from glob import glob
class SimpleSpice(): class SimpleSpice():
def scs2e(self, *args): def scs2e(self, *args):
return 0.1 return 0.1
...@@ -46,7 +48,20 @@ image_2_data = {} ...@@ -46,7 +48,20 @@ image_2_data = {}
for d in dirs: for d in dirs:
tmp = os.path.join(data_root, d) tmp = os.path.join(data_root, d)
image_2_data[d] = [os.path.join(tmp, f) for f in os.listdir(tmp) if not f.startswith('.')] image_2_data[d] = [os.path.join(tmp, f) for f in os.listdir(tmp) if not f.startswith('.') and os.path.splitext(f)[1] != '.lbl']
def get_image_label(image, label_type='pds3'):
if not isinstance(image, str):
try:
image = str(image)
except:
raise KeyError('Cannot coerce requested image name to string')
label_file = glob(os.path.join(data_root, '*',f'{image}_{label_type}.lbl'))
if not label_file:
raise Exception(f'Could not find label file for {image}')
return label_file[0]
def get_image_kernels(image): def get_image_kernels(image):
""" """
......
Object = IsisCube
Object = Core
StartByte = 65537
Format = Tile
TileSamples = 512
TileLines = 512
Group = Dimensions
Samples = 512
Lines = 512
Bands = 1
End_Group
Group = Pixels
Type = Real
ByteOrder = Lsb
Base = 0.0
Multiplier = 1.0
End_Group
End_Object
Group = Instrument
SpacecraftName = Messenger
InstrumentName = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA"
InstrumentId = MDIS-NAC
TargetName = Mercury
OriginalTargetName = MERCURY
StartTime = 2015-04-24T04:42:19.666463
StopTime = 2015-04-24T04:42:19.667463
SpacecraftClockCount = 2/0072174528:989000
MissionPhaseName = "MERCURY ORBIT YEAR 5"
ExposureDuration = 1 <MS>
ExposureType = AUTO
DetectorTemperature = -11.62 <DEGC>
FocalPlaneTemperature = 4.07 <DEGC>
FilterTemperature = N/A
OpticsTemperature = 17.08 <DEGC>
AttitudeQuality = Ok
FilterWheelPosition = 17348
PivotPosition = 15
FpuBinningMode = 1
PixelBinningMode = 0
SubFrameMode = 0
JailBars = 0
DpuId = DPU-A
PivotAngle = 0.04119873046875 <Degrees>
Unlutted = 1
LutInversionTable = $messenger/calibration/LUT_INVERT/MDISLUTINV_0.TAB
End_Group
Group = Archive
DataSetId = MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0
DataQualityId = 0000001000000000
ProducerId = "APPLIED COHERENT TECHNOLOGY CORPORATION"
EdrSourceProductId = 1072174528_IM6
ProductId = EN1072174528M
SequenceName = N/A
ObservationId = 8386282
ObservationType = (Monochrome, "Ridealong NAC")
SiteId = N/A
MissionElapsedTime = 72174528
EdrProductCreationTime = 2015-04-30T18:25:23
ObservationStartTime = 2015-04-24T04:42:19.666463
SpacecraftClockStartCount = 2/0072174528:989000
SpacecraftClockStopCount = 2/0072174528:990000
Exposure = 1
CCDTemperature = 1139
OriginalFilterNumber = 0
OrbitNumber = 4086
YearDoy = 2015114
SourceProductId = ("EN1072174528M", "MDISLUTINV_0")
End_Group
Group = BandBin
Name = "748 BP 53"
Number = 2
Center = 747.7 <NM>
Width = 52.6 <NM>
End_Group
Group = Kernels
NaifIkCode = -236820
End_Group
End_Object
Object = Label
Bytes = 65536
End_Object
Object = OriginalLabel
Name = IsisCube
StartByte = 1114113
Bytes = 7944
End_Object
End
PDS_VERSION_ID = PDS3
/* ** FILE FORMAT ** */
RECORD_TYPE = FIXED_LENGTH
RECORD_BYTES = 512
FILE_RECORDS = 0526
LABEL_RECORDS = 0014
/* ** POINTERS TO START BYTE OFFSET OF OBJECTS IN IMAGE FILE ** */
^IMAGE = 0015
/* ** GENERAL DATA DESCRIPTION PARAMETERS ** */
MISSION_NAME = MESSENGER
INSTRUMENT_HOST_NAME = MESSENGER
DATA_SET_ID = MESS-E/V/H-MDIS-2-EDR-RAWDATA-V1.0
DATA_QUALITY_ID = 0000001000000000
PRODUCT_ID = EN1072174528M
PRODUCT_VERSION_ID = 3
SOURCE_PRODUCT_ID = 1072174528_IM6
PRODUCER_INSTITUTION_NAME = "APPLIED COHERENT TECHNOLOGY CORPORATION"
SOFTWARE_NAME = MDIS2EDR
SOFTWARE_VERSION_ID = 1.1
MISSION_PHASE_NAME = "MERCURY ORBIT YEAR 5"
TARGET_NAME = MERCURY
SEQUENCE_NAME = N/A
OBSERVATION_ID = 8386282
OBSERVATION_TYPE = (Monochrome, "Ridealong NAC")
SITE_ID = N/A
/* ** TIME PARAMETERS ** */
START_TIME = 2015-04-24T04:42:19.666463
STOP_TIME = 2015-04-24T04:42:19.667463
SPACECRAFT_CLOCK_START_COUNT = 2/0072174528:989000
SPACECRAFT_CLOCK_STOP_COUNT = 2/0072174528:990000
ORBIT_NUMBER = 4086
PRODUCT_CREATION_TIME = 2015-04-30T18:25:23
/* ** INSTRUMENT ENGINEERING PARAMETERS ** */
INSTRUMENT_NAME = "MERCURY DUAL IMAGING SYSTEM NARROW ANGLE
CAMERA"
INSTRUMENT_ID = MDIS-NAC
FILTER_NAME = "748 BP 53"
FILTER_NUMBER = N/A
CENTER_FILTER_WAVELENGTH = 747.7 <NM>
BANDWIDTH = 52.6 <NM>
EXPOSURE_DURATION = 1 <MS>
EXPOSURE_TYPE = AUTO
DETECTOR_TEMPERATURE = -11.62 <DEGC>
FOCAL_PLANE_TEMPERATURE = 4.07 <DEGC>
FILTER_TEMPERATURE = N/A
OPTICS_TEMPERATURE = 17.08 <DEGC>
/* ** INSTRUMENT RAW PARAMETERS ** */
MESS:MET_EXP = 72174528
MESS:IMG_ID_LSB = 63210
MESS:IMG_ID_MSB = 127
MESS:ATT_CLOCK_COUNT = 72174526
MESS:ATT_Q1 = -0.21372859
MESS:ATT_Q2 = 0.89161116
MESS:ATT_Q3 = 0.18185951
MESS:ATT_Q4 = -0.35535437
MESS:ATT_FLAG = 6
MESS:PIV_POS_MOTOR = 24711
MESS:PIV_GOAL = N/A
MESS:PIV_POS = 15
MESS:PIV_READ = 20588
MESS:PIV_CAL = -26758
MESS:FW_GOAL = 17376
MESS:FW_POS = 17348
MESS:FW_READ = 17348
MESS:CCD_TEMP = 1139
MESS:CAM_T1 = 532
MESS:CAM_T2 = 590
MESS:EXPOSURE = 1
MESS:DPU_ID = 0
MESS:IMAGER = 1
MESS:SOURCE = 0
MESS:FPU_BIN = 1
MESS:COMP12_8 = 1
MESS:COMP_ALG = 1
MESS:COMP_FST = 1
MESS:TIME_PLS = 2
MESS:LATCH_UP = 0
MESS:EXP_MODE = 1
MESS:PIV_STAT = 3
MESS:PIV_MPEN = 0
MESS:PIV_PV = 1
MESS:PIV_RV = 1
MESS:FW_PV = 1
MESS:FW_RV = 1
MESS:AEX_STAT = 384
MESS:AEX_STHR = 5
MESS:AEX_TGTB = 1830
MESS:AEX_BACB = 240
MESS:AEX_MAXE = 989
MESS:AEX_MINE = 1
MESS:DLNKPRIO = 6
MESS:WVLRATIO = 0
MESS:PIXELBIN = 0
MESS:SUBFRAME = 0
MESS:SUBF_X1 = 0
MESS:SUBF_Y1 = 0
MESS:SUBF_DX1 = 0
MESS:SUBF_DY1 = 0
MESS:SUBF_X2 = 0
MESS:SUBF_Y2 = 0
MESS:SUBF_DX2 = 0
MESS:SUBF_DY2 = 0
MESS:SUBF_X3 = 0
MESS:SUBF_Y3 = 0
MESS:SUBF_DX3 = 0
MESS:SUBF_DY3 = 0
MESS:SUBF_X4 = 0
MESS:SUBF_Y4 = 0
MESS:SUBF_DX4 = 0
MESS:SUBF_DY4 = 0
MESS:SUBF_X5 = 0
MESS:SUBF_Y5 = 0
MESS:SUBF_DX5 = 0
MESS:SUBF_DY5 = 0
MESS:CRITOPNV = 0
MESS:JAILBARS = 0
MESS:JB_X0 = 0
MESS:JB_X1 = 0
MESS:JB_SPACE = 0
/* ** GEOMETRY INFORMATION ** */
RIGHT_ASCENSION = 166.36588 <DEG>
DECLINATION = -43.07155 <DEG>
TWIST_ANGLE = 139.85881 <DEG>
RA_DEC_REF_PIXEL = (256.00000, 256.00000)
RETICLE_POINT_RA = (167.79928, 166.25168, 166.49610,
164.92873) <DEG>
RETICLE_POINT_DECLINATION = (-42.96478, -42.01944, -44.11712,
-43.14701) <DEG>
/* ** TARGET PARAMETERS ** */
SC_TARGET_POSITION_VECTOR = (1844.15964, -966.49167, 1322.58870) <KM>
TARGET_CENTER_DISTANCE = 2466.63167 <KM>
/* ** TARGET WITHIN SENSOR FOV ** */
SLANT_DISTANCE = 27.62593 <KM>
CENTER_LATITUDE = 46.26998 <DEG>
CENTER_LONGITUDE = 248.17066 <DEG>
HORIZONTAL_PIXEL_SCALE = 1.40755 <M>
VERTICAL_PIXEL_SCALE = 1.40755 <M>
SMEAR_MAGNITUDE = 5.46538 <PIXELS>
SMEAR_AZIMUTH = 116.74551 <DEG>
NORTH_AZIMUTH = 285.65482 <DEG>
RETICLE_POINT_LATITUDE = (46.27574, 46.28052, 46.25946, 46.26440) <DEG>
RETICLE_POINT_LONGITUDE = (248.15510, 248.17933, 248.16185,
248.18619) <DEG>
/* ** SPACECRAFT POSITION WITH RESPECT TO CENTRAL BODY ** */
SUB_SPACECRAFT_LATITUDE = 46.31528 <DEG>
SUB_SPACECRAFT_LONGITUDE = 248.41010 <DEG>
SPACECRAFT_ALTITUDE = 26.63167 <KM>
SUB_SPACECRAFT_AZIMUTH = 0.75989 <DEG>
/* ** SPACECRAFT LOCATION ** */
SPACECRAFT_SOLAR_DISTANCE = 46897197.01783 <KM>
SC_SUN_POSITION_VECTOR = (-11803272.08016, 39512922.09768,
22332909.43056) <KM>
SC_SUN_VELOCITY_VECTOR = (59.06790, 11.91448, -2.90638) <KM/S>
/* ** VIEWING AND LIGHTING GEOMETRY (SUN ON TARGET) ** */
SOLAR_DISTANCE = 46897845.70492 <KM>
SUB_SOLAR_AZIMUTH = 179.40784 <DEG>
SUB_SOLAR_LATITUDE = 0.03430 <DEG>
SUB_SOLAR_LONGITUDE = 180.75406 <DEG>
INCIDENCE_ANGLE = 74.58267 <DEG>
PHASE_ANGLE = 90.08323 <DEG>
EMISSION_ANGLE = 15.50437 <DEG>
LOCAL_HOUR_ANGLE = 247.41661 <DEG>
Object = IMAGE
LINES = 512
LINE_SAMPLES = 512
SAMPLE_TYPE = UNSIGNED_INTEGER
SAMPLE_BITS = 8
UNIT = N/A
DARK_STRIP_MEAN = 28.711
/* ** IMAGE STATISTICS OF ** */
/* ** THE EXPOSED CCD AREA ** */
MINIMUM = 28.000
MAXIMUM = 78.000
MEAN = 46.360
STANDARD_DEVIATION = 10.323
/* ** PIXEL COUNTS ** */
SATURATED_PIXEL_COUNT = 0
MISSING_PIXELS = 0
End_Object
/* ** GEOMETRY FOR EACH SUBFRAME ** */
Group = SUBFRAME1_PARAMETERS
RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A)
RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A)
End_Group
Group = SUBFRAME2_PARAMETERS
RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A)
RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A)
End_Group
Group = SUBFRAME3_PARAMETERS
RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A)
RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A)
End_Group
Group = SUBFRAME4_PARAMETERS
RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A)
RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A)
End_Group
Group = SUBFRAME5_PARAMETERS
RETICLE_POINT_LATITUDE = (N/A, N/A, N/A, N/A)
RETICLE_POINT_LONGITUDE = (N/A, N/A, N/A, N/A)
End_Group
End
...@@ -2,14 +2,12 @@ import pytest ...@@ -2,14 +2,12 @@ import pytest
import ale import ale
from ale.drivers import co_drivers from ale.drivers import co_drivers
from unittest.mock import PropertyMock, patch from unittest.mock import PropertyMock, patch
# 'Mock' the spice module where it is imported # 'Mock' the spice module where it is imported
from conftest import SimpleSpice, get_mockkernels from conftest import SimpleSpice, get_mockkernels
simplespice = SimpleSpice() simplespice = SimpleSpice()
co_drivers.spice = simplespice co_drivers.spice = simplespice
from ale.drivers.co_drivers import CassiniIssPds3LabelNaifSpiceDriver from ale.drivers.co_drivers import CassiniIssPds3LabelNaifSpiceDriver
......
...@@ -47,8 +47,8 @@ def test_target_frame_id(test_naif_data): ...@@ -47,8 +47,8 @@ def test_target_frame_id(test_naif_data):
bods2c.assert_called_once_with("TARGET") bods2c.assert_called_once_with("TARGET")
cidfrm.assert_called_once_with(12345) cidfrm.assert_called_once_with(12345)
def test_spice_kernel_list(test_naif_data_with_kernels): def test_spice_kernel_list(test_naif_data_with_kernels):
with patch('spiceypy.furnsh') as furnsh: with patch('spiceypy.furnsh') as furnsh:
with test_naif_data_with_kernels as t: with test_naif_data_with_kernels as t:
assert furnsh.call_args_list == [call('one'), call('two'), call('three'), call('four')] assert furnsh.call_args_list == [call('one'), call('two'), call('three'), call('four')]
...@@ -156,11 +156,11 @@ def driver(): ...@@ -156,11 +156,11 @@ def driver():
return TestDriver('') return TestDriver('')
def test_camera_version(driver): def test_camera_version(driver):
meta_data = json.loads(isis_formatter.to_isis(driver)) meta_data = isis_formatter.to_isis(driver)
assert meta_data['CameraVersion'] == 1 assert meta_data['CameraVersion'] == 1
def test_instrument_pointing(driver): def test_instrument_pointing(driver):
meta_data = json.loads(isis_formatter.to_isis(driver)) meta_data = isis_formatter.to_isis(driver)
pointing = meta_data['InstrumentPointing'] pointing = meta_data['InstrumentPointing']
assert pointing['TimeDependentFrames'] == [1000, 1] assert pointing['TimeDependentFrames'] == [1000, 1]
assert pointing['ConstantFrames'] == [1010, 1000] assert pointing['ConstantFrames'] == [1010, 1000]
...@@ -172,7 +172,7 @@ def test_instrument_pointing(driver): ...@@ -172,7 +172,7 @@ def test_instrument_pointing(driver):
np.testing.assert_equal(pointing['Quaternions'], np.array([[0, 0, 0, -1], [0, 0, 0, -1]])) np.testing.assert_equal(pointing['Quaternions'], np.array([[0, 0, 0, -1], [0, 0, 0, -1]]))
def test_instrument_position(driver): def test_instrument_position(driver):
meta_data = json.loads(isis_formatter.to_isis(driver)) meta_data = isis_formatter.to_isis(driver)
position = meta_data['InstrumentPosition'] position = meta_data['InstrumentPosition']
assert position['SpkTableStartTime'] == 800 assert position['SpkTableStartTime'] == 800
assert position['SpkTableEndTime'] == 900 assert position['SpkTableEndTime'] == 900
...@@ -182,7 +182,7 @@ def test_instrument_position(driver): ...@@ -182,7 +182,7 @@ def test_instrument_position(driver):
np.testing.assert_equal(position['Velocities'], np.array([[0, -1, -2], [-3, -4, -5]])) np.testing.assert_equal(position['Velocities'], np.array([[0, -1, -2], [-3, -4, -5]]))
def test_body_rotation(driver): def test_body_rotation(driver):
meta_data = json.loads(isis_formatter.to_isis(driver)) meta_data = isis_formatter.to_isis(driver)
rotation = meta_data['BodyRotation'] rotation = meta_data['BodyRotation']
assert rotation['TimeDependentFrames'] == [100, 1] assert rotation['TimeDependentFrames'] == [100, 1]
assert rotation['CkTableStartTime'] == 0 assert rotation['CkTableStartTime'] == 0
...@@ -192,7 +192,7 @@ def test_body_rotation(driver): ...@@ -192,7 +192,7 @@ def test_body_rotation(driver):
np.testing.assert_equal(rotation['Quaternions'], np.array([[0, 0, 0, -1], [0, 0, 0, -1]])) np.testing.assert_equal(rotation['Quaternions'], np.array([[0, 0, 0, -1], [0, 0, 0, -1]]))
def test_sun_position(driver): def test_sun_position(driver):
meta_data = json.loads(isis_formatter.to_isis(driver)) meta_data = isis_formatter.to_isis(driver)
position = meta_data['SunPosition'] position = meta_data['SunPosition']
assert position['SpkTableStartTime'] == 600 assert position['SpkTableStartTime'] == 600
assert position['SpkTableEndTime'] == 700 assert position['SpkTableEndTime'] == 700
...@@ -202,7 +202,7 @@ def test_sun_position(driver): ...@@ -202,7 +202,7 @@ def test_sun_position(driver):
np.testing.assert_equal(position['Velocities'], np.array([[0, -1, -2], [-3, -4, -5]])) np.testing.assert_equal(position['Velocities'], np.array([[0, -1, -2], [-3, -4, -5]]))
def test_naif_keywords(driver): def test_naif_keywords(driver):
meta_data = json.loads(isis_formatter.to_isis(driver)) meta_data = isis_formatter.to_isis(driver)
assert meta_data['NaifKeywords'] == { assert meta_data['NaifKeywords'] == {
'keyword_1' : 0, 'keyword_1' : 0,
'keyword_2' : 'test' 'keyword_2' : 'test'
......
...@@ -11,7 +11,6 @@ from unittest.mock import PropertyMock, patch ...@@ -11,7 +11,6 @@ from unittest.mock import PropertyMock, patch
from conftest import SimpleSpice, get_mockkernels from conftest import SimpleSpice, get_mockkernels
simplespice = SimpleSpice() simplespice = SimpleSpice()
selene_drivers.spice = simplespice selene_drivers.spice = simplespice
from ale.drivers.selene_drivers import KaguyaTcPds3NaifSpiceDriver from ale.drivers.selene_drivers import KaguyaTcPds3NaifSpiceDriver
......
import pytest
from importlib import reload
import json
import ale
from ale import util
from ale.drivers import sort_drivers
from ale.base.data_naif import NaifSpice
from ale.base.data_isis import IsisSpice
from conftest import get_image_label, get_image_kernels, convert_kernels
def test_priority(tmpdir, monkeypatch):
drivers = [type('FooNaifSpice', (NaifSpice,), {}), type('BarIsisSpice', (IsisSpice,), {}), type('BazNaifSpice', (NaifSpice,), {}), type('FubarIsisSpice', (IsisSpice,), {})]
sorted_drivers = sort_drivers(drivers)
assert all([IsisSpice in klass.__bases__ for klass in sorted_drivers[:2]])
def test_mess_load():
updated_kernels, _ = convert_kernels(get_image_kernels('EN1072174528M'))
label_file = get_image_label('EN1072174528M')
usgscsm_isd_str = ale.loads(label_file, props={'kernels': updated_kernels}, formatter='usgscsm')
usgscsm_isd_obj = json.loads(usgscsm_isd_str)
assert usgscsm_isd_obj['name_platform'] == 'MESSENGER'
assert usgscsm_isd_obj['name_sensor'] == 'MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA'
assert usgscsm_isd_obj['name_model'] == 'USGS_ASTRO_FRAME_SENSOR_MODEL'
def test_load_invalid_label():
with pytest.raises(Exception):
ale.load('Not a label path')
def test_loads_invalid_label():
with pytest.raises(Exception):
ale.loads('Not a label path')
def test_load_invalid_spice_root(monkeypatch):
monkeypatch.delenv('ALESPICEROOT', raising=False)
reload(ale)
label_file = get_image_label('EN1072174528M')
with pytest.raises(Exception):
ale.load(label_file)
def test_load_mes_from_metakernels(tmpdir, monkeypatch):
monkeypatch.setenv('ALESPICEROOT', str(tmpdir))
# reload module to repopulate ale.spice_root
reload(ale)
updated_kernels, _ = convert_kernels(get_image_kernels('EN1072174528M'))
label_file = get_image_label('EN1072174528M')
tmpdir.mkdir('mes')
with open(tmpdir.join('mes', 'mes_2015_v1.tm'), 'w+') as mk_file:
mk_str = util.write_metakernel_from_kernel_list(updated_kernels)
print(mk_str)
mk_file.write(mk_str)
usgscsm_isd_obj = ale.load(label_file, verbose=True)
assert usgscsm_isd_obj['name_platform'] == 'MESSENGER'
assert usgscsm_isd_obj['name_sensor'] == 'MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA'
assert usgscsm_isd_obj['name_model'] == 'USGS_ASTRO_FRAME_SENSOR_MODEL'
def test_load_mes_with_no_metakernels(tmpdir, monkeypatch):
monkeypatch.setenv('ALESPICEROOT', str(tmpdir))
# reload module to repopulate ale.spice_root
reload(ale)
updated_kernels, _ = convert_kernels(get_image_kernels('EN1072174528M'))
label_file = get_image_label('EN1072174528M')
tmpdir.mkdir('mes')
# intentially make an mk file with wrong year
with open(tmpdir.join('mes', 'mes_2016_v1.tm'), 'w+') as mk_file:
mk_str = util.write_metakernel_from_kernel_list(updated_kernels)
print(mk_str)
mk_file.write(mk_str)
with pytest.raises(Exception):
usgscsm_isd_obj = ale.load(label_file, verbose=True)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment