From 7a8e2036f60a12da1f03da2e5b38e7ea62e0be2b Mon Sep 17 00:00:00 2001 From: Adam Paquette <acpaquette@usgs.gov> Date: Tue, 11 Dec 2018 14:18:45 -0700 Subject: [PATCH] Adds stripped down version of pfeffernusse --- .gitignore | 24 + minipf/__init__.py | 0 minipf/config.py | 9 + minipf/controllers/__init__.py | 0 minipf/controllers/default_controller.py | 56 ++ minipf/controllers/util.py | 0 minipf/drivers/__init__.py | 31 + minipf/drivers/base.py | 391 +++++++++ minipf/drivers/cassini_driver.py | 69 ++ minipf/drivers/distortion.py | 25 + minipf/drivers/lro_driver.py | 38 + minipf/drivers/mdis_driver.py | 58 ++ minipf/drivers/mro_driver.py | 37 + minipf/models/__init__.py | 19 + minipf/models/base_model_.py | 69 ++ minipf/models/data.py | 90 ++ minipf/models/isd200.py | 820 ++++++++++++++++++ minipf/models/isd200_detector_center.py | 94 ++ minipf/models/isd200_focal_length_model.py | 124 +++ minipf/models/isd200_radii.py | 120 +++ minipf/models/isd200_reference_height.py | 124 +++ minipf/models/isd200_sensor_position.py | 117 +++ minipf/models/isd200_sun_position.py | 117 +++ minipf/models/optical_distortion.py | 92 ++ minipf/models/optical_distortion_radial.py | 64 ++ .../models/optical_distortion_transverse.py | 90 ++ minipf/models/quaternion.py | 37 + minipf/models/quaternions.py | 68 ++ minipf/models/request_isd.py | 64 ++ minipf/models/xyz.py | 37 + minipf/util.py | 215 +++++ setup.py | 27 + 32 files changed, 3126 insertions(+) create mode 100644 minipf/__init__.py create mode 100644 minipf/config.py create mode 100644 minipf/controllers/__init__.py create mode 100644 minipf/controllers/default_controller.py create mode 100644 minipf/controllers/util.py create mode 100644 minipf/drivers/__init__.py create mode 100644 minipf/drivers/base.py create mode 100644 minipf/drivers/cassini_driver.py create mode 100644 minipf/drivers/distortion.py create mode 100644 minipf/drivers/lro_driver.py create mode 100644 minipf/drivers/mdis_driver.py create mode 100644 minipf/drivers/mro_driver.py create mode 100644 minipf/models/__init__.py create mode 100644 minipf/models/base_model_.py create mode 100644 minipf/models/data.py create mode 100644 minipf/models/isd200.py create mode 100644 minipf/models/isd200_detector_center.py create mode 100644 minipf/models/isd200_focal_length_model.py create mode 100644 minipf/models/isd200_radii.py create mode 100644 minipf/models/isd200_reference_height.py create mode 100644 minipf/models/isd200_sensor_position.py create mode 100644 minipf/models/isd200_sun_position.py create mode 100644 minipf/models/optical_distortion.py create mode 100644 minipf/models/optical_distortion_radial.py create mode 100644 minipf/models/optical_distortion_transverse.py create mode 100644 minipf/models/quaternion.py create mode 100644 minipf/models/quaternions.py create mode 100644 minipf/models/request_isd.py create mode 100644 minipf/models/xyz.py create mode 100644 minipf/util.py create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 28a356b..189b0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,30 @@ # Prerequisites *.d +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + # Compiled Object files *.slo *.lo diff --git a/minipf/__init__.py b/minipf/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/minipf/config.py b/minipf/config.py new file mode 100644 index 0000000..33f9395 --- /dev/null +++ b/minipf/config.py @@ -0,0 +1,9 @@ +""" +Config File +""" + +# Directory with metakernals +spice_root = "/data/spice/" +cassini = '/data/big/spice/co-s_j_e_v-spice-6-v1.0/cosp_1000/extras/mk' +mdis = '/data/spice/mess-e_v_h-spice-6-v1.0/messsp_1000/extras/mk' # Messenger +mro = '/data/spice/mro-m-spice-6-v1.0/mrosp_1000/extras/mk' # Mars Reconnaissance Orbiter diff --git a/minipf/controllers/__init__.py b/minipf/controllers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/minipf/controllers/default_controller.py b/minipf/controllers/default_controller.py new file mode 100644 index 0000000..c536b23 --- /dev/null +++ b/minipf/controllers/default_controller.py @@ -0,0 +1,56 @@ +# import connexion +# import six + +# from minipf.models.data import Data # noqa: E501 +# from minipf.models.isd200 import ISD200 # noqa: E501 +# from minipf.models.request_isd import RequestISD # noqa: E501 +from minipf import util +from minipf import drivers + +def create_isd(lbl_file): # noqa: E501 + """Converts Image Labels to ISDs + + Adds an item to the system # noqa: E501 + + :param request_isd: + :type request_isd: dict | bytes + + :rtype: ISD200 + """ + with open(lbl_file, "r") as fp: + lines = fp.read() + + return drivers.load(lines) + +def get_metakernel(mission, year, version): # noqa: E501 + """Get a specific kernel + + # noqa: E501 + + :param mission: + :type mission: str + :param year: + :type year: str + :param version: + :type version: str + + :rtype: Data + """ + if connexion.request.is_json: + request_isd = RequestISD.from_dict(connexion.request.get_json()) # noqa: E501 + + return util.get_metakernels(missions=mission, years=year, versions=version) + + +def metakernel_catalog(): # noqa: E501 + """Access Product Information + + Get Available Products and Related Metadata # noqa: E501 + + + :rtype: Data + """ + return 'do some magic!' + +if __name__ == "__main__": + print("Banana") diff --git a/minipf/controllers/util.py b/minipf/controllers/util.py new file mode 100644 index 0000000..e69de29 diff --git a/minipf/drivers/__init__.py b/minipf/drivers/__init__.py new file mode 100644 index 0000000..137ebaf --- /dev/null +++ b/minipf/drivers/__init__.py @@ -0,0 +1,31 @@ +import pvl +import zlib + +import importlib +import inspect +import itertools +from itertools import chain +import os +from glob import glob + +from abc import ABC + +# dynamically load drivers +__all__ = [os.path.splitext(os.path.basename(d))[0] for d in glob(os.path.join(os.path.dirname(__file__), '*_driver.py'))] +__driver_modules__ = [importlib.import_module('.'+m, package='minipf.drivers') for m in __all__] + +drivers = dict(chain.from_iterable(inspect.getmembers(dmod, lambda x: inspect.isclass(x) and "_driver" in x.__module__) for dmod in __driver_modules__)) + +def load(label): + for name, driver in drivers.items(): + try: + print("TRYING:", driver) + res = driver(label) + if res.is_valid(): + with res as r: + return res + + except Exception as e: + import traceback + traceback.print_exc() + raise Exception('No Such Driver for Label') diff --git a/minipf/drivers/base.py b/minipf/drivers/base.py new file mode 100644 index 0000000..92a270e --- /dev/null +++ b/minipf/drivers/base.py @@ -0,0 +1,391 @@ +from abc import ABC, abstractmethod + +from dateutil import parser +import numpy as np +import pvl +import spiceypy as spice + +from minipf.drivers import distortion +from minipf.models.isd200 import ISD200 + +class Base(ABC): + """ + Abstract base class for all PDS label parsing. Implementations should override + properties where a kernel provider deviates from the most broadly adopted + approach. + + Methods that must be provided: + - instrument_id + - metakernel + + """ + def __init__(self, label, *args, **kwargs): + self.label = pvl.loads(label) + + def __enter__(self): + """ + Called when the context is created. This is used + to get the kernels furnished. + """ + print("IN FURNISH") + if self.metakernel: + spice.furnsh(self.metakernel) + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + """ + Called when the context goes out of scope. Once + this is done, the object is out of scope and the + kernels can be unloaded. + """ + spice.unload(self.metakernel) + + def __str__(self): + return str(self.to_dict()) + + def is_valid(self): + try: + iid = self.instrument_id + return True + except Exception as e: + return False + + def to_dict(self): + return {p:getattr(self, p) for p in dir(self) if not p.startswith('__') or p.startswith('_')} + + def to_pfeffer_response(self): + """ + Parse the data into a valid minipf response + """ + data = self.to_dict() + # Take the flat reponse and create the minipf obj dicts + data['detector_center'] = {'line': data['detector_center'][0], + 'sample': data['detector_center'][1]} + + # Parse the distortion object out of the + + if isinstance(self, distortion.RadialDistortion): + data['optical_distortion'] = {'radial':{'coefficients':data['odtk']}} + elif isinstance(self, distortion.TransverseDistortion): + data['optical_distortion'] = {'transverse':{'x':data['odtx'], + 'y':data['odty']}} + + data['focal_length_model'] = {'focal_length': data['focal_length']} + if hasattr(self, 'focal_epsilon'): + data['focal_length_model']['focal_epsilon'] = data['focal_epsilon'] + + data['reference_height'] = {'minheight': data['reference_height'][0], + 'maxheight': data['reference_height'][1], + 'unit': 'm'} + + data['sensor_position'] = {'unit':'m', + 'velocities': data['sensor_velocity'], + 'positions': data['sensor_position']} + + data['sun_position'] = {'unit': 'm', + 'positions': data['sun_position'], + 'velocities': data['sun_velocity']} + + data['sensor_orientation'] = {'quaternions':data['sensor_orientation']} + + data['radii'] = {'semimajor':data['semimajor'], + 'semiminor':data['semiminor'], + 'unit': 'km'} + + data['name_platform'] = data['spacecraft_name'] + data['name_sensor'] = data['instrument_id'] + return ISD200.from_dict(data) + + def _compute_ephemerides(self): + """ + Helper function to pull position and velocity in one pass + so that the results can then be cached in the associated + properties. + """ + eph = np.empty((self.number_of_ephemerides, 3)) + eph_rates = np.empty(eph.shape) + current_et = self.starting_ephemeris_time + for i in range(self.number_of_ephemerides): + state, _ = spice.spkezr(self.spacecraft_name, + current_et, + self.reference_frame, + 'NONE', + self.target_name,) # If this is the sensor, insufficient, if this is the spacecraft, it works? Huh? + eph[i] = state[:3] + eph_rates[i] = state[3:] + current_et += getattr(self, 'dt_ephemeris', 0) + # By default, spice works in km + eph *= 1000 + eph_rates *= 1000 + self._sensor_velocity = eph_rates + self._sensor_position = eph + + + @property + @abstractmethod + def metakernel(self): + pass + + @property + @abstractmethod + def instrument_id(self): + pass + + + @property + def start_time(self): + return self.label['START_TIME'] + + @property + def image_lines(self): + return self.label['IMAGE']['LINES'] + + @property + def image_samples(self): + return self.label['IMAGE']['LINE_SAMPLES'] + + @property + def interpolation_method(self): + return 'lagrange' + + @property + def number_of_ephemerides(self): + return 1 + + @property + def target_name(self): + return self.label['TARGET_NAME'] + + @property + def _target_id(self): + return spice.bodn2c(self.label['TARGET_NAME']) + + @property + def starting_ephemeris_time(self): + if not hasattr(self, '_starting_ephemeris_time'): + sclock = self.label['SPACECRAFT_CLOCK_START_COUNT'] + self._starting_ephemeris_time = spice.scs2e(self.spacecraft_id, sclock) + return self._starting_ephemeris_time + + @property + def _exposure_duration(self): + return self.label['EXPOSURE_DURATION'].value * 0.001 # Scale to seconds + + @property + def spacecraft_clock_stop_count(self): + sc = self.label.get('SPACECRAFT_CLOCK_STOP_COUNT', None) + if sc == 'N/A': + sc = None + return sc + + @property + def ending_ephemeris_time(self): + if not hasattr(self, '_ending_ephemeris_time'): + self._ending_ephemeris_time = (self.image_lines * self._exposure_duration) + self.starting_ephemeris_time + return self._ending_ephemeris_time + + @property + def center_ephemeris_time(self): + if not hasattr(self, '_center_ephemeris_time'): + self._center_ephemeris_time = (self.starting_ephemeris_time + self.ending_ephemeris_time)/2 + return self._center_ephemeris_time + + @property + def detector_center(self): + return list(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)) + + @property + def spacecraft_name(self): + return self.label['MISSION_NAME'] + + @property + def ikid(self): + return spice.bods2c(self.instrument_id) + + @property + def fikid(self): + fn = self.label.get('FILTER_NUMBER', 0) + if fn == 'N/A': + fn = 0 + return self.ikid - int(fn) + + @property + def spacecraft_id(self): + return spice.bods2c(self.spacecraft_name) + + @property + def focal2pixel_lines(self): + return spice.gdpool('INS{}_ITRANSL'.format(self.fikid), 0, 3) + + @property + def focal2pixel_samples(self): + return spice.gdpool('INS{}_ITRANSS'.format(self.fikid), 0, 3) + + @property + def focal_length(self): + return float(spice.gdpool('INS{}_FOCAL_LENGTH'.format(self.ikid), 0, 1)[0]) + + @property + def starting_detector_line(self): + return 1 + + @property + def starting_detector_sample(self): + return 1 + + @property + def detector_sample_summing(self): + return 1 + + @property + def detector_line_summing(self): + return self.label.get('SAMPLING_FACTOR', 1) + + @property + def semimajor(self): + rad = spice.bodvrd(self.label['TARGET_NAME'], 'RADII', 3) + return rad[1][1] + + @property + def semiminor(self): + rad = spice.bodvrd(self.label['TARGET_NAME'], 'RADII', 3) + return rad[1][0] + + @property + def reference_frame(self): + return 'IAU_{}'.format(self.label['TARGET_NAME']) + + @property + def sun_position(self): + sun_state, _ = spice.spkezr("SUN", + self.center_ephemeris_time, + self.reference_frame, + 'NONE', + self.label['TARGET_NAME']) + + return [sun_state[:4].tolist()] + + @property + def sun_velocity(self): + sun_state, lt = spice.spkezr("SUN", + self.center_ephemeris_time, + self.reference_frame, + 'NONE', + self.label['TARGET_NAME']) + + return [sun_state[3:6].tolist()] + + @property + def sensor_position(self): + if not hasattr(self, '_sensor_position'): + self._compute_ephemerides() + return self._sensor_position.tolist() + + @property + def sensor_velocity(self): + if not hasattr(self, '_sensor_velocity'): + self._compute_ephemerides() + return self._sensor_velocity.tolist() + + @property + def sensor_orientation(self): + if not hasattr(self, '_sensor_orientation'): + current_et = self.starting_ephemeris_time + qua = np.empty((self.number_of_ephemerides, 4)) + for i in range(self.number_of_quaternions): + # Find the rotation matrix + camera2bodyfixed = spice.pxform(self.instrument_id, + 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._sensor_orientation = qua + return self._sensor_orientation.tolist() + + @property + def reference_height(self): + # TODO: This should be a reasonable # + return 0, 100 + +class LineScanner(Base): + + @property + def name_model(self): + return "USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL" + + @property + def _exposure_duration(self): + return self.label['LINE_EXPOSURE_DURATION'].value * 0.001 # Scale to seconds + + @property + def line_scan_rate(self): + """ + In the form: [start_line, line_time, exposure_duration] + The form below is for a fixed rate line scanner. + """ + return [[float(self.starting_detector_line), self.t0_ephemeris, self._exposure_duration]] + + @property + def detector_center(self): + if not hasattr(self, '_detector_center'): + center_line = float(spice.gdpool('INS{}_BORESIGHT_LINE'.format(self.ikid), 0, 1)[0]) + center_sample = float(spice.gdpool('INS{}_BORESIGHT_SAMPLE'.format(self.ikid), 0, 1)[0]) + self._detector_center = [center_line, center_sample] + return self._detector_center + + @property + def center_ephemeris_time(self): + """ + The center ephemeris time for a fixed rate line scanner. + """ + if not hasattr(self, '_center_ephemeris_time'): + halflines = self.image_lines / 2 + center_sclock = self.starting_ephemeris_time + halflines * self._exposure_duration + self._center_ephemeris_time = center_sclock + return self._center_ephemeris_time + + @property + def t0_ephemeris(self): + return self.starting_ephemeris_time - self.center_ephemeris_time + + @property + def t0_quaternion(self): + return self.starting_ephemeris_time - self.center_ephemeris_time + + @property + def dt_ephemeris(self): + return (self.ending_ephemeris_time - self.starting_ephemeris_time) / self.number_of_ephemerides + + @property + def dt_quaternion(self): + return (self.ending_ephemeris_time - self.starting_ephemeris_time) / self.number_of_ephemerides + + @property + def number_of_ephemerides(self): + return 909 + + @property + def number_of_quaternions(self): + return 909 + + + + @property + def _exposure_duration(self): + return self.label['LINE_EXPOSURE_DURATION'].value * 0.001 # Scale to seconds + +class Framer(Base): + + @property + def name_model(self): + return "USGS_ASTRO_FRAME_SENSOR_MODEL" + + @property + def number_of_ephemerides(self): + return 1 + + @property + def number_of_quaternions(self): + return 1 diff --git a/minipf/drivers/cassini_driver.py b/minipf/drivers/cassini_driver.py new file mode 100644 index 0000000..600187f --- /dev/null +++ b/minipf/drivers/cassini_driver.py @@ -0,0 +1,69 @@ +from glob import glob +import os + +import pvl +import spiceypy as spice +import numpy as np + +from minipf import config +from minipf.drivers.base import Framer +from minipf.drivers.distortion import RadialDistortion + + +class CassiniISS(Framer, RadialDistortion): + id_lookup = { + "ISSNA" : "CASSINI_ISS_NAC", + "ISSWA" : "CASSINI_ISS_WAC" + } + + @property + def metakernel(self): + metakernel_dir = config.cassini + mks = sorted(glob(os.path.join(metakernel_dir,'*.tm'))) + if not hasattr(self, '_metakernel'): + for mk in mks: + if str(self.start_time.year) in os.path.basename(mk): + self._metakernel = mk + return self._metakernel + + @property + def instrument_id(self): + return self.id_lookup[self.label['INSTRUMENT_ID']] + + @property + def focal_epsilon(self): + return float(spice.gdpool('INS{}_FL_UNCERTAINTY'.format(self.ikid), 0, 1)[0]) + + @property + def spacecraft_name(self): + return 'CASSINI' + + @property + def focal2pixel_samples(self): + # Microns to mm + pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + return [0.0, 1/pixel_size, 0.0] + + @property + def focal2pixel_lines(self): + pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + return [0.0, 0.0, 1/pixel_size] + + @property + def _exposure_duration(self): + # labels do not specify a unit explicitly + return self.label['EXPOSURE_DURATION'] * 0.001 # Scale to seconds + + @property + def odtk(self): + """ + The radial distortion coeffs are not defined in the ik kernels, instead + they are defined in the ISS Data User Guide (Knowles). Therefore, we + manually specify the codes here. + """ + if self.instrument_id == 'CASSINI_ISS_WAC': + # WAC + return [float('-6.2e-5'), 0, 0] + elif self.instrument_id == 'CASSINI_ISS_NAC': + # NAC + return [float('-8e-6'), 0, 0] diff --git a/minipf/drivers/distortion.py b/minipf/drivers/distortion.py new file mode 100644 index 0000000..b55c06e --- /dev/null +++ b/minipf/drivers/distortion.py @@ -0,0 +1,25 @@ +from abc import ABC +import spiceypy as spice + +from minipf.models.optical_distortion_transverse import OpticalDistortionTransverse + + +class TransverseDistortion(ABC): + """ + Exposes the properties that are used to describe a transverse distortion model. + """ + @property + def odtx(self): + return spice.gdpool('INS{}_OD_T_X'.format(self.ikid),0, 10) + + @property + def odty(self): + return spice.gdpool('INS{}_OD_T_Y'.format(self.ikid), 0, 10) + +class RadialDistortion(ABC): + """ + Exposes the properties that are used to describe a radial distortion model. + """ + @property + def odtk(self): + return spice.gdpool('INS{}_OD_K'.format(self.ikid),0, 3) \ No newline at end of file diff --git a/minipf/drivers/lro_driver.py b/minipf/drivers/lro_driver.py new file mode 100644 index 0000000..a3043ff --- /dev/null +++ b/minipf/drivers/lro_driver.py @@ -0,0 +1,38 @@ +from glob import glob +import os + +import numpy as np +import pvl +import spiceypy as spice + +from minipf.util import get_metakernels +from minipf.drivers.base import LineScanner +from minipf.drivers.distortion import RadialDistortion + +class LRO_LROC(LineScanner, RadialDistortion): + + @property + def metakernel(self): + metakernels = get_metakernels(years=self.start_time.year, missions='lro', versions='latest') + self._metakernel = metakernels['data'][0]['path'] + return self._metakernel + + @property + def instrument_id(self): + """ + Ignores Wide Angle for now + """ + + instrument = self.label.get("INSTRUMENT_ID") + + # should be left or right + frame_id = self.label.get("FRAME_ID") + + if instrument == "LROC" and frame_id == "LEFT": + return "LRO_LROCNACL" + elif instrument == "LROC" and frame_id == "RIGHT": + return "LRO_LROCNACR" + + @property + def spacecraft_name(self): + return "LRO" diff --git a/minipf/drivers/mdis_driver.py b/minipf/drivers/mdis_driver.py new file mode 100644 index 0000000..b014622 --- /dev/null +++ b/minipf/drivers/mdis_driver.py @@ -0,0 +1,58 @@ +from glob import glob +import os + +import pvl +import spiceypy as spice +import numpy as np + +from minipf import config +from minipf.drivers.base import Framer +from minipf.drivers.distortion import TransverseDistortion + + +class Messenger(Framer, TransverseDistortion): + id_lookup = { + 'MDIS-WAC': 'MSGR_MDIS_WAC', + 'MDIS-NAC':'MSGR_MDIS_NAC', + 'MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA':'MSGR_MDIS_NAC', + 'MERCURY DUAL IMAGING SYSTEM WIDE ANGLE CAMERA':'MSGR_MDIS_WAC' + } + + @property + def metakernel(self): + metakernel_dir = config.mdis + mks = sorted(glob(os.path.join(metakernel_dir,'*.tm'))) + if not hasattr(self, '_metakernel'): + for mk in mks: + if str(self.start_time.year) in os.path.basename(mk): + self._metakernel = mk + return self._metakernel + + @property + def instrument_id(self): + return self.id_lookup[self.label['INSTRUMENT_ID']] + + @property + def focal_length(self): + """ + """ + coeffs = spice.gdpool('INS{}_FL_TEMP_COEFFS '.format(self.fikid), 0, 5) + + # reverse coeffs, mdis coeffs are listed a_0, a_1, a_2 ... a_n where + # numpy wants them a_n, a_n-1, a_n-2 ... a_0 + f_t = np.poly1d(coeffs[::-1]) + + # eval at the focal_plane_tempature + return f_t(self.label['FOCAL_PLANE_TEMPERATURE'].value) + + @property + def focal_epsilon(self): + return float(spice.gdpool('INS{}_FL_UNCERTAINTY'.format(self.ikid), 0, 1)[0]) + + @property + def starting_detector_sample(self): + return int(spice.gdpool('INS{}_FPUBIN_START_SAMPLE'.format(self.ikid), 0, 1)[0]) + + @property + def starting_detector_line(self): + return int(spice.gdpool('INS{}_FPUBIN_START_LINE'.format(self.ikid), 0, 1)[0]) diff --git a/minipf/drivers/mro_driver.py b/minipf/drivers/mro_driver.py new file mode 100644 index 0000000..c3a6754 --- /dev/null +++ b/minipf/drivers/mro_driver.py @@ -0,0 +1,37 @@ +from glob import glob +import os + +import numpy as np +import pvl +import spiceypy as spice +from minipf import config + +from minipf.drivers.base import LineScanner +from minipf.drivers.distortion import RadialDistortion + +class MRO_CTX(LineScanner, RadialDistortion): + id_lookup = { + 'CONTEXT CAMERA':'MRO_CTX' + } + + @property + def metakernel(self): + metakernel_dir = config.mro + mks = sorted(glob(os.path.join(metakernel_dir,'*.tm'))) + if not hasattr(self, '_metakernel'): + self._metakernel = None + for mk in mks: + if str(self.start_time.year) in os.path.basename(mk): + self._metakernel = mk + return self._metakernel + + @property + def instrument_id(self): + return self.id_lookup[self.label['INSTRUMENT_NAME']] + + @property + def spacecraft_name(self): + name_lookup = { + 'MARS_RECONNAISSANCE_ORBITER': 'MRO' + } + return name_lookup[self.label['SPACECRAFT_NAME']] diff --git a/minipf/models/__init__.py b/minipf/models/__init__.py new file mode 100644 index 0000000..c1b09b0 --- /dev/null +++ b/minipf/models/__init__.py @@ -0,0 +1,19 @@ +# coding: utf-8 + +# flake8: noqa +from __future__ import absolute_import +# import models into model package +from minipf.models.data import Data +from minipf.models.isd200 import ISD200 +from minipf.models.isd200_detector_center import ISD200DetectorCenter +from minipf.models.isd200_focal_length_model import ISD200FocalLengthModel +from minipf.models.isd200_radii import ISD200Radii +from minipf.models.isd200_reference_height import ISD200ReferenceHeight +from minipf.models.isd200_sensor_position import ISD200SensorPosition +from minipf.models.isd200_sun_position import ISD200SunPosition +from minipf.models.optical_distortion import OpticalDistortion +from minipf.models.optical_distortion_radial import OpticalDistortionRadial +from minipf.models.optical_distortion_transverse import OpticalDistortionTransverse +from minipf.models.quaternions import Quaternions +from minipf.models.request_isd import RequestISD +from minipf.models.xyz import XYZ diff --git a/minipf/models/base_model_.py b/minipf/models/base_model_.py new file mode 100644 index 0000000..6535006 --- /dev/null +++ b/minipf/models/base_model_.py @@ -0,0 +1,69 @@ +import pprint + +import six +import typing + +from minipf import util + +T = typing.TypeVar('T') + + +class Model(object): + # openapiTypes: The key is attribute name and the + # value is attribute type. + openapi_types = {} + + # attributeMap: The key is attribute name and the + # value is json key in definition. + attribute_map = {} + + @classmethod + def from_dict(cls: typing.Type[T], dikt) -> T: + """Returns the dict as a model""" + return util.deserialize_model(dikt, cls) + + def to_dict(self): + """Returns the model properties as a dict + + :rtype: dict + """ + result = {} + + for attr, _ in six.iteritems(self.openapi_types): + value = getattr(self, attr) + if isinstance(value, list): + result[attr] = list(map( + lambda x: x.to_dict() if hasattr(x, "to_dict") else x, + value + )) + elif hasattr(value, "to_dict"): + result[attr] = value.to_dict() + elif isinstance(value, dict): + result[attr] = dict(map( + lambda item: (item[0], item[1].to_dict()) + if hasattr(item[1], "to_dict") else item, + value.items() + )) + else: + result[attr] = value + + return result + + def to_str(self): + """Returns the string representation of the model + + :rtype: str + """ + return pprint.pformat(self.to_dict()) + + def __repr__(self): + """For `print` and `pprint`""" + return self.to_str() + + def __eq__(self, other): + """Returns true if both objects are equal""" + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """Returns true if both objects are not equal""" + return not self == other diff --git a/minipf/models/data.py b/minipf/models/data.py new file mode 100644 index 0000000..5ffae90 --- /dev/null +++ b/minipf/models/data.py @@ -0,0 +1,90 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class Data(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, count: int=None, data: List[object]=None): # noqa: E501 + """Data - a model defined in OpenAPI + + :param count: The count of this Data. # noqa: E501 + :type count: int + :param data: The data of this Data. # noqa: E501 + :type data: List[object] + """ + self.openapi_types = { + 'count': int, + 'data': List[object] + } + + self.attribute_map = { + 'count': 'count', + 'data': 'data' + } + + self._count = count + self._data = data + + @classmethod + def from_dict(cls, dikt) -> 'Data': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The data of this Data. # noqa: E501 + :rtype: Data + """ + return util.deserialize_model(dikt, cls) + + @property + def count(self) -> int: + """Gets the count of this Data. + + + :return: The count of this Data. + :rtype: int + """ + return self._count + + @count.setter + def count(self, count: int): + """Sets the count of this Data. + + + :param count: The count of this Data. + :type count: int + """ + + self._count = count + + @property + def data(self) -> List[object]: + """Gets the data of this Data. + + + :return: The data of this Data. + :rtype: List[object] + """ + return self._data + + @data.setter + def data(self, data: List[object]): + """Sets the data of this Data. + + + :param data: The data of this Data. + :type data: List[object] + """ + + self._data = data diff --git a/minipf/models/isd200.py b/minipf/models/isd200.py new file mode 100644 index 0000000..51ad544 --- /dev/null +++ b/minipf/models/isd200.py @@ -0,0 +1,820 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf.models.isd200_detector_center import ISD200DetectorCenter # noqa: F401,E501 +from minipf.models.isd200_focal_length_model import ISD200FocalLengthModel # noqa: F401,E501 +from minipf.models.isd200_radii import ISD200Radii # noqa: F401,E501 +from minipf.models.isd200_reference_height import ISD200ReferenceHeight # noqa: F401,E501 +from minipf.models.isd200_sensor_position import ISD200SensorPosition # noqa: F401,E501 +from minipf.models.isd200_sun_position import ISD200SunPosition # noqa: F401,E501 +from minipf.models.optical_distortion import OpticalDistortion # noqa: F401,E501 +from minipf.models.quaternions import Quaternions # noqa: F401,E501 +from minipf import util + + +class ISD200(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, name_platform: str=None, name_sensor: str=None, detector_center: ISD200DetectorCenter=None, center_ephemeris_time: float=None, name_model: str=None, starting_ephemeris_time: float=None, focal_length_model: ISD200FocalLengthModel=None, image_lines: float=None, image_samples: float=None, radii: ISD200Radii=None, optical_distortion: OpticalDistortion=None, starting_detector_sample: float=None, starting_detector_line: float=None, focal2pixel_samples: List[float]=None, focal2pixel_lines: List[float]=None, sensor_position: ISD200SensorPosition=None, sun_position: ISD200SunPosition=None, sensor_orientation: Quaternions=None, line_scan_rate: List[List[float]]=None, detector_sample_summing: float=None, detector_line_summing: float=None, dt_ephemeris: float=None, t0_ephemeris: float=None, dt_quaternion: float=None, t0_quaternion: float=None, reference_height: ISD200ReferenceHeight=None, interpolation_method: str=None): # noqa: E501 + """ISD200 - a model defined in OpenAPI + + :param name_platform: The name_platform of this ISD200. # noqa: E501 + :type name_platform: str + :param name_sensor: The name_sensor of this ISD200. # noqa: E501 + :type name_sensor: str + :param detector_center: The detector_center of this ISD200. # noqa: E501 + :type detector_center: ISD200DetectorCenter + :param center_ephemeris_time: The center_ephemeris_time of this ISD200. # noqa: E501 + :type center_ephemeris_time: float + :param name_model: The name_model of this ISD200. # noqa: E501 + :type name_model: str + :param starting_ephemeris_time: The starting_ephemeris_time of this ISD200. # noqa: E501 + :type starting_ephemeris_time: float + :param focal_length_model: The focal_length_model of this ISD200. # noqa: E501 + :type focal_length_model: ISD200FocalLengthModel + :param image_lines: The image_lines of this ISD200. # noqa: E501 + :type image_lines: float + :param image_samples: The image_samples of this ISD200. # noqa: E501 + :type image_samples: float + :param radii: The radii of this ISD200. # noqa: E501 + :type radii: ISD200Radii + :param optical_distortion: The optical_distortion of this ISD200. # noqa: E501 + :type optical_distortion: OpticalDistortion + :param starting_detector_sample: The starting_detector_sample of this ISD200. # noqa: E501 + :type starting_detector_sample: float + :param starting_detector_line: The starting_detector_line of this ISD200. # noqa: E501 + :type starting_detector_line: float + :param focal2pixel_samples: The focal2pixel_samples of this ISD200. # noqa: E501 + :type focal2pixel_samples: List[float] + :param focal2pixel_lines: The focal2pixel_lines of this ISD200. # noqa: E501 + :type focal2pixel_lines: List[float] + :param sensor_position: The sensor_position of this ISD200. # noqa: E501 + :type sensor_position: ISD200SensorPosition + :param sun_position: The sun_position of this ISD200. # noqa: E501 + :type sun_position: ISD200SunPosition + :param sensor_orientation: The sensor_orientation of this ISD200. # noqa: E501 + :type sensor_orientation: Quaternions + :param line_scan_rate: The line_scan_rate of this ISD200. # noqa: E501 + :type line_scan_rate: List[List[float]] + :param detector_sample_summing: The detector_sample_summing of this ISD200. # noqa: E501 + :type detector_sample_summing: float + :param detector_line_summing: The detector_line_summing of this ISD200. # noqa: E501 + :type detector_line_summing: float + :param dt_ephemeris: The dt_ephemeris of this ISD200. # noqa: E501 + :type dt_ephemeris: float + :param t0_ephemeris: The t0_ephemeris of this ISD200. # noqa: E501 + :type t0_ephemeris: float + :param dt_quaternion: The dt_quaternion of this ISD200. # noqa: E501 + :type dt_quaternion: float + :param t0_quaternion: The t0_quaternion of this ISD200. # noqa: E501 + :type t0_quaternion: float + :param reference_height: The reference_height of this ISD200. # noqa: E501 + :type reference_height: ISD200ReferenceHeight + :param interpolation_method: The interpolation_method of this ISD200. # noqa: E501 + :type interpolation_method: str + """ + self.openapi_types = { + 'name_platform': str, + 'name_sensor': str, + 'detector_center': ISD200DetectorCenter, + 'center_ephemeris_time': float, + 'name_model': str, + 'starting_ephemeris_time': float, + 'focal_length_model': ISD200FocalLengthModel, + 'image_lines': float, + 'image_samples': float, + 'radii': ISD200Radii, + 'optical_distortion': OpticalDistortion, + 'starting_detector_sample': float, + 'starting_detector_line': float, + 'focal2pixel_samples': List[float], + 'focal2pixel_lines': List[float], + 'sensor_position': ISD200SensorPosition, + 'sun_position': ISD200SunPosition, + 'sensor_orientation': Quaternions, + 'line_scan_rate': List[List[float]], + 'detector_sample_summing': float, + 'detector_line_summing': float, + 'dt_ephemeris': float, + 't0_ephemeris': float, + 'dt_quaternion': float, + 't0_quaternion': float, + 'reference_height': ISD200ReferenceHeight, + 'interpolation_method': str + } + + self.attribute_map = { + 'name_platform': 'name_platform', + 'name_sensor': 'name_sensor', + 'detector_center': 'detector_center', + 'center_ephemeris_time': 'center_ephemeris_time', + 'name_model': 'name_model', + 'starting_ephemeris_time': 'starting_ephemeris_time', + 'focal_length_model': 'focal_length_model', + 'image_lines': 'image_lines', + 'image_samples': 'image_samples', + 'radii': 'radii', + 'optical_distortion': 'optical_distortion', + 'starting_detector_sample': 'starting_detector_sample', + 'starting_detector_line': 'starting_detector_line', + 'focal2pixel_samples': 'focal2pixel_samples', + 'focal2pixel_lines': 'focal2pixel_lines', + 'sensor_position': 'sensor_position', + 'sun_position': 'sun_position', + 'sensor_orientation': 'sensor_orientation', + 'line_scan_rate': 'line_scan_rate', + 'detector_sample_summing': 'detector_sample_summing', + 'detector_line_summing': 'detector_line_summing', + 'dt_ephemeris': 'dt_ephemeris', + 't0_ephemeris': 't0_ephemeris', + 'dt_quaternion': 'dt_quaternion', + 't0_quaternion': 't0_quaternion', + 'reference_height': 'reference_height', + 'interpolation_method': 'interpolation_method' + } + + self._name_platform = name_platform + self._name_sensor = name_sensor + self._detector_center = detector_center + self._center_ephemeris_time = center_ephemeris_time + self._name_model = name_model + self._starting_ephemeris_time = starting_ephemeris_time + self._focal_length_model = focal_length_model + self._image_lines = image_lines + self._image_samples = image_samples + self._radii = radii + self._optical_distortion = optical_distortion + self._starting_detector_sample = starting_detector_sample + self._starting_detector_line = starting_detector_line + self._focal2pixel_samples = focal2pixel_samples + self._focal2pixel_lines = focal2pixel_lines + self._sensor_position = sensor_position + self._sun_position = sun_position + self._sensor_orientation = sensor_orientation + self._line_scan_rate = line_scan_rate + self._detector_sample_summing = detector_sample_summing + self._detector_line_summing = detector_line_summing + self._dt_ephemeris = dt_ephemeris + self._t0_ephemeris = t0_ephemeris + self._dt_quaternion = dt_quaternion + self._t0_quaternion = t0_quaternion + self._reference_height = reference_height + self._interpolation_method = interpolation_method + + @classmethod + def from_dict(cls, dikt) -> 'ISD200': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200 of this ISD200. # noqa: E501 + :rtype: ISD200 + """ + return util.deserialize_model(dikt, cls) + + @property + def name_platform(self) -> str: + """Gets the name_platform of this ISD200. + + The name of the sensor platform, e.g., the spacecraft. # noqa: E501 + + :return: The name_platform of this ISD200. + :rtype: str + """ + return self._name_platform + + @name_platform.setter + def name_platform(self, name_platform: str): + """Sets the name_platform of this ISD200. + + The name of the sensor platform, e.g., the spacecraft. # noqa: E501 + + :param name_platform: The name_platform of this ISD200. + :type name_platform: str + """ + if name_platform is None: + raise ValueError("Invalid value for `name_platform`, must not be `None`") # noqa: E501 + + self._name_platform = name_platform + + @property + def name_sensor(self) -> str: + """Gets the name_sensor of this ISD200. + + The name of the sensor, e.g., MSGR_MDIS_NAC. # noqa: E501 + + :return: The name_sensor of this ISD200. + :rtype: str + """ + return self._name_sensor + + @name_sensor.setter + def name_sensor(self, name_sensor: str): + """Sets the name_sensor of this ISD200. + + The name of the sensor, e.g., MSGR_MDIS_NAC. # noqa: E501 + + :param name_sensor: The name_sensor of this ISD200. + :type name_sensor: str + """ + if name_sensor is None: + raise ValueError("Invalid value for `name_sensor`, must not be `None`") # noqa: E501 + + self._name_sensor = name_sensor + + @property + def detector_center(self) -> ISD200DetectorCenter: + """Gets the detector_center of this ISD200. + + + :return: The detector_center of this ISD200. + :rtype: ISD200DetectorCenter + """ + return self._detector_center + + @detector_center.setter + def detector_center(self, detector_center: ISD200DetectorCenter): + """Sets the detector_center of this ISD200. + + + :param detector_center: The detector_center of this ISD200. + :type detector_center: ISD200DetectorCenter + """ + + self._detector_center = detector_center + + @property + def center_ephemeris_time(self) -> float: + """Gets the center_ephemeris_time of this ISD200. + + The center ephemeris time of the image # noqa: E501 + + :return: The center_ephemeris_time of this ISD200. + :rtype: float + """ + return self._center_ephemeris_time + + @center_ephemeris_time.setter + def center_ephemeris_time(self, center_ephemeris_time: float): + """Sets the center_ephemeris_time of this ISD200. + + The center ephemeris time of the image # noqa: E501 + + :param center_ephemeris_time: The center_ephemeris_time of this ISD200. + :type center_ephemeris_time: float + """ + + self._center_ephemeris_time = center_ephemeris_time + + @property + def name_model(self) -> str: + """Gets the name_model of this ISD200. + + The name of the model to be instantiated # noqa: E501 + + :return: The name_model of this ISD200. + :rtype: str + """ + return self._name_model + + @name_model.setter + def name_model(self, name_model: str): + """Sets the name_model of this ISD200. + + The name of the model to be instantiated # noqa: E501 + + :param name_model: The name_model of this ISD200. + :type name_model: str + """ + if name_model is None: + raise ValueError("Invalid value for `name_model`, must not be `None`") # noqa: E501 + + self._name_model = name_model + + @property + def starting_ephemeris_time(self) -> float: + """Gets the starting_ephemeris_time of this ISD200. + + The starting ephemeris time of the image # noqa: E501 + + :return: The starting_ephemeris_time of this ISD200. + :rtype: float + """ + return self._starting_ephemeris_time + + @starting_ephemeris_time.setter + def starting_ephemeris_time(self, starting_ephemeris_time: float): + """Sets the starting_ephemeris_time of this ISD200. + + The starting ephemeris time of the image # noqa: E501 + + :param starting_ephemeris_time: The starting_ephemeris_time of this ISD200. + :type starting_ephemeris_time: float + """ + if starting_ephemeris_time is None: + raise ValueError("Invalid value for `starting_ephemeris_time`, must not be `None`") # noqa: E501 + + self._starting_ephemeris_time = starting_ephemeris_time + + @property + def focal_length_model(self) -> ISD200FocalLengthModel: + """Gets the focal_length_model of this ISD200. + + + :return: The focal_length_model of this ISD200. + :rtype: ISD200FocalLengthModel + """ + return self._focal_length_model + + @focal_length_model.setter + def focal_length_model(self, focal_length_model: ISD200FocalLengthModel): + """Sets the focal_length_model of this ISD200. + + + :param focal_length_model: The focal_length_model of this ISD200. + :type focal_length_model: ISD200FocalLengthModel + """ + if focal_length_model is None: + raise ValueError("Invalid value for `focal_length_model`, must not be `None`") # noqa: E501 + + self._focal_length_model = focal_length_model + + @property + def image_lines(self) -> float: + """Gets the image_lines of this ISD200. + + The number of lines in the image # noqa: E501 + + :return: The image_lines of this ISD200. + :rtype: float + """ + return self._image_lines + + @image_lines.setter + def image_lines(self, image_lines: float): + """Sets the image_lines of this ISD200. + + The number of lines in the image # noqa: E501 + + :param image_lines: The image_lines of this ISD200. + :type image_lines: float + """ + if image_lines is None: + raise ValueError("Invalid value for `image_lines`, must not be `None`") # noqa: E501 + + self._image_lines = image_lines + + @property + def image_samples(self) -> float: + """Gets the image_samples of this ISD200. + + The the number of samples in the image # noqa: E501 + + :return: The image_samples of this ISD200. + :rtype: float + """ + return self._image_samples + + @image_samples.setter + def image_samples(self, image_samples: float): + """Sets the image_samples of this ISD200. + + The the number of samples in the image # noqa: E501 + + :param image_samples: The image_samples of this ISD200. + :type image_samples: float + """ + if image_samples is None: + raise ValueError("Invalid value for `image_samples`, must not be `None`") # noqa: E501 + + self._image_samples = image_samples + + @property + def radii(self) -> ISD200Radii: + """Gets the radii of this ISD200. + + + :return: The radii of this ISD200. + :rtype: ISD200Radii + """ + return self._radii + + @radii.setter + def radii(self, radii: ISD200Radii): + """Sets the radii of this ISD200. + + + :param radii: The radii of this ISD200. + :type radii: ISD200Radii + """ + if radii is None: + raise ValueError("Invalid value for `radii`, must not be `None`") # noqa: E501 + + self._radii = radii + + @property + def optical_distortion(self) -> OpticalDistortion: + """Gets the optical_distortion of this ISD200. + + + :return: The optical_distortion of this ISD200. + :rtype: OpticalDistortion + """ + return self._optical_distortion + + @optical_distortion.setter + def optical_distortion(self, optical_distortion: OpticalDistortion): + """Sets the optical_distortion of this ISD200. + + + :param optical_distortion: The optical_distortion of this ISD200. + :type optical_distortion: OpticalDistortion + """ + + self._optical_distortion = optical_distortion + + @property + def starting_detector_sample(self) -> float: + """Gets the starting_detector_sample of this ISD200. + + The sample on the detector where the data starts # noqa: E501 + + :return: The starting_detector_sample of this ISD200. + :rtype: float + """ + return self._starting_detector_sample + + @starting_detector_sample.setter + def starting_detector_sample(self, starting_detector_sample: float): + """Sets the starting_detector_sample of this ISD200. + + The sample on the detector where the data starts # noqa: E501 + + :param starting_detector_sample: The starting_detector_sample of this ISD200. + :type starting_detector_sample: float + """ + if starting_detector_sample is None: + raise ValueError("Invalid value for `starting_detector_sample`, must not be `None`") # noqa: E501 + + self._starting_detector_sample = starting_detector_sample + + @property + def starting_detector_line(self) -> float: + """Gets the starting_detector_line of this ISD200. + + The line on the detector where the data starts # noqa: E501 + + :return: The starting_detector_line of this ISD200. + :rtype: float + """ + return self._starting_detector_line + + @starting_detector_line.setter + def starting_detector_line(self, starting_detector_line: float): + """Sets the starting_detector_line of this ISD200. + + The line on the detector where the data starts # noqa: E501 + + :param starting_detector_line: The starting_detector_line of this ISD200. + :type starting_detector_line: float + """ + if starting_detector_line is None: + raise ValueError("Invalid value for `starting_detector_line`, must not be `None`") # noqa: E501 + + self._starting_detector_line = starting_detector_line + + @property + def focal2pixel_samples(self) -> List[float]: + """Gets the focal2pixel_samples of this ISD200. + + Transformation x coefficients from focal plane (mm) to detector pixel coordinates # noqa: E501 + + :return: The focal2pixel_samples of this ISD200. + :rtype: List[float] + """ + return self._focal2pixel_samples + + @focal2pixel_samples.setter + def focal2pixel_samples(self, focal2pixel_samples: List[float]): + """Sets the focal2pixel_samples of this ISD200. + + Transformation x coefficients from focal plane (mm) to detector pixel coordinates # noqa: E501 + + :param focal2pixel_samples: The focal2pixel_samples of this ISD200. + :type focal2pixel_samples: List[float] + """ + if focal2pixel_samples is None: + raise ValueError("Invalid value for `focal2pixel_samples`, must not be `None`") # noqa: E501 + + self._focal2pixel_samples = focal2pixel_samples + + @property + def focal2pixel_lines(self) -> List[float]: + """Gets the focal2pixel_lines of this ISD200. + + Transformation y coefficients from focal plane (mm) to detector pixel coordinates # noqa: E501 + + :return: The focal2pixel_lines of this ISD200. + :rtype: List[float] + """ + return self._focal2pixel_lines + + @focal2pixel_lines.setter + def focal2pixel_lines(self, focal2pixel_lines: List[float]): + """Sets the focal2pixel_lines of this ISD200. + + Transformation y coefficients from focal plane (mm) to detector pixel coordinates # noqa: E501 + + :param focal2pixel_lines: The focal2pixel_lines of this ISD200. + :type focal2pixel_lines: List[float] + """ + if focal2pixel_lines is None: + raise ValueError("Invalid value for `focal2pixel_lines`, must not be `None`") # noqa: E501 + + self._focal2pixel_lines = focal2pixel_lines + + @property + def sensor_position(self) -> ISD200SensorPosition: + """Gets the sensor_position of this ISD200. + + + :return: The sensor_position of this ISD200. + :rtype: ISD200SensorPosition + """ + return self._sensor_position + + @sensor_position.setter + def sensor_position(self, sensor_position: ISD200SensorPosition): + """Sets the sensor_position of this ISD200. + + + :param sensor_position: The sensor_position of this ISD200. + :type sensor_position: ISD200SensorPosition + """ + + self._sensor_position = sensor_position + + @property + def sun_position(self) -> ISD200SunPosition: + """Gets the sun_position of this ISD200. + + + :return: The sun_position of this ISD200. + :rtype: ISD200SunPosition + """ + return self._sun_position + + @sun_position.setter + def sun_position(self, sun_position: ISD200SunPosition): + """Sets the sun_position of this ISD200. + + + :param sun_position: The sun_position of this ISD200. + :type sun_position: ISD200SunPosition + """ + + self._sun_position = sun_position + + @property + def sensor_orientation(self) -> Quaternions: + """Gets the sensor_orientation of this ISD200. + + + :return: The sensor_orientation of this ISD200. + :rtype: Quaternions + """ + return self._sensor_orientation + + @sensor_orientation.setter + def sensor_orientation(self, sensor_orientation: Quaternions): + """Sets the sensor_orientation of this ISD200. + + + :param sensor_orientation: The sensor_orientation of this ISD200. + :type sensor_orientation: Quaternions + """ + if sensor_orientation is None: + raise ValueError("Invalid value for `sensor_orientation`, must not be `None`") # noqa: E501 + + self._sensor_orientation = sensor_orientation + + @property + def line_scan_rate(self) -> List[List[float]]: + """Gets the line_scan_rate of this ISD200. + + The line rates of the detector map with the associated start line and time # noqa: E501 + + :return: The line_scan_rate of this ISD200. + :rtype: List[List[float]] + """ + return self._line_scan_rate + + @line_scan_rate.setter + def line_scan_rate(self, line_scan_rate: List[List[float]]): + """Sets the line_scan_rate of this ISD200. + + The line rates of the detector map with the associated start line and time # noqa: E501 + + :param line_scan_rate: The line_scan_rate of this ISD200. + :type line_scan_rate: List[List[float]] + """ + + self._line_scan_rate = line_scan_rate + + @property + def detector_sample_summing(self) -> float: + """Gets the detector_sample_summing of this ISD200. + + The summing in the sample-direction. A summing of 1 indicates no summing, summing of 2 indicates 2 pixel summing,4 indicates 4 pixel summing, etc # noqa: E501 + + :return: The detector_sample_summing of this ISD200. + :rtype: float + """ + return self._detector_sample_summing + + @detector_sample_summing.setter + def detector_sample_summing(self, detector_sample_summing: float): + """Sets the detector_sample_summing of this ISD200. + + The summing in the sample-direction. A summing of 1 indicates no summing, summing of 2 indicates 2 pixel summing,4 indicates 4 pixel summing, etc # noqa: E501 + + :param detector_sample_summing: The detector_sample_summing of this ISD200. + :type detector_sample_summing: float + """ + + self._detector_sample_summing = detector_sample_summing + + @property + def detector_line_summing(self) -> float: + """Gets the detector_line_summing of this ISD200. + + The summing in the line-direction # noqa: E501 + + :return: The detector_line_summing of this ISD200. + :rtype: float + """ + return self._detector_line_summing + + @detector_line_summing.setter + def detector_line_summing(self, detector_line_summing: float): + """Sets the detector_line_summing of this ISD200. + + The summing in the line-direction # noqa: E501 + + :param detector_line_summing: The detector_line_summing of this ISD200. + :type detector_line_summing: float + """ + + self._detector_line_summing = detector_line_summing + + @property + def dt_ephemeris(self) -> float: + """Gets the dt_ephemeris of this ISD200. + + The time between each ephemeris point. # noqa: E501 + + :return: The dt_ephemeris of this ISD200. + :rtype: float + """ + return self._dt_ephemeris + + @dt_ephemeris.setter + def dt_ephemeris(self, dt_ephemeris: float): + """Sets the dt_ephemeris of this ISD200. + + The time between each ephemeris point. # noqa: E501 + + :param dt_ephemeris: The dt_ephemeris of this ISD200. + :type dt_ephemeris: float + """ + + self._dt_ephemeris = dt_ephemeris + + @property + def t0_ephemeris(self) -> float: + """Gets the t0_ephemeris of this ISD200. + + First ephemeris time - center image time # noqa: E501 + + :return: The t0_ephemeris of this ISD200. + :rtype: float + """ + return self._t0_ephemeris + + @t0_ephemeris.setter + def t0_ephemeris(self, t0_ephemeris: float): + """Sets the t0_ephemeris of this ISD200. + + First ephemeris time - center image time # noqa: E501 + + :param t0_ephemeris: The t0_ephemeris of this ISD200. + :type t0_ephemeris: float + """ + + self._t0_ephemeris = t0_ephemeris + + @property + def dt_quaternion(self) -> float: + """Gets the dt_quaternion of this ISD200. + + Time spacing of quaternions. # noqa: E501 + + :return: The dt_quaternion of this ISD200. + :rtype: float + """ + return self._dt_quaternion + + @dt_quaternion.setter + def dt_quaternion(self, dt_quaternion: float): + """Sets the dt_quaternion of this ISD200. + + Time spacing of quaternions. # noqa: E501 + + :param dt_quaternion: The dt_quaternion of this ISD200. + :type dt_quaternion: float + """ + + self._dt_quaternion = dt_quaternion + + @property + def t0_quaternion(self) -> float: + """Gets the t0_quaternion of this ISD200. + + First quaternion time - center image time. # noqa: E501 + + :return: The t0_quaternion of this ISD200. + :rtype: float + """ + return self._t0_quaternion + + @t0_quaternion.setter + def t0_quaternion(self, t0_quaternion: float): + """Sets the t0_quaternion of this ISD200. + + First quaternion time - center image time. # noqa: E501 + + :param t0_quaternion: The t0_quaternion of this ISD200. + :type t0_quaternion: float + """ + + self._t0_quaternion = t0_quaternion + + @property + def reference_height(self) -> ISD200ReferenceHeight: + """Gets the reference_height of this ISD200. + + + :return: The reference_height of this ISD200. + :rtype: ISD200ReferenceHeight + """ + return self._reference_height + + @reference_height.setter + def reference_height(self, reference_height: ISD200ReferenceHeight): + """Sets the reference_height of this ISD200. + + + :param reference_height: The reference_height of this ISD200. + :type reference_height: ISD200ReferenceHeight + """ + if reference_height is None: + raise ValueError("Invalid value for `reference_height`, must not be `None`") # noqa: E501 + + self._reference_height = reference_height + + @property + def interpolation_method(self) -> str: + """Gets the interpolation_method of this ISD200. + + The type of interpolation method to use. # noqa: E501 + + :return: The interpolation_method of this ISD200. + :rtype: str + """ + return self._interpolation_method + + @interpolation_method.setter + def interpolation_method(self, interpolation_method: str): + """Sets the interpolation_method of this ISD200. + + The type of interpolation method to use. # noqa: E501 + + :param interpolation_method: The interpolation_method of this ISD200. + :type interpolation_method: str + """ + allowed_values = ["lagrange"] # noqa: E501 + if interpolation_method not in allowed_values: + raise ValueError( + "Invalid value for `interpolation_method` ({0}), must be one of {1}" + .format(interpolation_method, allowed_values) + ) + + self._interpolation_method = interpolation_method diff --git a/minipf/models/isd200_detector_center.py b/minipf/models/isd200_detector_center.py new file mode 100644 index 0000000..c44ad37 --- /dev/null +++ b/minipf/models/isd200_detector_center.py @@ -0,0 +1,94 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class ISD200DetectorCenter(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, line: float=None, sample: float=None): # noqa: E501 + """ISD200DetectorCenter - a model defined in OpenAPI + + :param line: The line of this ISD200DetectorCenter. # noqa: E501 + :type line: float + :param sample: The sample of this ISD200DetectorCenter. # noqa: E501 + :type sample: float + """ + self.openapi_types = { + 'line': float, + 'sample': float + } + + self.attribute_map = { + 'line': 'line', + 'sample': 'sample' + } + + self._line = line + self._sample = sample + + @classmethod + def from_dict(cls, dikt) -> 'ISD200DetectorCenter': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200_detector_center of this ISD200DetectorCenter. # noqa: E501 + :rtype: ISD200DetectorCenter + """ + return util.deserialize_model(dikt, cls) + + @property + def line(self) -> float: + """Gets the line of this ISD200DetectorCenter. + + + :return: The line of this ISD200DetectorCenter. + :rtype: float + """ + return self._line + + @line.setter + def line(self, line: float): + """Sets the line of this ISD200DetectorCenter. + + + :param line: The line of this ISD200DetectorCenter. + :type line: float + """ + if line is None: + raise ValueError("Invalid value for `line`, must not be `None`") # noqa: E501 + + self._line = line + + @property + def sample(self) -> float: + """Gets the sample of this ISD200DetectorCenter. + + + :return: The sample of this ISD200DetectorCenter. + :rtype: float + """ + return self._sample + + @sample.setter + def sample(self, sample: float): + """Sets the sample of this ISD200DetectorCenter. + + + :param sample: The sample of this ISD200DetectorCenter. + :type sample: float + """ + if sample is None: + raise ValueError("Invalid value for `sample`, must not be `None`") # noqa: E501 + + self._sample = sample diff --git a/minipf/models/isd200_focal_length_model.py b/minipf/models/isd200_focal_length_model.py new file mode 100644 index 0000000..01bcf31 --- /dev/null +++ b/minipf/models/isd200_focal_length_model.py @@ -0,0 +1,124 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class ISD200FocalLengthModel(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, key: str=None, focal_length: float=None, focal_epsilon: float=None): # noqa: E501 + """ISD200FocalLengthModel - a model defined in OpenAPI + + :param key: The key of this ISD200FocalLengthModel. # noqa: E501 + :type key: str + :param focal_length: The focal_length of this ISD200FocalLengthModel. # noqa: E501 + :type focal_length: float + :param focal_epsilon: The focal_epsilon of this ISD200FocalLengthModel. # noqa: E501 + :type focal_epsilon: float + """ + self.openapi_types = { + 'key': str, + 'focal_length': float, + 'focal_epsilon': float + } + + self.attribute_map = { + 'key': 'key', + 'focal_length': 'focal_length', + 'focal_epsilon': 'focal_epsilon' + } + + self._key = key + self._focal_length = focal_length + self._focal_epsilon = focal_epsilon + + @classmethod + def from_dict(cls, dikt) -> 'ISD200FocalLengthModel': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200_focal_length_model of this ISD200FocalLengthModel. # noqa: E501 + :rtype: ISD200FocalLengthModel + """ + return util.deserialize_model(dikt, cls) + + @property + def key(self) -> str: + """Gets the key of this ISD200FocalLengthModel. + + A key to get information about time/temp dependent focal length models # noqa: E501 + + :return: The key of this ISD200FocalLengthModel. + :rtype: str + """ + return self._key + + @key.setter + def key(self, key: str): + """Sets the key of this ISD200FocalLengthModel. + + A key to get information about time/temp dependent focal length models # noqa: E501 + + :param key: The key of this ISD200FocalLengthModel. + :type key: str + """ + + self._key = key + + @property + def focal_length(self) -> float: + """Gets the focal_length of this ISD200FocalLengthModel. + + The focal length in mm # noqa: E501 + + :return: The focal_length of this ISD200FocalLengthModel. + :rtype: float + """ + return self._focal_length + + @focal_length.setter + def focal_length(self, focal_length: float): + """Sets the focal_length of this ISD200FocalLengthModel. + + The focal length in mm # noqa: E501 + + :param focal_length: The focal_length of this ISD200FocalLengthModel. + :type focal_length: float + """ + if focal_length is None: + raise ValueError("Invalid value for `focal_length`, must not be `None`") # noqa: E501 + + self._focal_length = focal_length + + @property + def focal_epsilon(self) -> float: + """Gets the focal_epsilon of this ISD200FocalLengthModel. + + The uncertainty of the focal length in mm # noqa: E501 + + :return: The focal_epsilon of this ISD200FocalLengthModel. + :rtype: float + """ + return self._focal_epsilon + + @focal_epsilon.setter + def focal_epsilon(self, focal_epsilon: float): + """Sets the focal_epsilon of this ISD200FocalLengthModel. + + The uncertainty of the focal length in mm # noqa: E501 + + :param focal_epsilon: The focal_epsilon of this ISD200FocalLengthModel. + :type focal_epsilon: float + """ + + self._focal_epsilon = focal_epsilon diff --git a/minipf/models/isd200_radii.py b/minipf/models/isd200_radii.py new file mode 100644 index 0000000..c7bb518 --- /dev/null +++ b/minipf/models/isd200_radii.py @@ -0,0 +1,120 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class ISD200Radii(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, semimajor: float=None, semiminor: float=None, unit: str=None): # noqa: E501 + """ISD200Radii - a model defined in OpenAPI + + :param semimajor: The semimajor of this ISD200Radii. # noqa: E501 + :type semimajor: float + :param semiminor: The semiminor of this ISD200Radii. # noqa: E501 + :type semiminor: float + :param unit: The unit of this ISD200Radii. # noqa: E501 + :type unit: str + """ + self.openapi_types = { + 'semimajor': float, + 'semiminor': float, + 'unit': str + } + + self.attribute_map = { + 'semimajor': 'semimajor', + 'semiminor': 'semiminor', + 'unit': 'unit' + } + + self._semimajor = semimajor + self._semiminor = semiminor + self._unit = unit + + @classmethod + def from_dict(cls, dikt) -> 'ISD200Radii': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200_radii of this ISD200Radii. # noqa: E501 + :rtype: ISD200Radii + """ + return util.deserialize_model(dikt, cls) + + @property + def semimajor(self) -> float: + """Gets the semimajor of this ISD200Radii. + + + :return: The semimajor of this ISD200Radii. + :rtype: float + """ + return self._semimajor + + @semimajor.setter + def semimajor(self, semimajor: float): + """Sets the semimajor of this ISD200Radii. + + + :param semimajor: The semimajor of this ISD200Radii. + :type semimajor: float + """ + if semimajor is None: + raise ValueError("Invalid value for `semimajor`, must not be `None`") # noqa: E501 + + self._semimajor = semimajor + + @property + def semiminor(self) -> float: + """Gets the semiminor of this ISD200Radii. + + + :return: The semiminor of this ISD200Radii. + :rtype: float + """ + return self._semiminor + + @semiminor.setter + def semiminor(self, semiminor: float): + """Sets the semiminor of this ISD200Radii. + + + :param semiminor: The semiminor of this ISD200Radii. + :type semiminor: float + """ + + self._semiminor = semiminor + + @property + def unit(self) -> str: + """Gets the unit of this ISD200Radii. + + + :return: The unit of this ISD200Radii. + :rtype: str + """ + return self._unit + + @unit.setter + def unit(self, unit: str): + """Sets the unit of this ISD200Radii. + + + :param unit: The unit of this ISD200Radii. + :type unit: str + """ + if unit is None: + raise ValueError("Invalid value for `unit`, must not be `None`") # noqa: E501 + + self._unit = unit diff --git a/minipf/models/isd200_reference_height.py b/minipf/models/isd200_reference_height.py new file mode 100644 index 0000000..d82034d --- /dev/null +++ b/minipf/models/isd200_reference_height.py @@ -0,0 +1,124 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class ISD200ReferenceHeight(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, minheight: float=None, maxheight: float=None, unit: str=None): # noqa: E501 + """ISD200ReferenceHeight - a model defined in OpenAPI + + :param minheight: The minheight of this ISD200ReferenceHeight. # noqa: E501 + :type minheight: float + :param maxheight: The maxheight of this ISD200ReferenceHeight. # noqa: E501 + :type maxheight: float + :param unit: The unit of this ISD200ReferenceHeight. # noqa: E501 + :type unit: str + """ + self.openapi_types = { + 'minheight': float, + 'maxheight': float, + 'unit': str + } + + self.attribute_map = { + 'minheight': 'minheight', + 'maxheight': 'maxheight', + 'unit': 'unit' + } + + self._minheight = minheight + self._maxheight = maxheight + self._unit = unit + + @classmethod + def from_dict(cls, dikt) -> 'ISD200ReferenceHeight': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200_reference_height of this ISD200ReferenceHeight. # noqa: E501 + :rtype: ISD200ReferenceHeight + """ + return util.deserialize_model(dikt, cls) + + @property + def minheight(self) -> float: + """Gets the minheight of this ISD200ReferenceHeight. + + + :return: The minheight of this ISD200ReferenceHeight. + :rtype: float + """ + return self._minheight + + @minheight.setter + def minheight(self, minheight: float): + """Sets the minheight of this ISD200ReferenceHeight. + + + :param minheight: The minheight of this ISD200ReferenceHeight. + :type minheight: float + """ + if minheight is None: + raise ValueError("Invalid value for `minheight`, must not be `None`") # noqa: E501 + + self._minheight = minheight + + @property + def maxheight(self) -> float: + """Gets the maxheight of this ISD200ReferenceHeight. + + + :return: The maxheight of this ISD200ReferenceHeight. + :rtype: float + """ + return self._maxheight + + @maxheight.setter + def maxheight(self, maxheight: float): + """Sets the maxheight of this ISD200ReferenceHeight. + + + :param maxheight: The maxheight of this ISD200ReferenceHeight. + :type maxheight: float + """ + if maxheight is None: + raise ValueError("Invalid value for `maxheight`, must not be `None`") # noqa: E501 + + self._maxheight = maxheight + + @property + def unit(self) -> str: + """Gets the unit of this ISD200ReferenceHeight. + + The unit that heights are provided in # noqa: E501 + + :return: The unit of this ISD200ReferenceHeight. + :rtype: str + """ + return self._unit + + @unit.setter + def unit(self, unit: str): + """Sets the unit of this ISD200ReferenceHeight. + + The unit that heights are provided in # noqa: E501 + + :param unit: The unit of this ISD200ReferenceHeight. + :type unit: str + """ + if unit is None: + raise ValueError("Invalid value for `unit`, must not be `None`") # noqa: E501 + + self._unit = unit diff --git a/minipf/models/isd200_sensor_position.py b/minipf/models/isd200_sensor_position.py new file mode 100644 index 0000000..11d6146 --- /dev/null +++ b/minipf/models/isd200_sensor_position.py @@ -0,0 +1,117 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf.models.xyz import XYZ # noqa: F401,E501 +from minipf import util + + +class ISD200SensorPosition(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, velocities: List[XYZ]=None, unit: str=None, positions: List[XYZ]=None): # noqa: E501 + """ISD200SensorPosition - a model defined in OpenAPI + + :param velocities: The velocities of this ISD200SensorPosition. # noqa: E501 + :type velocities: List[XYZ] + :param unit: The unit of this ISD200SensorPosition. # noqa: E501 + :type unit: str + :param positions: The positions of this ISD200SensorPosition. # noqa: E501 + :type positions: List[XYZ] + """ + self.openapi_types = { + 'velocities': List[XYZ], + 'unit': str, + 'positions': List[XYZ] + } + + self.attribute_map = { + 'velocities': 'velocities', + 'unit': 'unit', + 'positions': 'positions' + } + + self._velocities = velocities + self._unit = unit + self._positions = positions + + @classmethod + def from_dict(cls, dikt) -> 'ISD200SensorPosition': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200_sensor_position of this ISD200SensorPosition. # noqa: E501 + :rtype: ISD200SensorPosition + """ + return util.deserialize_model(dikt, cls) + + @property + def velocities(self) -> List[XYZ]: + """Gets the velocities of this ISD200SensorPosition. + + + :return: The velocities of this ISD200SensorPosition. + :rtype: List[XYZ] + """ + return self._velocities + + @velocities.setter + def velocities(self, velocities: List[XYZ]): + """Sets the velocities of this ISD200SensorPosition. + + + :param velocities: The velocities of this ISD200SensorPosition. + :type velocities: List[XYZ] + """ + + self._velocities = velocities + + @property + def unit(self) -> str: + """Gets the unit of this ISD200SensorPosition. + + + :return: The unit of this ISD200SensorPosition. + :rtype: str + """ + return self._unit + + @unit.setter + def unit(self, unit: str): + """Sets the unit of this ISD200SensorPosition. + + + :param unit: The unit of this ISD200SensorPosition. + :type unit: str + """ + + self._unit = unit + + @property + def positions(self) -> List[XYZ]: + """Gets the positions of this ISD200SensorPosition. + + + :return: The positions of this ISD200SensorPosition. + :rtype: List[XYZ] + """ + return self._positions + + @positions.setter + def positions(self, positions: List[XYZ]): + """Sets the positions of this ISD200SensorPosition. + + + :param positions: The positions of this ISD200SensorPosition. + :type positions: List[XYZ] + """ + + self._positions = positions diff --git a/minipf/models/isd200_sun_position.py b/minipf/models/isd200_sun_position.py new file mode 100644 index 0000000..62e54db --- /dev/null +++ b/minipf/models/isd200_sun_position.py @@ -0,0 +1,117 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf.models.xyz import XYZ # noqa: F401,E501 +from minipf import util + + +class ISD200SunPosition(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, velocities: XYZ=None, unit: str=None, positions: XYZ=None): # noqa: E501 + """ISD200SunPosition - a model defined in OpenAPI + + :param velocities: The velocities of this ISD200SunPosition. # noqa: E501 + :type velocities: XYZ + :param unit: The unit of this ISD200SunPosition. # noqa: E501 + :type unit: str + :param positions: The positions of this ISD200SunPosition. # noqa: E501 + :type positions: XYZ + """ + self.openapi_types = { + 'velocities': XYZ, + 'unit': str, + 'positions': XYZ + } + + self.attribute_map = { + 'velocities': 'velocities', + 'unit': 'unit', + 'positions': 'positions' + } + + self._velocities = velocities + self._unit = unit + self._positions = positions + + @classmethod + def from_dict(cls, dikt) -> 'ISD200SunPosition': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The ISD200_sun_position of this ISD200SunPosition. # noqa: E501 + :rtype: ISD200SunPosition + """ + return util.deserialize_model(dikt, cls) + + @property + def velocities(self) -> XYZ: + """Gets the velocities of this ISD200SunPosition. + + + :return: The velocities of this ISD200SunPosition. + :rtype: XYZ + """ + return self._velocities + + @velocities.setter + def velocities(self, velocities: XYZ): + """Sets the velocities of this ISD200SunPosition. + + + :param velocities: The velocities of this ISD200SunPosition. + :type velocities: XYZ + """ + + self._velocities = velocities + + @property + def unit(self) -> str: + """Gets the unit of this ISD200SunPosition. + + + :return: The unit of this ISD200SunPosition. + :rtype: str + """ + return self._unit + + @unit.setter + def unit(self, unit: str): + """Sets the unit of this ISD200SunPosition. + + + :param unit: The unit of this ISD200SunPosition. + :type unit: str + """ + + self._unit = unit + + @property + def positions(self) -> XYZ: + """Gets the positions of this ISD200SunPosition. + + + :return: The positions of this ISD200SunPosition. + :rtype: XYZ + """ + return self._positions + + @positions.setter + def positions(self, positions: XYZ): + """Sets the positions of this ISD200SunPosition. + + + :param positions: The positions of this ISD200SunPosition. + :type positions: XYZ + """ + + self._positions = positions diff --git a/minipf/models/optical_distortion.py b/minipf/models/optical_distortion.py new file mode 100644 index 0000000..19c360c --- /dev/null +++ b/minipf/models/optical_distortion.py @@ -0,0 +1,92 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf.models.optical_distortion_radial import OpticalDistortionRadial # noqa: F401,E501 +from minipf.models.optical_distortion_transverse import OpticalDistortionTransverse # noqa: F401,E501 +from minipf import util + + +class OpticalDistortion(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, transverse: OpticalDistortionTransverse=None, radial: OpticalDistortionRadial=None): # noqa: E501 + """OpticalDistortion - a model defined in OpenAPI + + :param transverse: The transverse of this OpticalDistortion. # noqa: E501 + :type transverse: OpticalDistortionTransverse + :param radial: The radial of this OpticalDistortion. # noqa: E501 + :type radial: OpticalDistortionRadial + """ + self.openapi_types = { + 'transverse': OpticalDistortionTransverse, + 'radial': OpticalDistortionRadial + } + + self.attribute_map = { + 'transverse': 'transverse', + 'radial': 'radial' + } + + self._transverse = transverse + self._radial = radial + + @classmethod + def from_dict(cls, dikt) -> 'OpticalDistortion': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The optical_distortion of this OpticalDistortion. # noqa: E501 + :rtype: OpticalDistortion + """ + return util.deserialize_model(dikt, cls) + + @property + def transverse(self) -> OpticalDistortionTransverse: + """Gets the transverse of this OpticalDistortion. + + + :return: The transverse of this OpticalDistortion. + :rtype: OpticalDistortionTransverse + """ + return self._transverse + + @transverse.setter + def transverse(self, transverse: OpticalDistortionTransverse): + """Sets the transverse of this OpticalDistortion. + + + :param transverse: The transverse of this OpticalDistortion. + :type transverse: OpticalDistortionTransverse + """ + + self._transverse = transverse + + @property + def radial(self) -> OpticalDistortionRadial: + """Gets the radial of this OpticalDistortion. + + + :return: The radial of this OpticalDistortion. + :rtype: OpticalDistortionRadial + """ + return self._radial + + @radial.setter + def radial(self, radial: OpticalDistortionRadial): + """Sets the radial of this OpticalDistortion. + + + :param radial: The radial of this OpticalDistortion. + :type radial: OpticalDistortionRadial + """ + + self._radial = radial diff --git a/minipf/models/optical_distortion_radial.py b/minipf/models/optical_distortion_radial.py new file mode 100644 index 0000000..0c419cd --- /dev/null +++ b/minipf/models/optical_distortion_radial.py @@ -0,0 +1,64 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class OpticalDistortionRadial(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, coefficients: List[float]=None): # noqa: E501 + """OpticalDistortionRadial - a model defined in OpenAPI + + :param coefficients: The coefficients of this OpticalDistortionRadial. # noqa: E501 + :type coefficients: List[float] + """ + self.openapi_types = { + 'coefficients': List[float] + } + + self.attribute_map = { + 'coefficients': 'coefficients' + } + + self._coefficients = coefficients + + @classmethod + def from_dict(cls, dikt) -> 'OpticalDistortionRadial': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The optical_distortion_radial of this OpticalDistortionRadial. # noqa: E501 + :rtype: OpticalDistortionRadial + """ + return util.deserialize_model(dikt, cls) + + @property + def coefficients(self) -> List[float]: + """Gets the coefficients of this OpticalDistortionRadial. + + + :return: The coefficients of this OpticalDistortionRadial. + :rtype: List[float] + """ + return self._coefficients + + @coefficients.setter + def coefficients(self, coefficients: List[float]): + """Sets the coefficients of this OpticalDistortionRadial. + + + :param coefficients: The coefficients of this OpticalDistortionRadial. + :type coefficients: List[float] + """ + + self._coefficients = coefficients diff --git a/minipf/models/optical_distortion_transverse.py b/minipf/models/optical_distortion_transverse.py new file mode 100644 index 0000000..f875153 --- /dev/null +++ b/minipf/models/optical_distortion_transverse.py @@ -0,0 +1,90 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class OpticalDistortionTransverse(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, x: List[float]=None, y: List[float]=None): # noqa: E501 + """OpticalDistortionTransverse - a model defined in OpenAPI + + :param x: The x of this OpticalDistortionTransverse. # noqa: E501 + :type x: List[float] + :param y: The y of this OpticalDistortionTransverse. # noqa: E501 + :type y: List[float] + """ + self.openapi_types = { + 'x': List[float], + 'y': List[float] + } + + self.attribute_map = { + 'x': 'x', + 'y': 'y' + } + + self._x = x + self._y = y + + @classmethod + def from_dict(cls, dikt) -> 'OpticalDistortionTransverse': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The optical_distortion_transverse of this OpticalDistortionTransverse. # noqa: E501 + :rtype: OpticalDistortionTransverse + """ + return util.deserialize_model(dikt, cls) + + @property + def x(self) -> List[float]: + """Gets the x of this OpticalDistortionTransverse. + + + :return: The x of this OpticalDistortionTransverse. + :rtype: List[float] + """ + return self._x + + @x.setter + def x(self, x: List[float]): + """Sets the x of this OpticalDistortionTransverse. + + + :param x: The x of this OpticalDistortionTransverse. + :type x: List[float] + """ + + self._x = x + + @property + def y(self) -> List[float]: + """Gets the y of this OpticalDistortionTransverse. + + + :return: The y of this OpticalDistortionTransverse. + :rtype: List[float] + """ + return self._y + + @y.setter + def y(self, y: List[float]): + """Sets the y of this OpticalDistortionTransverse. + + + :param y: The y of this OpticalDistortionTransverse. + :type y: List[float] + """ + + self._y = y diff --git a/minipf/models/quaternion.py b/minipf/models/quaternion.py new file mode 100644 index 0000000..ea0cb62 --- /dev/null +++ b/minipf/models/quaternion.py @@ -0,0 +1,37 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class Quaternion(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """Quaternion - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'Quaternion': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Quaternion of this Quaternion. # noqa: E501 + :rtype: Quaternion + """ + return util.deserialize_model(dikt, cls) diff --git a/minipf/models/quaternions.py b/minipf/models/quaternions.py new file mode 100644 index 0000000..57acf3c --- /dev/null +++ b/minipf/models/quaternions.py @@ -0,0 +1,68 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class Quaternions(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, quaternions: List[List[float]]=None): # noqa: E501 + """Quaternions - a model defined in OpenAPI + + :param quaternions: The quaternions of this Quaternions. # noqa: E501 + :type quaternions: List[List[float]] + """ + self.openapi_types = { + 'quaternions': List[List[float]] + } + + self.attribute_map = { + 'quaternions': 'quaternions' + } + + self._quaternions = quaternions + + @classmethod + def from_dict(cls, dikt) -> 'Quaternions': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Quaternions of this Quaternions. # noqa: E501 + :rtype: Quaternions + """ + return util.deserialize_model(dikt, cls) + + @property + def quaternions(self) -> List[List[float]]: + """Gets the quaternions of this Quaternions. + + Orientation of the sensor provided in quaternions # noqa: E501 + + :return: The quaternions of this Quaternions. + :rtype: List[List[float]] + """ + return self._quaternions + + @quaternions.setter + def quaternions(self, quaternions: List[List[float]]): + """Sets the quaternions of this Quaternions. + + Orientation of the sensor provided in quaternions # noqa: E501 + + :param quaternions: The quaternions of this Quaternions. + :type quaternions: List[List[float]] + """ + if quaternions is None: + raise ValueError("Invalid value for `quaternions`, must not be `None`") # noqa: E501 + + self._quaternions = quaternions diff --git a/minipf/models/request_isd.py b/minipf/models/request_isd.py new file mode 100644 index 0000000..e48d088 --- /dev/null +++ b/minipf/models/request_isd.py @@ -0,0 +1,64 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class RequestISD(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self, label: str=None): # noqa: E501 + """RequestISD - a model defined in OpenAPI + + :param label: The label of this RequestISD. # noqa: E501 + :type label: str + """ + self.openapi_types = { + 'label': str + } + + self.attribute_map = { + 'label': 'label' + } + + self._label = label + + @classmethod + def from_dict(cls, dikt) -> 'RequestISD': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The request_ISD of this RequestISD. # noqa: E501 + :rtype: RequestISD + """ + return util.deserialize_model(dikt, cls) + + @property + def label(self) -> str: + """Gets the label of this RequestISD. + + + :return: The label of this RequestISD. + :rtype: str + """ + return self._label + + @label.setter + def label(self, label: str): + """Sets the label of this RequestISD. + + + :param label: The label of this RequestISD. + :type label: str + """ + + self._label = label diff --git a/minipf/models/xyz.py b/minipf/models/xyz.py new file mode 100644 index 0000000..7e18041 --- /dev/null +++ b/minipf/models/xyz.py @@ -0,0 +1,37 @@ +# coding: utf-8 + +from __future__ import absolute_import +from datetime import date, datetime # noqa: F401 + +from typing import List, Dict # noqa: F401 + +from minipf.models.base_model_ import Model +from minipf import util + + +class XYZ(Model): + """NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + + Do not edit the class manually. + """ + + def __init__(self): # noqa: E501 + """XYZ - a model defined in OpenAPI + + """ + self.openapi_types = { + } + + self.attribute_map = { + } + + @classmethod + def from_dict(cls, dikt) -> 'XYZ': + """Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The XYZ of this XYZ. # noqa: E501 + :rtype: XYZ + """ + return util.deserialize_model(dikt, cls) diff --git a/minipf/util.py b/minipf/util.py new file mode 100644 index 0000000..75e2345 --- /dev/null +++ b/minipf/util.py @@ -0,0 +1,215 @@ +import datetime + +import os +import six +import typing +import numpy as np +from glob import glob +from os import path +from itertools import groupby, filterfalse +from minipf import config + + + +def _deserialize(data, klass): + """Deserializes dict, list, str into an object. + + :param data: dict, list or str. + :param klass: class literal, or string of class name. + + :return: object. + """ + if data is None: + return None + if klass in six.integer_types or klass in (float, str, bool): + return _deserialize_primitive(data, klass) + elif klass == object: + return _deserialize_object(data) + elif klass == datetime.date: + return deserialize_date(data) + elif klass == datetime.datetime: + return deserialize_datetime(data) + elif type(klass) == typing._GenericAlias: + if klass.__origin__ == list: + return _deserialize_list(data, klass.__args__[0]) + if klass.__origin__ == dict: + return _deserialize_dict(data, klass.__args__[1]) + else: + return deserialize_model(data, klass) + + +def _deserialize_primitive(data, klass): + """Deserializes to primitive type. + + :param data: data to deserialize. + :param klass: class literal. + + :return: int, long, float, str, bool. + :rtype: int | long | float | str | bool + """ + try: + value = klass(data) + except UnicodeEncodeError: + value = six.u(data) + except TypeError: + value = data + return value + + +def _deserialize_object(value): + """Return an original value. + + :return: object. + """ + return value + + +def deserialize_date(string): + """Deserializes string to date. + + :param string: str. + :type string: str + :return: date. + :rtype: date + """ + try: + from dateutil.parser import parse + return parse(string).date() + except ImportError: + return string + + +def deserialize_datetime(string): + """Deserializes string to datetime. + + The string should be in iso8601 datetime format. + + :param string: str. + :type string: str + :return: datetime. + :rtype: datetime + """ + try: + from dateutil.parser import parse + return parse(string) + except ImportError: + return string + + +def deserialize_model(data, klass): + """Deserializes list or dict to model. + + :param data: dict, list. + :type data: dict | list + :param klass: class literal. + :return: model object. + """ + instance = klass() + + if not instance.openapi_types: + return data + + for attr, attr_type in six.iteritems(instance.openapi_types): + if data is not None \ + and instance.attribute_map[attr] in data \ + and isinstance(data, (list, dict)): + value = data[instance.attribute_map[attr]] + setattr(instance, attr, _deserialize(value, attr_type)) + + return instance + + +def _deserialize_list(data, boxed_type): + """Deserializes a list and its elements. + + :param data: list to deserialize. + :type data: list + :param boxed_type: class literal. + + :return: deserialized list. + :rtype: list + """ + return [_deserialize(sub_data, boxed_type) + for sub_data in data] + + +def _deserialize_dict(data, boxed_type): + """Deserializes a dict and its elements. + + :param data: dict to deserialize. + :type data: dict + :param boxed_type: class literal. + + :return: deserialized dict. + :rtype: dict + """ + return {k: _deserialize(v, boxed_type) + for k, v in six.iteritems(data)} + + +def get_metakernels(spice_dir=config.spice_root, missions=set(), years=set(), versions=set()): + """ + Given a root directory, get any subdirectory containing metakernels, + assume spice directory structure. + + Mostly doing filtering here, might be worth using Pandas? + """ + if not missions or missions == "all": + missions = set() + if not years or years == "all": + years = set() + if not versions or versions == "all": + versions = set() + + if isinstance(missions, str): + missions = {missions} + + if isinstance(years, str) or isinstance(years, int): + years = {str(years)} + else: + years = {str(year) for year in years} + + avail = { + 'count': 0, + 'data': [] + } + + mission_dirs = list(filter(os.path.isdir, glob(os.path.join(spice_dir, '*')))) + + for md in mission_dirs: + # Assuming spice root has the same name as the original on NAIF website" + mission = os.path.basename(md).split('-')[0] + if missions and mission not in missions: + continue + + metakernel_keys = ['mission', 'year', 'version', 'path'] + + # recursive glob to make metakernel search more robust to subtle directory structure differences + metakernel_paths = sorted(glob(os.path.join(md, '**','*.tm'), recursive=True)) + + metakernels = [dict(zip(metakernel_keys, [mission]+path.splitext(path.basename(k))[0].split('_')[1:3] + [k])) for k in metakernel_paths] + + # naive filter, do we really need anything else? + if years: + metakernels = list(filter(lambda x:x['year'] in years, metakernels)) + if versions: + if versions == 'latest': + latest = [] + # Panda's groupby is overrated + for k, g in groupby(metakernels, lambda x:x['year']): + items = list(g) + latest.append(max(items, key=lambda x:x['version'])) + metakernels = latest + else: + metakernels = list(filter(lambda x:x['version'] in versions, metakernels)) + + avail['data'].extend(metakernels) + + avail['count'] = len(avail['data']) + if not avail: + avail = { + 'count' : 0, + 'data' : 'ERROR: NONE OF {} ARE VALID MISSIONS'.format(missions) + } + + return avail diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..167fa74 --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +# coding: utf-8 + +import sys +from setuptools import setup, find_packages + +NAME = "minipf" +VERSION = "0.0.1" + +# To install the library, run the following +# +# python setup.py install +# +# prerequisite: setuptools +# http://pypi.python.org/pypi/setuptools + +setup( + name=NAME, + version=VERSION, + description="Barebones version of pfeffernusse", + author_email="jlaura@usgs.gov", + url="", + keywords=["Pfeffernusse"], + packages=find_packages(), + long_description="""\ + A SpiceAPI for extracting NAIF Spice Data + """ +) -- GitLab