From 8aab70936ae48010b3ef23d46cb6d87ca47d8e5c Mon Sep 17 00:00:00 2001 From: Austin Sanders Date: Thu, 2 Jun 2022 11:09:51 -0700 Subject: [PATCH 01/73] Initial spiceql integration --- ale/base/data_naif.py | 222 +++++++++++++++++++------------ ale/drivers/co_drivers.py | 9 +- ale/drivers/dawn_drivers.py | 15 ++- ale/drivers/galileo_drivers.py | 10 +- ale/drivers/hayabusa2_drivers.py | 2 - ale/drivers/lro_drivers.py | 54 ++++---- ale/drivers/mess_drivers.py | 15 ++- ale/drivers/mex_drivers.py | 15 ++- ale/drivers/mro_drivers.py | 3 +- ale/drivers/nh_drivers.py | 5 +- ale/drivers/selene_drivers.py | 182 +++++++++++++++++++++---- ale/drivers/tgo_drivers.py | 4 +- ale/drivers/viking_drivers.py | 5 +- ale/drivers/voyager_drivers.py | 2 +- 14 files changed, 365 insertions(+), 178 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 0f73b14cd..67ebf33d3 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -1,4 +1,5 @@ import spiceypy as spice +from pyspiceql import pyspiceql import numpy as np import scipy.constants @@ -19,7 +20,7 @@ def __enter__(self): to get the kernels furnished. """ if self.kernels: - [spice.furnsh(k) for k in self.kernels] + [pyspiceql.KernelPool.getInstance().load(k) for k in self.kernels] return self def __exit__(self, exc_type, exc_val, exc_tb): @@ -29,7 +30,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): kernels can be unloaded. """ if self.kernels: - [spice.unload(k) for k in self.kernels] + [pyspiceql.KernelPool.getInstance().unload(k) for k in self.kernels] @property def kernels(self): @@ -93,10 +94,12 @@ def light_time_correction(self): See https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/abcorr.html for the different options available. """ - try: - return spice.gcpool('INS{}_LIGHTTIME_CORRECTION'.format(self.ikid), 0, 1)[0] - except: - return 'LT+S' + if not hasattr(self, "_light_time_correction"): + try: + self._light_time_correction = pyspiceql.getKernelStringValue('INS{}_LIGHTTIME_CORRECTION'.format(self.ikid))[0] + except: + self._light_time_correction = 'LT+S' + return self._light_time_correction @property def odtx(self): @@ -109,7 +112,9 @@ def odtx(self): : list Optical distortion x coefficients """ - return spice.gdpool('INS{}_OD_T_X'.format(self.ikid),0, 10).tolist() + if not hasattr(self, "_odtx"): + self._odtx = pyspiceql.getKernelVectorValue('INS{}_OD_T_X'.format(self.ikid)).toList() + return self._odtx @property def odty(self): @@ -122,7 +127,9 @@ def odty(self): : list Optical distortion y coefficients """ - return spice.gdpool('INS{}_OD_T_Y'.format(self.ikid), 0, 10).tolist() + if not hasattr(self, "_odty"): + self._odty = pyspiceql.getKernelVectorValue('INS{}_OD_T_Y'.format(self.ikid)).toList() + return self._odty @property def odtk(self): @@ -135,7 +142,9 @@ def odtk(self): : list Radial distortion coefficients """ - return spice.gdpool('INS{}_OD_K'.format(self.ikid),0, 3).tolist() + if not hasattr(self, "_odtk"): + self._odtk = pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid)).toList() + return self._odtk @property def ikid(self): @@ -149,7 +158,9 @@ def ikid(self): : int Naif ID used to for identifying the instrument in Spice kernels """ - return spice.bods2c(self.instrument_id) + if not hasattr(self, "_ikid"): + self._ikid = pyspiceql.Kernel_translateFrame(self.instrument_id) + return self._ikid @property def spacecraft_id(self): @@ -163,7 +174,9 @@ def spacecraft_id(self): : int Naif ID code for the spacecraft """ - return spice.bods2c(self.spacecraft_name) + if not hasattr(self, "_spacecraft_id"): + self._spacecraft_id = pyspiceql.Kernel_translateFrame(self.spacecraft_name) + return self._spacecraft_id @property def target_id(self): @@ -177,7 +190,9 @@ def target_id(self): : int Naif ID code for the target body """ - return spice.bods2c(self.target_name) + if not hasattr(self, "_target_id"): + self._target_id = pyspiceql.Kernel_translateFrame(self.target_name) + return self._target_id @property def target_frame_id(self): @@ -191,8 +206,10 @@ def target_frame_id(self): : int Naif ID code for the target frame """ - frame_info = spice.cidfrm(self.target_id) - return frame_info[0] + if not hasattr(self, "_target_frame_id"): + frame_info = spice.cidfrm(self.target_id) + self._target_frame_id = frame_info[0] + return self._target_frame_id @property def sensor_frame_id(self): @@ -205,7 +222,9 @@ def sensor_frame_id(self): : int Naif ID code for the sensor frame """ - return self.ikid + if not hasattr(self, "_sensor_frame_id"): + self._sensor_frame_id = self.ikid + return self._sensor_frame_id @property def focal2pixel_lines(self): @@ -217,7 +236,9 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - return list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3)) + if not hasattr(self, "_focal2pixel_lines"): + self._focal2pixel_lines = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.ikid))) + return self._focal2pixel_lines @property def focal2pixel_samples(self): @@ -229,7 +250,9 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - return list(spice.gdpool('INS{}_ITRANSS'.format(self.ikid), 0, 3)) + if not hasattr(self, "_focal2pixel_lines"): + self._focal2pixel_samples = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSS'.format(self.ikid))) + return self._focal2pixel_samples @property def pixel2focal_x(self): @@ -241,7 +264,9 @@ def pixel2focal_x(self): : list detector to focal plane x """ - return list(spice.gdpool('INS{}_TRANSX'.format(self.ikid), 0, 3)) + if not hasattr(self, "_pixel2focal_x"): + self._pixel2focal_x = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSX'.format(self.ikid))) + return self._pixel2focal_x @property def pixel2focal_y(self): @@ -253,7 +278,9 @@ def pixel2focal_y(self): : list detector to focal plane y """ - return list(spice.gdpool('INS{}_TRANSY'.format(self.ikid), 0, 3)) + if not hasattr(self, "_pixel2focal_x"): + self._pixel2focal_y = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSY'.format(self.ikid))) + return self._pixel2focal_y @property def focal_length(self): @@ -266,7 +293,9 @@ def focal_length(self): : float focal length """ - return float(spice.gdpool('INS{}_FOCAL_LENGTH'.format(self.ikid), 0, 1)[0]) + if not hasattr(self, "_focal_length"): + self._focal_length = float(pyspiceql.getKernelStringValue('INS{}_FOCAL_LENGTH'.format(self.ikid))[0]) + return self._focal_length @property def pixel_size(self): @@ -277,7 +306,9 @@ def pixel_size(self): ------- : float pixel size """ - return spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + if not hasattr(self, "_pixel_size"): + self._pixel_size = pyspiceql.getKernelStringValue('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + return self._pixel_size @property def target_body_radii(self): @@ -291,8 +322,9 @@ def target_body_radii(self): : list Radius of all three axis of the target body """ - rad = spice.bodvrd(self.target_name, 'RADII', 3) - return rad[1] + if not hasattr(self, "_target_body_radii"): + self._target_body_radii = spice.bodvrd(self.target_name, 'RADII', 3)[1] + return self._target_body_radii @property def reference_frame(self): @@ -328,24 +360,27 @@ def sun_position(self): : (sun_positions, sun_velocities) a tuple containing a list of sun positions, a list of sun velocities """ - times = self.ephemeris_time - if len(times) > 1: - times = [times[0], times[-1]] - positions = [] - velocities = [] - - for time in times: - sun_state, _ = spice.spkezr("SUN", - time, - self.reference_frame, - 'LT+S', - self.target_name) - positions.append(sun_state[:3]) - velocities.append(sun_state[3:6]) - positions = 1000 * np.asarray(positions) - velocities = 1000 * np.asarray(velocities) - - return positions, velocities, times + if not hasattr(self, "_sun_position"): + times = [self.center_ephemeris_time] + if len(times) > 1: + times = [times[0], times[-1]] + positions = [] + velocities = [] + + for time in times: + sun_lt_state = pyspiceql.getTargetState(time, + self.target_name, + self.spacecraft_name, + 'J2000', + self.light_time_correction) + sun_state = sun_lt_state.starg + positions.append(sun_state[:3]) + velocities.append(sun_state[3:6]) + positions = 1000 * np.asarray(positions) + velocities = 1000 * np.asarray(velocities) + + self._sun_position = positions, velocities, times + return self._sun_position @property def sensor_position(self): @@ -380,45 +415,55 @@ def sensor_position(self): # location of the target. For more information, see: # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html if self.correct_lt_to_surface and self.light_time_correction.upper() == 'LT+S': - obs_tar_state, obs_tar_lt = spice.spkezr(target, - time, - 'J2000', - self.light_time_correction, - observer) + obs_tar = pyspiceql.getTargetState(time, + target, + observer, + 'J2000', + self.light_time_correction) + obs_tar_state = obs_tar.starg + obs_tar_lt = obs_tar.lt + # ssb to spacecraft - ssb_obs_state, ssb_obs_lt = spice.spkezr(observer, - time, - 'J2000', - 'NONE', - 'SSB') + ssb_obs = pyspiceql.getTargetState(time, + target, + 'SSB', + 'J2000', + "NONE") + ssb_obs_state = ssb_obs.starg + ssb_obs_lt = ssb_obs.lt radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = time - obs_tar_lt + radius_lt - ssb_tar_state, ssb_tar_lt = spice.spkezr(target, - adjusted_time, - 'J2000', - 'NONE', - 'SSB') + + ssb_tar = pyspiceql.getTargetState(adjusted_time, + target, + 'SSB', + 'J2000', + "NONE") + ssb_tar_state = ssb_tar.starg + ssb_tar_lt = ssb_tar.lt state = ssb_tar_state - ssb_obs_state + matrix = spice.sxform("J2000", self.reference_frame, time) state = spice.mxvg(matrix, state) else: - state, _ = spice.spkezr(target, - time, - self.reference_frame, - self.light_time_correction, - observer) + state = pyspiceql.getTargetState(time, + target, + observer, + self.reference_frame, + self.light_time_correction) if self.swap_observer_target: - pos.append(-state[:3]) - vel.append(-state[3:]) + pos.append(-state.starg[:3]) + vel.append(-state.starg[3:]) else: - pos.append(state[:3]) - vel.append(state[3:]) + pos.append(state.starg[:3]) + vel.append(state.starg[3:]) + # By default, SPICE works in km, so convert to m - self._position = [p * 1000 for p in pos] - self._velocity = [v * 1000 for v in vel] + self._position = 1000 * np.asarray(pos) + self._velocity = 1000 * np.asarray(vel) return self._position, self._velocity, self.ephemeris_time @property @@ -447,7 +492,7 @@ def frame_chain(self): velocity_axis = 2 # Get the default line translation with no potential flipping # from the driver - trans_x = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) + trans_x = np.array(self.focal2pixel_lines) if (trans_x[0] < trans_x[1]): velocity_axis = 1 @@ -492,7 +537,9 @@ def ephemeris_start_time(self): : double Starting ephemeris time of the image """ - return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_start_count) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = pyspiceql.sclkToEt(str(self.spacecraft_name), self.spacecraft_clock_start_count) + return self._ephemeris_start_time @property def ephemeris_stop_time(self): @@ -507,7 +554,9 @@ def ephemeris_stop_time(self): : double Ephemeris stop time of the image """ - return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_stop_count) + if not hasattr(self, "_ephemeris_stop_time"): + self._ephemeris_stop_time = pyspiceql.sclkToEt(self.spacecraft_name, self.spacecraft_clock_stop_count) + return self._ephemeris_stop_time @property def detector_center_sample(self): @@ -520,7 +569,9 @@ def detector_center_sample(self): : float Detector sample of the principal point """ - return float(spice.gdpool('INS{}_BORESIGHT_SAMPLE'.format(self.ikid), 0, 1)[0]) + if not hasattr(self, "_detector_center_sample"): + self._detector_center_sample = float(pyspiceql.getKernelStringValue('INS{}_BORESIGHT_SAMPLE'.format(self.ikid))[0]) + return self._detector_center_sample @property def detector_center_line(self): @@ -533,8 +584,9 @@ def detector_center_line(self): : float Detector line of the principal point """ - return float(spice.gdpool('INS{}_BORESIGHT_LINE'.format(self.ikid), 0, 1)[0]) - + if not hasattr(self, "_detector_center_line"): + self._detector_center_line = float(pyspiceql.getKernelStringValue('INS{}_BORESIGHT_LINE'.format(self.ikid))[0]) + return self._detector_center_line @property def swap_observer_target(self): @@ -547,11 +599,13 @@ def swap_observer_target(self): Expects ikid to be defined. This should be an integer containing the Naif Id code of the instrument. """ - try: - swap = spice.gcpool('INS{}_SWAP_OBSERVER_TARGET'.format(self.ikid), 0, 1)[0] - return swap.upper() == "TRUE" - except: - return False + if not hasattr(self, "_swap_observer_target"): + try: + swap = pyspiceql.getKernelStringValue('INS{}_SWAP_OBSERVER_TARGET'.format(self.ikid))[0] + self._swap_observer_target = swap.upper() == "TRUE" + except: + self._swap_observer_target = False + return self._swap_observer_target @property def correct_lt_to_surface(self): @@ -563,11 +617,13 @@ def correct_lt_to_surface(self): Expects ikid to be defined. This should be an integer containing the Naif Id code of the instrument. """ - try: - surface_correct = spice.gcpool('INS{}_LT_SURFACE_CORRECT'.format(self.ikid), 0, 1)[0] - return surface_correct.upper() == "TRUE" - except: - return False + if not hasattr(self, "_correct_lt_to_surface"): + try: + surface_correct = pyspiceql.getKernelStringValue('INS{}_LT_SURFACE_CORRECT'.format(self.ikid))[0] + self._correct_lt_to_surface = surface_correct.upper() == "TRUE" + except: + self._correct_lt_to_surface = False + return self._correct_lt_to_surface @property def naif_keywords(self): diff --git a/ale/drivers/co_drivers.py b/ale/drivers/co_drivers.py index a062d838d..de01c75b1 100644 --- a/ale/drivers/co_drivers.py +++ b/ale/drivers/co_drivers.py @@ -5,6 +5,7 @@ import pvl import spiceypy as spice +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice @@ -326,7 +327,7 @@ def focal_epsilon(self): : float focal epsilon """ - return float(spice.gdpool('INS{}_FL_UNCERTAINTY'.format(self.ikid), 0, 1)[0]) + return float(pyspiceql.getKernelVectorValue('INS{}_FL_UNCERTAINTY'.format(self.ikid))[0]) @property def spacecraft_name(self): @@ -353,7 +354,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ # Microns to mm - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 return [0.0, 1/pixel_size, 0.0] @property @@ -367,7 +368,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 return [0.0, 0.0, 1/pixel_size] @property @@ -443,7 +444,7 @@ def focal_length(self): try: default_focal_len = super(CassiniIssPds3LabelNaifSpiceDriver, self).focal_length except: - default_focal_len = float(spice.gdpool('INS{}_FOV_CENTER_PIXEL'.format(self.ikid), 0, 2)[0]) + default_focal_len = float(pyspiceql.getKernelVectorValue('INS{}_FOV_CENTER_PIXEL'.format(self.ikid))[0]) filters = tuple(self.label['FILTER_NAME']) diff --git a/ale/drivers/dawn_drivers.py b/ale/drivers/dawn_drivers.py index ee9b04321..00f1fc929 100644 --- a/ale/drivers/dawn_drivers.py +++ b/ale/drivers/dawn_drivers.py @@ -1,5 +1,4 @@ import pvl -import spiceypy as spice import os from glob import glob @@ -11,6 +10,7 @@ from ale.base.label_pds3 import Pds3Label from ale.base.type_distortion import NoDistortion from ale.base.type_sensor import Framer +from pyspiceql import pyspiceql ID_LOOKUP = { "FC1" : "DAWN_FC1", @@ -85,7 +85,7 @@ def ephemeris_start_time(self): """ if not hasattr(self, '_ephemeris_start_time'): sclock = self.spacecraft_clock_start_count - self._ephemeris_start_time = spice.scs2e(self.spacecraft_id, sclock) + self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) self._ephemeris_start_time += 193.0 / 1000.0 return self._ephemeris_start_time @@ -120,7 +120,7 @@ def odtk(self): : list Radial distortion coefficients """ - return spice.gdpool('INS{}_RAD_DIST_COEFF'.format(self.ikid),0, 1).tolist() + return pyspiceql.getKernelVectorValue('INS{}_RAD_DIST_COEFF'.format(self.ikid)).tolist() # TODO: Update focal2pixel samples and lines to reflect the rectangular # nature of dawn pixels @@ -136,7 +136,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ # Microns to mm - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 return [0.0, 1/pixel_size, 0.0] @property @@ -151,7 +151,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ # Microns to mm - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 return [0.0, 0.0, 1/pixel_size] @property @@ -182,7 +182,7 @@ def detector_center_sample(self): : float center detector sample """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)[0]) + 0.5 + return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid))[0]) + 0.5 @property def detector_center_line(self): @@ -200,7 +200,8 @@ def detector_center_line(self): : float center detector line """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)[1]) + 0.5 + return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid))[1]) + 0.5 + class DawnFcIsisLabelNaifSpiceDriver(Framer, IsisLabel, NaifSpice, NoDistortion, Driver): """ diff --git a/ale/drivers/galileo_drivers.py b/ale/drivers/galileo_drivers.py index c4b2d3476..4a7cab4b2 100644 --- a/ale/drivers/galileo_drivers.py +++ b/ale/drivers/galileo_drivers.py @@ -1,13 +1,12 @@ import datetime -import spiceypy as spice - import ale from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel from ale.base.type_sensor import Framer from ale.base.type_distortion import RadialDistortion from ale.base.base import Driver +from pyspiceql import pyspiceql ssi_id_lookup = { "SOLID STATE IMAGING SYSTEM" : "GLL_SSI_PLATFORM" @@ -62,8 +61,7 @@ def odtk(self): key_str = "_K1_COVER" else: key_str = "_K1" - k1 = spice.gdpool("INS" + str(self.ikid) + key_str, 0, 1); - return k1 + return pyspiceql.getKernelVectorValue("INS" + str(self.ikid) + key_str) @property def naif_keywords(self): @@ -76,7 +74,7 @@ def naif_keywords(self): Dictionary of keywords and values that ISIS creates and attaches to the label """ key = "INS" + str(self.ikid) + "_FOCAL_LENGTH_COVER"; - return {**super().naif_keywords, key: spice.gdpool(key, 0, 1)} + return {**super().naif_keywords, key: pyspiceql.getKernelStringValue(key)} @property def ephemeris_start_time(self): @@ -88,7 +86,7 @@ def ephemeris_start_time(self): : float start time """ - return spice.str2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + return pyspiceql.utc2et(self.utc_start_time) @property def center_ephemeris_time(self): diff --git a/ale/drivers/hayabusa2_drivers.py b/ale/drivers/hayabusa2_drivers.py index d2ab85f87..a392a5ecf 100644 --- a/ale/drivers/hayabusa2_drivers.py +++ b/ale/drivers/hayabusa2_drivers.py @@ -1,5 +1,3 @@ -import spiceypy as spice - import ale from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index 1cb50f427..6141c221c 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -5,6 +5,7 @@ import spiceypy as spice from glob import glob +from pyspiceql import pyspiceql from ale.util import get_metakernels, query_kernel_pool from ale.base import Driver from ale.base.data_naif import NaifSpice @@ -97,7 +98,7 @@ def odtk(self): : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ - return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 1).tolist() + return pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid)).tolist() @property def light_time_correction(self): @@ -143,7 +144,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) / self.sampling_factor + focal2pixel_lines = np.array(list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.ikid)))) / self.sampling_factor if self.spacecraft_direction < 0: return -focal2pixel_lines else: @@ -161,7 +162,7 @@ def ephemeris_start_time(self): : double Starting ephemeris time of the image """ - start_time = spice.scs2e(self.spacecraft_id, self.label['LRO:SPACECRAFT_CLOCK_PREROLL_COUNT']) + start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.label['LRO:SPACECRAFT_CLOCK_PREROLL_COUNT']) return start_time + self.constant_time_offset + self.additional_preroll * self.exposure_duration @property @@ -267,9 +268,10 @@ def spacecraft_direction(self): X value of the first velocity relative to the sensor """ frame_chain = self.frame_chain - lro_bus_id = spice.bods2c('LRO_SC_BUS') + lro_bus_id = pyspiceql.Kernel_translateFrame('LRO_SC_BUS') time = self.ephemeris_start_time - state, _ = spice.spkezr(self.spacecraft_name, time, 'J2000', 'None', self.target_name) + lt_state = pyspiceql.getTargetState(time, self.target_name, self.spacecraft_name, 'J2000', 'None') + state = lt_state.starg position = state[:3] velocity = state[3:] rotation = frame_chain.compute_rotation(1, lro_bus_id) @@ -338,7 +340,7 @@ def odtk(self): : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ - return spice.gdpool('INS{}_OD_K'.format(self.ikid), 0, 1).tolist() + return pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid)).tolist() @property def light_time_correction(self): @@ -384,7 +386,7 @@ def ephemeris_start_time(self): : double Starting ephemeris time of the image """ - start_time = spice.scs2e(self.spacecraft_id, self.label['IsisCube']['Instrument']['SpacecraftClockPrerollCount']) + start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.label['IsisCube']['Instrument']['SpacecraftClockPrerollCount']) return start_time + self.constant_time_offset + self.additional_preroll * self.exposure_duration @property @@ -412,7 +414,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = np.array(list(spice.gdpool('INS{}_ITRANSL'.format(self.ikid), 0, 3))) / self.sampling_factor + focal2pixel_lines = np.array(list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.ikid)))) / self.sampling_factor if self.spacecraft_direction < 0: return -focal2pixel_lines else: @@ -503,9 +505,10 @@ def spacecraft_direction(self): X value of the first velocity relative to the sensor """ frame_chain = self.frame_chain - lro_bus_id = spice.bods2c('LRO_SC_BUS') + lro_bus_id = pyspiceql.Kernel_translateFrame('LRO_SC_BUS') time = self.ephemeris_start_time - state, _ = spice.spkezr(self.spacecraft_name, time, 'J2000', 'None', self.target_name) + lt_state = pyspiceql.getTargetState(time, self.target_name, self.spacecraft_name, 'J2000', 'None') + state = lt_state.starg position = state[:3] velocity = state[3:] rotation = frame_chain.compute_rotation(1, lro_bus_id) @@ -742,7 +745,8 @@ def wavelength(self): # Get float value of frequency in GHz frequency = self.label['IsisCube']['Instrument']['Frequency'].value - wavelength = spice.clight() / frequency / 1000.0 + #wavelength = spice.clight() / frequency / 1000.0 + wavelength = 299792.458 / frequency / 1000.0 return wavelength @property @@ -800,7 +804,7 @@ def range_conversion_times(self): times for range conversion coefficients """ range_coefficients_utc = self.label['IsisCube']['Instrument']['RangeCoefficientSet'] - range_coefficients_et = [spice.str2et(elt[0]) for elt in range_coefficients_utc] + range_coefficients_et = [pyspiceql.utcToEt(elt[0]) for elt in range_coefficients_utc] return range_coefficients_et @@ -814,7 +818,7 @@ def ephemeris_start_time(self): : float start time """ - return spice.str2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) - self.line_exposure_duration + return pyspiceql.utcToEt(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) @property def ephemeris_stop_time(self): @@ -969,7 +973,7 @@ def odtk(self): ans = self.naif_keywords.get(key, None) if ans is None: raise Exception('Could not parse the distortion model coefficients using key: ' + key) - + ans = [x * -1 for x in ans] return ans @@ -1032,7 +1036,7 @@ def focal_length(self): if ans is None: raise Exception('Could not parse the focal length using key: ' + key) return ans - + @property def detector_center_sample(self): """ @@ -1112,7 +1116,7 @@ def ephemeris_start_time(self): """ if not hasattr(self, '_ephemeris_start_time'): sclock = self.label['IsisCube']['Instrument']['SpacecraftClockStartCount'] - self._ephemeris_start_time = spice.scs2e(self.spacecraft_id, sclock) + self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) return self._ephemeris_start_time @@ -1137,7 +1141,7 @@ def odtk(self): : list Radial distortion coefficients. """ - coeffs = spice.gdpool('INS{}_OD_K'.format(self.fikid), 0, 3).tolist() + coeffs = pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.fikid)).tolist() coeffs = [x * -1 for x in coeffs] return coeffs @@ -1273,7 +1277,7 @@ def pixel2focal_x(self): : list detector to focal plane x """ - return list(spice.gdpool('INS{}_TRANSX'.format(self.fikid), 0, 3)) + return list(pyspiceql.getKernelVectorValue('INS{}_TRANSX'.format(self.fikid))) @property @@ -1286,7 +1290,7 @@ def pixel2focal_y(self): : list detector to focal plane y """ - return list(spice.gdpool('INS{}_TRANSY'.format(self.fikid), 0, 3)) + return list(pyspiceql.getKernelVectorValue('INS{}_TRANSY'.format(self.fikid))) @property def focal2pixel_lines(self): @@ -1298,7 +1302,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - return list(spice.gdpool('INS{}_ITRANSL'.format(self.fikid), 0, 3)) + return list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.fikid))) @property def focal2pixel_samples(self): @@ -1310,7 +1314,7 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - return list(spice.gdpool('INS{}_ITRANSS'.format(self.fikid), 0, 3)) + return list(pyspiceql.getKernelVectorValue('INS{}_ITRANSS'.format(self.fikid))) @property @@ -1323,7 +1327,7 @@ def detector_start_line(self): : int Zero based Detector line corresponding to the first image line """ - offset = list(spice.gdpool('INS{}_FILTER_OFFSET'.format(self.fikid), 0, 3)) + offset = list(pyspiceql.getKernelVectorValue('INS{}_FILTER_OFFSET'.format(self.fikid))) try: # If multiple items are present, use the first one offset = offset[0] @@ -1343,7 +1347,7 @@ def focal_length(self): : float focal length """ - return float(spice.gdpool('INS{}_FOCAL_LENGTH'.format(self.fikid), 0, 1)[0]) + return float(pyspiceql.getKernelVectorValue('INS{}_FOCAL_LENGTH'.format(self.fikid))[0]) @property def detector_center_sample(self): @@ -1356,7 +1360,7 @@ def detector_center_sample(self): : float Detector sample of the principal point """ - return float(spice.gdpool('INS{}_BORESIGHT_SAMPLE'.format(self.fikid), 0, 1)[0]) - 0.5 + return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT_SAMPLE'.format(self.fikid))[0]) - 0.5 @property def detector_center_line(self): @@ -1369,4 +1373,4 @@ def detector_center_line(self): : float Detector line of the principal point """ - return float(spice.gdpool('INS{}_BORESIGHT_LINE'.format(self.fikid), 0, 1)[0]) - 0.5 + return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT_LINE'.format(self.fikid))[0]) - 0.5 diff --git a/ale/drivers/mess_drivers.py b/ale/drivers/mess_drivers.py index e537351c3..31df9febe 100644 --- a/ale/drivers/mess_drivers.py +++ b/ale/drivers/mess_drivers.py @@ -5,6 +5,7 @@ import spiceypy as spice import numpy as np +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.label_pds3 import Pds3Label @@ -164,7 +165,7 @@ def focal_length(self): : double focal length in meters """ - coeffs = spice.gdpool('INS{}_FL_TEMP_COEFFS'.format(self.fikid), 0, 6) + coeffs = pyspiceql.getKernelVectorValue('INS{}_FL_TEMP_COEFFS'.format(self.fikid)) # 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 @@ -246,7 +247,7 @@ def pixel_size(self): ------- : float pixel size """ - return spice.gdpool('INS{}_PIXEL_PITCH'.format(self.ikid), 0, 1) + return pyspiceql.getKernelStringValue('INS{}_PIXEL_PITCH'.format(self.ikid)) class MessengerMdisIsisLabelNaifSpiceDriver(IsisLabel, NaifSpice, Framer, NoDistortion, Driver): @@ -303,7 +304,7 @@ def ephemeris_start_time(self): """ if not hasattr(self, '_ephemeris_start_time'): sclock = self.spacecraft_clock_start_count - self._starting_ephemeris_time = spice.scs2e(self.spacecraft_id, sclock) + self._starting_ephemeris_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) return self._starting_ephemeris_time @property @@ -360,7 +361,7 @@ def focal_length(self): : double focal length in meters """ - coeffs = spice.gdpool('INS{}_FL_TEMP_COEFFS'.format(self.fikid), 0, 6) + coeffs = pyspiceql.getKernelVectorValue('INS{}_FL_TEMP_COEFFS'.format(self.fikid)) # 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]) @@ -383,7 +384,7 @@ def detector_center_sample(self): : float detector center sample """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 3)[0]) - 0.5 + return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid)[0])) - 0.5 @property @@ -401,7 +402,7 @@ def detector_center_line(self): : float detector center line """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 3)[1]) - 0.5 + return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid)[1])) - 0.5 @property def sensor_model_version(self): @@ -423,7 +424,7 @@ def pixel_size(self): ------- : float pixel size """ - return spice.gdpool('INS{}_PIXEL_PITCH'.format(self.ikid), 0, 1) + return pyspiceql.getKernelStringValue('INS{}_PIXEL_PITCH'.format(self.ikid)) @property def sampling_factor(self): diff --git a/ale/drivers/mex_drivers.py b/ale/drivers/mex_drivers.py index 3318337b6..a7d637642 100644 --- a/ale/drivers/mex_drivers.py +++ b/ale/drivers/mex_drivers.py @@ -8,6 +8,7 @@ import spiceypy as spice import warnings +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_isis import read_table_data from ale.base.data_isis import parse_table @@ -102,7 +103,7 @@ def ikid(self): : int Naif ID used to for identifying the instrument in Spice kernels """ - return spice.bods2c("MEX_HRSC_HEAD") + return pyspiceql.Kernel_translateFrame("MEX_HRSC_HEAD") @property @@ -120,7 +121,7 @@ def fikid(self): : int Naif ID code used in calculating focal length """ - return spice.bods2c(self.instrument_id) + return pyspiceql.Kernel_translateFrame(self.instrument_id) # TODO Since HRSC has different frames based on filters, need to check that @@ -625,7 +626,7 @@ def ikid(self): : int Naif ID used to for identifying the instrument in Spice kernels """ - return spice.bods2c("MEX_HRSC_HEAD") + return pyspiceql.Kernel_translateFrame("MEX_HRSC_HEAD") @property def fikid(self): @@ -642,7 +643,7 @@ def fikid(self): : int Naif ID code used in calculating focal length """ - return spice.bods2c(self.instrument_id) + return pyspiceql.Kernel_translateFrame(self.instrument_id) @property def focal_length(self): @@ -709,21 +710,21 @@ def sampling_factor(self): class MexSrcPds3NaifSpiceDriver(Framer, Pds3Label, NaifSpice, NoDistortion, Driver): """ - Driver for a PDS3 Mars Express (Mex) High Resolution Stereo Camera (HRSC) - Super Resolution + Driver for a PDS3 Mars Express (Mex) High Resolution Stereo Camera (HRSC) - Super Resolution Channel (SRC) image. """ @property def ikid(self): """ - Returns the Naif ID code for HRSC SRC. + Returns the Naif ID code for HRSC SRC. Returns ------- : int Naif ID used to for identifying the instrument in Spice kernels """ - return spice.bods2c("MEX_HRSC_SRC") + return pyspiceql.Kernel_translateFrame("MEX_HRSC_HEAD") @property diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 5b481ed20..710a957a1 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -1,5 +1,6 @@ import spiceypy as spice +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice @@ -357,7 +358,7 @@ def ephemeris_start_time(self): """ if not hasattr(self, '_ephemeris_start_time'): sclock = self.label['IsisCube']['Instrument']['SpacecraftClockCount'] - self._ephemeris_start_time = spice.scs2e(self.spacecraft_id, sclock) + self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) return self._ephemeris_start_time @property diff --git a/ale/drivers/nh_drivers.py b/ale/drivers/nh_drivers.py index 4fd7eb47a..8fae575f6 100644 --- a/ale/drivers/nh_drivers.py +++ b/ale/drivers/nh_drivers.py @@ -4,6 +4,7 @@ from ale import util +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.type_distortion import NoDistortion, LegendreDistortion from ale.base.data_naif import NaifSpice @@ -67,7 +68,7 @@ def detector_center_line(self): list : The center of the CCD formatted as line, sample """ - return float(spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 0, 3)[0]) + return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0]) @property def detector_center_sample(self): @@ -81,7 +82,7 @@ def detector_center_sample(self): list : The center of the CCD formatted as line, sample """ - return float(spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 0, 3)[1]) + return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1]) @property def sensor_name(self): diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index e73e92dbe..0892c2d11 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -1,4 +1,5 @@ import spiceypy as spice +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice @@ -243,9 +244,9 @@ def ikid(self): ikid of LISM_TC1 or LISM_TC2 """ if not hasattr(self, "_ikid"): - self._ikid = spice.bods2c("LISM_{}".format(super().instrument_id)) + return pyspiceql.Kernel_translateFrame("LISM_{}".format(super().instrument_id)) return self._ikid - + @property def spacecraft_name(self): """ @@ -300,7 +301,7 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = spice.sct2e(self.spacecraft_id, self.spacecraft_clock_start_count) + return pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_start_count) return self._ephemeris_start_time @property @@ -317,7 +318,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid)[0]) self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -335,7 +336,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid)[0]) self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -352,7 +353,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist() + self.__odkx = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_X'.format(self.ikid)).tolist() return self.__odkx @property @@ -368,7 +369,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist() + self.__odky = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_Y'.format(self.ikid)).tolist() return self.__odky @property @@ -384,7 +385,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 0, 1)[0] + self._boresight_x = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0] return self._boresight_x @property @@ -400,7 +401,11 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_y = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] + # TODO is this the right way to access this value? + # original: + # return spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] + + self._boresight_y = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1] return self._boresight_y @property @@ -426,6 +431,46 @@ def exposure_duration(self): except: return self.label['CORRECTED_SAMPLING_INTERVAL'].value * 0.001 # Scale to seconds + @property + def usgscsm_distortion_model(self): + """ + Kaguya uses a unique radial distortion model so we need to overwrite the + method packing the distortion model into the ISD. + + from the IK: + + Line-of-sight vector of pixel no. n can be expressed as below. + + Distortion coefficients information: + INS_DISTORTION_COEF_X = ( a0, a1, a2, a3) + INS_DISTORTION_COEF_Y = ( b0, b1, b2, b3), + + Distance r from the center: + r = - (n - INS_CENTER) * INS_PIXEL_SIZE. + + Line-of-sight vector v is calculated as + v[X] = INSBORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , + v[Y] = INSBORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , + v[Z] = INSBORESIGHT[Z] + + Expects odkx and odky to be defined. These should be a list of optical + distortion x and y coefficients respectively. + + Returns + ------- + : dict + radial distortion model + + """ + return { + "kaguyalism": { + "x" : self._odkx, + "y" : self._odky, + "boresight_x" : self.boresight_x, + "boresight_y" : self.boresight_y + } + } + @property def detector_start_sample(self): """ @@ -930,7 +975,7 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = spice.scs2e(self.spacecraft_id, self.spacecraft_clock_start_count) + self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_start_count) return self._ephemeris_start_time @property @@ -948,7 +993,7 @@ def detector_center_line(self): The detector line of the principle point """ if not hasattr(self, "_detector_center_line"): - self._detector_center_line = spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[1] - 0.5 + self._detector_center_line = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[1] - 0.5 return self._detector_center_line @property @@ -966,7 +1011,7 @@ def detector_center_sample(self): The detector sample of the principle point """ if not hasattr(self, "_detector_center_sample"): - self._detector_center_sample = spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[0] - 0.5 + self._detector_center_sample = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[0] - 0.5 return self._detector_center_sample @property @@ -983,7 +1028,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -1001,7 +1046,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -1018,7 +1063,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist() + self.__odkx = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist() return self.__odkx @property @@ -1034,7 +1079,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist() + self.__odky = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_Y'.format(self.ikid),0, 4).tolist() return self.__odky @property @@ -1050,7 +1095,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 0, 1)[0] + self._boresight_x = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0] return self._boresight_x @property @@ -1066,7 +1111,7 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_y = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] + self._boresight_y = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1] return self._boresight_y @property @@ -1092,6 +1137,46 @@ def line_exposure_duration(self): except: return self.label['CORRECTED_SAMPLING_INTERVAL'].value * 0.001 # Scale to seconds + @property + def usgscsm_distortion_model(self): + """ + Kaguya uses a unique radial distortion model so we need to overwrite the + method packing the distortion model into the ISD. + + from the IK: + + Line-of-sight vector of pixel no. n can be expressed as below. + + Distortion coefficients information: + INS_DISTORTION_COEF_X = ( a0, a1, a2, a3) + INS_DISTORTION_COEF_Y = ( b0, b1, b2, b3), + + Distance r from the center: + r = - (n - INS_CENTER) * INS_PIXEL_SIZE. + + Line-of-sight vector v is calculated as + v[X] = INSBORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , + v[Y] = INSBORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , + v[Z] = INSBORESIGHT[Z] + + Expects odkx and odky to be defined. These should be a list of optical + distortion x and y coefficients respectively. + + Returns + ------- + : dict + radial distortion model + + """ + return { + "kaguyalism": { + "x" : self._odkx, + "y" : self._odky, + "boresight_x" : self.boresight_x, + "boresight_y" : self.boresight_y + } + } + @property def sensor_model_version(self): """ @@ -1192,7 +1277,7 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = spice.sct2e(self.spacecraft_id, self.spacecraft_clock_start_count) + self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_start_count) return self._ephemeris_start_time @property @@ -1207,7 +1292,7 @@ def ephemeris_stop_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_stop_time"): - self._ephemeris_stop_time = spice.sct2e(self.spacecraft_id, self.spacecraft_clock_stop_count) + self._ephemeris_stop_time = pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_stop_count) return self._ephemeris_stop_time @property @@ -1242,7 +1327,7 @@ def detector_center_line(self): The detector line of the principle point """ if not hasattr(self, "_detector_center_line"): - self._detector_center_line = spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[1] - 0.5 + self._detector_center_line = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[1] - 0.5 return self._detector_center_line @property @@ -1260,7 +1345,7 @@ def detector_center_sample(self): The detector sample of the principle point """ if not hasattr(self, "_detector_center_sample"): - self._detector_center_sample = spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[0] - 0.5 + self._detector_center_sample = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[0] - 0.5 return self._detector_center_sample @property @@ -1276,7 +1361,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist() + self.__odkx = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_X'.format(self.ikid)).tolist() return self.__odkx @property @@ -1292,7 +1377,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist() + self.__odky = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist() return self.__odky @property @@ -1308,7 +1393,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 0, 1)[0] + self._boresight_x = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0] return self._boresight_x @property @@ -1324,9 +1409,50 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_y = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] + self._boresight_y = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1] return self._boresight_y + @property + def usgscsm_distortion_model(self): + """ + Kaguya uses a unique radial distortion model so we need to overwrite the + method packing the distortion model into the ISD. + + from the IK: + + Line-of-sight vector of pixel no. n can be expressed as below. + + Distortion coefficients information: + INS_DISTORTION_COEF_X = ( a0, a1, a2, a3) + INS_DISTORTION_COEF_Y = ( b0, b1, b2, b3), + + Distance r from the center: + r = - (n - INS_CENTER) * INS_PIXEL_SIZE. + + Line-of-sight vector v is calculated as + v[X] = INSBORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , + v[Y] = INSBORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , + v[Z] = INSBORESIGHT[Z] + + Expects odkx and odky to be defined. These should be a list of optical + distortion x and y coefficients respectively. + + Returns + ------- + : dict + radial distortion model + + """ + return { + "kaguyalism": { + "x" : self._odkx, + "y" : self._odky, + "boresight_x" : self.boresight_x, + "boresight_y" : self.boresight_y + } + } + + @property def line_exposure_duration(self): """ @@ -1364,7 +1490,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -1382,6 +1508,6 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines diff --git a/ale/drivers/tgo_drivers.py b/ale/drivers/tgo_drivers.py index 1f980230c..574d9e534 100644 --- a/ale/drivers/tgo_drivers.py +++ b/ale/drivers/tgo_drivers.py @@ -3,9 +3,9 @@ import struct import pvl -import spiceypy as spice import numpy as np +from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel @@ -50,7 +50,7 @@ def ephemeris_start_time(self): : float ephemeris start time of the image. """ - return spice.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + return pyspiceql.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f"))) @property def sensor_frame_id(self): diff --git a/ale/drivers/viking_drivers.py b/ale/drivers/viking_drivers.py index a0f1a1140..5577fe1f8 100644 --- a/ale/drivers/viking_drivers.py +++ b/ale/drivers/viking_drivers.py @@ -1,5 +1,3 @@ -import spiceypy as spice - import ale from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice @@ -7,6 +5,7 @@ from ale.base.type_sensor import Framer from ale.base.type_distortion import NoDistortion from ale.base.base import Driver +from pyspiceql import pyspiceql sensor_name_lookup = { "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A" : "Visual Imaging Subsystem Camera A", @@ -109,7 +108,7 @@ def ephemeris_start_time(self): : float ephemeris start time of the image """ - ephemeris_start_time = spice.scs2e(self.alt_ikid, str(self.spacecraft_clock_start_count)) + ephemeris_start_time = pyspiceql.sclkToEt(self.alt_ikid, str(self.spacecraft_clock_start_count)) if self.exposure_duration <= .420: offset1 = 7.0 / 8.0 * 4.48 diff --git a/ale/drivers/voyager_drivers.py b/ale/drivers/voyager_drivers.py index 17f6afc8b..9674d1a1e 100644 --- a/ale/drivers/voyager_drivers.py +++ b/ale/drivers/voyager_drivers.py @@ -62,7 +62,7 @@ def detector_center_line(self): @property def ephemeris_start_time(self): - inital_time = spice.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + inital_time = pyspiceql.utcToEt(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) # To get shutter end (close) time, subtract 2 seconds from the start time updated_time = inital_time - 2 # To get shutter start (open) time, take off the exposure duration from the end time. From 7e26fb55db6cf0e84ceeb73d4879b7b58634940a Mon Sep 17 00:00:00 2001 From: Austin Sanders Date: Thu, 2 Jun 2022 11:15:09 -0700 Subject: [PATCH 02/73] Reverted change to UTC start time --- ale/drivers/galileo_drivers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ale/drivers/galileo_drivers.py b/ale/drivers/galileo_drivers.py index 4a7cab4b2..f3f1e81f6 100644 --- a/ale/drivers/galileo_drivers.py +++ b/ale/drivers/galileo_drivers.py @@ -86,7 +86,7 @@ def ephemeris_start_time(self): : float start time """ - return pyspiceql.utc2et(self.utc_start_time) + return pyspiceql.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) @property def center_ephemeris_time(self): From 0a89f4b52abcd5e0bb278bec775a67111a466195 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Wed, 28 Sep 2022 12:34:22 -0700 Subject: [PATCH 03/73] Fixed erronious spiceql calls --- ale/base/data_naif.py | 30 ++++++++++++++---------------- ale/drivers/mro_drivers.py | 2 +- tests/pytests/test_util.py | 2 -- 3 files changed, 15 insertions(+), 19 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 67ebf33d3..3af8ec60f 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -143,7 +143,7 @@ def odtk(self): Radial distortion coefficients """ if not hasattr(self, "_odtk"): - self._odtk = pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid)).toList() + self._odtk = list(pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid))) return self._odtk @property @@ -250,7 +250,7 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - if not hasattr(self, "_focal2pixel_lines"): + if not hasattr(self, "_focal2pixel_samples"): self._focal2pixel_samples = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSS'.format(self.ikid))) return self._focal2pixel_samples @@ -278,7 +278,7 @@ def pixel2focal_y(self): : list detector to focal plane y """ - if not hasattr(self, "_pixel2focal_x"): + if not hasattr(self, "_pixel2focal_y"): self._pixel2focal_y = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSY'.format(self.ikid))) return self._pixel2focal_y @@ -294,7 +294,7 @@ def focal_length(self): focal length """ if not hasattr(self, "_focal_length"): - self._focal_length = float(pyspiceql.getKernelStringValue('INS{}_FOCAL_LENGTH'.format(self.ikid))[0]) + self._focal_length = float(pyspiceql.getKernelVectorValue('INS{}_FOCAL_LENGTH'.format(self.ikid))[0]) return self._focal_length @property @@ -307,7 +307,7 @@ def pixel_size(self): : float pixel size """ if not hasattr(self, "_pixel_size"): - self._pixel_size = pyspiceql.getKernelStringValue('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] * 0.001 + self._pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] * 0.001 return self._pixel_size @property @@ -373,7 +373,7 @@ def sun_position(self): self.spacecraft_name, 'J2000', self.light_time_correction) - sun_state = sun_lt_state.starg + sun_state = np.array(list(sun_lt_state.starg)) positions.append(sun_state[:3]) velocities.append(sun_state[3:6]) positions = 1000 * np.asarray(positions) @@ -420,7 +420,6 @@ def sensor_position(self): observer, 'J2000', self.light_time_correction) - obs_tar_state = obs_tar.starg obs_tar_lt = obs_tar.lt # ssb to spacecraft @@ -429,8 +428,7 @@ def sensor_position(self): 'SSB', 'J2000', "NONE") - ssb_obs_state = ssb_obs.starg - ssb_obs_lt = ssb_obs.lt + ssb_obs_state = np.array(list(ssb_obs.starg)) radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = time - obs_tar_lt + radius_lt @@ -440,8 +438,7 @@ def sensor_position(self): 'SSB', 'J2000', "NONE") - ssb_tar_state = ssb_tar.starg - ssb_tar_lt = ssb_tar.lt + ssb_tar_state = np.array(list(ssb_tar.starg)) state = ssb_tar_state - ssb_obs_state matrix = spice.sxform("J2000", self.reference_frame, time) @@ -452,19 +449,20 @@ def sensor_position(self): observer, self.reference_frame, self.light_time_correction) + state = np.array(list(state.starg)) if self.swap_observer_target: - pos.append(-state.starg[:3]) - vel.append(-state.starg[3:]) + pos.append(-state[:3]) + vel.append(-state[3:]) else: - pos.append(state.starg[:3]) - vel.append(state.starg[3:]) + pos.append(state[:3]) + vel.append(state[3:]) # By default, SPICE works in km, so convert to m self._position = 1000 * np.asarray(pos) self._velocity = 1000 * np.asarray(vel) - return self._position, self._velocity, self.ephemeris_time + return self._position, self._velocity, ephem @property def frame_chain(self): diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 710a957a1..11b20ce2b 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -358,7 +358,7 @@ def ephemeris_start_time(self): """ if not hasattr(self, '_ephemeris_start_time'): sclock = self.label['IsisCube']['Instrument']['SpacecraftClockCount'] - self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) + self._ephemeris_start_time = pyspiceql.sclkToEt(str(self.spacecraft_name).lower(), sclock) return self._ephemeris_start_time @property diff --git a/tests/pytests/test_util.py b/tests/pytests/test_util.py index 50c05902a..9fe3685dd 100644 --- a/tests/pytests/test_util.py +++ b/tests/pytests/test_util.py @@ -6,9 +6,7 @@ import pytest import tempfile -import spiceypy as spice import pvl -from unittest import mock from unittest.mock import MagicMock, patch from collections import OrderedDict From 0e4c165c652e56b28140ef555726eab44fc350b4 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Wed, 8 Mar 2023 19:01:52 -0700 Subject: [PATCH 04/73] Moved kernel accessing methods into there own file --- ale/kernel_access.py | 306 ++++++++++++++++++++++++++++++++++++++++++ ale/util.py | 307 +------------------------------------------ 2 files changed, 310 insertions(+), 303 deletions(-) create mode 100644 ale/kernel_access.py diff --git a/ale/kernel_access.py b/ale/kernel_access.py new file mode 100644 index 000000000..5742c4ed7 --- /dev/null +++ b/ale/kernel_access.py @@ -0,0 +1,306 @@ +from glob import glob +from itertools import groupby +import os +from os import path +import warnings + + +from ale import spice_root +from ale.util import get_isis_preferences + +def get_metakernels(spice_dir=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? + + Parameters + ---------- + spice_dir : str + Path containing Spice directories downloaded from NAIF's website + + missions : set, str + Mission or set of missions to search for + + years : set, str, int + year or set of years to search for + + versions : set, str + version or set of versions to search for + """ + 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': [] + } + + missions = [m.lower() for m in missions] + if spice_dir is not None: + mission_dirs = list(filter(path.isdir, glob(path.join(spice_dir, '*')))) + else: + warnings.warn("Unable to search mission directories without" + + "ALESPICEROOT being set. Defaulting to empty list") + mission_dirs = [] + + 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].split('_')[0] + if missions and all([m not in mission.lower() for m 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, '**','*.[Tt][Mm]'), recursive=True)) + + metakernels = [] + for k in metakernel_paths: + components = path.splitext(path.basename(k))[0].split('_') + [k] + if len(components) == 3: + components.insert(1, 'N/A') + + metakernels.append(dict(zip(metakernel_keys, components))) + + # naive filter, do we really need anything else? + if years: + metakernels = list(filter(lambda x:x['year'] in years or x['year'] == 'N/A', 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']) + + return avail + + +def generate_kernels_from_cube(cube, expand=False, format_as='list'): + """ + Parses a cube label to obtain the kernels from the Kernels group. + + Parameters + ---------- + cube : cube + Path to the cube to pull the kernels from. + expand : bool, optional + Whether or not to expand variables within kernel paths based on your IsisPreferences file. + See :func:`get_isis_preferences` for how the IsisPreferences file is found. + format_as : str, optional {'list', 'dict'} + How to return the kernels: either as a one-dimensional ordered list, or as a dictionary + of kernel lists. + + Returns + ------- + : list + One-dimensional ordered list of all kernels from the Kernels group in the cube. + : Dictionary + Dictionary of lists of kernels with the keys being the Keywords from the Kernels group of + cube itself, and the values being the values associated with that Keyword in the cube. + """ + # enforce key order + mk_paths = OrderedDict.fromkeys( + ['TargetPosition', 'InstrumentPosition', + 'InstrumentPointing', 'Frame', 'TargetAttitudeShape', + 'Instrument', 'InstrumentAddendum', 'LeapSecond', + 'SpacecraftClock', 'Extra']) + + # just work with full path + cube = os.path.abspath(cube) + cubelabel = pvl.load(cube) + + try: + kernel_group = cubelabel['IsisCube'] + except KeyError: + raise KeyError(f'{cubelabel}, Could not find kernels group, input cube [{cube}] may not be spiceinited') + + return get_kernels_from_isis_pvl(kernel_group, expand, format_as) + + +def get_kernels_from_isis_pvl(kernel_group, expand=True, format_as="list"): + # enforce key order + mk_paths = OrderedDict.fromkeys( + ['TargetPosition', 'InstrumentPosition', + 'InstrumentPointing', 'Frame', 'TargetAttitudeShape', + 'Instrument', 'InstrumentAddendum', 'LeapSecond', + 'SpacecraftClock', 'Extra']) + + + if isinstance(kernel_group, str): + kernel_group = pvl.loads(kernel_group) + + kernel_group = kernel_group["Kernels"] + + def load_table_data(key): + mk_paths[key] = kernel_group.get(key, None) + if isinstance(mk_paths[key], str): + mk_paths[key] = [mk_paths[key]] + while 'Table' in mk_paths[key]: mk_paths[key].remove('Table') + while 'Nadir' in mk_paths[key]: mk_paths[key].remove('Nadir') + + load_table_data('TargetPosition') + load_table_data('InstrumentPosition') + load_table_data('InstrumentPointing') + load_table_data('TargetAttitudeShape') + # the rest + mk_paths['Frame'] = [kernel_group.get('Frame', None)] + mk_paths['Instrument'] = [kernel_group.get('Instrument', None)] + mk_paths['InstrumentAddendum'] = [kernel_group.get('InstrumentAddendum', None)] + mk_paths['SpacecraftClock'] = [kernel_group.get('SpacecraftClock', None)] + mk_paths['LeapSecond'] = [kernel_group.get('LeapSecond', None)] + mk_paths['Clock'] = [kernel_group.get('Clock', None)] + mk_paths['Extra'] = [kernel_group.get('Extra', None)] + + # handles issue with OsirisRex instrument kernels being in a 2d list + if isinstance(mk_paths['Instrument'][0], list): + mk_paths['Instrument'] = np.concatenate(mk_paths['Instrument']).flat + + if (format_as == 'list'): + # get kernels as 1-d string list + kernels = [] + for kernel in chain.from_iterable(mk_paths.values()): + if isinstance(kernel, str): + kernels.append(kernel) + elif isinstance(kernel, list): + kernels.extend(kernel) + if expand: + isisprefs = get_isis_preferences() + if not "DataDirectory" in isisprefs: + warnings.warn("No IsisPreferences file found, is your ISISROOT env var set?") + + kernels = [expandvars(k, isisprefs['DataDirectory'], case_sensitive=False) for k in kernels] + # Ensure that the ISIS Addendum kernel is last in case it overrides + # some values from the default Instrument kernel + # Sorts planetary constants kernel first so it can be overridden by more specific kernels + kernels = sorted(kernels, key=lambda x: "Addendum" in x) + kernels = sorted(kernels, key=lambda x: "pck00" in x, reverse=True) + return kernels + elif (format_as == 'dict'): + # return created dict + if expand: + isisprefs = get_isis_preferences() + for kern_list in mk_paths: + for index, kern in enumerate(mk_paths[kern_list]): + if kern is not None: + mk_paths[kern_list][index] = expandvars(kern, isisprefs['DataDirectory'], case_sensitive=False) + return mk_paths + else: + raise Exception(f'{format_as} is not a valid return format') + + +def find_kernels(cube, isis_data, format_as=dict): + """ + Find all kernels for a cube and return a json object with categorized kernels. + + Parameters + ---------- + + cube : str + Path to an ISIS cube + + isis_data : str + path to $ISISDATA + + format_as : obj + What type to return the kernels as, ISIS3-like dict/PVL or flat list + + Returns + ------- + : obj + Container with kernels + """ + def remove_dups(listofElements): + # Create an empty list to store unique elements + uniqueList = [] + + # Iterate over the original list and for each element + # add it to uniqueList, if its not already there. + for elem in listofElements: + if elem not in uniqueList: + uniqueList.append(elem) + + # Return the list of unique elements + return uniqueList + + cube_label = pvl.load(cube) + mission_lookup_table = get_isis_mission_translations(isis_data) + + mission_dir = mission_lookup_table[cube_label["IsisCube"]["Instrument"]["SpacecraftName"]] + mission_dir = path.join(isis_data, mission_dir.lower()) + + kernel_dir = path.join(mission_dir, "kernels") + base_kernel_dir = path.join(isis_data, "base", "kernels") + + kernel_types = [ name for name in os.listdir(kernel_dir) if os.path.isdir(os.path.join(kernel_dir, name)) ] + kernel_types.extend(name for name in os.listdir(base_kernel_dir) if os.path.isdir(os.path.join(base_kernel_dir, name))) + kernel_types = set(kernel_types) + + db_files = [] + for typ in kernel_types: + files = sorted(glob(path.join(kernel_dir, typ, "*.db"))) + base_files = sorted(glob(path.join(base_kernel_dir, typ, "*.db"))) + files = [list(it) for k,it in groupby(files, key=lambda f:os.path.basename(f).split(".")[0])] + base_files = [list(it) for k,it in groupby(base_files, key=lambda f:os.path.basename(f).split(".")[0])] + + for instrument_dbs in files: + db_files.append(read_pvl(sorted(instrument_dbs)[-1], True)) + for base_dbs in base_files: + db_files.append(read_pvl(sorted(base_dbs)[-1], True)) + + + kernels = {} + for f in db_files: + #TODO: Error checking + typ = f[0][0] + kernel_search_results = search_isis_db(f[0][1], cube_label, isis_data) + + if not kernel_search_results: + kernels[typ] = None + else: + try: + kernels[typ]["kernels"].extend(kernel_search_results["kernels"]) + if any(kernel_search_results.get("types", [None])): + kernels[typ]["types"].extend(kernel_search_results["types"]) + except: + kernels[typ] = {} + kernels[typ]["kernels"] = kernel_search_results["kernels"] + if any(kernel_search_results.get("types", [None])): + kernels[typ]["types"] = kernel_search_results["types"] + + for k,v in kernels.items(): + if v: + kernels[k]["kernels"] = remove_dups(v["kernels"]) + + if format_as == dict: + return kernels + elif format_as == list: + kernel_list = [] + for _,kernels in kernels.items(): + if kernels: + kernel_list.extend(kernels["kernels"]) + return kernel_list + else: + warnings.warn(f"{format_as} is not a valid format, returning as dict") + return kernels diff --git a/ale/util.py b/ale/util.py index dd841c238..e583a0a08 100644 --- a/ale/util.py +++ b/ale/util.py @@ -2,21 +2,17 @@ from os import path from glob import glob -from itertools import filterfalse, groupby import warnings import pvl -import collections from collections import OrderedDict try: from collections.abc import Mapping except ImportError: from collections import Mapping -from itertools import chain from datetime import datetime import pytz -import numpy as np import subprocess import re @@ -25,97 +21,6 @@ import spiceypy as spice -from ale import spice_root - -def get_metakernels(spice_dir=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? - - Parameters - ---------- - spice_dir : str - Path containing Spice directories downloaded from NAIF's website - - missions : set, str - Mission or set of missions to search for - - years : set, str, int - year or set of years to search for - - versions : set, str - version or set of versions to search for - """ - 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': [] - } - - missions = [m.lower() for m in missions] - if spice_dir is not None: - mission_dirs = list(filter(path.isdir, glob(path.join(spice_dir, '*')))) - else: - warnings.warn("Unable to search mission directories without" + - "ALESPICEROOT being set. Defaulting to empty list") - mission_dirs = [] - - 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].split('_')[0] - if missions and all([m not in mission.lower() for m 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, '**','*.[Tt][Mm]'), recursive=True)) - - metakernels = [] - for k in metakernel_paths: - components = path.splitext(path.basename(k))[0].split('_') + [k] - if len(components) == 3: - components.insert(1, 'N/A') - - metakernels.append(dict(zip(metakernel_keys, components))) - - # naive filter, do we really need anything else? - if years: - metakernels = list(filter(lambda x:x['year'] in years or x['year'] == 'N/A', 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']) - - return avail - - def find_latest_metakernel(path, year): metakernel = None mks = sorted(glob(os.path.join(path,'*.[Tt][Mm]'))) @@ -198,117 +103,6 @@ def replace_var(m): return path -def generate_kernels_from_cube(cube, expand=False, format_as='list'): - """ - Parses a cube label to obtain the kernels from the Kernels group. - - Parameters - ---------- - cube : cube - Path to the cube to pull the kernels from. - expand : bool, optional - Whether or not to expand variables within kernel paths based on your IsisPreferences file. - See :func:`get_isis_preferences` for how the IsisPreferences file is found. - format_as : str, optional {'list', 'dict'} - How to return the kernels: either as a one-dimensional ordered list, or as a dictionary - of kernel lists. - - Returns - ------- - : list - One-dimensional ordered list of all kernels from the Kernels group in the cube. - : Dictionary - Dictionary of lists of kernels with the keys being the Keywords from the Kernels group of - cube itself, and the values being the values associated with that Keyword in the cube. - """ - # enforce key order - mk_paths = OrderedDict.fromkeys( - ['TargetPosition', 'InstrumentPosition', - 'InstrumentPointing', 'Frame', 'TargetAttitudeShape', - 'Instrument', 'InstrumentAddendum', 'LeapSecond', - 'SpacecraftClock', 'Extra']) - - # just work with full path - cube = os.path.abspath(cube) - cubelabel = pvl.load(cube) - - try: - kernel_group = cubelabel['IsisCube'] - except KeyError: - raise KeyError(f'{cubelabel}, Could not find kernels group, input cube [{cube}] may not be spiceinited') - - return get_kernels_from_isis_pvl(kernel_group, expand, format_as) - -def get_kernels_from_isis_pvl(kernel_group, expand=True, format_as="list"): - # enforce key order - mk_paths = OrderedDict.fromkeys( - ['TargetPosition', 'InstrumentPosition', - 'InstrumentPointing', 'Frame', 'TargetAttitudeShape', - 'Instrument', 'InstrumentAddendum', 'LeapSecond', - 'SpacecraftClock', 'Extra']) - - - if isinstance(kernel_group, str): - kernel_group = pvl.loads(kernel_group) - - kernel_group = kernel_group["Kernels"] - - def load_table_data(key): - mk_paths[key] = kernel_group.get(key, None) - if isinstance(mk_paths[key], str): - mk_paths[key] = [mk_paths[key]] - while 'Table' in mk_paths[key]: mk_paths[key].remove('Table') - while 'Nadir' in mk_paths[key]: mk_paths[key].remove('Nadir') - - load_table_data('TargetPosition') - load_table_data('InstrumentPosition') - load_table_data('InstrumentPointing') - load_table_data('TargetAttitudeShape') - # the rest - mk_paths['Frame'] = [kernel_group.get('Frame', None)] - mk_paths['Instrument'] = [kernel_group.get('Instrument', None)] - mk_paths['InstrumentAddendum'] = [kernel_group.get('InstrumentAddendum', None)] - mk_paths['SpacecraftClock'] = [kernel_group.get('SpacecraftClock', None)] - mk_paths['LeapSecond'] = [kernel_group.get('LeapSecond', None)] - mk_paths['Clock'] = [kernel_group.get('Clock', None)] - mk_paths['Extra'] = [kernel_group.get('Extra', None)] - - # handles issue with OsirisRex instrument kernels being in a 2d list - if isinstance(mk_paths['Instrument'][0], list): - mk_paths['Instrument'] = np.concatenate(mk_paths['Instrument']).flat - - if (format_as == 'list'): - # get kernels as 1-d string list - kernels = [] - for kernel in chain.from_iterable(mk_paths.values()): - if isinstance(kernel, str): - kernels.append(kernel) - elif isinstance(kernel, list): - kernels.extend(kernel) - if expand: - isisprefs = get_isis_preferences() - if not "DataDirectory" in isisprefs: - warnings.warn("No IsisPreferences file found, is your ISISROOT env var set?") - - kernels = [expandvars(k, isisprefs['DataDirectory'], case_sensitive=False) for k in kernels] - # Ensure that the ISIS Addendum kernel is last in case it overrides - # some values from the default Instrument kernel - # Sorts planetary constants kernel first so it can be overridden by more specific kernels - kernels = sorted(kernels, key=lambda x: "Addendum" in x) - kernels = sorted(kernels, key=lambda x: "pck00" in x, reverse=True) - return kernels - elif (format_as == 'dict'): - # return created dict - if expand: - isisprefs = get_isis_preferences() - for kern_list in mk_paths: - for index, kern in enumerate(mk_paths[kern_list]): - if kern is not None: - mk_paths[kern_list][index] = expandvars(kern, isisprefs['DataDirectory'], case_sensitive=False) - return mk_paths - else: - raise Exception(f'{format_as} is not a valid return format') - def write_metakernel_from_cube(cube, mkpath=None): # add ISISPREF paths as path_symbols and path_values to avoid custom expand logic pvlprefs = get_isis_preferences() @@ -344,6 +138,7 @@ def write_metakernel_from_cube(cube, mkpath=None): return body + def get_ck_frames(kernel): """ Get all of the reference frames defined in a kernel. @@ -368,6 +163,7 @@ def get_ck_frames(kernel): # Sort the output list for testability return sorted(list(ids)) + def create_spk_dependency_tree(kernels): """ construct the dependency tree for the body states in a set of kernels. @@ -401,6 +197,7 @@ def create_spk_dependency_tree(kernels): return dep_tree + def spkmerge_config_string(dep_tree, output_spk, bodies, lsk, start, stop): """ Create the contents of an spkmerge config file that will produce a spk that @@ -449,6 +246,7 @@ def spkmerge_config_string(dep_tree, output_spk, bodies, lsk, start, stop): config += f" INCLUDE_COMMENTS = no\n" return config + def write_metakernel_from_kernel_list(kernels): """ Parameters @@ -485,7 +283,6 @@ def write_metakernel_from_kernel_list(kernels): return body - def duckpool(naifvar, start=0, length=10, default=None): """ Duck typing friendly version of spiceypy kernel pool functions. @@ -812,99 +609,3 @@ def search_isis_db(dbobj, labelobj, isis_data): if any(types): kernels["types"] = types return kernels - - -def find_kernels(cube, isis_data, format_as=dict): - """ - Find all kernels for a cube and return a json object with categorized kernels. - - Parameters - ---------- - - cube : str - Path to an ISIS cube - - isis_data : str - path to $ISISDATA - - format_as : obj - What type to return the kernels as, ISIS3-like dict/PVL or flat list - - Returns - ------- - : obj - Container with kernels - """ - def remove_dups(listofElements): - # Create an empty list to store unique elements - uniqueList = [] - - # Iterate over the original list and for each element - # add it to uniqueList, if its not already there. - for elem in listofElements: - if elem not in uniqueList: - uniqueList.append(elem) - - # Return the list of unique elements - return uniqueList - - cube_label = pvl.load(cube) - mission_lookup_table = get_isis_mission_translations(isis_data) - - mission_dir = mission_lookup_table[cube_label["IsisCube"]["Instrument"]["SpacecraftName"]] - mission_dir = path.join(isis_data, mission_dir.lower()) - - kernel_dir = path.join(mission_dir, "kernels") - base_kernel_dir = path.join(isis_data, "base", "kernels") - - kernel_types = [ name for name in os.listdir(kernel_dir) if os.path.isdir(os.path.join(kernel_dir, name)) ] - kernel_types.extend(name for name in os.listdir(base_kernel_dir) if os.path.isdir(os.path.join(base_kernel_dir, name))) - kernel_types = set(kernel_types) - - db_files = [] - for typ in kernel_types: - files = sorted(glob(path.join(kernel_dir, typ, "*.db"))) - base_files = sorted(glob(path.join(base_kernel_dir, typ, "*.db"))) - files = [list(it) for k,it in groupby(files, key=lambda f:os.path.basename(f).split(".")[0])] - base_files = [list(it) for k,it in groupby(base_files, key=lambda f:os.path.basename(f).split(".")[0])] - - for instrument_dbs in files: - db_files.append(read_pvl(sorted(instrument_dbs)[-1], True)) - for base_dbs in base_files: - db_files.append(read_pvl(sorted(base_dbs)[-1], True)) - - - kernels = {} - for f in db_files: - #TODO: Error checking - typ = f[0][0] - kernel_search_results = search_isis_db(f[0][1], cube_label, isis_data) - - if not kernel_search_results: - kernels[typ] = None - else: - try: - kernels[typ]["kernels"].extend(kernel_search_results["kernels"]) - if any(kernel_search_results.get("types", [None])): - kernels[typ]["types"].extend(kernel_search_results["types"]) - except: - kernels[typ] = {} - kernels[typ]["kernels"] = kernel_search_results["kernels"] - if any(kernel_search_results.get("types", [None])): - kernels[typ]["types"] = kernel_search_results["types"] - - for k,v in kernels.items(): - if v: - kernels[k]["kernels"] = remove_dups(v["kernels"]) - - if format_as == dict: - return kernels - elif format_as == list: - kernel_list = [] - for _,kernels in kernels.items(): - if kernels: - kernel_list.extend(kernels["kernels"]) - return kernel_list - else: - warnings.warn(f"{format_as} is not a valid format, returning as dict") - return kernels From 983505683c4d2a9a04e779cd8a9c0061f74d048c Mon Sep 17 00:00:00 2001 From: acpaquette Date: Wed, 8 Mar 2023 19:04:51 -0700 Subject: [PATCH 05/73] Added initial ability to access SpiceQL service --- ale/base/__init__.py | 75 +++++++++++++++++++++++++++++ ale/base/data_naif.py | 91 +++++++++++++++++++++++++++++++++-- ale/drivers/viking_drivers.py | 6 ++- 3 files changed, 166 insertions(+), 6 deletions(-) diff --git a/ale/base/__init__.py b/ale/base/__init__.py index 0312f47f4..1f1fbd339 100644 --- a/ale/base/__init__.py +++ b/ale/base/__init__.py @@ -1 +1,76 @@ from ale.base.base import Driver + +spiceql_mission_map = { + "CHANDRAYAAN-1_M3": "", + "CASSINI_ISS_NAC": "cassini", + "CASSINI_ISS_WAC": "cassini", + "DAWN_FC2_FILTER_1": "", + "DAWN_FC2_FILTER_2": "", + "DAWN_FC2_FILTER_3": "", + "DAWN_FC2_FILTER_4": "", + "DAWN_FC2_FILTER_5": "", + "DAWN_FC2_FILTER_6": "", + "DAWN_FC2_FILTER_7": "", + "DAWN_FC2_FILTER_8": "", + "GLL_SSI_PLATFORM": "galileo", + "HAYABUSA2_ONC-W2": "", + "JUNO_JUNOCAM": "juno", + "LRO_LROCNACL": "lroc", + "LRO_LROCNACR": "lroc", + "LRO_LROCWAC_UV": "lroc", + "LRO_LROCWAC_VIS": "lroc", + "LRO_MINIRF": "", + "MSGR_MDIS_WAC": "mdis", + "MSGR_MDIS_NAC": "mdis", + "MEX_HRSC_SRC": "src", + "MEX_HRSC_IR": "hrsc", + "MGS_MOC_NA": "mgs", + "MGS_MOC_WA_RED": "mgs", + "MGS_MOC_WA_BLUE": "mgs", + "MRO_MARCI_VIS": "marci", + "MRO_MARCI_UV": "marci", + "MRO_CTX": "ctx", + "MRO_HIRISE": "hirise", + "MRO_CRISM_VNIR": "crism", + "NEAR EARTH ASTEROID RENDEZVOUS": "", + "MSL_MASTCAM_RIGHT": "", + "MSL_MASTCAM_LEFT": "", + "NH_LORRI": "", + "NH_RALPH_LEISA": "", + "NH_MVIC": "", + "ISIS_NH_RALPH_MVIC_METHANE": "", + "THEMIS_IR": "odyssey", + "THEMIS_VIS": "odyssey", + "ORX_OCAMS_MAPCAM": "", + "ORX_OCAMS_POLYCAM": "", + "ORX_OCAMS_SAMCAM": "", + "LISM_MI-VIS1": "kaguya", + "LISM_MI-VIS2": "kaguya", + "LISM_MI-VIS3": "kaguya", + "LISM_MI-VIS4": "kaguya", + "LISM_MI-VIS5": "kaguya", + "LISM_MI-NIR1": "kaguya", + "LISM_MI-NIR2": "kaguya", + "LISM_MI-NIR3": "kaguya", + "LISM_MI-NIR4": "kaguya", + "LISM_TC1_WDF": "kaguya", + "LISM_TC1_WTF": "kaguya", + "LISM_TC1_SDF": "kaguya", + "LISM_TC1_STF": "kaguya", + "LISM_TC1_WDN": "kaguya", + "LISM_TC1_WTN": "kaguya", + "LISM_TC1_SDN": "kaguya", + "LISM_TC1_STN": "kaguya", + "LISM_TC1_WDH": "kaguya", + "LISM_TC1_WTH": "kaguya", + "LISM_TC1_SDH": "kaguya", + "LISM_TC1_STH": "kaguya", + "LISM_TC1_SSH": "kaguya", + "TGO_CASSIS": "cassis", + "VIKING ORBITER 1": "viking1", + "VIKING ORBITER 2": "viking2", + "VG1_ISSNA": "", + "VG1_ISSWA": "", + "VG2_ISSNA": "", + "VG2_ISSWA": "" +} \ No newline at end of file diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 3af8ec60f..3bd82baf1 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -1,10 +1,14 @@ -import spiceypy as spice -from pyspiceql import pyspiceql +import json +import requests +import warnings + import numpy as np +import pyspiceql import scipy.constants +import spiceypy as spice import ale -from ale.base.type_sensor import Framer +from ale.base import spiceql_mission_map from ale.transformation import FrameChain from ale.rotation import TimeDependentRotation from ale import util @@ -76,6 +80,29 @@ def kernels(self): return self._kernels + @property + def use_web(self): + """ + Reads the web property in the props dictionary to define the use_web value. + This property dictates if you are running in a web enabled driver + + Returns + ------- + : bool + Boolean defining if you are running web enabled(True) or Disabled(False) + """ + if not hasattr(self, '_use_web'): + self._use_web = False + + if "web" in self._props.keys(): + web_prop = self._props["web"] + if not isinstance(web_prop, bool): + warnings.warn(f"Web value {web_prop} not a boolean type, setting web to False") + web_prop = False + self._use_web = web_prop + + return self._use_web + @property def light_time_correction(self): """ @@ -659,4 +686,60 @@ def instrument_time_bias(self): : int Time bias in ephemeris time """ - return 0 \ No newline at end of file + return 0 + + @property + def spiceql_mission(self): + """ + Access the mapping between a SpiceQL "mission" and the driver. + The mapping can be found under ale.base.__init__.py + + See Also + -------- + ale.base.__init__.py + """ + return spiceql_mission_map[self.instrument_id] + + def spiceql_call(self, function_name = "", function_args = {}): + """ + Interface to SpiceQL (Spice Query Library) for both Offline and Online use + + This function will access the value passed through props defined as `web`. This + value determines the access pattern for spice data. When set to Online, you will + access the SpiceQL service provided through the USGS Astro AWS platform. This service + performs kernel and data aquisition. If set to Offline, you will access locally loaded + kernels, and SpiceQL will do no searching for you. + + Parameters + ---------- + functions_name : str + String defineing the function to call, properly exposed SpiceQL + functions should map 1-to-1 with endpoints on the service + + function_args : dict + Dictionary of arguments used by the function + + Returns : any + Any return from a SpiceQL function + """ + if not self.use_web: + func = getattr(pyspiceql, function_name) + + # Ensure that in offline mode we anticipate the user loading/passing their own kernels + # to ALE + function_args["searchKernels"] = self.use_web + return func(**function_args) + + try: + url = "http://localhost:9000/2015-03-31/functions/function/invocations" + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + function_args["func"] = function_name + r = requests.get(url, data=json.dumps(function_args), headers=headers, verify=False) + r.raise_for_status() + if r.json()["statusCode"] != 200: + raise requests.HTTPError(f"Recieved code {r.json()['statusCode']} from spice server, with error: {r.json()}") + return r.json()["body"]["return"] + except requests.exceptions.HTTPError as err: + raise err diff --git a/ale/drivers/viking_drivers.py b/ale/drivers/viking_drivers.py index 5577fe1f8..22464b5a9 100644 --- a/ale/drivers/viking_drivers.py +++ b/ale/drivers/viking_drivers.py @@ -1,4 +1,4 @@ -import ale +from ale.base import spiceql_mission_map from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice from ale.base.label_isis import IsisLabel @@ -151,7 +151,9 @@ def detector_center_line(self): def detector_center_sample(self): return 0 - + @property + def spiceql_mission(self): + return spiceql_mission_map[self.spacecraft_name] class VikingIsisLabelIsisSpiceDriver(Framer, IsisLabel, IsisSpice, NoDistortion, Driver): From ee7a562c94052333748bd46874ead7f605683226 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Wed, 8 Mar 2023 19:05:35 -0700 Subject: [PATCH 06/73] General drive import and spacing cleanup --- ale/base/base.py | 1 - ale/drivers/lro_drivers.py | 8 +------- ale/drivers/mess_drivers.py | 7 ------- ale/drivers/mro_drivers.py | 2 ++ ale/drivers/msi_drivers.py | 11 ++--------- ale/drivers/selene_drivers.py | 1 + ale/drivers/tgo_drivers.py | 10 ++-------- 7 files changed, 8 insertions(+), 32 deletions(-) diff --git a/ale/base/base.py b/ale/base/base.py index 7bddcea50..ccffee7ce 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -1,4 +1,3 @@ -import pvl import json import tempfile diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index 6141c221c..470bee06a 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -1,12 +1,8 @@ -import os -import re import numpy as np -import pvl import spiceypy as spice -from glob import glob from pyspiceql import pyspiceql -from ale.util import get_metakernels, query_kernel_pool +from ale.util import query_kernel_pool from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice @@ -278,8 +274,6 @@ def spacecraft_direction(self): rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) return rotated_velocity[0] - - class LroLrocNacIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver): @property def instrument_id(self): diff --git a/ale/drivers/mess_drivers.py b/ale/drivers/mess_drivers.py index 31df9febe..e56e9bf8d 100644 --- a/ale/drivers/mess_drivers.py +++ b/ale/drivers/mess_drivers.py @@ -1,8 +1,3 @@ -from glob import glob -import os - -import pvl -import spiceypy as spice import numpy as np from pyspiceql import pyspiceql @@ -73,7 +68,6 @@ def instrument_id(self): """ return ID_LOOKUP[super().instrument_id] - class MessengerMdisPds3NaifSpiceDriver(Framer, Pds3Label, NaifSpice, NoDistortion, Driver): """ Driver for reading MDIS PDS3 labels. Requires a Spice mixin to acquire additional @@ -249,7 +243,6 @@ def pixel_size(self): """ return pyspiceql.getKernelStringValue('INS{}_PIXEL_PITCH'.format(self.ikid)) - class MessengerMdisIsisLabelNaifSpiceDriver(IsisLabel, NaifSpice, Framer, NoDistortion, Driver): """ Driver for reading MDIS ISIS3 Labels. These are Labels that have been ingested diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 11b20ce2b..708eb08ac 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -513,6 +513,7 @@ def platform_name(self): """ return self.label['SPACECRAFT_NAME'] + hirise_ccd_lookup = { 0: 0, 1: 1, @@ -702,6 +703,7 @@ def sensor_model_version(self): return 1 + class MroCrismIsisLabelNaifSpiceDriver(LineScanner, IsisLabel, NaifSpice, NoDistortion, Driver): """ Driver for reading Crism ISIS labels. diff --git a/ale/drivers/msi_drivers.py b/ale/drivers/msi_drivers.py index c06476f35..c213c5692 100644 --- a/ale/drivers/msi_drivers.py +++ b/ale/drivers/msi_drivers.py @@ -1,16 +1,9 @@ -import os -import spiceypy as spice -import json -import numpy as np -import pvl -import ale from ale.base import Driver from ale.base.label_isis import IsisLabel from ale.base.data_naif import NaifSpice -from ale.base.type_distortion import RadialDistortion, NoDistortion -from ale.base.type_sensor import Framer, LineScanner -from ale.util import generate_kernels_from_cube +from ale.base.type_distortion import NoDistortion +from ale.base.type_sensor import Framer from ale.base.type_sensor import Framer from ale.base.type_distortion import NoDistortion diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index 0892c2d11..c3320e425 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -829,6 +829,7 @@ def usgscsm_distortion_model(self): def sensor_model_version(self): return 2 + class KaguyaMiPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, KaguyaSeleneDistortion, Driver): """ Driver for a PDS3 Kaguya Multiband Imager (Mi) images. Specifically level2b2 Vis and Nir images. diff --git a/ale/drivers/tgo_drivers.py b/ale/drivers/tgo_drivers.py index 574d9e534..5e65546a1 100644 --- a/ale/drivers/tgo_drivers.py +++ b/ale/drivers/tgo_drivers.py @@ -1,11 +1,5 @@ -from glob import glob -import os - -import struct -import pvl -import numpy as np - from pyspiceql import pyspiceql + from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel @@ -50,7 +44,7 @@ def ephemeris_start_time(self): : float ephemeris start time of the image. """ - return pyspiceql.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f"))) + return pyspiceql.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) @property def sensor_frame_id(self): From 731169748b54a50fece8fbcd8429de0d118d2673 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Mar 2023 20:55:33 -0700 Subject: [PATCH 07/73] Adds spiceql call warpper to kernel access function set --- ale/kernel_access.py | 65 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ale/kernel_access.py b/ale/kernel_access.py index 5742c4ed7..0dfe4d423 100644 --- a/ale/kernel_access.py +++ b/ale/kernel_access.py @@ -1,9 +1,12 @@ from glob import glob from itertools import groupby +import json import os from os import path +import requests import warnings +import pyspiceql from ale import spice_root from ale.util import get_isis_preferences @@ -304,3 +307,65 @@ def remove_dups(listofElements): else: warnings.warn(f"{format_as} is not a valid format, returning as dict") return kernels + + +def spiceql_call(function_name = "", function_args = {}, use_web=False): + """ + Interface to SpiceQL (Spice Query Library) for both Offline and Online use + + This function will access the value passed through props defined as `web`. This + value determines the access pattern for spice data. When set to Online, you will + access the SpiceQL service provided through the USGS Astro AWS platform. This service + performs kernel and data aquisition. If set to Offline, you will access locally loaded + kernels, and SpiceQL will do no searching for you. + + Parameters + ---------- + functions_name : str + String defineing the function to call, properly exposed SpiceQL + functions should map 1-to-1 with endpoints on the service + + function_args : dict + Dictionary of arguments used by the function + + Returns : any + Any return from a SpiceQL function + """ + if not use_web: + func = getattr(pyspiceql, function_name) + + # Ensure that in offline mode we anticipate the user loading/passing their own kernels + # to ALE + # function_args["searchKernels"] = self.use_web + return func(**function_args) + url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" + url += function_name + headers = { + 'accept': '*/*', + 'Content-Type': 'application/json' + } + + r = requests.get(url, params=function_args, headers=headers, verify=False) + r.raise_for_status() + response = r.json() + + if r.status_code != 200: + raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") + elif response["statusCode"] != 200: + raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") + return response["body"]["return"] + + # Code for accessing SpiceQL docker container + # try: + # url = "http://localhost:9000/2015-03-31/functions/function/invocations" + # headers = { + # 'Content-Type': 'application/x-www-form-urlencoded', + # } + # function_args["func"] = function_name + # r = requests.get(url, data=json.dumps(function_args), headers=headers, verify=False) + # r.raise_for_status() + # if r.json()["statusCode"] != 200: + # raise requests.HTTPError(f"Recieved code {r.json()['statusCode']} from spice server, with error: {r.json()}") + # return r.json()["body"]["return"] + # except requests.exceptions.HTTPError as err: + # raise err \ No newline at end of file From 6a20a5a35b669c6a84e37cc23bb72e8461edfe19 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Mar 2023 20:55:52 -0700 Subject: [PATCH 08/73] Line space changes and removed commented line --- ale/kernel_access.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ale/kernel_access.py b/ale/kernel_access.py index 0dfe4d423..27d45441f 100644 --- a/ale/kernel_access.py +++ b/ale/kernel_access.py @@ -336,8 +336,8 @@ def spiceql_call(function_name = "", function_args = {}, use_web=False): # Ensure that in offline mode we anticipate the user loading/passing their own kernels # to ALE - # function_args["searchKernels"] = self.use_web return func(**function_args) + url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" url += function_name headers = { From 187eb7aba74dfbdbc872f0a379a6ac65d774cc20 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Mar 2023 20:57:30 -0700 Subject: [PATCH 09/73] Updates tranformation and data_naif with spiceql_calls --- ale/base/data_naif.py | 246 ++++++++++++++++++++++-------------------- ale/transformation.py | 68 ++++++------ 2 files changed, 166 insertions(+), 148 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 3bd82baf1..09297d96e 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -1,5 +1,3 @@ -import json -import requests import warnings import numpy as np @@ -11,6 +9,7 @@ from ale.base import spiceql_mission_map from ale.transformation import FrameChain from ale.rotation import TimeDependentRotation +from ale import kernel_access from ale import util class NaifSpice(): @@ -123,7 +122,7 @@ def light_time_correction(self): """ if not hasattr(self, "_light_time_correction"): try: - self._light_time_correction = pyspiceql.getKernelStringValue('INS{}_LIGHTTIME_CORRECTION'.format(self.ikid))[0] + self._light_time_correction = self.naif_keywords['INS{}_LIGHTTIME_CORRECTION'.format(self.ikid)][0] except: self._light_time_correction = 'LT+S' return self._light_time_correction @@ -140,7 +139,7 @@ def odtx(self): Optical distortion x coefficients """ if not hasattr(self, "_odtx"): - self._odtx = pyspiceql.getKernelVectorValue('INS{}_OD_T_X'.format(self.ikid)).toList() + self._odtx = self.naif_keywords['INS{}_OD_T_X'.format(self.ikid)] return self._odtx @property @@ -155,7 +154,7 @@ def odty(self): Optical distortion y coefficients """ if not hasattr(self, "_odty"): - self._odty = pyspiceql.getKernelVectorValue('INS{}_OD_T_Y'.format(self.ikid)).toList() + self._odty = self.naif_keywords['INS{}_OD_T_Y'.format(self.ikid)] return self._odty @property @@ -170,7 +169,7 @@ def odtk(self): Radial distortion coefficients """ if not hasattr(self, "_odtk"): - self._odtk = list(pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid))) + self._odtk = self.naif_keywords['INS{}_OD_K'.format(self.ikid)] return self._odtk @property @@ -186,7 +185,7 @@ def ikid(self): Naif ID used to for identifying the instrument in Spice kernels """ if not hasattr(self, "_ikid"): - self._ikid = pyspiceql.Kernel_translateFrame(self.instrument_id) + self._ikid = self.spiceql_call("translateNameToCode", {"frame": self.instrument_id, "mission": self.spiceql_mission}) return self._ikid @property @@ -202,7 +201,7 @@ def spacecraft_id(self): Naif ID code for the spacecraft """ if not hasattr(self, "_spacecraft_id"): - self._spacecraft_id = pyspiceql.Kernel_translateFrame(self.spacecraft_name) + self._spacecraft_id = self.spiceql_call("translateNameToCode", {"frame": self.spacecraft_name, "mission": self.spiceql_mission}) return self._spacecraft_id @property @@ -218,7 +217,7 @@ def target_id(self): Naif ID code for the target body """ if not hasattr(self, "_target_id"): - self._target_id = pyspiceql.Kernel_translateFrame(self.target_name) + self._target_id = self.spiceql_call("translateNameToCode", {"frame": self.target_name, "mission": self.spiceql_mission}) return self._target_id @property @@ -234,8 +233,8 @@ def target_frame_id(self): Naif ID code for the target frame """ if not hasattr(self, "_target_frame_id"): - frame_info = spice.cidfrm(self.target_id) - self._target_frame_id = frame_info[0] + frame_info = self.spiceql_call("getTargetFrameInfo", {"targetId": self.target_id, "mission": self.spiceql_mission}) + self._target_frame_id = frame_info["frameCode"] return self._target_frame_id @property @@ -264,7 +263,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - self._focal2pixel_lines = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.ikid))) + self._focal2pixel_lines = self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)] return self._focal2pixel_lines @property @@ -278,7 +277,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - self._focal2pixel_samples = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSS'.format(self.ikid))) + self._focal2pixel_samples = self.naif_keywords['INS{}_ITRANSS'.format(self.ikid)] return self._focal2pixel_samples @property @@ -292,7 +291,7 @@ def pixel2focal_x(self): detector to focal plane x """ if not hasattr(self, "_pixel2focal_x"): - self._pixel2focal_x = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSX'.format(self.ikid))) + self._pixel2focal_x = self.naif_keywords['INS{}_ITRANSX'.format(self.ikid)] return self._pixel2focal_x @property @@ -306,7 +305,7 @@ def pixel2focal_y(self): detector to focal plane y """ if not hasattr(self, "_pixel2focal_y"): - self._pixel2focal_y = list(pyspiceql.getKernelVectorValue('INS{}_ITRANSY'.format(self.ikid))) + self._pixel2focal_y = self.naif_keywords['INS{}_ITRANSY'.format(self.ikid)] return self._pixel2focal_y @property @@ -321,7 +320,7 @@ def focal_length(self): focal length """ if not hasattr(self, "_focal_length"): - self._focal_length = float(pyspiceql.getKernelVectorValue('INS{}_FOCAL_LENGTH'.format(self.ikid))[0]) + self._focal_length = self.naif_keywords['INS{}_FOCAL_LENGTH'.format(self.ikid)] return self._focal_length @property @@ -334,7 +333,7 @@ def pixel_size(self): : float pixel size """ if not hasattr(self, "_pixel_size"): - self._pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] * 0.001 + self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] * 0.001 return self._pixel_size @property @@ -350,7 +349,7 @@ def target_body_radii(self): Radius of all three axis of the target body """ if not hasattr(self, "_target_body_radii"): - self._target_body_radii = spice.bodvrd(self.target_name, 'RADII', 3)[1] + self._target_body_radii = self.naif_keywords[f"BODY{self.target_id}_RADII"] return self._target_body_radii @property @@ -367,7 +366,8 @@ def reference_frame(self): """ if not hasattr(self, "_reference_frame"): try: - self._reference_frame = spice.cidfrm(spice.bodn2c(self.target_name))[1] + frame_info = self.spiceql_call("getTargetFrameInfo", {"targetId": self.target_id, "mission": self.spiceql_mission}) + self._reference_frame = frame_info["frameName"] except: self._reference_frame = 'IAU_{}'.format(self.target_name) return self._reference_frame @@ -394,13 +394,14 @@ def sun_position(self): positions = [] velocities = [] - for time in times: - sun_lt_state = pyspiceql.getTargetState(time, - self.target_name, - self.spacecraft_name, - 'J2000', - self.light_time_correction) - sun_state = np.array(list(sun_lt_state.starg)) + sun_lt_states = self.spiceql_call("getTargetStates",{"ets": str(times), + "target": self.target_name, + "observer": self.spacecraft_name, + "frame": 'J2000', + "abcorr": self.light_time_correction, + "mission": self.spiceql_mission}) + for sun_state in sun_lt_states: + sun_state = np.array(sun_state) positions.append(sun_state[:3]) velocities.append(sun_state[3:6]) positions = 1000 * np.asarray(positions) @@ -427,6 +428,10 @@ def sensor_position(self): """ if not hasattr(self, '_position'): ephem = self.ephemeris_time + + if isinstance(ephem, np.ndarray): + ephem = ephem.tolist() + pos = [] vel = [] @@ -437,47 +442,74 @@ def sensor_position(self): target = self.target_name observer = self.spacecraft_name - for time in ephem: - # spkezr returns a vector from the observer's location to the aberration-corrected - # location of the target. For more information, see: - # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html - if self.correct_lt_to_surface and self.light_time_correction.upper() == 'LT+S': - obs_tar = pyspiceql.getTargetState(time, - target, - observer, - 'J2000', - self.light_time_correction) - obs_tar_lt = obs_tar.lt - - # ssb to spacecraft - ssb_obs = pyspiceql.getTargetState(time, - target, - 'SSB', - 'J2000', - "NONE") - ssb_obs_state = np.array(list(ssb_obs.starg)) - - radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) - adjusted_time = time - obs_tar_lt + radius_lt - - ssb_tar = pyspiceql.getTargetState(adjusted_time, - target, - 'SSB', - 'J2000', - "NONE") - ssb_tar_state = np.array(list(ssb_tar.starg)) - state = ssb_tar_state - ssb_obs_state - - matrix = spice.sxform("J2000", self.reference_frame, time) + # spkezr returns a vector from the observer's location to the aberration-corrected + # location of the target. For more information, see: + # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html + if self.correct_lt_to_surface and self.light_time_correction.upper() == 'LT+S': + print("BANANA", ephem) + obs_tars = self.spiceql_call("getTargetStates",{"ets": str(ephem), + "target": target, + "observer": observer, + "frame": "J2000", + "abcorr": self.light_time_correction, + "mission": self.spiceql_mission}) + # obs_tar = pyspiceql.getTargetState(time, + # target, + # observer, + # 'J2000', + # self.light_time_correction) + obs_tar_lts = np.array(obs_tars)[:,-1] + + # ssb to spacecraft + ssb_obs = self.spiceql_call("getTargetStates",{"ets": str(ephem), + "target": target, + "observer": "SSB", + "frame": "J2000", + "abcorr": "NONE", + "mission": self.spiceql_mission}) + # ssb_obs = pyspiceql.getTargetState(time, + # target, + # 'SSB', + # 'J2000', + # "NONE") + ssb_obs_states = np.array(ssb_obs)[:,0:6] + + radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) + adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt + + ssb_tars = self.spiceql_call("getTargetStates",{"ets": str(adjusted_time), + "target": target, + "observer": "SSB", + "frame": "J2000", + "abcorr": "NONE", + "mission": self.spiceql_mission}) + # ssb_tar = pyspiceql.getTargetState(adjusted_time, + # target, + # 'SSB', + # 'J2000', + # "NONE") + ssb_tar_state = np.array(ssb_tars)[:,0:6] + _states = ssb_tar_state - ssb_obs_states + states = [] + for state in _states: + matrix = spice.sxform("J2000", self.reference_frame, ephem) state = spice.mxvg(matrix, state) - else: - state = pyspiceql.getTargetState(time, - target, - observer, - self.reference_frame, - self.light_time_correction) - state = np.array(list(state.starg)) - + states.append(state) + else: + states = self.spiceql_call("getTargetStates",{"ets": str(ephem), + "target": target, + "observer": observer, + "frame": self.reference_frame, + "abcorr": self.light_time_correction, + "mission": self.spiceql_mission}) + # state = pyspiceql.getTargetState(time, + # target, + # observer, + # self.reference_frame, + # self.light_time_correction) + states = np.array(states)[:,0:6] + + for state in states: if self.swap_observer_target: pos.append(-state[:3]) vel.append(-state[3:]) @@ -501,7 +533,9 @@ def frame_chain(self): center_ephemeris_time=self.center_ephemeris_time, ephemeris_times=self.ephemeris_time, nadir=nadir, exact_ck_times=exact_ck_times, - inst_time_bias=self.instrument_time_bias) + inst_time_bias=self.instrument_time_bias, + mission=self.spiceql_mission, + use_web=self.use_web) if nadir: # Logic for nadir calculation was taken from ISIS3 @@ -563,7 +597,7 @@ def ephemeris_start_time(self): Starting ephemeris time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = pyspiceql.sclkToEt(str(self.spacecraft_name), self.spacecraft_clock_start_count) + self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frameCode": self.spacecraft_id, "sclk": self.spacecraft_clock_start_count, "mission": self.spiceql_mission}) return self._ephemeris_start_time @property @@ -580,7 +614,7 @@ def ephemeris_stop_time(self): Ephemeris stop time of the image """ if not hasattr(self, "_ephemeris_stop_time"): - self._ephemeris_stop_time = pyspiceql.sclkToEt(self.spacecraft_name, self.spacecraft_clock_stop_count) + self._ephemeris_stop_time = self.spiceql_call("strSclkToEt", {"frameCode": str(self.spacecraft_id), "sclk": self.spacecraft_clock_stop_count, "mission": self.spiceql_mission}) return self._ephemeris_stop_time @property @@ -595,7 +629,7 @@ def detector_center_sample(self): Detector sample of the principal point """ if not hasattr(self, "_detector_center_sample"): - self._detector_center_sample = float(pyspiceql.getKernelStringValue('INS{}_BORESIGHT_SAMPLE'.format(self.ikid))[0]) + self._detector_center_sample = self.naif_keywords['INS{}_BORESIGHT_SAMPLE'.format(self.ikid)] return self._detector_center_sample @property @@ -610,7 +644,7 @@ def detector_center_line(self): Detector line of the principal point """ if not hasattr(self, "_detector_center_line"): - self._detector_center_line = float(pyspiceql.getKernelStringValue('INS{}_BORESIGHT_LINE'.format(self.ikid))[0]) + self._detector_center_line = self.naif_keywords['INS{}_BORESIGHT_LINE'.format(self.ikid)] return self._detector_center_line @property @@ -626,7 +660,7 @@ def swap_observer_target(self): """ if not hasattr(self, "_swap_observer_target"): try: - swap = pyspiceql.getKernelStringValue('INS{}_SWAP_OBSERVER_TARGET'.format(self.ikid))[0] + swap = self.naif_keywords['INS{}_SWAP_OBSERVER_TARGET'.format(self.ikid)] self._swap_observer_target = swap.upper() == "TRUE" except: self._swap_observer_target = False @@ -644,7 +678,7 @@ def correct_lt_to_surface(self): """ if not hasattr(self, "_correct_lt_to_surface"): try: - surface_correct = pyspiceql.getKernelStringValue('INS{}_LT_SURFACE_CORRECT'.format(self.ikid))[0] + surface_correct = self.naif_keywords['INS{}_LT_SURFACE_CORRECT'.format(self.ikid)] self._correct_lt_to_surface = surface_correct.upper() == "TRUE" except: self._correct_lt_to_surface = False @@ -661,14 +695,15 @@ def naif_keywords(self): if not hasattr(self, "_naif_keywords"): self._naif_keywords = dict() - self._naif_keywords['BODY{}_RADII'.format(self.target_id)] = self.target_body_radii self._naif_keywords['BODY_FRAME_CODE'] = self.target_frame_id self._naif_keywords['BODY_CODE'] = self.target_id - self._naif_keywords = {**self._naif_keywords, **util.query_kernel_pool(f"*{self.ikid}*"), **util.query_kernel_pool(f"*{self.target_id}*")} - + self._naif_keywords = {**self._naif_keywords, + **self.spiceql_call("findMissionKeywords", {"key": f"*{self.ikid}*", "mission": self.spiceql_mission}), + **self.spiceql_call("findTargetKeywords", {"key": f"*{self.target_id}*", "mission": self.spiceql_mission})} + try: - self._naif_keywords = {**self._naif_keywords, **util.query_kernel_pool(f"*{self.fikid}*")} + self._naif_keywords = {**self._naif_keywords, **self.spiceql_call("findMissionKeywords", {"key": f"*{self.fikid}*", "mission": self.spiceql_mission})} except AttributeError as error: pass @@ -702,44 +737,19 @@ def spiceql_mission(self): def spiceql_call(self, function_name = "", function_args = {}): """ - Interface to SpiceQL (Spice Query Library) for both Offline and Online use - - This function will access the value passed through props defined as `web`. This - value determines the access pattern for spice data. When set to Online, you will - access the SpiceQL service provided through the USGS Astro AWS platform. This service - performs kernel and data aquisition. If set to Offline, you will access locally loaded - kernels, and SpiceQL will do no searching for you. - - Parameters - ---------- - functions_name : str - String defineing the function to call, properly exposed SpiceQL - functions should map 1-to-1 with endpoints on the service - - function_args : dict - Dictionary of arguments used by the function - - Returns : any - Any return from a SpiceQL function - """ - if not self.use_web: - func = getattr(pyspiceql, function_name) - - # Ensure that in offline mode we anticipate the user loading/passing their own kernels - # to ALE - function_args["searchKernels"] = self.use_web - return func(**function_args) - - try: - url = "http://localhost:9000/2015-03-31/functions/function/invocations" - headers = { - 'Content-Type': 'application/x-www-form-urlencoded', - } - function_args["func"] = function_name - r = requests.get(url, data=json.dumps(function_args), headers=headers, verify=False) - r.raise_for_status() - if r.json()["statusCode"] != 200: - raise requests.HTTPError(f"Recieved code {r.json()['statusCode']} from spice server, with error: {r.json()}") - return r.json()["body"]["return"] - except requests.exceptions.HTTPError as err: - raise err + Driver based wrapper for accessing spice data through spiceql + + See Also + -------- + ale.kernel_access.spiceql_call + + Returns + ------- + : json + Json data from the SpiceQL call + """ + # Ideally this would work if a user passed no kernels but still + # set ISISDATA + if (not hasattr(self, "kernels")): + function_args["searchKernels"] = True + return kernel_access.spiceql_call(function_name, function_args, self.use_web) \ No newline at end of file diff --git a/ale/transformation.py b/ale/transformation.py index 711393192..24a39508d 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -1,10 +1,9 @@ import numpy as np -from numpy.polynomial.polynomial import polyval, polyder +from numpy.polynomial.polynomial import polyval import networkx as nx from networkx.algorithms.shortest_paths.generic import shortest_path -import spiceypy as spice - +from ale.kernel_access import spiceql_call from ale.rotation import ConstantRotation, TimeDependentRotation def create_rotations(rotation_table): @@ -96,14 +95,14 @@ class FrameChain(nx.DiGraph): of frame rotations in the frame chain """ @classmethod - def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris_times=[], nadir=False, exact_ck_times=False, inst_time_bias=0): + def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris_times=[], nadir=False, exact_ck_times=False, inst_time_bias=0, use_web=False, mission=""): frame_chain = cls() - sensor_times = [] # Default assume one time - target_times = np.asarray(ephemeris_times) + target_times = ephemeris_times if len(target_times) > 1: - target_times = np.asarray([ephemeris_times[0], ephemeris_times[-1]]) - + target_times = [ephemeris_times[0], ephemeris_times[-1]] + + sensor_times = [] if exact_ck_times and len(ephemeris_times) > 1 and not nadir: try: sensor_times = cls.extract_exact_ck_times(ephemeris_times[0] + inst_time_bias, ephemeris_times[-1] + inst_time_bias, sensor_frame) @@ -111,10 +110,12 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris pass if (len(sensor_times) == 0): - sensor_times = np.array(ephemeris_times) + sensor_times = ephemeris_times + if isinstance(sensor_times, np.ndarray): + sensor_times = sensor_times.tolist() - sensor_time_dependent_frames, sensor_constant_frames = cls.frame_trace(sensor_frame, center_ephemeris_time, nadir) - target_time_dependent_frames, target_constant_frames = cls.frame_trace(target_frame, center_ephemeris_time) + sensor_time_dependent_frames, sensor_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, "initialFrame": sensor_frame, "mission": mission}, use_web) + target_time_dependent_frames, target_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, "initialFrame": target_frame, "mission": mission}, use_web) sensor_time_dependent_frames = list(zip(sensor_time_dependent_frames[:-1], sensor_time_dependent_frames[1:])) constant_frames = list(zip(sensor_constant_frames[:-1], sensor_constant_frames[1:])) @@ -123,15 +124,20 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris constant_frames.extend(target_constant_frames) - frame_chain.compute_time_dependent_rotations(sensor_time_dependent_frames, sensor_times, inst_time_bias) - frame_chain.compute_time_dependent_rotations(target_time_dependent_frames, target_times, 0) + # Add all time dependent frame chains to the graph + frame_chain.compute_time_dependent_rotiations(sensor_time_dependent_frames, sensor_times, inst_time_bias, mission, use_web=use_web) + frame_chain.compute_time_dependent_rotiations(target_time_dependent_frames, target_times, 0, mission, use_web=use_web) + # Add all constant frame chains to the graph for s, d in constant_frames: quats = np.zeros(4) - rotation_matrix = spice.pxform(spice.frmnam(s), spice.frmnam(d), ephemeris_times[0]) - quat_from_rotation = spice.m2q(rotation_matrix) - quats[:3] = quat_from_rotation[1:] - quats[3] = quat_from_rotation[0] + quat_and_av = spiceql_call("getTargetOrientations",{"ets": str([ephemeris_times[0]]), + "toFrame": d, + "refFrame": s, + "mission": mission}, + use_web=use_web)[0] + quats[:3] = quat_and_av[1:4] + quats[3] = quat_and_av[0] rotation = ConstantRotation(quats, s, d) @@ -380,7 +386,7 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): return times - def compute_time_dependent_rotations(self, frames, times, time_bias): + def compute_time_dependent_rotiations(self, frames, times, time_bias, mission="", use_web=False): """ Computes the time dependent rotations based on a list of tuples that define the relationships between frames as (source, destination) and a list of times to @@ -396,18 +402,20 @@ def compute_time_dependent_rotations(self, frames, times, time_bias): for s, d in frames: quats = np.zeros((len(times), 4)) avs = [] - for j, time in enumerate(times): - try: - state_matrix = spice.sxform(spice.frmnam(s), spice.frmnam(d), time) - rotation_matrix, av = spice.xf2rav(state_matrix) - avs.append(av) - except: - rotation_matrix = spice.pxform(spice.frmnam(s), spice.frmnam(d), time) - quat_from_rotation = spice.m2q(rotation_matrix) - quats[j,:3] = quat_from_rotation[1:] - quats[j,3] = quat_from_rotation[0] - - if not avs: + quats_and_avs = spiceql_call("getTargetOrientations",{"ets": str(times), + "toFrame": d, + "refFrame": s, + "mission": mission}, + use_web=use_web) + _quats = np.array(quats_and_avs)[:, 0:4] + for j, quat in enumerate(_quats): + quats[j,:3] = quat[1:] + quats[j,3] = quat[0] + + if (len(quats_and_avs[0]) > 4): + avs = np.array(quats_and_avs)[:, 4:] + + if len(avs) == 0: avs = None biased_times = [time - time_bias for time in times] rotation = TimeDependentRotation(quats, biased_times, s, d, av=avs) From a9f28dcce22a790cad602a2085351ee068d3f8a2 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Mar 2023 20:58:10 -0700 Subject: [PATCH 10/73] Fixes other instances of the from_spice call --- ale/base/type_sensor.py | 4 +++- ale/drivers/co_drivers.py | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ale/base/type_sensor.py b/ale/base/type_sensor.py index eca917801..d9b6787ba 100644 --- a/ale/base/type_sensor.py +++ b/ale/base/type_sensor.py @@ -535,7 +535,9 @@ def frame_chain(self): target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, ephemeris_times=self.ephemeris_time, - nadir=nadir, exact_ck_times=False) + nadir=nadir, exact_ck_times=False, + mission=self.spiceql_mission, + use_web=self.use_web) cahvor_quats = Rotation.from_matrix(self.cahvor_rotation_matrix).as_quat() if nadir: diff --git a/ale/drivers/co_drivers.py b/ale/drivers/co_drivers.py index de01c75b1..e6edfcc8d 100644 --- a/ale/drivers/co_drivers.py +++ b/ale/drivers/co_drivers.py @@ -282,7 +282,9 @@ def frame_chain(self): target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, ephemeris_times=self.ephemeris_time, - exact_ck_times=True) + exact_ck_times=True, + mission=self.spiceql_mission, + use_web=self.use_web) rotation = ConstantRotation([[0, 0, 1, 0]], self.sensor_frame_id, self._original_naif_sensor_frame_id) @@ -511,7 +513,9 @@ def frame_chain(self): target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, ephemeris_times=self.ephemeris_time, - exact_ck_times=True) + exact_ck_times=True, + mission=self.spiceql_mission, + use_web=self.use_web) rotation = ConstantRotation([[0, 0, 1, 0]], self.sensor_frame_id, self._original_naif_sensor_frame_id) From f4932219ea0a57c5dfe984ee8beace5512b9956f Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Mar 2023 20:59:41 -0700 Subject: [PATCH 11/73] Updates MroCtxIsisLabelNaifSpice Driver to fully use spiceql --- ale/drivers/mro_drivers.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 708eb08ac..2bcda9164 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -1,6 +1,5 @@ import spiceypy as spice -from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice @@ -344,23 +343,6 @@ def sensor_name(self): """ return "CONTEXT CAMERA" - @property - def ephemeris_start_time(self): - """ - Returns the ephemeris start time of the image. - Expects spacecraft_id to be defined. This should be the integer - Naif ID code for the spacecraft. - - Returns - ------- - : float - ephemeris start time of the image - """ - if not hasattr(self, '_ephemeris_start_time'): - sclock = self.label['IsisCube']['Instrument']['SpacecraftClockCount'] - self._ephemeris_start_time = pyspiceql.sclkToEt(str(self.spacecraft_name).lower(), sclock) - return self._ephemeris_start_time - @property def ephemeris_stop_time(self): """ @@ -703,7 +685,6 @@ def sensor_model_version(self): return 1 - class MroCrismIsisLabelNaifSpiceDriver(LineScanner, IsisLabel, NaifSpice, NoDistortion, Driver): """ Driver for reading Crism ISIS labels. From e33a6381118641755efc4b5f6c1b59b8e45e6c92 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Mar 2023 21:11:28 -0700 Subject: [PATCH 12/73] Allow for no kernels to be passed in NaifSpice drivers --- ale/base/data_naif.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 09297d96e..4e9c502a7 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -40,7 +40,7 @@ def kernels(self): """ Get the NAIF SPICE Kernels to furnish - There are two ways to specify which kernels a driver will use: + There are three ways to specify which kernels a driver will use: 1. Passing the 'kernels' property into load(s) or at instantiation. This can be either a straight iterable or a dictionary that specifies @@ -51,14 +51,18 @@ def kernels(self): `shortMissionName-versionInfo`. The directory corresponding to the driver's mission will be searched for the appropriate meta kernel to load. + 3. Default to using SpiceQL for extracting spice information which does not + require kernels to be set. If used with `web: False` the user will have to + specifiy either `SPICEDATA, ALESPICEROOT, or ISISDATA` ato point to there + data area See Also -------- - ale.util.get_kernels_from_isis_pvl : Function used to parse ISIS style dict - ale.util.get_metakernels : Function that searches ALESPICEROOT for meta kernels - ale.util.generate_kernels_from_cube : Helper function to get an ISIS style dict - from an ISIS cube that has been through - spiceinit + ale.kernel_access.get_kernels_from_isis_pvl : Function used to parse ISIS style dict + ale.kernel_access.get_metakernels : Function that searches ALESPICEROOT for meta kernels + ale.kernel_access.generate_kernels_from_cube : Helper function to get an ISIS style dict + from an ISIS cube that has been through + spiceinit """ if not hasattr(self, '_kernels'): @@ -67,15 +71,14 @@ def kernels(self): self._kernels = util.get_kernels_from_isis_pvl(self._props['kernels']) except Exception as e: self._kernels = self._props['kernels'] - else: - if not ale.spice_root: - raise EnvironmentError(f'ale.spice_root is not set, cannot search for metakernels. ale.spice_root = "{ale.spice_root}"') - + elif ale.spice_root: search_results = util.get_metakernels(ale.spice_root, missions=self.short_mission_name, years=self.utc_start_time.year, versions='latest') if search_results['count'] == 0: raise ValueError(f'Failed to find metakernels. mission: {self.short_mission_name}, year:{self.utc_start_time.year}, versions="latest" spice root = "{ale.spice_root}"') self._kernels = [search_results['data'][0]['path']] + else: + self._kernels = [] return self._kernels From f4d909dd82bf1fb443cf227947e3bba1fc3906fb Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 27 Mar 2023 16:04:51 -0700 Subject: [PATCH 13/73] Addressed mro_ctx_load test --- ale/base/data_naif.py | 51 ++++++++++++++------------------------- ale/base/type_sensor.py | 3 ++- ale/drivers/co_drivers.py | 6 +++-- ale/kernel_access.py | 10 ++++++-- ale/transformation.py | 40 +++++++++++++++++++++++------- 5 files changed, 63 insertions(+), 47 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 4e9c502a7..84b561470 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -104,6 +104,12 @@ def use_web(self): self._use_web = web_prop return self._use_web + + @property + def search_kernels(self): + if not hasattr(self, "_search_kernels"): + self._search_kernels = self.kernels == [] + return self._search_kernels @property def light_time_correction(self): @@ -397,11 +403,11 @@ def sun_position(self): positions = [] velocities = [] - sun_lt_states = self.spiceql_call("getTargetStates",{"ets": str(times), - "target": self.target_name, - "observer": self.spacecraft_name, - "frame": 'J2000', - "abcorr": self.light_time_correction, + sun_lt_states = self.spiceql_call("getTargetStates",{"ets": times, + "target": "SUN", + "observer": self.target_name, + "frame": self.reference_frame, + "abcorr": "LT+S", "mission": self.spiceql_mission}) for sun_state in sun_lt_states: sun_state = np.array(sun_state) @@ -449,48 +455,32 @@ def sensor_position(self): # location of the target. For more information, see: # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html if self.correct_lt_to_surface and self.light_time_correction.upper() == 'LT+S': - print("BANANA", ephem) - obs_tars = self.spiceql_call("getTargetStates",{"ets": str(ephem), + obs_tars = self.spiceql_call("getTargetStates",{"ets": ephem, "target": target, "observer": observer, "frame": "J2000", "abcorr": self.light_time_correction, "mission": self.spiceql_mission}) - # obs_tar = pyspiceql.getTargetState(time, - # target, - # observer, - # 'J2000', - # self.light_time_correction) obs_tar_lts = np.array(obs_tars)[:,-1] # ssb to spacecraft - ssb_obs = self.spiceql_call("getTargetStates",{"ets": str(ephem), + ssb_obs = self.spiceql_call("getTargetStates",{"ets": ephem, "target": target, "observer": "SSB", "frame": "J2000", "abcorr": "NONE", "mission": self.spiceql_mission}) - # ssb_obs = pyspiceql.getTargetState(time, - # target, - # 'SSB', - # 'J2000', - # "NONE") ssb_obs_states = np.array(ssb_obs)[:,0:6] radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt - ssb_tars = self.spiceql_call("getTargetStates",{"ets": str(adjusted_time), + ssb_tars = self.spiceql_call("getTargetStates",{"ets": adjusted_time, "target": target, "observer": "SSB", "frame": "J2000", "abcorr": "NONE", "mission": self.spiceql_mission}) - # ssb_tar = pyspiceql.getTargetState(adjusted_time, - # target, - # 'SSB', - # 'J2000', - # "NONE") ssb_tar_state = np.array(ssb_tars)[:,0:6] _states = ssb_tar_state - ssb_obs_states states = [] @@ -499,17 +489,12 @@ def sensor_position(self): state = spice.mxvg(matrix, state) states.append(state) else: - states = self.spiceql_call("getTargetStates",{"ets": str(ephem), + states = self.spiceql_call("getTargetStates",{"ets": ephem, "target": target, "observer": observer, "frame": self.reference_frame, "abcorr": self.light_time_correction, "mission": self.spiceql_mission}) - # state = pyspiceql.getTargetState(time, - # target, - # observer, - # self.reference_frame, - # self.light_time_correction) states = np.array(states)[:,0:6] for state in states: @@ -538,7 +523,8 @@ def frame_chain(self): nadir=nadir, exact_ck_times=exact_ck_times, inst_time_bias=self.instrument_time_bias, mission=self.spiceql_mission, - use_web=self.use_web) + use_web=self.use_web, + search_kernels=self.search_kernels) if nadir: # Logic for nadir calculation was taken from ISIS3 @@ -753,6 +739,5 @@ def spiceql_call(self, function_name = "", function_args = {}): """ # Ideally this would work if a user passed no kernels but still # set ISISDATA - if (not hasattr(self, "kernels")): - function_args["searchKernels"] = True + function_args["searchKernels"] = self.search_kernels return kernel_access.spiceql_call(function_name, function_args, self.use_web) \ No newline at end of file diff --git a/ale/base/type_sensor.py b/ale/base/type_sensor.py index d9b6787ba..91e7e104e 100644 --- a/ale/base/type_sensor.py +++ b/ale/base/type_sensor.py @@ -537,7 +537,8 @@ def frame_chain(self): ephemeris_times=self.ephemeris_time, nadir=nadir, exact_ck_times=False, mission=self.spiceql_mission, - use_web=self.use_web) + use_web=self.use_web, + search_kernels=self.search_kernels) cahvor_quats = Rotation.from_matrix(self.cahvor_rotation_matrix).as_quat() if nadir: diff --git a/ale/drivers/co_drivers.py b/ale/drivers/co_drivers.py index e6edfcc8d..414d2be14 100644 --- a/ale/drivers/co_drivers.py +++ b/ale/drivers/co_drivers.py @@ -284,7 +284,8 @@ def frame_chain(self): ephemeris_times=self.ephemeris_time, exact_ck_times=True, mission=self.spiceql_mission, - use_web=self.use_web) + use_web=self.use_web, + search_kernels=self.search_kernels) rotation = ConstantRotation([[0, 0, 1, 0]], self.sensor_frame_id, self._original_naif_sensor_frame_id) @@ -515,7 +516,8 @@ def frame_chain(self): ephemeris_times=self.ephemeris_time, exact_ck_times=True, mission=self.spiceql_mission, - use_web=self.use_web) + use_web=self.use_web, + search_kernels=self.search_kernels) rotation = ConstantRotation([[0, 0, 1, 0]], self.sensor_frame_id, self._original_naif_sensor_frame_id) diff --git a/ale/kernel_access.py b/ale/kernel_access.py index 27d45441f..efc8fbd42 100644 --- a/ale/kernel_access.py +++ b/ale/kernel_access.py @@ -1,11 +1,11 @@ from glob import glob from itertools import groupby -import json import os from os import path import requests import warnings +import numpy as np import pyspiceql from ale import spice_root @@ -345,7 +345,13 @@ def spiceql_call(function_name = "", function_args = {}, use_web=False): 'Content-Type': 'application/json' } - r = requests.get(url, params=function_args, headers=headers, verify=False) + # Convert any lists being passed over the wire to strings + clean_function_args = function_args + for key, value in function_args.items(): + if isinstance(value, list) or isinstance(value, np.ndarray): + clean_function_args[key] = str(value) + + r = requests.get(url, params=clean_function_args, headers=headers, verify=False) r.raise_for_status() response = r.json() diff --git a/ale/transformation.py b/ale/transformation.py index 24a39508d..c6270e003 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -94,9 +94,21 @@ class FrameChain(nx.DiGraph): A of ephemeris times that need to be rotated for each set of frame rotations in the frame chain """ + def __init__(self, use_web=False, search_kernels=False, incoming_graph_data=None, **attr): + super().__init__(incoming_graph_data, **attr) + self.use_web = use_web + self.search_kernels = search_kernels + @classmethod - def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris_times=[], nadir=False, exact_ck_times=False, inst_time_bias=0, use_web=False, mission=""): - frame_chain = cls() + def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, + ephemeris_times=[], + nadir=False, + exact_ck_times=False, + inst_time_bias=0, + use_web=False, + search_kernels=False, + mission=""): + frame_chain = cls(use_web, search_kernels) # Default assume one time target_times = ephemeris_times if len(target_times) > 1: @@ -114,8 +126,16 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris if isinstance(sensor_times, np.ndarray): sensor_times = sensor_times.tolist() - sensor_time_dependent_frames, sensor_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, "initialFrame": sensor_frame, "mission": mission}, use_web) - target_time_dependent_frames, target_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, "initialFrame": target_frame, "mission": mission}, use_web) + sensor_time_dependent_frames, sensor_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, + "initialFrame": sensor_frame, + "mission": mission, + "searchKernels": frame_chain.search_kernels}, + frame_chain.use_web) + target_time_dependent_frames, target_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, + "initialFrame": target_frame, + "mission": mission, + "searchKernels": frame_chain.search_kernels}, + frame_chain.use_web) sensor_time_dependent_frames = list(zip(sensor_time_dependent_frames[:-1], sensor_time_dependent_frames[1:])) constant_frames = list(zip(sensor_constant_frames[:-1], sensor_constant_frames[1:])) @@ -131,10 +151,11 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, ephemeris # Add all constant frame chains to the graph for s, d in constant_frames: quats = np.zeros(4) - quat_and_av = spiceql_call("getTargetOrientations",{"ets": str([ephemeris_times[0]]), + quat_and_av = spiceql_call("getTargetOrientations",{"ets": [ephemeris_times[0]], "toFrame": d, "refFrame": s, - "mission": mission}, + "mission": mission, + "searchKernels": frame_chain.search_kernels}, use_web=use_web)[0] quats[:3] = quat_and_av[1:4] quats[3] = quat_and_av[0] @@ -402,11 +423,12 @@ def compute_time_dependent_rotiations(self, frames, times, time_bias, mission="" for s, d in frames: quats = np.zeros((len(times), 4)) avs = [] - quats_and_avs = spiceql_call("getTargetOrientations",{"ets": str(times), + quats_and_avs = spiceql_call("getTargetOrientations",{"ets": times, "toFrame": d, "refFrame": s, - "mission": mission}, - use_web=use_web) + "mission": mission, + "searchKernels": self.search_kernels}, + use_web=self.use_web) _quats = np.array(quats_and_avs)[:, 0:4] for j, quat in enumerate(_quats): quats[j,:3] = quat[1:] From f79c91822ec0f10f82447ff74af6a20b8c95c578 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 12 May 2023 16:22:42 -0700 Subject: [PATCH 14/73] Move write_metakernel_from_cube to kernel_access --- ale/kernel_access.py | 134 +++++++++++++++++++++---------------------- ale/util.py | 60 ------------------- 2 files changed, 65 insertions(+), 129 deletions(-) diff --git a/ale/kernel_access.py b/ale/kernel_access.py index efc8fbd42..997f8bf0b 100644 --- a/ale/kernel_access.py +++ b/ale/kernel_access.py @@ -1,15 +1,19 @@ +from collections import OrderedDict from glob import glob -from itertools import groupby +from itertools import groupby, chain import os from os import path -import requests +import re import warnings import numpy as np -import pyspiceql +import pvl from ale import spice_root from ale.util import get_isis_preferences +from ale.util import get_isis_mission_translations +from ale.util import read_pvl +from ale.util import search_isis_db def get_metakernels(spice_dir=spice_root, missions=set(), years=set(), versions=set()): """ @@ -142,6 +146,30 @@ def generate_kernels_from_cube(cube, expand=False, format_as='list'): return get_kernels_from_isis_pvl(kernel_group, expand, format_as) +def dict_to_lower(d): + return {k.lower():v if not isinstance(v, dict) else dict_to_lower(v) for k,v in d.items()} + + +def expandvars(path, env_dict=os.environ, default=None, case_sensitive=True): + if env_dict != os.environ: + env_dict = dict_merge(env_dict, os.environ) + + while "$" in path: + user_dict = env_dict if case_sensitive else dict_to_lower(env_dict) + + def replace_var(m): + group1 = m.group(1) if case_sensitive else m.group(1).lower() + val = user_dict.get(m.group(2) or group1 if default is None else default) + if not val: + raise KeyError(f"Failed to evaluate {m.group(0)} from env_dict. " + + f"Should {m.group(0)} be an environment variable?") + + return val + reVar = r'\$(\w+|\{([^}]*)\})' + path = re.sub(reVar, replace_var, path) + return path + + def get_kernels_from_isis_pvl(kernel_group, expand=True, format_as="list"): # enforce key order mk_paths = OrderedDict.fromkeys( @@ -309,69 +337,37 @@ def remove_dups(listofElements): return kernels -def spiceql_call(function_name = "", function_args = {}, use_web=False): - """ - Interface to SpiceQL (Spice Query Library) for both Offline and Online use - - This function will access the value passed through props defined as `web`. This - value determines the access pattern for spice data. When set to Online, you will - access the SpiceQL service provided through the USGS Astro AWS platform. This service - performs kernel and data aquisition. If set to Offline, you will access locally loaded - kernels, and SpiceQL will do no searching for you. - - Parameters - ---------- - functions_name : str - String defineing the function to call, properly exposed SpiceQL - functions should map 1-to-1 with endpoints on the service - - function_args : dict - Dictionary of arguments used by the function - - Returns : any - Any return from a SpiceQL function - """ - if not use_web: - func = getattr(pyspiceql, function_name) - - # Ensure that in offline mode we anticipate the user loading/passing their own kernels - # to ALE - return func(**function_args) - - url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" - url += function_name - headers = { - 'accept': '*/*', - 'Content-Type': 'application/json' - } - - # Convert any lists being passed over the wire to strings - clean_function_args = function_args - for key, value in function_args.items(): - if isinstance(value, list) or isinstance(value, np.ndarray): - clean_function_args[key] = str(value) - - r = requests.get(url, params=clean_function_args, headers=headers, verify=False) - r.raise_for_status() - response = r.json() - - if r.status_code != 200: - raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") - elif response["statusCode"] != 200: - raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") - return response["body"]["return"] - - # Code for accessing SpiceQL docker container - # try: - # url = "http://localhost:9000/2015-03-31/functions/function/invocations" - # headers = { - # 'Content-Type': 'application/x-www-form-urlencoded', - # } - # function_args["func"] = function_name - # r = requests.get(url, data=json.dumps(function_args), headers=headers, verify=False) - # r.raise_for_status() - # if r.json()["statusCode"] != 200: - # raise requests.HTTPError(f"Recieved code {r.json()['statusCode']} from spice server, with error: {r.json()}") - # return r.json()["body"]["return"] - # except requests.exceptions.HTTPError as err: - # raise err \ No newline at end of file +def write_metakernel_from_cube(cube, mkpath=None): + # add ISISPREF paths as path_symbols and path_values to avoid custom expand logic + pvlprefs = get_isis_preferences() + + kernels = generate_kernels_from_cube(cube) + + # make sure kernels are mk strings + kernels = ["'"+k+"'" for k in kernels] + + paths = OrderedDict(pvlprefs['DataDirectory']) + path_values = ["'"+os.path.expandvars(path)+"'" for path in paths.values()] + path_symbols = ["'"+symbol.lower()+"'" for symbol in paths.keys()] + + body = '\n\n'.join([ + 'KPL/MK', + f'Metakernel Generated from an ISIS cube: {cube}', + '\\begindata', + 'PATH_VALUES = (', + '\n'.join(path_values), + ')', + 'PATH_SYMBOLS = (', + '\n'.join(path_symbols), + ')', + 'KERNELS_TO_LOAD = (', + '\n'.join(kernels), + ')', + '\\begintext' + ]) + + if mkpath is not None: + with open(mkpath, 'w') as f: + f.write(body) + + return body diff --git a/ale/util.py b/ale/util.py index e583a0a08..9cc5c9059 100644 --- a/ale/util.py +++ b/ale/util.py @@ -79,66 +79,6 @@ def get_isis_preferences(isis_preferences=None): return finalprefs -def dict_to_lower(d): - return {k.lower():v if not isinstance(v, dict) else dict_to_lower(v) for k,v in d.items()} - - -def expandvars(path, env_dict=os.environ, default=None, case_sensitive=True): - if env_dict != os.environ: - env_dict = dict_merge(env_dict, os.environ) - - while "$" in path: - user_dict = env_dict if case_sensitive else dict_to_lower(env_dict) - - def replace_var(m): - group1 = m.group(1) if case_sensitive else m.group(1).lower() - val = user_dict.get(m.group(2) or group1 if default is None else default) - if not val: - raise KeyError(f"Failed to evaluate {m.group(0)} from env_dict. " + - f"Should {m.group(0)} be an environment variable?") - - return val - reVar = r'\$(\w+|\{([^}]*)\})' - path = re.sub(reVar, replace_var, path) - return path - - -def write_metakernel_from_cube(cube, mkpath=None): - # add ISISPREF paths as path_symbols and path_values to avoid custom expand logic - pvlprefs = get_isis_preferences() - - kernels = generate_kernels_from_cube(cube) - - # make sure kernels are mk strings - kernels = ["'"+k+"'" for k in kernels] - - paths = OrderedDict(pvlprefs['DataDirectory']) - path_values = ["'"+os.path.expandvars(path)+"'" for path in paths.values()] - path_symbols = ["'"+symbol.lower()+"'" for symbol in paths.keys()] - - body = '\n\n'.join([ - 'KPL/MK', - f'Metakernel Generated from an ISIS cube: {cube}', - '\\begindata', - 'PATH_VALUES = (', - '\n'.join(path_values), - ')', - 'PATH_SYMBOLS = (', - '\n'.join(path_symbols), - ')', - 'KERNELS_TO_LOAD = (', - '\n'.join(kernels), - ')', - '\\begintext' - ]) - - if mkpath is not None: - with open(mkpath, 'w') as f: - f.write(body) - - return body - - def get_ck_frames(kernel): """ Get all of the reference frames defined in a kernel. From ef1aac224f4d18a7e3f1779ee5112eba622e10a5 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 12 May 2023 16:22:59 -0700 Subject: [PATCH 15/73] Added module for access spiceql --- ale/spiceql_access.py | 198 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 ale/spiceql_access.py diff --git a/ale/spiceql_access.py b/ale/spiceql_access.py new file mode 100644 index 000000000..8e512d5fb --- /dev/null +++ b/ale/spiceql_access.py @@ -0,0 +1,198 @@ +import asyncio +import math +import requests + +import aiohttp +import numpy as np + +import pyspiceql + +def stringify_web_args(function_args): + """ + Takes a dictionary of args and converts them into web acceptable strings + + Parameters + ---------- + function_args : dict + + Returns + ------- + clean_function_args : dict + """ + clean_function_args = function_args + for key, value in function_args.items(): + if isinstance(value, np.ndarray): + clean_function_args[key] = str(list(value)) + if isinstance(value, list): + clean_function_args[key] = str(value) + if isinstance(value, bool): + clean_function_args[key] = str(value) + + return clean_function_args + +def check_response(response): + """ + Checks that a response from the spice server returned correctly + + Parameters + ---------- + : obj + Request response object + """ + response.raise_for_status() + + if response.status_code != 200: + raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") + + if response.json()["statusCode"] != 200: + raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") + +async def async_spiceql_call(session, function_name = "", function_args = {}, use_web=False): + """ + Interface to SpiceQL (Spice Query Library) for both Offline and Online use + + This function will access the value passed through props defined as `web`. This + value determines the access pattern for spice data. When set to Online, you will + access the SpiceQL service provided through the USGS Astro AWS platform. This service + performs kernel and data aquisition. If set to Offline, you will access locally loaded + kernels, and SpiceQL will do no searching for you. The async version of the function + allows for asynchronous spiceql calls. + + Parameters + ---------- + session : obj + aiohttp client session object + + functions_name : str + String defineing the function to call, properly exposed SpiceQL + functions should map 1-to-1 with endpoints on the service + + function_args : dict + Dictionary of arguments used by the function + + use_web : bool + Boolean value to either use the USGS web service when set to True + or local data when set to False + + Returns : any + Any return from a SpiceQL function + """ + if use_web == False: + func = getattr(pyspiceql, function_name) + return func(**function_args) + url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" + url += function_name + headers = { + 'accept': '*/*', + 'Content-Type': 'application/json' + } + + clean_function_args = stringify_web_args(function_args) + async with session.get(url, params=clean_function_args, headers=headers, ssl=False) as response: + web_response = await response.json() + return web_response["body"]["return"] + +def spiceql_call(function_name = "", function_args = {}, use_web=False): + """ + Interface to SpiceQL (Spice Query Library) for both Offline and Online use + + This function will access the value passed through props defined as `web`. This + value determines the access pattern for spice data. When set to Online, you will + access the SpiceQL service provided through the USGS Astro AWS platform. This service + performs kernel and data aquisition. If set to Offline, you will access locally loaded + kernels, and SpiceQL will do no searching for you. + + Parameters + ---------- + functions_name : str + String defineing the function to call, properly exposed SpiceQL + functions should map 1-to-1 with endpoints on the service + + function_args : dict + Dictionary of arguments used by the function + + use_web : bool + Boolean value to either use the USGS web service when set to True + or local data when set to False + + Returns : any + Any return from a SpiceQL function + """ + if use_web == False: + func = getattr(pyspiceql, function_name) + return func(**function_args) + + url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" + url += function_name + headers = { + 'accept': '*/*', + 'Content-Type': 'application/json' + } + + # Convert any args being passed over the wire to strings + clean_function_args = stringify_web_args(function_args) + + response = requests.get(url, params=clean_function_args, headers=headers, verify=False) + check_response(response) + return response.json()["body"]["return"] + +async def get_ephem_data(times, function_name, batch_size=400, web=False, **kwargs): + """ + This function provides access to ephemeris data aquisition in spiceql. + For the web service there is a limited number of times that can be + requested at once due to URL size limits. This limit is ~400 times. + This function is used to chunk up the requests to be submitted all at + once when accessing the web service. + + When accessing local data, the function queries all of the times at once. + + Parameters + ---------- + times : list + List of ephemeris times to get data for + + function_name : str + The name of the spiceql function to run. This can be + either getTargetOrientations or getTargetStates + + batch_size : int + Number of times to request to the web services at once. + Where the number of request is times / batch_size + + web : bool + Boolean value to either use the USGS web service when set to True + or local data when set to False + + kwargs : dict + Arguments to be passed to the spiceql function + + Returns + ------- + results : list + Returns a list of ephemeris data to the user as a list + of lists. Where each element corrisponds to the time + requested in times. + """ + valid_functions = ["getTargetOrientations", "getTargetStates"] + if function_name not in valid_functions: + raise ValueError(f"The function name {function_name} is not supported " + "by this function please pass one of the following: " + str(valid_functions)) + if not web: + function_args = {**kwargs} + function_args["ets"] = times + rotation = spiceql_call(function_name, function_args, web) + return rotation + + tasks = [] + batches = math.ceil(len(times) / batch_size) + async with aiohttp.ClientSession() as session: + for i in range(1, batches+1): + batch_times = times[(i - 1) * batch_size: i * batch_size] + function_args = {**kwargs} + function_args["ets"] = batch_times + tasks.append(asyncio.create_task(async_spiceql_call(session, function_name, function_args, use_web=web))) + responses = await asyncio.gather(*tasks) + results = [] + for response in responses: + results += response + return results From d1220aa2b0cb0f8970fa2fd1c7b3fba1e06f6d19 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 12 May 2023 16:24:08 -0700 Subject: [PATCH 16/73] Updated NaifSpice and from_spice to use async functions --- ale/base/data_naif.py | 65 ++++++++------- ale/transformation.py | 178 ++++++++++++++++++------------------------ 2 files changed, 114 insertions(+), 129 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 84b561470..41566f727 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -1,4 +1,5 @@ import warnings +import asyncio import numpy as np import pyspiceql @@ -9,7 +10,7 @@ from ale.base import spiceql_mission_map from ale.transformation import FrameChain from ale.rotation import TimeDependentRotation -from ale import kernel_access +from ale import spiceql_access from ale import util class NaifSpice(): @@ -108,7 +109,9 @@ def use_web(self): @property def search_kernels(self): if not hasattr(self, "_search_kernels"): - self._search_kernels = self.kernels == [] + self._search_kernels = False + if not self.kernels and self.use_web: + self._search_kernels = True return self._search_kernels @property @@ -455,32 +458,35 @@ def sensor_position(self): # location of the target. For more information, see: # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html if self.correct_lt_to_surface and self.light_time_correction.upper() == 'LT+S': - obs_tars = self.spiceql_call("getTargetStates",{"ets": ephem, - "target": target, - "observer": observer, - "frame": "J2000", - "abcorr": self.light_time_correction, - "mission": self.spiceql_mission}) + kwargs = {"target": target, + "observer": observer, + "frame": "J2000", + "abcorr": self.light_time_correctio, + "mission": self.spiceql_mission, + "searchKernels": self.search_kernels} + obs_tars = asyncio.run(spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web)) obs_tar_lts = np.array(obs_tars)[:,-1] # ssb to spacecraft - ssb_obs = self.spiceql_call("getTargetStates",{"ets": ephem, - "target": target, - "observer": "SSB", - "frame": "J2000", - "abcorr": "NONE", - "mission": self.spiceql_mission}) + kwargs = {"target": target, + "observer": "SSB", + "frame": "J2000", + "abcorr": "NONE", + "mission": self.spiceql_mission, + "searchKernels": self.search_kernels} + ssb_obs = asyncio.run(spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web)) ssb_obs_states = np.array(ssb_obs)[:,0:6] radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt - ssb_tars = self.spiceql_call("getTargetStates",{"ets": adjusted_time, - "target": target, - "observer": "SSB", - "frame": "J2000", - "abcorr": "NONE", - "mission": self.spiceql_mission}) + kwargs = {"target": target, + "observer": "SSB", + "frame": "J2000", + "abcorr": "NONE", + "mission": self.spiceql_mission, + "searchKernels": self.search_kernels} + ssb_tars = asyncio.run(spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", **kwargs, web=self.use_web)) ssb_tar_state = np.array(ssb_tars)[:,0:6] _states = ssb_tar_state - ssb_obs_states states = [] @@ -489,12 +495,13 @@ def sensor_position(self): state = spice.mxvg(matrix, state) states.append(state) else: - states = self.spiceql_call("getTargetStates",{"ets": ephem, - "target": target, - "observer": observer, - "frame": self.reference_frame, - "abcorr": self.light_time_correction, - "mission": self.spiceql_mission}) + kwargs = {"target": target, + "observer": observer, + "frame": self.reference_frame, + "abcorr": self.light_time_correction, + "mission": self.spiceql_mission, + "searchKernels": self.search_kernels} + states = asyncio.run(spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web)) states = np.array(states)[:,0:6] for state in states: @@ -737,7 +744,7 @@ def spiceql_call(self, function_name = "", function_args = {}): : json Json data from the SpiceQL call """ - # Ideally this would work if a user passed no kernels but still - # set ISISDATA + # This will work if a user passed no kernels but still set ISISDATA + # just might take a bit function_args["searchKernels"] = self.search_kernels - return kernel_access.spiceql_call(function_name, function_args, self.use_web) \ No newline at end of file + return spiceql_access.spiceql_call(function_name, function_args, self.use_web) \ No newline at end of file diff --git a/ale/transformation.py b/ale/transformation.py index c6270e003..ec6601982 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -1,9 +1,15 @@ +import asyncio +import aiohttp + import numpy as np from numpy.polynomial.polynomial import polyval import networkx as nx from networkx.algorithms.shortest_paths.generic import shortest_path +import spiceypy as spice + +import pyspiceql -from ale.kernel_access import spiceql_call +from ale.spiceql_access import get_ephem_data, async_spiceql_call, spiceql_call from ale.rotation import ConstantRotation, TimeDependentRotation def create_rotations(rotation_table): @@ -117,8 +123,13 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, sensor_times = [] if exact_ck_times and len(ephemeris_times) > 1 and not nadir: try: - sensor_times = cls.extract_exact_ck_times(ephemeris_times[0] + inst_time_bias, ephemeris_times[-1] + inst_time_bias, sensor_frame) + sensor_times = spiceql_call("extractExactCkTimes", {"observStart": ephemeris_times[0] + inst_time_bias, + "observStop": ephemeris_times[-1] + inst_time_bias, + "targetFrame": sensor_frame, + "searchKernels": frame_chain.search_kernels}) except Exception as e: + print("BANANANANA \n\n") + print(e) pass if (len(sensor_times) == 0): @@ -126,16 +137,9 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, if isinstance(sensor_times, np.ndarray): sensor_times = sensor_times.tolist() - sensor_time_dependent_frames, sensor_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, - "initialFrame": sensor_frame, - "mission": mission, - "searchKernels": frame_chain.search_kernels}, - frame_chain.use_web) - target_time_dependent_frames, target_constant_frames = spiceql_call("frameTrace", {"et": center_ephemeris_time, - "initialFrame": target_frame, - "mission": mission, - "searchKernels": frame_chain.search_kernels}, - frame_chain.use_web) + frames = asyncio.run(frame_chain.frame_trace(center_ephemeris_time, sensor_frame, target_frame, mission)) + sensor_time_dependent_frames, sensor_constant_frames = frames[0] + target_time_dependent_frames, target_constant_frames = frames[1] sensor_time_dependent_frames = list(zip(sensor_time_dependent_frames[:-1], sensor_time_dependent_frames[1:])) constant_frames = list(zip(sensor_constant_frames[:-1], sensor_constant_frames[1:])) @@ -145,86 +149,38 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, constant_frames.extend(target_constant_frames) # Add all time dependent frame chains to the graph - frame_chain.compute_time_dependent_rotiations(sensor_time_dependent_frames, sensor_times, inst_time_bias, mission, use_web=use_web) - frame_chain.compute_time_dependent_rotiations(target_time_dependent_frames, target_times, 0, mission, use_web=use_web) - - # Add all constant frame chains to the graph - for s, d in constant_frames: - quats = np.zeros(4) - quat_and_av = spiceql_call("getTargetOrientations",{"ets": [ephemeris_times[0]], - "toFrame": d, - "refFrame": s, - "mission": mission, - "searchKernels": frame_chain.search_kernels}, - use_web=use_web)[0] - quats[:3] = quat_and_av[1:4] - quats[3] = quat_and_av[0] - - rotation = ConstantRotation(quats, s, d) - - frame_chain.add_edge(rotation=rotation) + asyncio.run(frame_chain.generate_time_dependent_rotiations(sensor_time_dependent_frames, sensor_times, inst_time_bias, mission)) + asyncio.run(frame_chain.generate_time_dependent_rotiations(target_time_dependent_frames, target_times, 0, mission)) + asyncio.run(frame_chain.generate_constant_rotations(constant_frames, ephemeris_times[0], mission)) return frame_chain - @staticmethod - def frame_trace(reference_frame, ephemeris_time, nadir=False): - if nadir: - return [], [] - - frame_codes = [reference_frame] - _, frame_type, _ = spice.frinfo(frame_codes[-1]) - frame_types = [frame_type] - - - while(frame_codes[-1] != 1): - try: - center, frame_type, frame_type_id = spice.frinfo(frame_codes[-1]) - except Exception as e: - print(e) - break - - if frame_type == 1 or frame_type == 2: - frame_code = 1 - - elif frame_type == 3: - try: - matrix, frame_code = spice.ckfrot(frame_type_id, ephemeris_time) - except: - raise Exception(f"The ck rotation from frame {frame_codes[-1]} can not " + - f"be found due to no pointing available at requested time {ephemeris_time} " + - "or a problem with the frame") - elif frame_type == 4: - try: - matrix, frame_code = spice.tkfram(frame_type_id) - except: - raise Exception(f"The tk rotation from frame {frame_codes[-1]} can not " + - "be found") - elif frame_type == 5: - matrix, frame_code = spice.zzdynrot(frame_type_id, center, ephemeris_time) - - else: - raise Exception(f"The frame {frame_codes[-1]} has a type {frame_type_id} " + - "not supported by your version of Naif Spicelib. " + - "You need to update.") - - frame_codes.append(frame_code) - frame_types.append(frame_type) - constant_frames = [] - while frame_codes: - if frame_types[0] == 4: - constant_frames.append(frame_codes.pop(0)) - frame_types.pop(0) - else: - break - - time_dependent_frames = [] - if len(constant_frames) != 0: - time_dependent_frames.append(constant_frames[-1]) - - while frame_codes: - time_dependent_frames.append(frame_codes.pop(0)) - - return time_dependent_frames, constant_frames + async def frame_trace(self, time, sensorFrame, targetFrame, mission, nadir=False): + if not self.use_web: + results = [pyspiceql.frameTrace(time, sensorFrame, mission, searchKernels=self.search_kernels)] + results.append(pyspiceql.frameTrace(time, targetFrame, mission, searchKernels=self.search_kernels)) + return results + tasks = [] + async with aiohttp.ClientSession() as session: + tasks.append(asyncio.create_task(async_spiceql_call(session, + "frameTrace", + {"et": time, + "initialFrame": sensorFrame, + "mission": mission, + "searchKernels": self.search_kernels}, + use_web=self.use_web))) + tasks.append(asyncio.create_task(async_spiceql_call(session, + "frameTrace", + {"et": time, + "initialFrame": targetFrame, + "mission": mission, + "searchKernels": self.search_kernels}, + use_web=self.use_web))) + responses = await asyncio.gather(*tasks) + results = [] + for response in responses: + results.append(response) + return results @classmethod def from_isis_tables(cls, *args, inst_pointing={}, body_orientation={}, **kwargs): @@ -327,9 +283,9 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): """ times = [] - FILESIZ = 128; - TYPESIZ = 32; - SOURCESIZ = 128; + FILESIZ = 128 + TYPESIZ = 32 + SOURCESIZ = 128 currentTime = observStart @@ -337,6 +293,9 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): if (count > 1): msg = "Unable to get exact CK record times when more than 1 CK is loaded, Aborting" raise Exception(msg) + elif (count < 1): + msg = "No CK kernels loaded, Aborting" + raise Exception(msg) _, _, _, handle = spice.kdata(0, "ck", FILESIZ, TYPESIZ, SOURCESIZ) spice.dafbfs(handle) @@ -407,7 +366,7 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): return times - def compute_time_dependent_rotiations(self, frames, times, time_bias, mission="", use_web=False): + async def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=""): """ Computes the time dependent rotations based on a list of tuples that define the relationships between frames as (source, destination) and a list of times to @@ -420,15 +379,16 @@ def compute_time_dependent_rotiations(self, frames, times, time_bias, mission="" times : list A list of times to compute the rotation at """ + frame_tasks = [] for s, d in frames: + kwargs = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} + frame_tasks.append(asyncio.create_task(get_ephem_data(times, "getTargetOrientations", **kwargs, web=self.use_web))) + quats_and_avs_per_frame = await asyncio.gather(*frame_tasks) + + for i, frame in enumerate(frames): + quats_and_avs = quats_and_avs_per_frame[i] quats = np.zeros((len(times), 4)) avs = [] - quats_and_avs = spiceql_call("getTargetOrientations",{"ets": times, - "toFrame": d, - "refFrame": s, - "mission": mission, - "searchKernels": self.search_kernels}, - use_web=self.use_web) _quats = np.array(quats_and_avs)[:, 0:4] for j, quat in enumerate(_quats): quats[j,:3] = quat[1:] @@ -440,5 +400,23 @@ def compute_time_dependent_rotiations(self, frames, times, time_bias, mission="" if len(avs) == 0: avs = None biased_times = [time - time_bias for time in times] - rotation = TimeDependentRotation(quats, biased_times, s, d, av=avs) + rotation = TimeDependentRotation(quats, biased_times, frame[0], frame[1], av=avs) + self.add_edge(rotation=rotation) + + async def generate_constant_rotations(self, frames, time, mission): + frame_tasks = [] + for s, d in frames: + kwargs = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} + frame_tasks.append(asyncio.create_task(get_ephem_data([time], "getTargetOrientations", **kwargs, web=self.use_web))) + quats_and_avs_per_frame = await asyncio.gather(*frame_tasks) + + # Add all constant frame chains to the graph + for i, frame in enumerate(frames): + quats = np.zeros(4) + quat_and_av = quats_and_avs_per_frame[i][0] + quats[:3] = quat_and_av[1:4] + quats[3] = quat_and_av[0] + + rotation = ConstantRotation(quats, frame[0], frame[1]) + self.add_edge(rotation=rotation) \ No newline at end of file From 2d494dcdc15c9905a70ed5ec81296a2ef12cdd7e Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 12 May 2023 16:25:23 -0700 Subject: [PATCH 17/73] Updated mro tests --- ale/drivers/mro_drivers.py | 6 +-- tests/pytests/data/isds/ctx_isd.json | 62 ++++++++++++++++++++++++++-- tests/pytests/test_mro_drivers.py | 48 ++++++++++++++------- 3 files changed, 94 insertions(+), 22 deletions(-) diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 2bcda9164..f412cbf3e 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -578,7 +578,7 @@ def ephemeris_start_time(self): # The -74999 is the code to select the transformation from # high-precision MRO SCLK to ET - start_time = spice.scs2e(-74999, self.spacecraft_clock_start_count) + start_time = self.spiceql_call("strSclkToEt", {"frameCode": -74999, "sclk": self.spacecraft_clock_start_count, "mission": self.spiceql_mission}) # Adjust the start time so that it is the effective time for # the first line in the image file. Note that on 2006-03-29, this # time is now subtracted as opposed to adding it. The computed start @@ -618,7 +618,7 @@ def ccd_ikid(self): """ if not hasattr(self, "_ccd_ikid"): ccd_number = hirise_ccd_lookup[self.label["IsisCube"]["Instrument"]["CpmmNumber"]] - self._ccd_ikid = spice.bods2c("MRO_HIRISE_CCD{}".format(ccd_number)) + self._ccd_ikid = self.spiceql_call("translateNameToCode", {"frame": "MRO_HIRISE_CCD{}".format(ccd_number), "mission": self.spiceql_mission}) return self._ccd_ikid @property @@ -672,7 +672,7 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - return {**super().naif_keywords, **util.query_kernel_pool(f"*{self.ccd_ikid}*")} + return {**super().naif_keywords, **self.spiceql_call("findMissionKeywords", {"key": f"*{self.ccd_ikid}*", "mission": self.spiceql_mission})} @property def sensor_model_version(self): diff --git a/tests/pytests/data/isds/ctx_isd.json b/tests/pytests/data/isds/ctx_isd.json index 8b0f2cf8c..abdb89adf 100644 --- a/tests/pytests/data/isds/ctx_isd.json +++ b/tests/pytests/data/isds/ctx_isd.json @@ -5014,7 +5014,15 @@ 61339176915162.99, 61899057915627.0, 63521451859691.0, - 65622287643263.0 + 65622287643263.0, + 65888349770746.99, + 67842962942791.0, + 69529271265267.0, + 70724085076049.0, + 71692166304603.0, + 75099259007666.0, + 79809852390453.0, + 281474976710650.0 ], "SCLK01_N_FIELDS_74999": 2.0, "SCLK01_OUTPUT_DELIM_74999": 1.0, @@ -5038,7 +5046,47 @@ 5164027215872.0, -552398346.816, 1.0, - 7230770577408.0 + 7230770577408.0, + -520862345.816, + 1.0, + 11369919545344.0, + -457703944.816, + 1.0, + 16545271316480.0, + -378734343.816, + 1.0, + 20684420284416.0, + -315575942.816, + 1.0, + 22751163645952.0, + -284039941.816, + 1.0, + 25848447500288.0, + -236779140.816, + 1.0, + 27915190861824.0, + -205243139.81599998, + 1.0, + 29981934223360.0, + -173707138.81599998, + 1.0, + 33090542698496.004, + -126273537.81599998, + 1.0, + 36187826552832.0, + -79012736.816, + 1.0, + 39296435027968.0, + -31579135.816, + 0.99999999999999, + 52973626698957.0, + 177118246.859, + 0.99999852023164, + 52993689169101.0, + 177424375.406, + 1.0, + 52995043929293.01, + 177445047.406 ], "SCLK01_TIME_SYSTEM_74999": 2.0, "SCLK_PARTITION_START_74999": [ @@ -5051,7 +5099,15 @@ 61228279791616.0, 61339176927232.0, 61899057922048.0, - 63521451868160.0 + 63521451868160.0, + 65622287646719.99, + 65888349782016.0, + 67842962948096.0, + 69529271271424.01, + 70724085088256.0, + 71692166299648.0, + 75099259011072.0, + 79809852407808.0 ], "BODY499_POLE_RA": [ 317.68143, diff --git a/tests/pytests/test_mro_drivers.py b/tests/pytests/test_mro_drivers.py index 3515e7400..3dca76eb3 100644 --- a/tests/pytests/test_mro_drivers.py +++ b/tests/pytests/test_mro_drivers.py @@ -1,7 +1,7 @@ import os import json import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import pytest @@ -127,14 +127,20 @@ def test_sensor_name(self): assert self.driver.sensor_name == "CONTEXT CAMERA" def test_ephemeris_start_time(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-74, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - scs2e.assert_called_with(-74, '0928283918:060') + calls = [call('translateNameToCode', {'frame': 'MRO', 'mission': 'ctx', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -74, 'sclk': '0928283918:060', 'mission': 'ctx', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 2 def test_ephemeris_stop_time(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-74, 12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == (12345 + self.driver.exposure_duration * self.driver.image_lines) - scs2e.assert_called_with(-74, '0928283918:060') + calls = [call('translateNameToCode', {'frame': 'MRO', 'mission': 'ctx', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -74, 'sclk': '0928283918:060', 'mission': 'ctx', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 2 def test_spacecraft_name(self): assert self.driver.spacecraft_name == "MRO" @@ -143,10 +149,15 @@ def test_detector_start_sample(self): assert self.driver.detector_start_sample == 0 def test_detector_center_sample(self): - with patch('ale.drivers.mro_drivers.spice.bods2c', return_value='-499') as bodsc, \ - patch('ale.drivers.mro_drivers.spice.gdpool', return_value=[12345]) as gdpool: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-499, {"frameCode":[-499]}, -74021, {'INS-74021_BORESIGHT_SAMPLE': 12345}, {}]) as spiceql_call: assert self.driver.detector_center_sample == 12345 - .5 - gdpool.assert_called_with('INS-499_BORESIGHT_SAMPLE', 0, 1) + calls = [call('translateNameToCode', {'frame': 'Mars', 'mission': 'ctx', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -499, 'mission': 'ctx', 'searchKernels': False}, False), + call('translateNameToCode', {'frame': 'MRO_CTX', 'mission': 'ctx', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-74021*', 'mission': 'ctx', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': '*-499*', 'mission': 'ctx', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 5 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -168,10 +179,15 @@ def test_detector_start_sample(self): assert self.driver.detector_start_sample == 0 def test_detector_center_sample(self): - with patch('ale.drivers.mro_drivers.spice.bods2c', return_value='-499') as bodsc, \ - patch('ale.drivers.mro_drivers.spice.gdpool', return_value=[12345]) as gdpool: - assert self.driver.detector_center_sample == 12345 - .5 - gdpool.assert_called_with('INS-499_BORESIGHT_SAMPLE', 0, 1) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-499, {"frameCode":[-499]}, -74021, {'INS-74021_BORESIGHT_SAMPLE': 12345}, {}]) as spiceql_call: + assert self.driver.detector_center_sample == 12345 - .5 + calls = [call('translateNameToCode', {'frame': 'MARS', 'mission': 'ctx', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -499, 'mission': 'ctx', 'searchKernels': False}, False), + call('translateNameToCode', {'frame': 'MRO_CTX', 'mission': 'ctx', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-74021*', 'mission': 'ctx', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': '*-499*', 'mission': 'ctx', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 5 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -197,17 +213,17 @@ def test_un_binned_rate(self): assert self.driver.un_binned_rate == 0.0000836875 def test_ephemeris_start_time(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12344.997489375 - scs2e.assert_called_with(-74999, '848201291:62546') + spiceql_call.assert_called_with('strSclkToEt', {'frameCode': -74999, 'sclk': '848201291:62546', 'mission': 'hirise', 'searchKernels': False}, False) def test_exposure_duration(self): assert self.driver.exposure_duration == 0.00033475 def test_ccd_ikid(self): - with patch('ale.drivers.mro_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', return_value=12345) as spiceql_call: assert self.driver.ccd_ikid == 12345 - bods2c.assert_called_with('MRO_HIRISE_CCD12') + spiceql_call.assert_called_with('translateNameToCode', {'frame': 'MRO_HIRISE_CCD12', 'mission': 'hirise', 'searchKernels': False}, False) def test_sensor_frame_id(self): assert self.driver.sensor_frame_id == -74690 From 3e83d347b47c058abeff80fee639c0eb5b399790 Mon Sep 17 00:00:00 2001 From: Kelvin Rodriguez Date: Thu, 13 Jul 2023 10:40:59 -0700 Subject: [PATCH 18/73] some minor speed improvements --- ale/__init__.py | 2 ++ ale/base/base.py | 23 +++++++++++++++++++++++ ale/drivers/__init__.py | 1 + ale/formatters/formatter.py | 19 +++++++++++-------- ale/formatters/isis_formatter.py | 11 +++++++++++ ale/formatters/usgscsm_formatter.py | 10 +++++++++- ale/isd_generate.py | 19 ++++++++++++++----- ale/spiceql_access.py | 4 ++++ ale/transformation.py | 2 +- 9 files changed, 76 insertions(+), 15 deletions(-) diff --git a/ale/__init__.py b/ale/__init__.py index 8e156801e..1fdfcff66 100644 --- a/ale/__init__.py +++ b/ale/__init__.py @@ -2,6 +2,8 @@ import warnings from pkg_resources import get_distribution, DistributionNotFound +warnings.filterwarnings("ignore") + try: _dist = get_distribution('ale') diff --git a/ale/base/base.py b/ale/base/base.py index ccffee7ce..71e52877a 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -2,6 +2,7 @@ import tempfile import os +from multiprocessing.pool import ThreadPool class Driver(): """ @@ -36,6 +37,28 @@ def __init__(self, file, num_ephem=909, num_quats=909, props={}, parsed_label=No if parsed_label: self._label = parsed_label + def to_dict(self, properties=[]): + def get_property(prop_name): + try: + return getattr(self, prop_name) + except: + return None + + if not properties: + for attr in dir(self): + if isinstance(getattr(self.__class__, attr, None), property): + properties.append(attr) + + data = {} + + with ThreadPool() as pool: + jobs = pool.starmap_async(get_property, [(name,) for name in properties]) + jobs = jobs.get() + + for result, property_name in zip(jobs, properties): + data[property_name] = result + return data + @property def image_lines(self): """ diff --git a/ale/drivers/__init__.py b/ale/drivers/__init__.py index dbb2609c2..3103ce65e 100644 --- a/ale/drivers/__init__.py +++ b/ale/drivers/__init__.py @@ -164,6 +164,7 @@ def load(label, props={}, formatter='ale', verbose=False, only_isis_spice=False, traceback.print_exc() raise Exception('No Such Driver for Label') + def loads(label, props='', formatter='ale', indent = 2, verbose=False, only_isis_spice=False, only_naif_spice=False): """ Attempt to load a given label from all possible drivers. diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py index afeb2f966..0564ff684 100644 --- a/ale/formatters/formatter.py +++ b/ale/formatters/formatter.py @@ -1,6 +1,7 @@ import json import numpy as np from scipy.interpolate import interp1d, BPoly +import time from networkx.algorithms.shortest_paths.generic import shortest_path @@ -22,7 +23,9 @@ def to_isd(driver): string The ISIS compatible meta data as a JSON encoded string. """ - + + data = driver.to_dict(["sensor_position", "sun_position", "frame_chain", "naif_keywords"]) + meta_data = {} meta_data['isis_camera_version'] = driver.sensor_model_version @@ -86,7 +89,7 @@ def to_isd(driver): 'unit' : 'km' } - frame_chain = driver.frame_chain + frame_chain = data["frame_chain"] target_frame = driver.target_frame_id J2000 = 1 # J2000 frame id @@ -142,8 +145,8 @@ def to_isd(driver): instrument_pointing['constant_rotation'] = constant_rotation.rotation_matrix().flatten() meta_data['instrument_pointing'] = instrument_pointing - # interior orientation - meta_data['naif_keywords'] = driver.naif_keywords + # interiror orientation + meta_data['naif_keywords'] = data["naif_keywords"] if isinstance(driver,LineScanner) or isinstance(driver, Framer) or isinstance(driver, PushFrame): @@ -167,7 +170,7 @@ def to_isd(driver): j2000_rotation = frame_chain.compute_rotation(target_frame, J2000) instrument_position = {} - positions, velocities, times = driver.sensor_position + positions, velocities, times = data["sensor_position"] instrument_position['spk_table_start_time'] = times[0] instrument_position['spk_table_end_time'] = times[-1] instrument_position['spk_table_original_size'] = len(times) @@ -178,11 +181,11 @@ def to_isd(driver): instrument_position['positions'] = positions instrument_position['velocities'] = velocities instrument_position["reference_frame"] = j2000_rotation.dest - + meta_data['instrument_position'] = instrument_position - + sun_position = {} - positions, velocities, times = driver.sun_position + positions, velocities, times = data["sun_position"] sun_position['spk_table_start_time'] = times[0] sun_position['spk_table_end_time'] = times[-1] sun_position['spk_table_original_size'] = len(times) diff --git a/ale/formatters/isis_formatter.py b/ale/formatters/isis_formatter.py index 3f9cb601f..fb1a99bf5 100644 --- a/ale/formatters/isis_formatter.py +++ b/ale/formatters/isis_formatter.py @@ -73,6 +73,8 @@ def to_isis(driver): meta_data['BodyRotation'] = body_rotation + t0 = time.process_time() + j2000_rotation = frame_chain.compute_rotation(target_frame, 1) instrument_position = {} @@ -84,10 +86,17 @@ def to_isis(driver): # Rotate positions and velocities into J2000 then scale into kilometers velocities = j2000_rotation.rotate_velocity_at(positions, velocities, times)/1000 positions = j2000_rotation.apply_at(positions, times)/1000 + t1 = time.process_time() + print(f"Total time to get orientations: {t1-t0}") + + t0 = time.process_time() instrument_position['Positions'] = positions instrument_position['Velocities'] = velocities meta_data['InstrumentPosition'] = instrument_position + t1 = time.process_time() + print(f"Total time to get positions: {t1-t0}") + t0 = time.process_time() sun_position = {} positions, velocities, times = driver.sun_position sun_position['SpkTableStartTime'] = times[0] @@ -100,5 +109,7 @@ def to_isis(driver): sun_position['Positions'] = positions sun_position['Velocities'] = velocities meta_data['SunPosition'] = sun_position + t1 = time.process_time() + print(f"Total time to get sun positions: {t1-t0}") return meta_data diff --git a/ale/formatters/usgscsm_formatter.py b/ale/formatters/usgscsm_formatter.py index 1a63284cd..cf1f40d35 100644 --- a/ale/formatters/usgscsm_formatter.py +++ b/ale/formatters/usgscsm_formatter.py @@ -1,6 +1,7 @@ import json import numpy as np from scipy.interpolate import interp1d, BPoly +import time from ale.transformation import FrameChain @@ -37,19 +38,26 @@ def to_usgscsm(driver): 'semiminor' : body_radii[2], 'unit' : 'km' } + + t0 = time.process_time() positions, velocities, position_times = driver.sensor_position isd_data['sensor_position'] = { 'positions' : positions, 'velocities' : velocities, 'unit' : 'm' } - + t1 = time.process_time() + print(f"Total time to get positions: {t1-t0}") + + t0 = time.process_time() sun_positions, sun_velocities, _ = driver.sun_position isd_data['sun_position'] = { 'positions' : sun_positions, 'velocities' : sun_velocities, 'unit' : 'm' } + t1 = time.process_time() + print(f"Total time to get orientations: {t1-t0}") if (driver.projection != ""): isd_data["projection"] = driver.projection diff --git a/ale/isd_generate.py b/ale/isd_generate.py index 6b9695b2a..95ccc2ca0 100755 --- a/ale/isd_generate.py +++ b/ale/isd_generate.py @@ -85,6 +85,11 @@ def main(): version=f"ale version {ale.__version__}", help="Shows ale version number." ) + parser.add_argument( + "-w", "--use_web_spice", + action="store_true", + help="Get spice over the restful interface." + ) parser.add_argument( "input", nargs="+", @@ -109,7 +114,7 @@ def main(): if len(args.input) == 1: try: - file_to_isd(args.input[0], args.out, kernels=k, log_level=log_level, only_isis_spice=args.only_isis_spice, only_naif_spice=args.only_naif_spice, local=args.local) + file_to_isd(args.input[0], args.out, kernels=k, log_level=log_level, only_isis_spice=args.only_isis_spice, only_naif_spice=args.only_naif_spice, local=args.local, use_web=args.use_web_spice) except Exception as err: # Seriously, this just throws a generic Exception? sys.exit(f"File {args.input[0]}: {err}") @@ -124,7 +129,8 @@ def main(): "only_isis_spice": args.only_isis_spice, "only_naif_spice": args.only_naif_spice, "local": args.local, - "nadir": args.nadir} + "nadir": args.nadir, + "use_web":args.use_web_spice} ): f for f in args.input } for f in concurrent.futures.as_completed(futures): @@ -146,8 +152,8 @@ def file_to_isd( only_isis_spice=False, only_naif_spice=False, local=False, - nadir=False -): + nadir=False, + use_web=False): """ Returns nothing, but acts as a thin wrapper to take the *file* and generate an ISD at *out* (if given, defaults to replacing the extension on *file* @@ -178,6 +184,9 @@ def file_to_isd( if nadir: props['nadir'] = nadir + if use_web: + props["web"] = use_web + if kernels is not None: kernels = [str(PurePath(p)) for p in kernels] props["kernels"] = kernels @@ -185,7 +194,7 @@ def file_to_isd( else: usgscsm_str = ale.loads(file, props=props, verbose=log_level>logging.INFO, only_isis_spice=only_isis_spice, only_naif_spice=only_naif_spice) - logger.info(f"Writing: {isd_file}") + # logger.info(f"Writing: {isd_file}") isd_file.write_text(usgscsm_str) return diff --git a/ale/spiceql_access.py b/ale/spiceql_access.py index 8e512d5fb..47ec5dbb5 100644 --- a/ale/spiceql_access.py +++ b/ale/spiceql_access.py @@ -1,6 +1,7 @@ import asyncio import math import requests +import time import aiohttp import numpy as np @@ -134,6 +135,7 @@ def spiceql_call(function_name = "", function_args = {}, use_web=False): response = requests.get(url, params=clean_function_args, headers=headers, verify=False) check_response(response) + return response.json()["body"]["return"] async def get_ephem_data(times, function_name, batch_size=400, web=False, **kwargs): @@ -195,4 +197,6 @@ async def get_ephem_data(times, function_name, batch_size=400, web=False, **kwar results = [] for response in responses: results += response + + return results diff --git a/ale/transformation.py b/ale/transformation.py index ec6601982..6cf903ecc 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -128,7 +128,6 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, "targetFrame": sensor_frame, "searchKernels": frame_chain.search_kernels}) except Exception as e: - print("BANANANANA \n\n") print(e) pass @@ -366,6 +365,7 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): return times + async def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=""): """ Computes the time dependent rotations based on a list of tuples that define the From f99a504cada8083922ef730119a7040359582de4 Mon Sep 17 00:00:00 2001 From: Rodriguez Date: Thu, 20 Jul 2023 17:33:08 -0700 Subject: [PATCH 19/73] added some more parallelization --- ale/base/data_naif.py | 4 +- ale/drivers/mro_drivers.py | 6 +- ale/formatters/formatter.py | 127 ++++++++++++++++----------------- ale/spiceql_access.py | 13 +++- ale/util.py | 138 ++++++++++++++++++++++++++++++++++++ 5 files changed, 219 insertions(+), 69 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 41566f727..933756530 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -13,6 +13,7 @@ from ale import spiceql_access from ale import util + class NaifSpice(): """ Mix-in for reading data from NAIF SPICE Kernels. @@ -747,4 +748,5 @@ def spiceql_call(self, function_name = "", function_args = {}): # This will work if a user passed no kernels but still set ISISDATA # just might take a bit function_args["searchKernels"] = self.search_kernels - return spiceql_access.spiceql_call(function_name, function_args, self.use_web) \ No newline at end of file + return spiceql_access.spiceql_call(function_name, function_args, self.use_web) + diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index f412cbf3e..9c0b257fd 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -8,6 +8,7 @@ from ale.base.type_distortion import RadialDistortion, NoDistortion from ale.base.type_sensor import LineScanner from ale.base.type_distortion import NoDistortion +from ale.util import CachedDict from ale import util @@ -672,7 +673,10 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - return {**super().naif_keywords, **self.spiceql_call("findMissionKeywords", {"key": f"*{self.ccd_ikid}*", "mission": self.spiceql_mission})} + if not hasattr(self, "_mrohirise_naif_keywords"): + _mrohirise_naif_keywords = {**super().naif_keywords, **self.spiceql_call("findMissionKeywords", {"key": f"*{self.ccd_ikid}*", "mission": self.spiceql_mission})} + return _mrohirise_naif_keywords + @property def sensor_model_version(self): diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py index 0564ff684..47c8cc20a 100644 --- a/ale/formatters/formatter.py +++ b/ale/formatters/formatter.py @@ -24,18 +24,17 @@ def to_isd(driver): The ISIS compatible meta data as a JSON encoded string. """ - data = driver.to_dict(["sensor_position", "sun_position", "frame_chain", "naif_keywords"]) + driver_data = driver.to_dict() + isd = {} + + isd['isis_camera_version'] = driver_data["sensor_model_version"] - meta_data = {} - - meta_data['isis_camera_version'] = driver.sensor_model_version - # general information - meta_data['image_lines'] = driver.image_lines - meta_data['image_samples'] = driver.image_samples - meta_data['name_platform'] = driver.platform_name - meta_data['name_sensor'] = driver.sensor_name - meta_data['reference_height'] = { + isd['image_lines'] = driver_data["image_lines"] + isd['image_samples'] = driver_data["image_samples"] + isd['name_platform'] = driver_data["platform_name"] + isd['name_sensor'] = driver_data["sensor_name"] + isd['reference_height'] = { "maxheight": 1000, "minheight": -1000, "unit": "m" @@ -43,54 +42,54 @@ def to_isd(driver): # line scan sensor model specifics if isinstance(driver, LineScanner): - meta_data['name_model'] = 'USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL' - meta_data['interpolation_method'] = 'lagrange' + isd['name_model'] = 'USGS_ASTRO_LINE_SCANNER_SENSOR_MODEL' + isd['interpolation_method'] = 'lagrange' - start_lines, start_times, scan_rates = driver.line_scan_rate - meta_data['line_scan_rate'] = [[line, time, rate] for line, time, rate in zip(start_lines, start_times, scan_rates)] - meta_data['starting_ephemeris_time'] = driver.ephemeris_start_time - meta_data['center_ephemeris_time'] = driver.center_ephemeris_time + start_lines, start_times, scan_rates = driver_data["line_scan_rate"] + isd['line_scan_rate'] = [[line, time, rate] for line, time, rate in zip(start_lines, start_times, scan_rates)] + isd['starting_ephemeris_time'] = driver_data["ephemeris_start_time"] + isd['center_ephemeris_time'] = driver_data["center_ephemeris_time"] # frame sensor model specifics if isinstance(driver, Framer): - meta_data['name_model'] = 'USGS_ASTRO_FRAME_SENSOR_MODEL' - meta_data['center_ephemeris_time'] = driver.center_ephemeris_time + isd['name_model'] = 'USGS_ASTRO_FRAME_SENSOR_MODEL' + isd['center_ephemeris_time'] = driver.center_ephemeris_time if isinstance(driver, PushFrame): - meta_data['name_model'] = 'USGS_ASTRO_PUSH_FRAME_SENSOR_MODEL' - meta_data['starting_ephemeris_time'] = driver.ephemeris_start_time - meta_data['ending_ephemeris_time'] = driver.ephemeris_stop_time - meta_data['center_ephemeris_time'] = driver.center_ephemeris_time - meta_data['exposure_duration'] = driver.exposure_duration - meta_data['interframe_delay'] = driver.interframe_delay - meta_data['framelet_order_reversed'] = driver.framelet_order_reversed - meta_data['framelets_flipped'] = driver.framelets_flipped - meta_data['framelet_height'] = driver.framelet_height - meta_data['num_lines_overlap'] = driver.num_lines_overlap + isd['name_model'] = 'USGS_ASTRO_PUSH_FRAME_SENSOR_MODEL' + isd['starting_ephemeris_time'] = driver_data["ephemeris_start_time"] + isd['ending_ephemeris_time'] = driver_data["ephemeris_stop_time"] + isd['center_ephemeris_time'] = driver_data["center_ephemeris_time"] + isd['exposure_duration'] = driver_data["exposure_duration"] + isd['interframe_delay'] = driver_data["interframe_delay"] + isd['framelet_order_reversed'] = driver_data["framelet_order_reversed"] + isd['framelets_flipped'] = driver_data["framelets_flipped"] + isd['framelet_height'] = driver_data["framelet_height"] + isd['num_lines_overlap'] = driver_data["num_lines_overlap"] # SAR sensor model specifics if isinstance(driver, Radar): - meta_data['name_model'] = 'USGS_ASTRO_SAR_SENSOR_MODEL' - meta_data['starting_ephemeris_time'] = driver.ephemeris_start_time - meta_data['ending_ephemeris_time'] = driver.ephemeris_stop_time - meta_data['center_ephemeris_time'] = driver.center_ephemeris_time - meta_data['wavelength'] = driver.wavelength - meta_data['line_exposure_duration'] = driver.line_exposure_duration - meta_data['scaled_pixel_width'] = driver.scaled_pixel_width - meta_data['range_conversion_times'] = driver.range_conversion_times - meta_data['range_conversion_coefficients'] = driver.range_conversion_coefficients - meta_data['look_direction'] = driver.look_direction + isd['name_model'] = 'USGS_ASTRO_SAR_SENSOR_MODEL' + isd['starting_ephemeris_time'] = driver_data["ephemeris_start_time"] + isd['ending_ephemeris_time'] = driver_data["ephemeris_stop_time"] + isd['center_ephemeris_time'] = driver_data["center_ephemeris_time"] + isd['wavelength'] = driver_data["wavelength"] + isd['line_exposure_duration'] = driver_data["line_exposure_duration"] + isd['scaled_pixel_width'] = driver_data["scaled_pixel_width"] + isd['range_conversion_times'] = driver_data["range_conversion_times"] + isd['range_conversion_coefficients'] = driver_data["range_conversion_coefficients"] + isd['look_direction'] = driver_data["look_direction"] # Target body body_radii = driver.target_body_radii - meta_data['radii'] = { + isd['radii'] = { 'semimajor' : body_radii[0], 'semiminor' : body_radii[2], 'unit' : 'km' } - frame_chain = data["frame_chain"] - target_frame = driver.target_frame_id + frame_chain = driver_data["frame_chain"] + target_frame = driver_data["target_frame_id"] J2000 = 1 # J2000 frame id body_rotation = {} @@ -116,10 +115,10 @@ def to_isd(driver): body_rotation['constant_rotation'] = constant_rotation.rotation_matrix().flatten() body_rotation["reference_frame"] = destination_frame - meta_data['body_rotation'] = body_rotation + isd['body_rotation'] = body_rotation # sensor orientation - sensor_frame = driver.sensor_frame_id + sensor_frame = driver_data["sensor_frame_id"] instrument_pointing = {} source_frame, destination_frame, _ = frame_chain.last_time_dependent_frame_between(1, sensor_frame) @@ -143,34 +142,34 @@ def to_isd(driver): instrument_pointing['constant_frames'] = shortest_path(frame_chain, sensor_frame, destination_frame) constant_rotation = frame_chain.compute_rotation(destination_frame, sensor_frame) instrument_pointing['constant_rotation'] = constant_rotation.rotation_matrix().flatten() - meta_data['instrument_pointing'] = instrument_pointing + isd['instrument_pointing'] = instrument_pointing # interiror orientation - meta_data['naif_keywords'] = data["naif_keywords"] + isd['naif_keywords'] = driver.naif_keywords if isinstance(driver,LineScanner) or isinstance(driver, Framer) or isinstance(driver, PushFrame): - meta_data['detector_sample_summing'] = driver.sample_summing - meta_data['detector_line_summing'] = driver.line_summing + isd['detector_sample_summing'] = driver.sample_summing + isd['detector_line_summing'] = driver.line_summing - meta_data['focal_length_model'] = { + isd['focal_length_model'] = { 'focal_length' : driver.focal_length } - meta_data['detector_center'] = { - 'line' : driver.detector_center_line, - 'sample' : driver.detector_center_sample + isd['detector_center'] = { + 'line' : driver_data["detector_center_line"], + 'sample' : driver_data["detector_center_sample"] } - meta_data['focal2pixel_lines'] = driver.focal2pixel_lines - meta_data['focal2pixel_samples'] = driver.focal2pixel_samples - meta_data['optical_distortion'] = driver.usgscsm_distortion_model + isd['focal2pixel_lines'] = driver_data["focal2pixel_lines"] + isd['focal2pixel_samples'] = driver_data["focal2pixel_samples"] + isd['optical_distortion'] = driver_data["usgscsm_distortion_model"] - meta_data['starting_detector_line'] = driver.detector_start_line - meta_data['starting_detector_sample'] = driver.detector_start_sample + isd['starting_detector_line'] = driver_data.detector_start_line + isd['starting_detector_sample'] = driver_data.detector_start_sample j2000_rotation = frame_chain.compute_rotation(target_frame, J2000) instrument_position = {} - positions, velocities, times = data["sensor_position"] + positions, velocities, times = driver_data["sensor_position"] instrument_position['spk_table_start_time'] = times[0] instrument_position['spk_table_end_time'] = times[-1] instrument_position['spk_table_original_size'] = len(times) @@ -182,10 +181,10 @@ def to_isd(driver): instrument_position['velocities'] = velocities instrument_position["reference_frame"] = j2000_rotation.dest - meta_data['instrument_position'] = instrument_position + isd['instrument_position'] = instrument_position sun_position = {} - positions, velocities, times = data["sun_position"] + positions, velocities, times = driver_data["sun_position"] sun_position['spk_table_start_time'] = times[0] sun_position['spk_table_end_time'] = times[-1] sun_position['spk_table_original_size'] = len(times) @@ -197,14 +196,14 @@ def to_isd(driver): sun_position['velocities'] = velocities sun_position["reference_frame"] = j2000_rotation.dest - meta_data['sun_position'] = sun_position + isd['sun_position'] = sun_position if (driver.projection != ""): - meta_data["projection"] = driver.projection - meta_data["geotransform"] = driver.geotransform + isd["projection"] = driver.projection + isd["geotransform"] = driver.geotransform # check that there is a valid sensor model name - if 'name_model' not in meta_data: + if 'name_model' not in isd: raise Exception('No CSM sensor model name found!') - return meta_data + return isd diff --git a/ale/spiceql_access.py b/ale/spiceql_access.py index 47ec5dbb5..42652c490 100644 --- a/ale/spiceql_access.py +++ b/ale/spiceql_access.py @@ -8,6 +8,7 @@ import pyspiceql + def stringify_web_args(function_args): """ Takes a dictionary of args and converts them into web acceptable strings @@ -40,13 +41,15 @@ def check_response(response): : obj Request response object """ + response.raise_for_status() if response.status_code != 200: - raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") + raise requests.HTTPError(f"Recieved code {response.status_code} from spice server, with error: {response.json()}") if response.json()["statusCode"] != 200: - raise requests.HTTPError(f"Recieved code {response['statusCode']} from spice server, with error: {response}") + raise requests.HTTPError(f"Recieved code {response.json()['statusCode']} from spice server, with error: {response.json()}") + async def async_spiceql_call(session, function_name = "", function_args = {}, use_web=False): """ @@ -81,7 +84,10 @@ async def async_spiceql_call(session, function_name = "", function_args = {}, us if use_web == False: func = getattr(pyspiceql, function_name) return func(**function_args) + url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" + # url = "https://d68posrslrzct.cloudfront.net/api/spiceql/" + url += function_name headers = { 'accept': '*/*', @@ -93,6 +99,7 @@ async def async_spiceql_call(session, function_name = "", function_args = {}, us web_response = await response.json() return web_response["body"]["return"] + def spiceql_call(function_name = "", function_args = {}, use_web=False): """ Interface to SpiceQL (Spice Query Library) for both Offline and Online use @@ -122,7 +129,7 @@ def spiceql_call(function_name = "", function_args = {}, use_web=False): if use_web == False: func = getattr(pyspiceql, function_name) return func(**function_args) - + url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" url += function_name headers = { diff --git a/ale/util.py b/ale/util.py index 9cc5c9059..eecac5747 100644 --- a/ale/util.py +++ b/ale/util.py @@ -21,6 +21,144 @@ import spiceypy as spice + + +class CachedDict(): + """ + A subclass of dict that tracks the accessed keys. + """ + + def __init__(self, **kwargs): + """ + Initialize the CachedDict object. + + Parameters + ---------- + *args : positional arguments + Variable length argument list. + **kwargs : keyword arguments + Arbitrary keyword arguments. + """ + self.data = dict(**kwargs) + self.accessed_keys = set() + + + def __str__(self): + """ + to string function + + Returns + ------- + str + str representation of dictionary with filtered items + """ + return str(self.to_dict) + + + def __getitem__(self, key): + """ + Get the value corresponding to the given key. + + Parameters + ---------- + key + The key to retrieve the value for. + + Returns + ------- + value + The value corresponding to the key. + """ + self.accessed_keys.add(key) + return self.data.__getitem__(key) + + def __setitem__(self, key, value): + """ + Set the value for the given key. + + Parameters + ---------- + key + The key to set the value for. + value + The value to be set. + """ + return self.data.__setitem__(key, value) + + def __delitem__(self, key): + """ + Delete the value corresponding to the given key. + + Parameters + ---------- + key + The key to delete. + """ + self.accessed_keys.remove(key) + return self.data.__delitem__(key) + + def keys(self): + """ + Get the list of keys that have been accessed. + + Returns + ------- + list + A list of keys. + """ + return list(self.accessed_keys) + + def values(self): + """ + Get the list of values corresponding to the accessed keys. + + Returns + ------- + list + A list of values. + """ + return [self[key] for key in self.accessed_keys if key in self] + + def items(self): + """ + Get the list of key-value pairs corresponding to the accessed keys. + + Returns + ------- + list + A list of key-value pairs. + """ + return [(key, self.data[key]) for key in self.accessed_keys if key in self] + + def is_key_accessed(self, key): + """ + Check if a key has been accessed or not. + + Parameters + ---------- + key + The key to check. + + Returns + ------- + bool + True if the key has been accessed, False otherwise. + """ + return key in self.accessed_keys + + + def to_dict(self): + """ + returns a dictionary of only keys accessed + + Returns + ------- + dict + Dictionary of just the keys accessed + """ + return dict(zip(self.keys(), self.values())) + + def find_latest_metakernel(path, year): metakernel = None mks = sorted(glob(os.path.join(path,'*.[Tt][Mm]'))) From 2cefbaff2550fa7dd21e082f9c1c46abdb32c7af Mon Sep 17 00:00:00 2001 From: acpaquette Date: Thu, 28 Sep 2023 21:08:08 -0700 Subject: [PATCH 20/73] Updates to all drivers for spiceql --- ale/base/base.py | 18 +++- ale/base/data_naif.py | 59 ++++++++---- ale/base/type_sensor.py | 2 +- ale/drivers/chandrayaan_drivers.py | 28 ++---- ale/drivers/co_drivers.py | 22 +++-- ale/drivers/dawn_drivers.py | 13 ++- ale/drivers/galileo_drivers.py | 21 +---- ale/drivers/lro_drivers.py | 126 +++++++++++++------------- ale/drivers/mess_drivers.py | 31 ++----- ale/drivers/mex_drivers.py | 20 +++- ale/drivers/mgs_drivers.py | 25 +---- ale/drivers/mro_drivers.py | 14 ++- ale/drivers/msl_drivers.py | 2 +- ale/drivers/nh_drivers.py | 30 ++---- ale/drivers/osirisrex_drivers.py | 8 +- ale/drivers/selene_drivers.py | 97 +++++++++++--------- ale/drivers/tgo_drivers.py | 4 +- ale/drivers/viking_drivers.py | 20 ++-- ale/drivers/voyager_drivers.py | 15 +-- ale/spiceql_access.py | 45 +++++---- tests/pytests/test_kaguya_drivers.py | 8 +- tests/pytests/test_mro_drivers.py | 2 +- tests/pytests/test_voyager_drivers.py | 1 + 23 files changed, 312 insertions(+), 299 deletions(-) diff --git a/ale/base/base.py b/ale/base/base.py index 71e52877a..b61dfea6c 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -38,10 +38,10 @@ def __init__(self, file, num_ephem=909, num_quats=909, props={}, parsed_label=No self._label = parsed_label def to_dict(self, properties=[]): - def get_property(prop_name): + def get_property(prop_name): try: return getattr(self, prop_name) - except: + except Exception as e: return None if not properties: @@ -50,13 +50,21 @@ def get_property(prop_name): properties.append(attr) data = {} + if "naif_keywords" in properties: + properties.remove("naif_keywords") + data["naif_keywords"] = getattr(self, "naif_keywords") + if "frame_chain" in properties: + properties.remove("frame_chain") + data["frame_chain"] = getattr(self, "frame_chain") + with ThreadPool() as pool: jobs = pool.starmap_async(get_property, [(name,) for name in properties]) - jobs = jobs.get() + results = jobs.get() + + for result, property_name in zip(results, properties): + data[property_name] = result - for result, property_name in zip(jobs, properties): - data[property_name] = result return data @property diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 933756530..227bbc232 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -4,6 +4,7 @@ import numpy as np import pyspiceql import scipy.constants +from scipy.spatial.transform import Rotation as R import spiceypy as spice import ale @@ -11,6 +12,7 @@ from ale.transformation import FrameChain from ale.rotation import TimeDependentRotation from ale import spiceql_access +from ale import spice_root from ale import util @@ -26,6 +28,7 @@ def __enter__(self): """ if self.kernels: [pyspiceql.KernelPool.getInstance().load(k) for k in self.kernels] + [spice.furnsh(k) for k in self.kernels] return self def __exit__(self, exc_type, exc_val, exc_tb): @@ -36,6 +39,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): """ if self.kernels: [pyspiceql.KernelPool.getInstance().unload(k) for k in self.kernels] + [spice.unload(k) for k in self.kernels] @property def kernels(self): @@ -135,7 +139,7 @@ def light_time_correction(self): """ if not hasattr(self, "_light_time_correction"): try: - self._light_time_correction = self.naif_keywords['INS{}_LIGHTTIME_CORRECTION'.format(self.ikid)][0] + self._light_time_correction = self.naif_keywords['INS{}_LIGHTTIME_CORRECTION'.format(self.ikid)] except: self._light_time_correction = 'LT+S' return self._light_time_correction @@ -462,39 +466,42 @@ def sensor_position(self): kwargs = {"target": target, "observer": observer, "frame": "J2000", - "abcorr": self.light_time_correctio, + "abcorr": self.light_time_correction, "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - obs_tars = asyncio.run(spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web)) + obs_tars = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) obs_tar_lts = np.array(obs_tars)[:,-1] # ssb to spacecraft - kwargs = {"target": target, + kwargs = {"target": observer, "observer": "SSB", "frame": "J2000", "abcorr": "NONE", "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - ssb_obs = asyncio.run(spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web)) + ssb_obs = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) ssb_obs_states = np.array(ssb_obs)[:,0:6] radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt - + kwargs = {"target": target, "observer": "SSB", "frame": "J2000", "abcorr": "NONE", "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - ssb_tars = asyncio.run(spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", **kwargs, web=self.use_web)) - ssb_tar_state = np.array(ssb_tars)[:,0:6] - _states = ssb_tar_state - ssb_obs_states + ssb_tars = spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", **kwargs, web=self.use_web) + ssb_tar_states = np.array(ssb_tars)[:,0:6] + + # print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_tar_state, ssb_tar_lt)) + _states = ssb_tar_states - ssb_obs_states + states = [] - for state in _states: - matrix = spice.sxform("J2000", self.reference_frame, ephem) - state = spice.mxvg(matrix, state) - states.append(state) + for i, state in enumerate(_states): + matrix = spice.sxform("J2000", self.reference_frame, ephem[i]) + rotated_state = spice.mxvg(matrix, state) + states.append(rotated_state) else: kwargs = {"target": target, "observer": observer, @@ -502,7 +509,7 @@ def sensor_position(self): "abcorr": self.light_time_correction, "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - states = asyncio.run(spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web)) + states = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) states = np.array(states)[:,0:6] for state in states: @@ -517,7 +524,8 @@ def sensor_position(self): # By default, SPICE works in km, so convert to m self._position = 1000 * np.asarray(pos) self._velocity = 1000 * np.asarray(vel) - return self._position, self._velocity, ephem + self._ephem = ephem + return self._position, self._velocity, self._ephem @property def frame_chain(self): @@ -676,8 +684,14 @@ def correct_lt_to_surface(self): if not hasattr(self, "_correct_lt_to_surface"): try: surface_correct = self.naif_keywords['INS{}_LT_SURFACE_CORRECT'.format(self.ikid)] - self._correct_lt_to_surface = surface_correct.upper() == "TRUE" - except: + if isinstance(surface_correct, str): + self._correct_lt_to_surface = surface_correct.upper() == "TRUE" + elif isinstance(surface_correct, bool): + self._correct_lt_to_surface = surface_correct + else: + raise Exception(f"Cannot decode LT surface correct value {surface_correct}") + except Exception as e: + print self._correct_lt_to_surface = False return self._correct_lt_to_surface @@ -748,5 +762,16 @@ def spiceql_call(self, function_name = "", function_args = {}): # This will work if a user passed no kernels but still set ISISDATA # just might take a bit function_args["searchKernels"] = self.search_kernels + + # Bodge solution for memo funcs in offline mode + memo_funcs = ["translateNameToCode", "translateCodeToName"] + + try: + data_dir = pyspiceql.getDataDirectory() + except Exception as e: + data_dir = "" + + if function_name in memo_funcs and data_dir == "" and self.use_web == False: + function_name = f"NonMemo_{function_name}" return spiceql_access.spiceql_call(function_name, function_args, self.use_web) diff --git a/ale/base/type_sensor.py b/ale/base/type_sensor.py index 91e7e104e..31b2f9591 100644 --- a/ale/base/type_sensor.py +++ b/ale/base/type_sensor.py @@ -43,7 +43,7 @@ def line_scan_rate(self): Exposure durations """ t0_ephemeris = self.ephemeris_start_time - self.center_ephemeris_time - return [0.5], [t0_ephemeris], [self.exposure_duration] + return [[0.5], [t0_ephemeris], [self.exposure_duration]] @property def ephemeris_time(self): diff --git a/ale/drivers/chandrayaan_drivers.py b/ale/drivers/chandrayaan_drivers.py index 86bb108f3..4a444fc26 100644 --- a/ale/drivers/chandrayaan_drivers.py +++ b/ale/drivers/chandrayaan_drivers.py @@ -23,19 +23,6 @@ def instrument_id(self): } return inst_id_lookup[super().instrument_id] - @property - def ikid(self): - """ - Returns the ikid/frame code from the ISIS label. This is attached - via chan1m3 on ingestion into an ISIS cube - - Returns - ------- - : int - ikid for chandrayaan moon mineralogy mapper - """ - return spice.namfrm(self.instrument_id) - @property def sensor_model_version(self): """ @@ -89,7 +76,9 @@ def ephemeris_start_time(self): : float start time """ - return spice.str2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_start_time @property def ephemeris_stop_time(self): @@ -101,7 +90,9 @@ def ephemeris_stop_time(self): : float stop time """ - return spice.str2et(self.utc_stop_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + if not hasattr(self, "_ephemeris_stop_time"): + self._ephemeris_stop_time = self.spiceql_call("utcToEt", {"utc": self.utc_stop_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_stop_time @property @@ -192,9 +183,10 @@ def range_conversion_times(self): : List times for range conversion coefficients """ - range_coefficients_utc = self.label['IsisCube']['Instrument']['RangeCoefficientSet'] - range_coefficients_et = [spice.str2et(elt[0]) for elt in range_coefficients_utc] - return range_coefficients_et + if not hasattr(self, "range_coefficients_et"): + range_coefficients_utc = self.label['IsisCube']['Instrument']['RangeCoefficientSet'] + self._range_coefficients_et = [self.spiceql_call("utcToEt", {"utc": elt[0]}) for elt in range_coefficients_utc] + return self._range_coefficients_et @property diff --git a/ale/drivers/co_drivers.py b/ale/drivers/co_drivers.py index 414d2be14..12182c894 100644 --- a/ale/drivers/co_drivers.py +++ b/ale/drivers/co_drivers.py @@ -164,7 +164,9 @@ def ephemeris_start_time(self): : float start time """ - return spice.str2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f"))[0] + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_start_time @property def center_ephemeris_time(self): @@ -214,7 +216,7 @@ def focal_length(self): try: default_focal_len = super(CassiniIssPds3LabelNaifSpiceDriver, self).focal_length except: - default_focal_len = float(spice.gdpool('INS{}_DEFAULT_FOCAL_LENGTH'.format(self.ikid), 0, 2)[0]) + default_focal_len = float(self.naif_keywords['INS{}_DEFAULT_FOCAL_LENGTH'.format(self.ikid)]) filters = tuple(self.label["IsisCube"]["BandBin"]['FilterName'].split("/")) @@ -275,9 +277,9 @@ def frame_chain(self): try: # Call frinfo to check if the ISIS iak has been loaded with the # additional reference frame. Otherwise, Fail and add it manually - _ = spice.frinfo(self.sensor_frame_id) + _ = self.spiceql_call("getFrameInfo", {"frame": self.sensor_frame_id, "mission": self.spiceql_mission}) self._frame_chain = super().frame_chain - except spice.utils.exceptions.NotFoundError as e: + except Exception as e: self._frame_chain = FrameChain.from_spice(sensor_frame=self._original_naif_sensor_frame_id, target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, @@ -330,7 +332,7 @@ def focal_epsilon(self): : float focal epsilon """ - return float(pyspiceql.getKernelVectorValue('INS{}_FL_UNCERTAINTY'.format(self.ikid))[0]) + return float(self.naif_keywords['INS{}_FL_UNCERTAINTY'.format(self.ikid)][0]) @property def spacecraft_name(self): @@ -357,7 +359,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ # Microns to mm - pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 + pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0]) * .001 return [0.0, 1/pixel_size, 0.0] @property @@ -371,7 +373,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 + pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0]) * .001 return [0.0, 0.0, 1/pixel_size] @property @@ -447,7 +449,7 @@ def focal_length(self): try: default_focal_len = super(CassiniIssPds3LabelNaifSpiceDriver, self).focal_length except: - default_focal_len = float(pyspiceql.getKernelVectorValue('INS{}_FOV_CENTER_PIXEL'.format(self.ikid))[0]) + default_focal_len = float(self.naif_keywords['INS{}_FOV_CENTER_PIXEL'.format(self.ikid)][0]) filters = tuple(self.label['FILTER_NAME']) @@ -507,9 +509,9 @@ def frame_chain(self): try: # Call frinfo to check if the ISIS iak has been loaded with the # additional reference frame. Otherwise, Fail and add it manually - _ = spice.frinfo(self.sensor_frame_id) + _ = self.spiceql_call("getFrameInfo", {"frame": self.sensor_frame_id, "mission": self.spiceql_mission}) self._frame_chain = super().frame_chain - except spice.utils.exceptions.NotFoundError as e: + except Exception as e: self._frame_chain = FrameChain.from_spice(sensor_frame=self._original_naif_sensor_frame_id, target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, diff --git a/ale/drivers/dawn_drivers.py b/ale/drivers/dawn_drivers.py index 00f1fc929..d8233a18c 100644 --- a/ale/drivers/dawn_drivers.py +++ b/ale/drivers/dawn_drivers.py @@ -84,8 +84,7 @@ def ephemeris_start_time(self): account for the CCD being discharged or cleared. """ if not hasattr(self, '_ephemeris_start_time'): - sclock = self.spacecraft_clock_start_count - self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) + self._ephemeris_start_time = super().ephemeris_start_time self._ephemeris_start_time += 193.0 / 1000.0 return self._ephemeris_start_time @@ -120,7 +119,7 @@ def odtk(self): : list Radial distortion coefficients """ - return pyspiceql.getKernelVectorValue('INS{}_RAD_DIST_COEFF'.format(self.ikid)).tolist() + return self.naif_keywords['INS{}_RAD_DIST_COEFF'.format(self.ikid)].tolist() # TODO: Update focal2pixel samples and lines to reflect the rectangular # nature of dawn pixels @@ -136,7 +135,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ # Microns to mm - pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 + pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0]) * .001 return [0.0, 1/pixel_size, 0.0] @property @@ -151,7 +150,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ # Microns to mm - pixel_size = float(pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0]) * .001 + pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0]) * .001 return [0.0, 0.0, 1/pixel_size] @property @@ -182,7 +181,7 @@ def detector_center_sample(self): : float center detector sample """ - return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid))[0]) + 0.5 + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][0]) + 0.5 @property def detector_center_line(self): @@ -200,7 +199,7 @@ def detector_center_line(self): : float center detector line """ - return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid))[1]) + 0.5 + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][1]) + 0.5 class DawnFcIsisLabelNaifSpiceDriver(Framer, IsisLabel, NaifSpice, NoDistortion, Driver): diff --git a/ale/drivers/galileo_drivers.py b/ale/drivers/galileo_drivers.py index f3f1e81f6..09f1dc9a5 100644 --- a/ale/drivers/galileo_drivers.py +++ b/ale/drivers/galileo_drivers.py @@ -58,23 +58,10 @@ def odtk(self): start_time_as_date = self.label["IsisCube"]["Instrument"]["StartTime"].replace(tzinfo=None) if start_time_as_date < removeCoverDate: - key_str = "_K1_COVER" + key_str = "K1_COVER" else: - key_str = "_K1" - return pyspiceql.getKernelVectorValue("INS" + str(self.ikid) + key_str) - - @property - def naif_keywords(self): - """ - Adds the focal length cover keyword to the already populated naif keywords - - Returns - ------- - : dict - Dictionary of keywords and values that ISIS creates and attaches to the label - """ - key = "INS" + str(self.ikid) + "_FOCAL_LENGTH_COVER"; - return {**super().naif_keywords, key: pyspiceql.getKernelStringValue(key)} + key_str = "K1" + return self.naif_keywords[f"INS{str(self.ikid)}_{key_str}"] @property def ephemeris_start_time(self): @@ -86,7 +73,7 @@ def ephemeris_start_time(self): : float start time """ - return pyspiceql.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + return self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) @property def center_ephemeris_time(self): diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index 470bee06a..d91559bba 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -94,7 +94,7 @@ def odtk(self): : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ - return pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid)).tolist() + return self.naif_keywords['INS{}_OD_K'.format(self.ikid)].tolist() @property def light_time_correction(self): @@ -140,7 +140,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = np.array(list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.ikid)))) / self.sampling_factor + focal2pixel_lines = np.array(list(self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)])) / self.sampling_factor if self.spacecraft_direction < 0: return -focal2pixel_lines else: @@ -158,8 +158,12 @@ def ephemeris_start_time(self): : double Starting ephemeris time of the image """ - start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.label['LRO:SPACECRAFT_CLOCK_PREROLL_COUNT']) - return start_time + self.constant_time_offset + self.additional_preroll * self.exposure_duration + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frameCode": self.spacecraft_id, + "sclk": self.label['LRO:SPACECRAFT_CLOCK_PREROLL_COUNT'], + "mission": self.spiceql_mission}) + self._ephemeris_start_time += self.constant_time_offset + self.additional_preroll * self.exposure_duration + return self._ephemeris_start_time @property def exposure_duration(self): @@ -263,16 +267,21 @@ def spacecraft_direction(self): direction : double X value of the first velocity relative to the sensor """ - frame_chain = self.frame_chain - lro_bus_id = pyspiceql.Kernel_translateFrame('LRO_SC_BUS') - time = self.ephemeris_start_time - lt_state = pyspiceql.getTargetState(time, self.target_name, self.spacecraft_name, 'J2000', 'None') - state = lt_state.starg - position = state[:3] - velocity = state[3:] - rotation = frame_chain.compute_rotation(1, lro_bus_id) - rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) - return rotated_velocity[0] + if not hasattr(self, "_spacecraft_direction"): + frame_chain = self.frame_chain + lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) + time = self.ephemeris_start_time + lt_state = self.spiceql_call("getTargetState", {'et': time, + 'target': self.target_name, + 'observer': self.spacecraft_name, + 'frame': 'J2000', + 'abcorr': 'None'}) + state = lt_state.starg + velocity = state[3:] + rotation = frame_chain.compute_rotation(1, lro_bus_id) + rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) + self._spacecraft_direction = rotated_velocity[0] + return self._spacecraft_direction class LroLrocNacIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver): @property @@ -334,7 +343,7 @@ def odtk(self): : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ - return pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.ikid)).tolist() + return self.naif_keywords['INS{}_OD_K'.format(self.ikid)].tolist() @property def light_time_correction(self): @@ -380,8 +389,12 @@ def ephemeris_start_time(self): : double Starting ephemeris time of the image """ - start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.label['IsisCube']['Instrument']['SpacecraftClockPrerollCount']) - return start_time + self.constant_time_offset + self.additional_preroll * self.exposure_duration + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frameCode": self.spacecraft_id, + "sclk": self.label['IsisCube']['Instrument']['SpacecraftClockPrerollCount'], + "mission": self.spiceql_mission}) + self._ephemeris_start_time += self.constant_time_offset + self.additional_preroll * self.exposure_duration + return self._ephemeris_start_time @property def exposure_duration(self): @@ -408,7 +421,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = np.array(list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.ikid)))) / self.sampling_factor + focal2pixel_lines = np.array(list(self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)])) / self.sampling_factor if self.spacecraft_direction < 0: return -focal2pixel_lines else: @@ -498,16 +511,21 @@ def spacecraft_direction(self): direction : double X value of the first velocity relative to the sensor """ - frame_chain = self.frame_chain - lro_bus_id = pyspiceql.Kernel_translateFrame('LRO_SC_BUS') - time = self.ephemeris_start_time - lt_state = pyspiceql.getTargetState(time, self.target_name, self.spacecraft_name, 'J2000', 'None') - state = lt_state.starg - position = state[:3] - velocity = state[3:] - rotation = frame_chain.compute_rotation(1, lro_bus_id) - rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) - return rotated_velocity[0] + if not hasattr(self, "_spacecraft_direction"): + frame_chain = self.frame_chain + lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) + time = self.ephemeris_start_time + lt_state = self.spiceql_call("getTargetState", {'et': time, + 'target': self.target_name, + 'observer': self.spacecraft_name, + 'frame': 'J2000', + 'abcorr': 'None'}) + state = lt_state.starg + velocity = state[3:] + rotation = frame_chain.compute_rotation(1, lro_bus_id) + rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) + self._spacecraft_direction = rotated_velocity[0] + return self._spacecraft_direction class LroLrocNacIsisLabelIsisSpiceDriver(LineScanner, IsisSpice, IsisLabel, Driver): @@ -797,9 +815,10 @@ def range_conversion_times(self): : List times for range conversion coefficients """ - range_coefficients_utc = self.label['IsisCube']['Instrument']['RangeCoefficientSet'] - range_coefficients_et = [pyspiceql.utcToEt(elt[0]) for elt in range_coefficients_utc] - return range_coefficients_et + if not hasattr(self, "_range_conversion_times"): + range_coefficients_utc = self.label['IsisCube']['Instrument']['RangeCoefficientSet'] + self._range_conversion_times = [self.spiceql_call("utcToEt", {"utc": elt[0]}) for elt in range_coefficients_utc] + return self._range_conversion_times @property @@ -812,7 +831,9 @@ def ephemeris_start_time(self): : float start time """ - return pyspiceql.utcToEt(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_start_time @property def ephemeris_stop_time(self): @@ -826,7 +847,9 @@ def ephemeris_stop_time(self): : float stop time """ - return self.ephemeris_start_time + (self.image_lines * self.line_exposure_duration) + (self.line_exposure_duration * 2) + if not hasattr(self, "_ephemeris_stop_time"): + self._ephemeris_stop_time = self.ephemeris_start_time + (self.image_lines * self.line_exposure_duration) + (self.line_exposure_duration * 2) + return self._ephemeris_stop_time @property def look_direction(self): @@ -1095,25 +1118,6 @@ def instrument_id(self): def sensor_model_version(self): return 2 - - @property - def ephemeris_start_time(self): - """ - Returns the ephemeris start time of the image. - Expects spacecraft_id to be defined. This should be the integer - Naif ID code for the spacecraft. - - Returns - ------- - : float - ephemeris start time of the image - """ - if not hasattr(self, '_ephemeris_start_time'): - sclock = self.label['IsisCube']['Instrument']['SpacecraftClockStartCount'] - self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) - return self._ephemeris_start_time - - @property def sensor_name(self): """ @@ -1135,7 +1139,7 @@ def odtk(self): : list Radial distortion coefficients. """ - coeffs = pyspiceql.getKernelVectorValue('INS{}_OD_K'.format(self.fikid)).tolist() + coeffs = self.naif_keywords['INS{}_OD_K'.format(self.fikid)].tolist() coeffs = [x * -1 for x in coeffs] return coeffs @@ -1271,7 +1275,7 @@ def pixel2focal_x(self): : list detector to focal plane x """ - return list(pyspiceql.getKernelVectorValue('INS{}_TRANSX'.format(self.fikid))) + return list(self.naif_keywords['INS{}_TRANSX'.format(self.fikid)]) @property @@ -1284,7 +1288,7 @@ def pixel2focal_y(self): : list detector to focal plane y """ - return list(pyspiceql.getKernelVectorValue('INS{}_TRANSY'.format(self.fikid))) + return list(self.naif_keywords['INS{}_TRANSY'.format(self.fikid)]) @property def focal2pixel_lines(self): @@ -1296,7 +1300,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - return list(pyspiceql.getKernelVectorValue('INS{}_ITRANSL'.format(self.fikid))) + return list(self.naif_keywords['INS{}_ITRANSL'.format(self.fikid)]) @property def focal2pixel_samples(self): @@ -1308,7 +1312,7 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - return list(pyspiceql.getKernelVectorValue('INS{}_ITRANSS'.format(self.fikid))) + return list(self.naif_keywords['INS{}_ITRANSS'.format(self.fikid)]) @property @@ -1321,7 +1325,7 @@ def detector_start_line(self): : int Zero based Detector line corresponding to the first image line """ - offset = list(pyspiceql.getKernelVectorValue('INS{}_FILTER_OFFSET'.format(self.fikid))) + offset = list(self.naif_keywords['INS{}_FILTER_OFFSET'.format(self.fikid)]) try: # If multiple items are present, use the first one offset = offset[0] @@ -1341,7 +1345,7 @@ def focal_length(self): : float focal length """ - return float(pyspiceql.getKernelVectorValue('INS{}_FOCAL_LENGTH'.format(self.fikid))[0]) + return float(self.naif_keywords['INS{}_FOCAL_LENGTH'.format(self.fikid)][0]) @property def detector_center_sample(self): @@ -1354,7 +1358,7 @@ def detector_center_sample(self): : float Detector sample of the principal point """ - return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT_SAMPLE'.format(self.fikid))[0]) - 0.5 + return float(self.naif_keywords['INS{}_BORESIGHT_SAMPLE'.format(self.fikid)][0]) - 0.5 @property def detector_center_line(self): @@ -1367,4 +1371,4 @@ def detector_center_line(self): : float Detector line of the principal point """ - return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT_LINE'.format(self.fikid))[0]) - 0.5 + return float(self.naif_keywords['INS{}_BORESIGHT_LINE'.format(self.fikid)][0]) - 0.5 diff --git a/ale/drivers/mess_drivers.py b/ale/drivers/mess_drivers.py index e56e9bf8d..e7b1ad19b 100644 --- a/ale/drivers/mess_drivers.py +++ b/ale/drivers/mess_drivers.py @@ -159,7 +159,7 @@ def focal_length(self): : double focal length in meters """ - coeffs = pyspiceql.getKernelVectorValue('INS{}_FL_TEMP_COEFFS'.format(self.fikid)) + coeffs = self.naif_keywords['INS{}_FL_TEMP_COEFFS'.format(self.fikid)] # 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 @@ -241,7 +241,7 @@ def pixel_size(self): ------- : float pixel size """ - return pyspiceql.getKernelStringValue('INS{}_PIXEL_PITCH'.format(self.ikid)) + return self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)] class MessengerMdisIsisLabelNaifSpiceDriver(IsisLabel, NaifSpice, Framer, NoDistortion, Driver): """ @@ -281,25 +281,6 @@ def instrument_id(self): """ return ID_LOOKUP[super().instrument_id] - @property - def ephemeris_start_time(self): - """ - Returns the ephemeris_start_time of the image. - Expects spacecraft_clock_start_count to be defined. This should be a float - containing the start clock count of the spacecraft. - Expects spacecraft_id to be defined. This should be the integer Naif ID code - for the spacecraft. - - Returns - ------- - : float - ephemeris start time of the image. - """ - if not hasattr(self, '_ephemeris_start_time'): - sclock = self.spacecraft_clock_start_count - self._starting_ephemeris_time = pyspiceql.sclkToEt(self.spacecraft_id, sclock) - return self._starting_ephemeris_time - @property def usgscsm_distortion_model(self): """ @@ -354,7 +335,7 @@ def focal_length(self): : double focal length in meters """ - coeffs = pyspiceql.getKernelVectorValue('INS{}_FL_TEMP_COEFFS'.format(self.fikid)) + coeffs = self.naif_keywords['INS{}_FL_TEMP_COEFFS'.format(self.fikid)] # 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]) @@ -377,7 +358,7 @@ def detector_center_sample(self): : float detector center sample """ - return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid)[0])) - 0.5 + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][0]) - 0.5 @property @@ -395,7 +376,7 @@ def detector_center_line(self): : float detector center line """ - return float(pyspiceql.getKernelVectorValue('INS{}_CCD_CENTER'.format(self.ikid)[1])) - 0.5 + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][1]) - 0.5 @property def sensor_model_version(self): @@ -417,7 +398,7 @@ def pixel_size(self): ------- : float pixel size """ - return pyspiceql.getKernelStringValue('INS{}_PIXEL_PITCH'.format(self.ikid)) + return self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)] @property def sampling_factor(self): diff --git a/ale/drivers/mex_drivers.py b/ale/drivers/mex_drivers.py index a7d637642..15da83cdd 100644 --- a/ale/drivers/mex_drivers.py +++ b/ale/drivers/mex_drivers.py @@ -103,7 +103,9 @@ def ikid(self): : int Naif ID used to for identifying the instrument in Spice kernels """ - return pyspiceql.Kernel_translateFrame("MEX_HRSC_HEAD") + if not hasattr(self, "_ikid"): + self._ikid = self.spiceql_call("translateNameToCode", {"frame": "MEX_HRSC_HEAD", "mission": self.spiceql_mission}) + return self._ikid @property @@ -121,7 +123,9 @@ def fikid(self): : int Naif ID code used in calculating focal length """ - return pyspiceql.Kernel_translateFrame(self.instrument_id) + if not hasattr(self, "_fikid"): + self._fikid = self.spiceql_call("translateNameToCode", {"frame": self.instrument_id, "mission": self.spiceql_mission}) + return self._fikid # TODO Since HRSC has different frames based on filters, need to check that @@ -626,7 +630,9 @@ def ikid(self): : int Naif ID used to for identifying the instrument in Spice kernels """ - return pyspiceql.Kernel_translateFrame("MEX_HRSC_HEAD") + if not hasattr(self, "_ikid"): + self._ikid = self.spiceql_call("translateNameToCode", {"frame": "MEX_HRSC_HEAD", "mission": self.spiceql_mission}) + return self._ikid @property def fikid(self): @@ -643,7 +649,9 @@ def fikid(self): : int Naif ID code used in calculating focal length """ - return pyspiceql.Kernel_translateFrame(self.instrument_id) + if not hasattr(self, "_fikid"): + self._fikid = self.spiceql_call("translateNameToCode", {"frame": self.instrument_id, "mission": self.spiceql_mission}) + return self._fikid @property def focal_length(self): @@ -724,7 +732,9 @@ def ikid(self): : int Naif ID used to for identifying the instrument in Spice kernels """ - return pyspiceql.Kernel_translateFrame("MEX_HRSC_HEAD") + if not hasattr(self, "_ikid"): + self._ikid = self.spiceql_call("translateNameToCode", {"frame": "MEX_HRSC_HEAD", "mission": self.spiceql_mission}) + return self._ikid @property diff --git a/ale/drivers/mgs_drivers.py b/ale/drivers/mgs_drivers.py index 681acd0d5..d83b97f01 100644 --- a/ale/drivers/mgs_drivers.py +++ b/ale/drivers/mgs_drivers.py @@ -79,7 +79,7 @@ def detector_center_sample(self): : float Detector sample of the principal point """ - return float(spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 1)[0]) + return float(self.naif_keywords['INS{}_CENTER'.format(self.ikid)][0]) @property def detector_center_line(self): @@ -92,7 +92,7 @@ def detector_center_line(self): : float Detector line of the principal point """ - return float(spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[1]) + return float(self.naif_keywords['INS{}_CENTER'.format(self.ikid)][1]) @property @@ -181,23 +181,6 @@ def sensor_name(self): """ return self.instrument_id - @property - def ephemeris_start_time(self): - """ - Returns the ephemeris start time of the image. - Expects spacecraft_id to be defined. This should be the integer - Naif ID code for the spacecraft. - - Returns - ------- - : float - ephemeris start time of the image - """ - if not hasattr(self, '_ephemeris_start_time'): - sclock = self.label['IsisCube']['Instrument']['SpacecraftClockCount'] - self._ephemeris_start_time = spice.scs2e(self.spacecraft_id, sclock) - return self._ephemeris_start_time - @property def ephemeris_stop_time(self): """ @@ -229,7 +212,7 @@ def detector_center_sample(self): : float Detector sample of the principal point """ - return float(spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 1)[0]) + return float(self.naif_keywords['INS{}_CENTER'.format(self.ikid)][0]) @property def detector_center_line(self): @@ -242,7 +225,7 @@ def detector_center_line(self): : float Detector line of the principal point """ - return float(spice.gdpool('INS{}_CENTER'.format(self.ikid), 0, 2)[1]) + return float(self.naif_keywords['INS{}_CENTER'.format(self.ikid)][1]) @property diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 9c0b257fd..23681ace6 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -54,7 +54,7 @@ def base_ikid(self): Naif ID used to for identifying the instrument in Spice kernels """ if not hasattr(self, "_base_ikid"): - self._base_ikid = spice.bods2c("MRO_MARCI") + self._base_ikid = self.spiceql_call("translateNameToCode", {"frame": "MRO_MARCI", "mission": self.spiceql_mission}) return self._base_ikid @property @@ -219,7 +219,7 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - return list(spice.gdpool('INS{}_ITRANSS'.format(self.base_ikid), 0, 3)) + return list(self.naif_keywords['INS{}_ITRANSS'.format(self.base_ikid)]) @property def focal2pixel_lines(self): @@ -231,7 +231,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - return list(spice.gdpool('INS{}_ITRANSL'.format(self.base_ikid), 0, 3)) + return list(self.naif_keywords['INS{}_ITRANSL'.format(self.base_ikid)]) @property def naif_keywords(self): @@ -726,7 +726,9 @@ def ephemeris_start_time(self): : double Starting ephemeris time of the image """ - return spice.scs2e(-74999, self.spacecraft_clock_start_count) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frameCode": -74999, "sclk": self.spacecraft_clock_start_count, "mission": self.spiceql_mission}) + return self._ephemeris_start_time @property def ephemeris_stop_time(self): @@ -741,7 +743,9 @@ def ephemeris_stop_time(self): : double Ephemeris stop time of the image """ - return spice.scs2e(-74999, self.spacecraft_clock_stop_count) + if not hasattr(self, "_ephemeris_stop_time"): + self._ephemeris_stop_time = self.spiceql_call("strSclkToEt", {"frameCode": -74999, "sclk": self.spacecraft_clock_stop_count, "mission": self.spiceql_mission}) + return self._ephemeris_stop_time @property def spacecraft_name(self): diff --git a/ale/drivers/msl_drivers.py b/ale/drivers/msl_drivers.py index 4aa009a74..9f830dc85 100644 --- a/ale/drivers/msl_drivers.py +++ b/ale/drivers/msl_drivers.py @@ -113,7 +113,7 @@ def sensor_frame_id(self): """ if not hasattr(self, "_site_frame_id"): site_frame = "MSL_SITE_" + str(self.label["GEOMETRIC_CAMERA_MODEL_PARMS"]["REFERENCE_COORD_SYSTEM_INDEX"][0]) - self._site_frame_id= spice.bods2c(site_frame) + self._site_frame_id = self.spiceql_call("translateNameToCode", {"frame": site_frame, "mission": self.spiceql_mission}) return self._site_frame_id @property diff --git a/ale/drivers/nh_drivers.py b/ale/drivers/nh_drivers.py index 8fae575f6..3a0071459 100644 --- a/ale/drivers/nh_drivers.py +++ b/ale/drivers/nh_drivers.py @@ -68,7 +68,7 @@ def detector_center_line(self): list : The center of the CCD formatted as line, sample """ - return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0]) + return float(self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][0]) @property def detector_center_sample(self): @@ -82,7 +82,7 @@ def detector_center_sample(self): list : The center of the CCD formatted as line, sample """ - return float(pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1]) + return float(self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1]) @property def sensor_name(self): @@ -137,20 +137,6 @@ def ikid(self): """ return self.label['IsisCube']['Kernels']['NaifFrameCode'][0] - @property - def ephemeris_start_time(self): - """ - Returns the ephemeris start time of the image. - Expects spacecraft_id to be defined. This should be the integer - Naif ID code for the spacecraft. - - Returns - ------- - : float - ephemeris start time of the image - """ - return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_start_count) - @property def ephemeris_stop_time(self): """ @@ -335,7 +321,7 @@ def odtx(self): : list Optical distortion x coefficients """ - return spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.parent_id),0, 20).tolist() + return self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.parent_id)].tolist() @property @@ -348,7 +334,7 @@ def odty(self): : list Optical distortion y coefficients """ - return spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.parent_id), 0, 20).tolist() + return self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.parent_id)].tolist() @property def band_times(self): @@ -358,7 +344,7 @@ def band_times(self): for time in band_times: if type(time) is pvl.Quantity: time = time.value - self._ephem_band_times.append(spice.utc2et(time.strftime("%Y-%m-%d %H:%M:%S.%f"))) + self._ephem_band_times.append(self.spiceql_call("utcToEt", {"utc": time.strftime("%Y-%m-%d %H:%M:%S.%f")})) return self._ephem_band_times @@ -471,7 +457,7 @@ def ikid(self): # Attempt to get the frame code using frame name, # If that fails, try to get it directly from the cube label try: - self._ikid = spice.frmname(self.instrument_id) + self._ikid = self.spiceql_call("translateNameToCode", {"frame": self.instrument_id, "mission": self.spiceql_mission}) except: self._ikid = self.label["IsisCube"]["Kernels"]["NaifFrameCode"].value return self._ikid @@ -536,7 +522,7 @@ def odtx(self): : list Optical distortion x coefficients """ - return spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.parent_id),0, 20).tolist() + return self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.parent_id)] @property def odty(self): @@ -548,7 +534,7 @@ def odty(self): : list Optical distortion y coefficients """ - return spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.parent_id), 0, 20).tolist() + return self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.parent_id)] @property def naif_keywords(self): diff --git a/ale/drivers/osirisrex_drivers.py b/ale/drivers/osirisrex_drivers.py index 1123fa35a..b7e2317e5 100644 --- a/ale/drivers/osirisrex_drivers.py +++ b/ale/drivers/osirisrex_drivers.py @@ -78,7 +78,7 @@ def detector_center_line(self): : int The detector line of the principle point """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)[1]) + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)]) @property def detector_center_sample(self): @@ -92,7 +92,7 @@ def detector_center_sample(self): The detector sample of the principle point """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)[0]) + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)]) @property def filter_name(self): @@ -118,6 +118,6 @@ def odtk(self): Radial distortion coefficients """ if self.filter_name == "UNKNOWN": - return spice.gdpool('INS{}_OD_K'.format(self.ikid),0, 3).tolist() + return self.naif_keywords['INS{}_OD_K'.format(self.ikid)] else: - return spice.gdpool('INS{ikid}_OD_K_{filter}'.format(ikid = self.ikid, filter = self.filter_name),0, 3).tolist() + return self.naif_keywords['INS{ikid}_OD_K_{filter}'.format(ikid = self.ikid, filter = self.filter_name)] diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index c3320e425..8e1d2e4d3 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -222,7 +222,7 @@ def sensor_frame_id(self): Sensor frame id """ if not hasattr(self, "_sensor_frame_id"): - self._sensor_frame_id = spice.namfrm("LISM_{}_HEAD".format(super().instrument_id)) + self._sensor_frame_id = self.spiceql_call("translateNameToCode", {"frame": "LISM_{}_HEAD".format(super().instrument_id), "mission": self.spiceql_mission}) return self._sensor_frame_id @property @@ -244,7 +244,7 @@ def ikid(self): ikid of LISM_TC1 or LISM_TC2 """ if not hasattr(self, "_ikid"): - return pyspiceql.Kernel_translateFrame("LISM_{}".format(super().instrument_id)) + self._ikid = self.spiceql_call("translateNameToCode", {"frame": "LISM_{}".format(super().instrument_id), "mission": self.spiceql_mission}) return self._ikid @property @@ -301,7 +301,9 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - return pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_start_count) + self._ephemeris_start_time = self.spiceql_call("doubleSclkToEt", {"frameCode": self.spacecraft_id, + "sclk": self.spacecraft_clock_start_count, + "mission": self.spiceql_mission}) return self._ephemeris_start_time @property @@ -318,7 +320,9 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid)[0]) + print('INS{}_PIXEL_SIZE'.format(self.ikid)) + print(self.naif_keywords) + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -336,7 +340,8 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid)[0]) + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] + print(pixel_size) self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -353,7 +358,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_X'.format(self.ikid)).tolist() + self.__odkx = self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.ikid)] return self.__odkx @property @@ -369,7 +374,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_Y'.format(self.ikid)).tolist() + self.__odky = self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.ikid)] return self.__odky @property @@ -385,7 +390,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0] + self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][0] return self._boresight_x @property @@ -401,11 +406,7 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - # TODO is this the right way to access this value? - # original: - # return spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] - - self._boresight_y = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1] + self._boresight_y = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1] return self._boresight_y @property @@ -602,7 +603,7 @@ def sensor_frame_id(self): Sensor frame id """ if not hasattr(self, "_sensor_frame_id"): - self._sensor_frame_id = spice.namfrm("LISM_{}_HEAD".format(super().instrument_id)) + self._sensor_frame_id = self.spiceql_call("translateNameToCode", {"frame": "LISM_{}_HEAD".format(super().instrument_id), "mission": self.spiceql_mission}) return self._sensor_frame_id @property @@ -611,7 +612,7 @@ def ikid(self): Read the ikid from the cube label """ if not hasattr(self, "_ikid"): - self._ikid = spice.bods2c("LISM_{}".format(super().instrument_id)) + self._ikid = self.spiceql_call("translateNameToCode", {"frame": "LISM_{}".format(super().instrument_id), "mission": self.spiceql_mission}) return self._ikid @property @@ -641,7 +642,10 @@ def ephemeris_start_time(self): Starting ephemeris time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = spice.sct2e(self.spacecraft_id, float(self.spacecraft_clock_start_count)) + self._ephemeris_start_time = self.spiceql_call("doubleSclkToEt", + {"frameCode": self.spacecraft_id, + "sclk": float(self.spacecraft_clock_start_count), + "mission": self.spiceql_mission}) return self._ephemeris_start_time @property @@ -699,7 +703,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -717,7 +721,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -734,7 +738,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = spice.gdpool('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist() + self.__odkx = self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.ikid)] return self.__odkx @property @@ -750,7 +754,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = spice.gdpool('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist() + self.__odky = self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.ikid)] return self.__odky @property @@ -766,7 +770,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 0, 1)[0] + self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][0] return self._boresight_x @property @@ -782,7 +786,7 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_y = spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] + self._boresight_y = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1] return self._boresight_y @property @@ -919,7 +923,7 @@ def sensor_frame_id(self): """ if not hasattr(self, "_sensor_frame_id"): spectra = self.base_band[3] - self._sensor_frame_id = spice.namfrm(f"LISM_MI_{spectra}_HEAD") + self._sensor_frame_id = self.spiceql_call("translateNameToCode", {"frame": f"LISM_MI_{spectra}_HEAD", "mission": self.spiceql_mission}) return self._sensor_frame_id @property @@ -976,9 +980,10 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_start_count) + self._ephemeris_start_time = self.spiceql_call("doubleSclkToEt", {"frameCode": self.spacecraft_id, + "sclk": self.spacecraft_clock_start_count, + "mission": self.spiceql_mission}) return self._ephemeris_start_time - @property def detector_center_line(self): """ @@ -994,7 +999,7 @@ def detector_center_line(self): The detector line of the principle point """ if not hasattr(self, "_detector_center_line"): - self._detector_center_line = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[1] - 0.5 + self._detector_center_line = self.naif_keywords['INS{}_CENTER'.format(self.ikid)][1] - 0.5 return self._detector_center_line @property @@ -1012,7 +1017,7 @@ def detector_center_sample(self): The detector sample of the principle point """ if not hasattr(self, "_detector_center_sample"): - self._detector_center_sample = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[0] - 0.5 + self._detector_center_sample = self.naif_keywords['INS{}_CENTER'.format(self.ikid)][0] - 0.5 return self._detector_center_sample @property @@ -1029,7 +1034,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -1047,7 +1052,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -1064,7 +1069,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_X'.format(self.ikid),0, 4).tolist() + self.__odkx = self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.ikid)] return self.__odkx @property @@ -1080,7 +1085,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_Y'.format(self.ikid),0, 4).tolist() + self.__odky = self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.ikid)] return self.__odky @property @@ -1096,7 +1101,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0] + self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][0] return self._boresight_x @property @@ -1112,7 +1117,7 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_y = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1] + self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1] return self._boresight_y @property @@ -1278,7 +1283,9 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_start_count) + self._ephemeris_start_time = self.spiceql_call("doubleSclkToEt", {"frameCode": self.spacecraft_id, + "sclk": self.spacecraft_clock_start_count, + "mission": self.spiceql_mission}) return self._ephemeris_start_time @property @@ -1293,7 +1300,9 @@ def ephemeris_stop_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_stop_time"): - self._ephemeris_stop_time = pyspiceql.sclkToEt(self.spacecraft_id, self.spacecraft_clock_stop_count) + self._ephemeris_stop_time = self.spiceql_call("doubleSclkToEt", {"frameCode": self.spacecraft_id, + "sclk": self.spacecraft_clock_stop_count, + "mission": self.spiceql_mission}) return self._ephemeris_stop_time @property @@ -1309,7 +1318,7 @@ def sensor_frame_id(self): """ if not hasattr(self, "_sensor_frame_id"): spectra = self.base_band[3] - self._sensor_frame_id = spice.namfrm(f"LISM_MI_{spectra}_HEAD") + self._sensor_frame_id = self.spiceql_call("translateNameToCode", {"frame": f"LISM_MI_{spectra}_HEAD", "mission": self.spiceql_mission}) return self._sensor_frame_id @@ -1328,7 +1337,7 @@ def detector_center_line(self): The detector line of the principle point """ if not hasattr(self, "_detector_center_line"): - self._detector_center_line = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[1] - 0.5 + self._detector_center_line = self.naif_keywords['INS{}_CENTER'.format(self.ikid)][1] - 0.5 return self._detector_center_line @property @@ -1346,7 +1355,7 @@ def detector_center_sample(self): The detector sample of the principle point """ if not hasattr(self, "_detector_center_sample"): - self._detector_center_sample = pyspiceql.getKernelVectorValue('INS{}_CENTER'.format(self.ikid))[0] - 0.5 + self._detector_center_sample = self.naif_keywords['INS{}_CENTER'.format(self.ikid)][0] - 0.5 return self._detector_center_sample @property @@ -1362,7 +1371,7 @@ def _odkx(self): Optical distortion x coefficients """ if not hasattr(self, "__odkx"): - self.__odkx = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_X'.format(self.ikid)).tolist() + self.__odkx = self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.ikid)] return self.__odkx @property @@ -1378,7 +1387,7 @@ def _odky(self): Optical distortion y coefficients """ if not hasattr(self, "__odky"): - self.__odky = pyspiceql.getKernelVectorValue('INS{}_DISTORTION_COEF_Y'.format(self.ikid), 0, 4).tolist() + self.__odky = self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.ikid)] return self.__odky @property @@ -1394,7 +1403,7 @@ def boresight_x(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_x"): - self._boresight_x = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[0] + self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][0] return self._boresight_x @property @@ -1410,7 +1419,7 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_y = pyspiceql.getKernelVectorValue('INS{}_BORESIGHT'.format(self.ikid))[1] + self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1] return self._boresight_y @property @@ -1491,7 +1500,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -1509,6 +1518,6 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = pyspiceql.getKernelVectorValue('INS{}_PIXEL_SIZE'.format(self.ikid))[0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines diff --git a/ale/drivers/tgo_drivers.py b/ale/drivers/tgo_drivers.py index 5e65546a1..412320dfc 100644 --- a/ale/drivers/tgo_drivers.py +++ b/ale/drivers/tgo_drivers.py @@ -44,7 +44,9 @@ def ephemeris_start_time(self): : float ephemeris start time of the image. """ - return pyspiceql.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_start_time @property def sensor_frame_id(self): diff --git a/ale/drivers/viking_drivers.py b/ale/drivers/viking_drivers.py index 22464b5a9..36b42c8cb 100644 --- a/ale/drivers/viking_drivers.py +++ b/ale/drivers/viking_drivers.py @@ -24,8 +24,6 @@ class VikingIsisLabelNaifSpiceDriver(Framer, IsisLabel, NaifSpice, NoDistortion, Driver): - - @property def instrument_id(self): """ @@ -108,15 +106,19 @@ def ephemeris_start_time(self): : float ephemeris start time of the image """ - ephemeris_start_time = pyspiceql.sclkToEt(self.alt_ikid, str(self.spacecraft_clock_start_count)) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frame": self.alt_ikid, + "sclk": self.spacecraft_clock_start_count, + "mission": self.spiceql_mission}) + if self.exposure_duration <= .420: + offset1 = 7.0 / 8.0 * 4.48 + else: + offset1 = 3.0 / 8.0 * 4.48 + offset2 = 1.0 / 64.0 * 4.48 - if self.exposure_duration <= .420: - offset1 = 7.0 / 8.0 * 4.48 - else: - offset1 = 3.0 / 8.0 * 4.48 - offset2 = 1.0 / 64.0 * 4.48 + self._ephemeris_start_time += offset1 + offset2 - return ephemeris_start_time + offset1 + offset2 + return self._ephemeris_start_time @property def focal_length(self): diff --git a/ale/drivers/voyager_drivers.py b/ale/drivers/voyager_drivers.py index 9674d1a1e..f2eea37e2 100644 --- a/ale/drivers/voyager_drivers.py +++ b/ale/drivers/voyager_drivers.py @@ -50,7 +50,7 @@ def spacecraft_name(self): @property def pixel_size(self): - return spice.gdpool('INS{}_PIXEL_PITCH'.format(self.ikid), 0, 1)[0] + return self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)][0] @property def detector_center_sample(self): @@ -62,12 +62,13 @@ def detector_center_line(self): @property def ephemeris_start_time(self): - inital_time = pyspiceql.utcToEt(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) - # To get shutter end (close) time, subtract 2 seconds from the start time - updated_time = inital_time - 2 - # To get shutter start (open) time, take off the exposure duration from the end time. - start_time = updated_time - self.exposure_duration - return start_time + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + # To get shutter end (close) time, subtract 2 seconds from the start time + self._ephemeris_start_time -= 2 + # To get shutter start (open) time, take off the exposure duration from the end time. + self._ephemeris_start_time -= self.exposure_duration + return self._ephemeris_start_time @property def ephemeris_stop_time(self): diff --git a/ale/spiceql_access.py b/ale/spiceql_access.py index 42652c490..404a56a34 100644 --- a/ale/spiceql_access.py +++ b/ale/spiceql_access.py @@ -3,7 +3,7 @@ import requests import time -import aiohttp +from multiprocessing.pool import ThreadPool import numpy as np import pyspiceql @@ -145,7 +145,7 @@ def spiceql_call(function_name = "", function_args = {}, use_web=False): return response.json()["body"]["return"] -async def get_ephem_data(times, function_name, batch_size=400, web=False, **kwargs): +def get_ephem_data(times, function_name, batch_size=400, web=False, **kwargs): """ This function provides access to ephemeris data aquisition in spiceql. For the web service there is a limited number of times that can be @@ -189,21 +189,34 @@ async def get_ephem_data(times, function_name, batch_size=400, web=False, **kwar if not web: function_args = {**kwargs} function_args["ets"] = times - rotation = spiceql_call(function_name, function_args, web) - return rotation + ephemeris_data = spiceql_call(function_name, function_args, web) + return ephemeris_data - tasks = [] batches = math.ceil(len(times) / batch_size) - async with aiohttp.ClientSession() as session: - for i in range(1, batches+1): - batch_times = times[(i - 1) * batch_size: i * batch_size] - function_args = {**kwargs} - function_args["ets"] = batch_times - tasks.append(asyncio.create_task(async_spiceql_call(session, function_name, function_args, use_web=web))) - responses = await asyncio.gather(*tasks) - results = [] - for response in responses: - results += response + job_args_list = [] + for i in range(1, batches+1): + batch_times = times[(i - 1) * batch_size: i * batch_size] + function_args = {**kwargs} + function_args["ets"] = batch_times + job_args_list.append(function_args) + with ThreadPool() as pool: + jobs = pool.starmap_async(spiceql_call, job_args_list) + results = jobs.get() + + return results + + # tasks = [] + + # async with aiohttp.ClientSession() as session: + # for i in range(1, batches+1): + # batch_times = times[(i - 1) * batch_size: i * batch_size] + # function_args = {**kwargs} + # function_args["ets"] = batch_times + # tasks.append(asyncio.create_task(async_spiceql_call(session, function_name, function_args, use_web=web))) + # responses = await asyncio.gather(*tasks) + # results = [] + # for response in responses: + # results += response - return results + # return results diff --git a/tests/pytests/test_kaguya_drivers.py b/tests/pytests/test_kaguya_drivers.py index 54da2ffba..776aa1564 100644 --- a/tests/pytests/test_kaguya_drivers.py +++ b/tests/pytests/test_kaguya_drivers.py @@ -7,6 +7,7 @@ import pytest from ale.drivers import AleJsonEncoder +from ale.formatters.formatter import to_isd from conftest import get_isd, get_image_label, get_image_kernels, convert_kernels, compare_dicts import ale @@ -42,8 +43,11 @@ def test_kaguya_load(test_kernels, label_type, image): compare_isd = get_isd(image_dict[image]) label_file = get_image_label(image, label_type) - isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) - isd_obj = json.loads(isd_str) + # isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) + driver = KaguyaTcIsisLabelNaifSpiceDriver(label_file, props={'kernels': test_kernels[image]}) + with driver as active_driver: + isd_obj = to_isd(active_driver) + # isd_obj = json.loads(isd_str) assert compare_dicts(isd_obj, compare_isd) == [] diff --git a/tests/pytests/test_mro_drivers.py b/tests/pytests/test_mro_drivers.py index 3dca76eb3..37a8d6b90 100644 --- a/tests/pytests/test_mro_drivers.py +++ b/tests/pytests/test_mro_drivers.py @@ -52,7 +52,7 @@ def test_mro_ctx_load(test_ctx_kernels, label_type, kernel_type): isd_str = ale.loads(label_file) compare_isd = get_isd('ctx_isis') else: - isd_str = ale.loads(label_file, props={'kernels': test_ctx_kernels}) + isd_str = ale.loads(label_file, props={'kernels': test_ctx_kernels}, verbose=False) compare_isd = get_isd('ctx') isd_obj = json.loads(isd_str) diff --git a/tests/pytests/test_voyager_drivers.py b/tests/pytests/test_voyager_drivers.py index df8b8712b..28904a35f 100644 --- a/tests/pytests/test_voyager_drivers.py +++ b/tests/pytests/test_voyager_drivers.py @@ -300,6 +300,7 @@ def test_kernels(): @pytest.mark.parametrize("label_type", ['isis3']) @pytest.mark.parametrize("image", image_dict.keys()) def test_voyager_load(test_kernels, label_type, image): + print(test_kernels[image]) label_file = get_image_label(image, label_type) usgscsm_isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=True) From 07532e303190a796720a46089f2fd8b6ea61dc8a Mon Sep 17 00:00:00 2001 From: acpaquette Date: Thu, 28 Sep 2023 21:08:48 -0700 Subject: [PATCH 21/73] Missed changes to transformation.py --- ale/transformation.py | 73 ++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/ale/transformation.py b/ale/transformation.py index 6cf903ecc..67ea3c675 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -1,5 +1,4 @@ -import asyncio -import aiohttp +from multiprocessing.pool import ThreadPool import numpy as np from numpy.polynomial.polynomial import polyval @@ -124,8 +123,10 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, if exact_ck_times and len(ephemeris_times) > 1 and not nadir: try: sensor_times = spiceql_call("extractExactCkTimes", {"observStart": ephemeris_times[0] + inst_time_bias, - "observStop": ephemeris_times[-1] + inst_time_bias, + "observEnd": ephemeris_times[-1] + inst_time_bias, "targetFrame": sensor_frame, + "mission": mission, + "ckQuality": "", "searchKernels": frame_chain.search_kernels}) except Exception as e: print(e) @@ -136,7 +137,7 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, if isinstance(sensor_times, np.ndarray): sensor_times = sensor_times.tolist() - frames = asyncio.run(frame_chain.frame_trace(center_ephemeris_time, sensor_frame, target_frame, mission)) + frames = frame_chain.frame_trace(center_ephemeris_time, sensor_frame, target_frame, mission) sensor_time_dependent_frames, sensor_constant_frames = frames[0] target_time_dependent_frames, target_constant_frames = frames[1] @@ -148,37 +149,30 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, constant_frames.extend(target_constant_frames) # Add all time dependent frame chains to the graph - asyncio.run(frame_chain.generate_time_dependent_rotiations(sensor_time_dependent_frames, sensor_times, inst_time_bias, mission)) - asyncio.run(frame_chain.generate_time_dependent_rotiations(target_time_dependent_frames, target_times, 0, mission)) - asyncio.run(frame_chain.generate_constant_rotations(constant_frames, ephemeris_times[0], mission)) + frame_chain.generate_time_dependent_rotiations(sensor_time_dependent_frames, sensor_times, inst_time_bias, mission) + frame_chain.generate_time_dependent_rotiations(target_time_dependent_frames, target_times, 0, mission) + frame_chain.generate_constant_rotations(constant_frames, ephemeris_times[0], mission) return frame_chain - async def frame_trace(self, time, sensorFrame, targetFrame, mission, nadir=False): + def frame_trace(self, time, sensorFrame, targetFrame, mission, nadir=False): if not self.use_web: results = [pyspiceql.frameTrace(time, sensorFrame, mission, searchKernels=self.search_kernels)] results.append(pyspiceql.frameTrace(time, targetFrame, mission, searchKernels=self.search_kernels)) return results - tasks = [] - async with aiohttp.ClientSession() as session: - tasks.append(asyncio.create_task(async_spiceql_call(session, - "frameTrace", - {"et": time, - "initialFrame": sensorFrame, - "mission": mission, - "searchKernels": self.search_kernels}, - use_web=self.use_web))) - tasks.append(asyncio.create_task(async_spiceql_call(session, - "frameTrace", - {"et": time, - "initialFrame": targetFrame, - "mission": mission, - "searchKernels": self.search_kernels}, - use_web=self.use_web))) - responses = await asyncio.gather(*tasks) - results = [] - for response in responses: - results.append(response) + jobs = [] + jobs.append({"et": time, + "initialFrame": sensorFrame, + "mission": mission, + "searchKernels": self.search_kernels}) + jobs.append({"et": time, + "initialFrame": targetFrame, + "mission": mission, + "searchKernels": self.search_kernels}) + with ThreadPool() as pool: + jobs = pool.starmap_async(spiceql_call, [("frameTrace", job, self.use_web)for job in jobs]) + results = jobs.get() + return results @classmethod @@ -366,7 +360,7 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): return times - async def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=""): + def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=""): """ Computes the time dependent rotations based on a list of tuples that define the relationships between frames as (source, destination) and a list of times to @@ -379,11 +373,13 @@ async def generate_time_dependent_rotiations(self, frames, times, time_bias, mis times : list A list of times to compute the rotation at """ - frame_tasks = [] + quats_and_avs_per_frame = [] for s, d in frames: kwargs = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} - frame_tasks.append(asyncio.create_task(get_ephem_data(times, "getTargetOrientations", **kwargs, web=self.use_web))) - quats_and_avs_per_frame = await asyncio.gather(*frame_tasks) + quats_and_avs_per_frame.append(get_ephem_data(times, "getTargetOrientations", **kwargs, web=self.use_web)) + # with ThreadPool() as pool: + # jobs = pool.starmap_async(get_ephem_data, frame_tasks) + # quats_and_avs_per_frame = jobs.get() for i, frame in enumerate(frames): quats_and_avs = quats_and_avs_per_frame[i] @@ -403,12 +399,17 @@ async def generate_time_dependent_rotiations(self, frames, times, time_bias, mis rotation = TimeDependentRotation(quats, biased_times, frame[0], frame[1], av=avs) self.add_edge(rotation=rotation) - async def generate_constant_rotations(self, frames, time, mission): - frame_tasks = [] + def generate_constant_rotations(self, frames, time, mission): + quats_and_avs_per_frame = [] for s, d in frames: kwargs = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} - frame_tasks.append(asyncio.create_task(get_ephem_data([time], "getTargetOrientations", **kwargs, web=self.use_web))) - quats_and_avs_per_frame = await asyncio.gather(*frame_tasks) + quats_and_avs_per_frame.append(get_ephem_data([time], "getTargetOrientations", **kwargs, web=self.use_web)) + # frame_tasks = [] + # for s, d in frames: + # frame_tasks.append([[time], "getTargetOrientations", d, s, mission, self.search_kernels, self.use_web]) + # with ThreadPool() as pool: + # jobs = pool.starmap_async(get_ephem_data, frame_tasks) + # quats_and_avs_per_frame = jobs.get() # Add all constant frame chains to the graph for i, frame in enumerate(frames): From cf388b128185ead6b5e2388837c530a1f6c6d833 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 29 Sep 2023 00:56:24 -0700 Subject: [PATCH 22/73] More Kaguya debugging --- ale/base/base.py | 2 ++ ale/base/data_naif.py | 45 ++++++++++++++++++++++++++-- ale/drivers/selene_drivers.py | 14 ++++----- tests/pytests/test_kaguya_drivers.py | 1 + 4 files changed, 52 insertions(+), 10 deletions(-) diff --git a/ale/base/base.py b/ale/base/base.py index b61dfea6c..3f9d0175c 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -4,6 +4,8 @@ import os from multiprocessing.pool import ThreadPool +import pvl + class Driver(): """ Base class for all Drivers. diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 227bbc232..cb3c1f1a0 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -405,7 +405,7 @@ def sun_position(self): a tuple containing a list of sun positions, a list of sun velocities """ if not hasattr(self, "_sun_position"): - times = [self.center_ephemeris_time] + times = self.ephemeris_time if len(times) > 1: times = [times[0], times[-1]] positions = [] @@ -472,6 +472,14 @@ def sensor_position(self): obs_tars = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) obs_tar_lts = np.array(obs_tars)[:,-1] + time = ephem[0] + obs_tar_state, obs_tar_lt = spice.spkezr(target, + time, + 'J2000', + self.light_time_correction, + observer) + print("{:.16f}, {:.16f}".format(obs_tar_lts[0], obs_tar_lt)) + # ssb to spacecraft kwargs = {"target": observer, "observer": "SSB", @@ -482,8 +490,22 @@ def sensor_position(self): ssb_obs = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) ssb_obs_states = np.array(ssb_obs)[:,0:6] + # ssb to spacecraft + ssb_obs_state, ssb_obs_lt = spice.spkezr(observer, + time, + 'J2000', + 'NONE', + 'SSB') + + + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_obs_states[0])) + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_obs_state)) + radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt + + print("{:.16f}".format(adjusted_time[0])) + print("{:.16f}".format(time - obs_tar_lt + radius_lt)) kwargs = {"target": target, "observer": "SSB", @@ -494,14 +516,33 @@ def sensor_position(self): ssb_tars = spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", **kwargs, web=self.use_web) ssb_tar_states = np.array(ssb_tars)[:,0:6] - # print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_tar_state, ssb_tar_lt)) + ssb_tar_state, ssb_tar_lt = spice.spkezr(target, + time - obs_tar_lt + radius_lt, + 'J2000', + 'NONE', + 'SSB') + + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_tar_states[0])) + print(len(ssb_tar_state)) + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_tar_state)) + + old_state = ssb_tar_state - ssb_obs_state _states = ssb_tar_states - ssb_obs_states + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*_states[0])) + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*old_state)) + states = [] for i, state in enumerate(_states): matrix = spice.sxform("J2000", self.reference_frame, ephem[i]) rotated_state = spice.mxvg(matrix, state) states.append(rotated_state) + + matrix = spice.sxform("J2000", self.reference_frame, time) + old_state = spice.mxvg(matrix, old_state) + + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*states[0])) + print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*old_state)) else: kwargs = {"target": target, "observer": observer, diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index 8e1d2e4d3..fb6c1569b 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -132,9 +132,10 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = super().focal2pixel_lines - focal2pixel_lines[1] = -focal2pixel_lines[1] - return focal2pixel_lines + if not hasattr(self, "_focal2pixel_lines"): + self._focal2pixel_lines = super().focal2pixel_lines + self._focal2pixel_lines[1] = -self._focal2pixel_lines[1] + return self._focal2pixel_lines @property def sensor_model_version(self): @@ -320,8 +321,6 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - print('INS{}_PIXEL_SIZE'.format(self.ikid)) - print(self.naif_keywords) pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -341,7 +340,6 @@ def focal2pixel_lines(self): """ if not hasattr(self, "_focal2pixel_lines"): pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - print(pixel_size) self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -703,7 +701,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines @@ -721,7 +719,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples diff --git a/tests/pytests/test_kaguya_drivers.py b/tests/pytests/test_kaguya_drivers.py index 776aa1564..293e127d5 100644 --- a/tests/pytests/test_kaguya_drivers.py +++ b/tests/pytests/test_kaguya_drivers.py @@ -46,6 +46,7 @@ def test_kaguya_load(test_kernels, label_type, image): # isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) driver = KaguyaTcIsisLabelNaifSpiceDriver(label_file, props={'kernels': test_kernels[image]}) with driver as active_driver: + print(active_driver.sun_position) isd_obj = to_isd(active_driver) # isd_obj = json.loads(isd_str) From c54a72e0b78876f9890d3a95e2fcc5973acbf106 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 29 Sep 2023 01:03:33 -0700 Subject: [PATCH 23/73] More debugging --- ale/base/data_naif.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index cb3c1f1a0..953154b52 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -473,6 +473,7 @@ def sensor_position(self): obs_tar_lts = np.array(obs_tars)[:,-1] time = ephem[0] + print("{:.16f}".format(time)) obs_tar_state, obs_tar_lt = spice.spkezr(target, time, 'J2000', From 2a6e0078a423551fe90c4f841689d9faa1668c7a Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 29 Sep 2023 01:15:10 -0700 Subject: [PATCH 24/73] More debugging --- ale/base/data_naif.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 953154b52..8c8c8fdea 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -454,6 +454,7 @@ def sensor_position(self): target = self.spacecraft_name observer = self.target_name + print(target, observer) ## Check for ISIS flag to fix target and observer swapping if self.swap_observer_target: target = self.target_name From dde7bec7cf6318d4178e21500e921a8663c8e8f1 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 29 Sep 2023 13:15:31 -0700 Subject: [PATCH 25/73] Various fixes to drivers and transformation --- ale/base/__init__.py | 9 ++++-- ale/base/base.py | 16 ++------- ale/base/data_naif.py | 52 +++++------------------------- ale/drivers/chandrayaan_drivers.py | 4 +-- ale/drivers/clementine_drivers.py | 4 ++- ale/drivers/co_drivers.py | 4 +-- ale/drivers/dawn_drivers.py | 2 +- ale/drivers/mro_drivers.py | 4 +-- ale/formatters/formatter.py | 4 +-- ale/transformation.py | 24 +++++++------- 10 files changed, 41 insertions(+), 82 deletions(-) diff --git a/ale/base/__init__.py b/ale/base/__init__.py index 1f1fbd339..935a9f861 100644 --- a/ale/base/__init__.py +++ b/ale/base/__init__.py @@ -1,7 +1,8 @@ from ale.base.base import Driver spiceql_mission_map = { - "CHANDRAYAAN-1_M3": "", + "CHANDRAYAAN-1_M3": "m3", + "CHANDRAYAAN-1_MRFFR": "mrffr", "CASSINI_ISS_NAC": "cassini", "CASSINI_ISS_WAC": "cassini", "DAWN_FC2_FILTER_1": "", @@ -72,5 +73,9 @@ "VG1_ISSNA": "", "VG1_ISSWA": "", "VG2_ISSNA": "", - "VG2_ISSWA": "" + "VG2_ISSWA": "", + "ULTRAVIOLET/VISIBLE CAMERA": "uvvis", + "Near Infrared Camera": "nir", + "High Resolution Camera": "clementine1", + "Long Wave Infrared Camera": "clementine1", } \ No newline at end of file diff --git a/ale/base/base.py b/ale/base/base.py index 3f9d0175c..4a1ce883f 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -52,21 +52,9 @@ def get_property(prop_name): properties.append(attr) data = {} - if "naif_keywords" in properties: - properties.remove("naif_keywords") - data["naif_keywords"] = getattr(self, "naif_keywords") - if "frame_chain" in properties: - properties.remove("frame_chain") - data["frame_chain"] = getattr(self, "frame_chain") - - - with ThreadPool() as pool: - jobs = pool.starmap_async(get_property, [(name,) for name in properties]) - results = jobs.get() - - for result, property_name in zip(results, properties): - data[property_name] = result + for prop in properties: + data[prop] = get_property(prop) return data @property diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 8c8c8fdea..3568d1cae 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -454,7 +454,6 @@ def sensor_position(self): target = self.spacecraft_name observer = self.target_name - print(target, observer) ## Check for ISIS flag to fix target and observer swapping if self.swap_observer_target: target = self.target_name @@ -473,15 +472,6 @@ def sensor_position(self): obs_tars = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) obs_tar_lts = np.array(obs_tars)[:,-1] - time = ephem[0] - print("{:.16f}".format(time)) - obs_tar_state, obs_tar_lt = spice.spkezr(target, - time, - 'J2000', - self.light_time_correction, - observer) - print("{:.16f}, {:.16f}".format(obs_tar_lts[0], obs_tar_lt)) - # ssb to spacecraft kwargs = {"target": observer, "observer": "SSB", @@ -492,23 +482,10 @@ def sensor_position(self): ssb_obs = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) ssb_obs_states = np.array(ssb_obs)[:,0:6] - # ssb to spacecraft - ssb_obs_state, ssb_obs_lt = spice.spkezr(observer, - time, - 'J2000', - 'NONE', - 'SSB') - - - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_obs_states[0])) - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_obs_state)) radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt - print("{:.16f}".format(adjusted_time[0])) - print("{:.16f}".format(time - obs_tar_lt + radius_lt)) - kwargs = {"target": target, "observer": "SSB", "frame": "J2000", @@ -518,33 +495,14 @@ def sensor_position(self): ssb_tars = spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", **kwargs, web=self.use_web) ssb_tar_states = np.array(ssb_tars)[:,0:6] - ssb_tar_state, ssb_tar_lt = spice.spkezr(target, - time - obs_tar_lt + radius_lt, - 'J2000', - 'NONE', - 'SSB') - - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_tar_states[0])) - print(len(ssb_tar_state)) - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*ssb_tar_state)) - - old_state = ssb_tar_state - ssb_obs_state _states = ssb_tar_states - ssb_obs_states - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*_states[0])) - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*old_state)) states = [] for i, state in enumerate(_states): matrix = spice.sxform("J2000", self.reference_frame, ephem[i]) rotated_state = spice.mxvg(matrix, state) states.append(rotated_state) - - matrix = spice.sxform("J2000", self.reference_frame, time) - old_state = spice.mxvg(matrix, old_state) - - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*states[0])) - print("{:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}, {:.16f}".format(*old_state)) else: kwargs = {"target": target, "observer": observer, @@ -590,6 +548,8 @@ def frame_chain(self): # SpiceRotation::setEphemerisTimeNadir rotation = self._frame_chain.compute_rotation(self.target_frame_id, 1) p_vec, v_vec, times = self.sensor_position + print(rotation) + print(p_vec[0], v_vec[0], times[0]) rotated_positions = rotation.apply_at(p_vec, times) rotated_velocities = rotation.rotate_velocity_at(p_vec, v_vec, times) @@ -709,7 +669,12 @@ def swap_observer_target(self): if not hasattr(self, "_swap_observer_target"): try: swap = self.naif_keywords['INS{}_SWAP_OBSERVER_TARGET'.format(self.ikid)] - self._swap_observer_target = swap.upper() == "TRUE" + if isinstance(swap, str): + self._swap_observer_target = swap.upper() == "TRUE" + elif isinstance(swap, bool): + self._swap_observer_target = swap + else: + raise Exception(f"Cannot decode swap observer target value {swap}") except: self._swap_observer_target = False return self._swap_observer_target @@ -734,7 +699,6 @@ def correct_lt_to_surface(self): else: raise Exception(f"Cannot decode LT surface correct value {surface_correct}") except Exception as e: - print self._correct_lt_to_surface = False return self._correct_lt_to_surface diff --git a/ale/drivers/chandrayaan_drivers.py b/ale/drivers/chandrayaan_drivers.py index 4a444fc26..150719bdc 100644 --- a/ale/drivers/chandrayaan_drivers.py +++ b/ale/drivers/chandrayaan_drivers.py @@ -235,8 +235,8 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - transx = [-1* self.scaled_pixel_height, self.scaled_pixel_height, 0.0] - transy = [0,0,0] + transx = [-1 * self.scaled_pixel_height, self.scaled_pixel_height, 0.0] + transy = [0.0 ,0.0 , 0.0] transs = [1.0, 1.0 / self.scaled_pixel_height, 0.0] transl = [0.0, 0.0, 0.0] return {**super().naif_keywords, diff --git a/ale/drivers/clementine_drivers.py b/ale/drivers/clementine_drivers.py index 0b0991f4c..8ae32d64f 100644 --- a/ale/drivers/clementine_drivers.py +++ b/ale/drivers/clementine_drivers.py @@ -73,7 +73,9 @@ def sensor_model_version(self): @property def ephemeris_start_time(self): - return spice.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_start_time @property def ephemeris_stop_time(self): diff --git a/ale/drivers/co_drivers.py b/ale/drivers/co_drivers.py index 12182c894..e50b0d03d 100644 --- a/ale/drivers/co_drivers.py +++ b/ale/drivers/co_drivers.py @@ -359,7 +359,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ # Microns to mm - pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0]) * .001 + pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)]) * .001 return [0.0, 1/pixel_size, 0.0] @property @@ -373,7 +373,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0]) * .001 + pixel_size = float(self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)]) * .001 return [0.0, 0.0, 1/pixel_size] @property diff --git a/ale/drivers/dawn_drivers.py b/ale/drivers/dawn_drivers.py index d8233a18c..162c8f0db 100644 --- a/ale/drivers/dawn_drivers.py +++ b/ale/drivers/dawn_drivers.py @@ -119,7 +119,7 @@ def odtk(self): : list Radial distortion coefficients """ - return self.naif_keywords['INS{}_RAD_DIST_COEFF'.format(self.ikid)].tolist() + return self.naif_keywords['INS{}_RAD_DIST_COEFF'.format(self.ikid)] # TODO: Update focal2pixel samples and lines to reflect the rectangular # nature of dawn pixels diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index 23681ace6..ad377ba7c 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -219,7 +219,7 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - return list(self.naif_keywords['INS{}_ITRANSS'.format(self.base_ikid)]) + return self.naif_keywords['INS{}_ITRANSS'.format(self.base_ikid)] @property def focal2pixel_lines(self): @@ -231,7 +231,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - return list(self.naif_keywords['INS{}_ITRANSL'.format(self.base_ikid)]) + return self.naif_keywords['INS{}_ITRANSL'.format(self.base_ikid)] @property def naif_keywords(self): diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py index 47c8cc20a..3b6fa1a81 100644 --- a/ale/formatters/formatter.py +++ b/ale/formatters/formatter.py @@ -199,8 +199,8 @@ def to_isd(driver): isd['sun_position'] = sun_position if (driver.projection != ""): - isd["projection"] = driver.projection - isd["geotransform"] = driver.geotransform + isd["projection"] = driver_data["projection"] + isd["geotransform"] = driver_data["geotransform"] # check that there is a valid sensor model name if 'name_model' not in isd: diff --git a/ale/transformation.py b/ale/transformation.py index 67ea3c675..8a463e72d 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -127,9 +127,9 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, "targetFrame": sensor_frame, "mission": mission, "ckQuality": "", - "searchKernels": frame_chain.search_kernels}) + "searchKernels": frame_chain.search_kernels}, + use_web=frame_chain.use_web) except Exception as e: - print(e) pass if (len(sensor_times) == 0): @@ -137,7 +137,7 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, if isinstance(sensor_times, np.ndarray): sensor_times = sensor_times.tolist() - frames = frame_chain.frame_trace(center_ephemeris_time, sensor_frame, target_frame, mission) + frames = frame_chain.frame_trace(center_ephemeris_time, sensor_frame, target_frame, nadir, mission) sensor_time_dependent_frames, sensor_constant_frames = frames[0] target_time_dependent_frames, target_constant_frames = frames[1] @@ -155,16 +155,13 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, return frame_chain - def frame_trace(self, time, sensorFrame, targetFrame, mission, nadir=False): - if not self.use_web: - results = [pyspiceql.frameTrace(time, sensorFrame, mission, searchKernels=self.search_kernels)] - results.append(pyspiceql.frameTrace(time, targetFrame, mission, searchKernels=self.search_kernels)) - return results + def frame_trace(self, time, sensorFrame, targetFrame, nadir=False, mission=""): jobs = [] - jobs.append({"et": time, - "initialFrame": sensorFrame, - "mission": mission, - "searchKernels": self.search_kernels}) + if not nadir: + jobs.append({"et": time, + "initialFrame": sensorFrame, + "mission": mission, + "searchKernels": self.search_kernels}) jobs.append({"et": time, "initialFrame": targetFrame, "mission": mission, @@ -173,6 +170,9 @@ def frame_trace(self, time, sensorFrame, targetFrame, mission, nadir=False): jobs = pool.starmap_async(spiceql_call, [("frameTrace", job, self.use_web)for job in jobs]) results = jobs.get() + if nadir: + results.insert(0, [[], []]) + return results @classmethod From a021b54a212e0700ec7764ef316f9c85015dae3e Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 29 Sep 2023 13:27:27 -0700 Subject: [PATCH 26/73] More debugging --- ale/base/data_naif.py | 5 ++++- tests/pytests/test_chandrayaan_driver.py | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 3568d1cae..a1c41fad7 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -552,6 +552,8 @@ def frame_chain(self): print(p_vec[0], v_vec[0], times[0]) rotated_positions = rotation.apply_at(p_vec, times) rotated_velocities = rotation.rotate_velocity_at(p_vec, v_vec, times) + print(rotated_positions[0]) + print(rotated_velocities[0]) p_vec = rotated_positions v_vec = rotated_velocities @@ -559,7 +561,7 @@ def frame_chain(self): velocity_axis = 2 # Get the default line translation with no potential flipping # from the driver - trans_x = np.array(self.focal2pixel_lines) + trans_x = self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)] if (trans_x[0] < trans_x[1]): velocity_axis = 1 @@ -568,6 +570,7 @@ def frame_chain(self): quats = np.array(quats)[:,[1,2,3,0]] rotation = TimeDependentRotation(quats, times, 1, self.sensor_frame_id) + print(rotation) self._frame_chain.add_edge(rotation) return self._frame_chain diff --git a/tests/pytests/test_chandrayaan_driver.py b/tests/pytests/test_chandrayaan_driver.py index 637d7cb73..7410a73cf 100644 --- a/tests/pytests/test_chandrayaan_driver.py +++ b/tests/pytests/test_chandrayaan_driver.py @@ -43,11 +43,11 @@ def test_chandrayaan_mrffr_load(mrffr_kernels): label_file = get_image_label("fsb_00720_1cd_xhu_84n209_v1", label_type="isis3") compare_dict = get_isd("chandrayaan_mrffr") - isd_str = ale.loads(label_file, props={"kernels": mrffr_kernels, "nadir": True}, verbose=True) + isd_str = ale.loads(label_file, props={"kernels": mrffr_kernels, "nadir": True}, verbose=False) isd_obj = json.loads(isd_str) x = compare_dicts(isd_obj, compare_dict) assert x == [] - + assert False # ========= Test chandrayaan isislabel and naifspice driver ========= class test_chandrayaan_isis_naif(unittest.TestCase): From 07ea9a9424c027fe5dd37778695121b5c2f9ca0e Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 2 Oct 2023 13:11:25 -0700 Subject: [PATCH 27/73] More driver fixes --- ale/base/__init__.py | 7 ++++++ ale/base/data_naif.py | 9 +++----- ale/drivers/chandrayaan_drivers.py | 20 ++++++++-------- ale/drivers/lro_drivers.py | 37 +++++++++++++++++++----------- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/ale/base/__init__.py b/ale/base/__init__.py index 935a9f861..56417c299 100644 --- a/ale/base/__init__.py +++ b/ale/base/__init__.py @@ -14,6 +14,8 @@ "DAWN_FC2_FILTER_7": "", "DAWN_FC2_FILTER_8": "", "GLL_SSI_PLATFORM": "galileo", + "HAYABUSA_AMICA": "amica", + "HAYABUSA_NIRS": "nirs", "HAYABUSA2_ONC-W2": "", "JUNO_JUNOCAM": "juno", "LRO_LROCNACL": "lroc", @@ -67,6 +69,11 @@ "LISM_TC1_SDH": "kaguya", "LISM_TC1_STH": "kaguya", "LISM_TC1_SSH": "kaguya", + "LO1_HIGH_RESOLUTION_CAMERA": "", + "LO2_HIGH_RESOLUTION_CAMERA": "", + "LO3_HIGH_RESOLUTION_CAMERA": "", + "LO4_HIGH_RESOLUTION_CAMERA": "", + "LO5_HIGH_RESOLUTION_CAMERA": "", "TGO_CASSIS": "cassis", "VIKING ORBITER 1": "viking1", "VIKING ORBITER 2": "viking2", diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index a1c41fad7..ad7eeb78e 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -548,12 +548,8 @@ def frame_chain(self): # SpiceRotation::setEphemerisTimeNadir rotation = self._frame_chain.compute_rotation(self.target_frame_id, 1) p_vec, v_vec, times = self.sensor_position - print(rotation) - print(p_vec[0], v_vec[0], times[0]) rotated_positions = rotation.apply_at(p_vec, times) rotated_velocities = rotation.rotate_velocity_at(p_vec, v_vec, times) - print(rotated_positions[0]) - print(rotated_velocities[0]) p_vec = rotated_positions v_vec = rotated_velocities @@ -561,7 +557,9 @@ def frame_chain(self): velocity_axis = 2 # Get the default line translation with no potential flipping # from the driver - trans_x = self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)] + trans_x_key = f"INS{self.ikid}_ITRANSL" + trans_x = self.spiceql_call("findMissionKeywords", {"key": trans_x_key, + "mission": self.spiceql_mission})[trans_x_key] if (trans_x[0] < trans_x[1]): velocity_axis = 1 @@ -570,7 +568,6 @@ def frame_chain(self): quats = np.array(quats)[:,[1,2,3,0]] rotation = TimeDependentRotation(quats, times, 1, self.sensor_frame_id) - print(rotation) self._frame_chain.add_edge(rotation) return self._frame_chain diff --git a/ale/drivers/chandrayaan_drivers.py b/ale/drivers/chandrayaan_drivers.py index 150719bdc..1c2184b7b 100644 --- a/ale/drivers/chandrayaan_drivers.py +++ b/ale/drivers/chandrayaan_drivers.py @@ -235,12 +235,14 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - transx = [-1 * self.scaled_pixel_height, self.scaled_pixel_height, 0.0] - transy = [0.0 ,0.0 , 0.0] - transs = [1.0, 1.0 / self.scaled_pixel_height, 0.0] - transl = [0.0, 0.0, 0.0] - return {**super().naif_keywords, - f"INS{self.ikid}_TRANSX": transx, - f"INS{self.ikid}_TRANSY": transy, - f"INS{self.ikid}_ITRANSS": transs, - f"INS{self.ikid}_ITRANSL": transl} + if not hasattr(self, "_naif_keywords"): + transx = [-1 * self.scaled_pixel_height, self.scaled_pixel_height, 0.0] + transy = [0.0 ,0.0 , 0.0] + transs = [1.0, 1.0 / self.scaled_pixel_height, 0.0] + transl = [0.0, 0.0, 0.0] + self._naif_keywords = {**super().naif_keywords, + f"INS{self.ikid}_TRANSX": transx, + f"INS{self.ikid}_TRANSY": transy, + f"INS{self.ikid}_ITRANSS": transs, + f"INS{self.ikid}_ITRANSL": transl} + return self._naif_keywords diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index d91559bba..e3bc62504 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -94,7 +94,7 @@ def odtk(self): : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ - return self.naif_keywords['INS{}_OD_K'.format(self.ikid)].tolist() + return self.naif_keywords['INS{}_OD_K'.format(self.ikid)] @property def light_time_correction(self): @@ -140,7 +140,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = np.array(list(self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)])) / self.sampling_factor + focal2pixel_lines = np.array(self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)]) / self.sampling_factor if self.spacecraft_direction < 0: return -focal2pixel_lines else: @@ -343,7 +343,7 @@ def odtk(self): : list Radial distortion coefficients. There is only one coefficient for LROC NAC l/r """ - return self.naif_keywords['INS{}_OD_K'.format(self.ikid)].tolist() + return self.naif_keywords['INS{}_OD_K'.format(self.ikid)] @property def light_time_correction(self): @@ -421,7 +421,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - focal2pixel_lines = np.array(list(self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)])) / self.sampling_factor + focal2pixel_lines = np.array(self.naif_keywords['INS{}_ITRANSL'.format(self.ikid)]) / self.sampling_factor if self.spacecraft_direction < 0: return -focal2pixel_lines else: @@ -513,18 +513,27 @@ def spacecraft_direction(self): """ if not hasattr(self, "_spacecraft_direction"): frame_chain = self.frame_chain + print("Banan") lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) + print(lro_bus_id) time = self.ephemeris_start_time - lt_state = self.spiceql_call("getTargetState", {'et': time, - 'target': self.target_name, - 'observer': self.spacecraft_name, - 'frame': 'J2000', - 'abcorr': 'None'}) - state = lt_state.starg - velocity = state[3:] + print(time, self.target_name, self.spacecraft_name) + states = self.spiceql_call("getTargetStates", {'ets': [time], + 'target': self.spacecraft_name, + 'observer': self.target_name, + 'frame': 'J2000', + 'abcorr': 'None', + 'mission': self.spiceql_mission, + 'ckQuality': "", + 'spkQuality': ""}) + velocity = states[0][3:6] + print(velocity) rotation = frame_chain.compute_rotation(1, lro_bus_id) + print(rotation._rots.as_matrix()[0]) rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) + print(rotated_velocity[0]) self._spacecraft_direction = rotated_velocity[0] + print(self._spacecraft_direction) return self._spacecraft_direction @@ -1139,7 +1148,7 @@ def odtk(self): : list Radial distortion coefficients. """ - coeffs = self.naif_keywords['INS{}_OD_K'.format(self.fikid)].tolist() + coeffs = self.naif_keywords['INS{}_OD_K'.format(self.fikid)] coeffs = [x * -1 for x in coeffs] return coeffs @@ -1300,7 +1309,7 @@ def focal2pixel_lines(self): : list focal plane to detector lines """ - return list(self.naif_keywords['INS{}_ITRANSL'.format(self.fikid)]) + return self.naif_keywords['INS{}_ITRANSL'.format(self.fikid)] @property def focal2pixel_samples(self): @@ -1312,7 +1321,7 @@ def focal2pixel_samples(self): : list focal plane to detector samples """ - return list(self.naif_keywords['INS{}_ITRANSS'.format(self.fikid)]) + return self.naif_keywords['INS{}_ITRANSS'.format(self.fikid)] @property From 107d1a619d97fa4afacf4012286d3a639b17a3ff Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 2 Oct 2023 13:16:32 -0700 Subject: [PATCH 28/73] Removed debugging prints --- ale/drivers/lro_drivers.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index e3bc62504..326a3261e 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -513,11 +513,8 @@ def spacecraft_direction(self): """ if not hasattr(self, "_spacecraft_direction"): frame_chain = self.frame_chain - print("Banan") lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) - print(lro_bus_id) time = self.ephemeris_start_time - print(time, self.target_name, self.spacecraft_name) states = self.spiceql_call("getTargetStates", {'ets': [time], 'target': self.spacecraft_name, 'observer': self.target_name, @@ -527,13 +524,9 @@ def spacecraft_direction(self): 'ckQuality': "", 'spkQuality': ""}) velocity = states[0][3:6] - print(velocity) rotation = frame_chain.compute_rotation(1, lro_bus_id) - print(rotation._rots.as_matrix()[0]) rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) - print(rotated_velocity[0]) self._spacecraft_direction = rotated_velocity[0] - print(self._spacecraft_direction) return self._spacecraft_direction From ae3abaa902c078a7b73e7918cd3c1bb0aad6221a Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 2 Oct 2023 14:48:57 -0700 Subject: [PATCH 29/73] Got all load tests passing --- ale/base/__init__.py | 2 + ale/base/base.py | 5 ++- ale/base/data_naif.py | 2 +- ale/drivers/mariner_drivers.py | 18 ++++++++- ale/drivers/mex_drivers.py | 2 +- ale/drivers/nh_drivers.py | 22 +++++------ ale/drivers/osirisrex_drivers.py | 8 ++-- ale/drivers/selene_drivers.py | 47 ++--------------------- ale/drivers/viking_drivers.py | 2 +- ale/formatters/formatter.py | 7 ---- tests/pytests/test_kaguya_drivers.py | 8 +--- tests/pytests/test_mgs_drivers.py | 3 +- tests/pytests/test_newhorizons_drivers.py | 9 +---- tests/pytests/test_voyager_drivers.py | 3 +- 14 files changed, 47 insertions(+), 91 deletions(-) diff --git a/ale/base/__init__.py b/ale/base/__init__.py index 56417c299..7f4bec72b 100644 --- a/ale/base/__init__.py +++ b/ale/base/__init__.py @@ -23,6 +23,8 @@ "LRO_LROCWAC_UV": "lroc", "LRO_LROCWAC_VIS": "lroc", "LRO_MINIRF": "", + "M10_VIDICON_A": "m10_vidicon_a", + "M10_VIDICON_B": "m10_vidicon_b", "MSGR_MDIS_WAC": "mdis", "MSGR_MDIS_NAC": "mdis", "MEX_HRSC_SRC": "src", diff --git a/ale/base/base.py b/ale/base/base.py index 4a1ce883f..0dee35e3e 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -39,14 +39,15 @@ def __init__(self, file, num_ephem=909, num_quats=909, props={}, parsed_label=No if parsed_label: self._label = parsed_label - def to_dict(self, properties=[]): + def to_dict(self, properties=None): def get_property(prop_name): try: return getattr(self, prop_name) except Exception as e: return None - if not properties: + if properties is None: + properties = [] for attr in dir(self): if isinstance(getattr(self.__class__, attr, None), property): properties.append(attr) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index ad7eeb78e..aee059ab9 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -622,7 +622,7 @@ def ephemeris_stop_time(self): Ephemeris stop time of the image """ if not hasattr(self, "_ephemeris_stop_time"): - self._ephemeris_stop_time = self.spiceql_call("strSclkToEt", {"frameCode": str(self.spacecraft_id), "sclk": self.spacecraft_clock_stop_count, "mission": self.spiceql_mission}) + self._ephemeris_stop_time = self.spiceql_call("strSclkToEt", {"frameCode": self.spacecraft_id, "sclk": self.spacecraft_clock_stop_count, "mission": self.spiceql_mission}) return self._ephemeris_stop_time @property diff --git a/ale/drivers/mariner_drivers.py b/ale/drivers/mariner_drivers.py index 661a7ea9c..8c6cd1194 100644 --- a/ale/drivers/mariner_drivers.py +++ b/ale/drivers/mariner_drivers.py @@ -1,4 +1,4 @@ -import spiceypy as spice +from ale.base import spiceql_mission_map from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel from ale.base.type_sensor import Framer @@ -81,7 +81,9 @@ def ephemeris_start_time(self): : float start time """ - return spice.str2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) - (self.exposure_duration / 2.0) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) - (self.exposure_duration / 2.0) + return self._ephemeris_start_time @property def light_time_correction(self): @@ -97,4 +99,16 @@ def light_time_correction(self): for the different options available. """ return 'NONE' + + @property + def spiceql_mission(self): + """ + Access the mapping between a SpiceQL "mission" and the driver. + The mapping can be found under ale.base.__init__.py + + See Also + -------- + ale.base.__init__.py + """ + return spiceql_mission_map[super().instrument_id] \ No newline at end of file diff --git a/ale/drivers/mex_drivers.py b/ale/drivers/mex_drivers.py index 15da83cdd..b35804d9f 100644 --- a/ale/drivers/mex_drivers.py +++ b/ale/drivers/mex_drivers.py @@ -733,7 +733,7 @@ def ikid(self): Naif ID used to for identifying the instrument in Spice kernels """ if not hasattr(self, "_ikid"): - self._ikid = self.spiceql_call("translateNameToCode", {"frame": "MEX_HRSC_HEAD", "mission": self.spiceql_mission}) + self._ikid = self.spiceql_call("translateNameToCode", {"frame": "MEX_HRSC_SRC", "mission": self.spiceql_mission}) return self._ikid diff --git a/ale/drivers/nh_drivers.py b/ale/drivers/nh_drivers.py index 3a0071459..801a3da76 100644 --- a/ale/drivers/nh_drivers.py +++ b/ale/drivers/nh_drivers.py @@ -1,10 +1,6 @@ import numpy as np -import spiceypy as spice import pvl -from ale import util - -from pyspiceql import pyspiceql from ale.base import Driver from ale.base.type_distortion import NoDistortion, LegendreDistortion from ale.base.data_naif import NaifSpice @@ -321,7 +317,7 @@ def odtx(self): : list Optical distortion x coefficients """ - return self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.parent_id)].tolist() + return self.naif_keywords['INS{}_DISTORTION_COEF_X'.format(self.parent_id)] @property @@ -334,7 +330,7 @@ def odty(self): : list Optical distortion y coefficients """ - return self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.parent_id)].tolist() + return self.naif_keywords['INS{}_DISTORTION_COEF_Y'.format(self.parent_id)] @property def band_times(self): @@ -408,9 +404,10 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - return {**super().naif_keywords, - f"INS{self.parent_id}_DISTORTION_COEF_X": self.odtx, - f"INS{self.parent_id}_DISTORTION_COEF_Y": self.odty} + if not hasattr(self, "_naif_keywords"): + self._naif_keywords = {**super().naif_keywords, + **self.spiceql_call("findMissionKeywords", {"key": f"INS{self.parent_id}_DISTORTION_COEF_*", "mission": self.spiceql_mission})} + return self._naif_keywords class NewHorizonsMvicTdiIsisLabelNaifSpiceDriver(LineScanner, IsisLabel, NaifSpice, LegendreDistortion, Driver): """ @@ -546,9 +543,10 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - return {**super().naif_keywords, - f"INS{self.parent_id}_DISTORTION_COEF_X": self.odtx, - f"INS{self.parent_id}_DISTORTION_COEF_Y": self.odty} + if not hasattr(self, "_naif_keywords"): + self._naif_keywords = {**super().naif_keywords, + **self.spiceql_call("findMissionKeywords", {"key": f"INS{self.parent_id}_DISTORTION_COEF_*", "mission": self.spiceql_mission})} + return self._naif_keywords @property def sensor_model_version(self): diff --git a/ale/drivers/osirisrex_drivers.py b/ale/drivers/osirisrex_drivers.py index b7e2317e5..34359fd29 100644 --- a/ale/drivers/osirisrex_drivers.py +++ b/ale/drivers/osirisrex_drivers.py @@ -78,7 +78,7 @@ def detector_center_line(self): : int The detector line of the principle point """ - return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)]) + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][1]) @property def detector_center_sample(self): @@ -92,7 +92,7 @@ def detector_center_sample(self): The detector sample of the principle point """ - return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)]) + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][0]) @property def filter_name(self): @@ -118,6 +118,6 @@ def odtk(self): Radial distortion coefficients """ if self.filter_name == "UNKNOWN": - return self.naif_keywords['INS{}_OD_K'.format(self.ikid)] + return self.naif_keywords['INS{}_OD_K'.format(self.ikid)][0:3] else: - return self.naif_keywords['INS{ikid}_OD_K_{filter}'.format(ikid = self.ikid, filter = self.filter_name)] + return self.naif_keywords['INS{ikid}_OD_K_{filter}'.format(ikid = self.ikid, filter = self.filter_name)][0:3] diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index fb6c1569b..6abec2d91 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -1417,50 +1417,9 @@ def boresight_y(self): Boresight focal plane x coordinate """ if not hasattr(self, "_boresight_y"): - self._boresight_x = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1] + self._boresight_y = self.naif_keywords['INS{}_BORESIGHT'.format(self.ikid)][1] return self._boresight_y - @property - def usgscsm_distortion_model(self): - """ - Kaguya uses a unique radial distortion model so we need to overwrite the - method packing the distortion model into the ISD. - - from the IK: - - Line-of-sight vector of pixel no. n can be expressed as below. - - Distortion coefficients information: - INS_DISTORTION_COEF_X = ( a0, a1, a2, a3) - INS_DISTORTION_COEF_Y = ( b0, b1, b2, b3), - - Distance r from the center: - r = - (n - INS_CENTER) * INS_PIXEL_SIZE. - - Line-of-sight vector v is calculated as - v[X] = INSBORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , - v[Y] = INSBORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , - v[Z] = INSBORESIGHT[Z] - - Expects odkx and odky to be defined. These should be a list of optical - distortion x and y coefficients respectively. - - Returns - ------- - : dict - radial distortion model - - """ - return { - "kaguyalism": { - "x" : self._odkx, - "y" : self._odky, - "boresight_x" : self.boresight_x, - "boresight_y" : self.boresight_y - } - } - - @property def line_exposure_duration(self): """ @@ -1498,7 +1457,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] self._focal2pixel_samples = [0, 0, -1/pixel_size] return self._focal2pixel_samples @@ -1516,6 +1475,6 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] + pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] self._focal2pixel_lines = [0, 1/pixel_size, 0] return self._focal2pixel_lines diff --git a/ale/drivers/viking_drivers.py b/ale/drivers/viking_drivers.py index 36b42c8cb..15f06c2d8 100644 --- a/ale/drivers/viking_drivers.py +++ b/ale/drivers/viking_drivers.py @@ -107,7 +107,7 @@ def ephemeris_start_time(self): ephemeris start time of the image """ if not hasattr(self, "_ephemeris_start_time"): - self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frame": self.alt_ikid, + self._ephemeris_start_time = self.spiceql_call("strSclkToEt", {"frameCode": self.alt_ikid, "sclk": self.spacecraft_clock_start_count, "mission": self.spiceql_mission}) if self.exposure_duration <= .420: diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py index 3b6fa1a81..fbbc22dd0 100644 --- a/ale/formatters/formatter.py +++ b/ale/formatters/formatter.py @@ -1,13 +1,6 @@ -import json -import numpy as np -from scipy.interpolate import interp1d, BPoly -import time - from networkx.algorithms.shortest_paths.generic import shortest_path -from ale.transformation import FrameChain from ale.base.type_sensor import LineScanner, Framer, Radar, PushFrame -from ale.rotation import ConstantRotation, TimeDependentRotation def to_isd(driver): """ diff --git a/tests/pytests/test_kaguya_drivers.py b/tests/pytests/test_kaguya_drivers.py index 293e127d5..b67d7c3cd 100644 --- a/tests/pytests/test_kaguya_drivers.py +++ b/tests/pytests/test_kaguya_drivers.py @@ -43,12 +43,8 @@ def test_kaguya_load(test_kernels, label_type, image): compare_isd = get_isd(image_dict[image]) label_file = get_image_label(image, label_type) - # isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) - driver = KaguyaTcIsisLabelNaifSpiceDriver(label_file, props={'kernels': test_kernels[image]}) - with driver as active_driver: - print(active_driver.sun_position) - isd_obj = to_isd(active_driver) - # isd_obj = json.loads(isd_str) + isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) + isd_obj = json.loads(isd_str) assert compare_dicts(isd_obj, compare_isd) == [] diff --git a/tests/pytests/test_mgs_drivers.py b/tests/pytests/test_mgs_drivers.py index 5dbe6828c..cf171670b 100644 --- a/tests/pytests/test_mgs_drivers.py +++ b/tests/pytests/test_mgs_drivers.py @@ -24,9 +24,8 @@ def test_nac_load(test_nac_kernels): label_file = get_image_label('m0402852', 'isis') compare_dict = get_isd("mgsmocna") - isd_str = ale.loads(label_file, props={'kernels': test_nac_kernels}, verbose=True) + isd_str = ale.loads(label_file, props={'kernels': test_nac_kernels}) isd_obj = json.loads(isd_str) - print(json.dumps(isd_obj, indent=2)) assert compare_dicts(isd_obj, compare_dict) == [] diff --git a/tests/pytests/test_newhorizons_drivers.py b/tests/pytests/test_newhorizons_drivers.py index 40f09c65d..c97d56085 100644 --- a/tests/pytests/test_newhorizons_drivers.py +++ b/tests/pytests/test_newhorizons_drivers.py @@ -2,13 +2,8 @@ import ale import os import json -import pvl import numpy as np -from ale.drivers import co_drivers -from ale.formatters.isis_formatter import to_isis -from ale.formatters.formatter import to_isd -from ale.base.data_isis import IsisSpice import unittest from unittest.mock import patch @@ -24,8 +19,8 @@ 'mc3_0034948318_0x536_sci_1': get_isd("nhmvic_tdi") } -@pytest.fixture() -def test_kernels(scope="module"): +@pytest.fixture(scope="module") +def test_kernels(): updated_kernels = {} binary_kernels = {} for image in image_dict.keys(): diff --git a/tests/pytests/test_voyager_drivers.py b/tests/pytests/test_voyager_drivers.py index 28904a35f..74c76c96d 100644 --- a/tests/pytests/test_voyager_drivers.py +++ b/tests/pytests/test_voyager_drivers.py @@ -303,9 +303,8 @@ def test_voyager_load(test_kernels, label_type, image): print(test_kernels[image]) label_file = get_image_label(image, label_type) - usgscsm_isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=True) + usgscsm_isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) usgscsm_isd_obj = json.loads(usgscsm_isd_str) - print(json.dumps(usgscsm_isd_obj, indent=2)) isd_name = image compare_dict = get_isd(isd_name) From ad0859600768ae0452965bab60f9fee7f2594b07 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Tue, 7 Nov 2023 15:02:30 -0700 Subject: [PATCH 30/73] Fixed parallel property aquisition in to_dict --- ale/base/base.py | 48 ++++++++++++++++++++++- ale/base/data_naif.py | 22 +++++++---- ale/spiceql_access.py | 88 ++++++------------------------------------- ale/transformation.py | 64 ++++++++++++------------------- 4 files changed, 98 insertions(+), 124 deletions(-) diff --git a/ale/base/base.py b/ale/base/base.py index 0dee35e3e..88069df2e 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -4,6 +4,7 @@ import os from multiprocessing.pool import ThreadPool +import time import pvl class Driver(): @@ -44,6 +45,7 @@ def get_property(prop_name): try: return getattr(self, prop_name) except Exception as e: + print(prop_name, e) return None if properties is None: @@ -52,11 +54,53 @@ def get_property(prop_name): if isinstance(getattr(self.__class__, attr, None), property): properties.append(attr) - data = {} + spice_props = ["ikid", + "ephemeris_start_time", + "ephemeris_stop_time", + "spacecraft_id", + "target_id", + "target_frame_id", + "reference_frame", + "sensor_frame_id"] + + # Remove position and orientation properties + ephemeris_props = ["sensor_position", "sun_position", "frame_chain"] + for prop in ephemeris_props or prop in spice_props: + properties.remove(prop) + + if "fikid" in properties: + properties.remove("fikid") + spice_props.append("fikid") + properties.remove("sensor_orientation") + data = {} + + start = time.time() + with ThreadPool() as pool: + jobs = pool.starmap_async(get_property, [(name,) for name in spice_props]) + jobs = jobs.get() + + for result, property_name in zip(jobs, spice_props): + data[property_name] = result + end = time.time() + print(f"TOTAL SPICE TIME: {end - start}") + + start = time.time() for prop in properties: data[prop] = get_property(prop) - return data + end = time.time() + print(f"TOTAL OTHER TIME: {end - start}") + + start = time.time() + with ThreadPool() as pool: + jobs = pool.starmap_async(get_property, [(name,) for name in ephemeris_props]) + jobs = jobs.get() + + for result, property_name in zip(jobs, ephemeris_props): + data[property_name] = result + end = time.time() + print(f"TOTAL EPHEM TIME: {end - start}") + return data @property def image_lines(self): diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index aee059ab9..fc8b51534 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -1,5 +1,5 @@ import warnings -import asyncio +from multiprocessing.pool import ThreadPool import numpy as np import pyspiceql @@ -463,14 +463,14 @@ def sensor_position(self): # location of the target. For more information, see: # https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/spicelib/spkezr.html if self.correct_lt_to_surface and self.light_time_correction.upper() == 'LT+S': + position_tasks = [] kwargs = {"target": target, "observer": observer, "frame": "J2000", "abcorr": self.light_time_correction, "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - obs_tars = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) - obs_tar_lts = np.array(obs_tars)[:,-1] + position_tasks.append([ephem, "getTargetStates", 400, self.use_web, kwargs]) # ssb to spacecraft kwargs = {"target": observer, @@ -479,9 +479,17 @@ def sensor_position(self): "abcorr": "NONE", "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - ssb_obs = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) - ssb_obs_states = np.array(ssb_obs)[:,0:6] + position_tasks.append([ephem, "getTargetStates", 400, self.use_web, kwargs]) + + # Build graph async + with ThreadPool() as pool: + jobs = pool.starmap_async(spiceql_access.get_ephem_data, position_tasks) + results = jobs.get() + obs_tars, ssb_obs = results + + obs_tar_lts = np.array(obs_tars)[:,-1] + ssb_obs_states = np.array(ssb_obs)[:,0:6] radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt @@ -492,7 +500,7 @@ def sensor_position(self): "abcorr": "NONE", "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - ssb_tars = spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", **kwargs, web=self.use_web) + ssb_tars = spiceql_access.get_ephem_data(adjusted_time, "getTargetStates", web=self.use_web, function_args=kwargs) ssb_tar_states = np.array(ssb_tars)[:,0:6] _states = ssb_tar_states - ssb_obs_states @@ -510,7 +518,7 @@ def sensor_position(self): "abcorr": self.light_time_correction, "mission": self.spiceql_mission, "searchKernels": self.search_kernels} - states = spiceql_access.get_ephem_data(ephem, "getTargetStates", **kwargs, web=self.use_web) + states = spiceql_access.get_ephem_data(ephem, "getTargetStates", web=self.use_web, function_args=kwargs) states = np.array(states)[:,0:6] for state in states: diff --git a/ale/spiceql_access.py b/ale/spiceql_access.py index 404a56a34..46002bad3 100644 --- a/ale/spiceql_access.py +++ b/ale/spiceql_access.py @@ -48,57 +48,7 @@ def check_response(response): raise requests.HTTPError(f"Recieved code {response.status_code} from spice server, with error: {response.json()}") if response.json()["statusCode"] != 200: - raise requests.HTTPError(f"Recieved code {response.json()['statusCode']} from spice server, with error: {response.json()}") - - -async def async_spiceql_call(session, function_name = "", function_args = {}, use_web=False): - """ - Interface to SpiceQL (Spice Query Library) for both Offline and Online use - - This function will access the value passed through props defined as `web`. This - value determines the access pattern for spice data. When set to Online, you will - access the SpiceQL service provided through the USGS Astro AWS platform. This service - performs kernel and data aquisition. If set to Offline, you will access locally loaded - kernels, and SpiceQL will do no searching for you. The async version of the function - allows for asynchronous spiceql calls. - - Parameters - ---------- - session : obj - aiohttp client session object - - functions_name : str - String defineing the function to call, properly exposed SpiceQL - functions should map 1-to-1 with endpoints on the service - - function_args : dict - Dictionary of arguments used by the function - - use_web : bool - Boolean value to either use the USGS web service when set to True - or local data when set to False - - Returns : any - Any return from a SpiceQL function - """ - if use_web == False: - func = getattr(pyspiceql, function_name) - return func(**function_args) - - url = "https://spiceql-dev.prod-asc.chs.usgs.gov/v1/" - # url = "https://d68posrslrzct.cloudfront.net/api/spiceql/" - - url += function_name - headers = { - 'accept': '*/*', - 'Content-Type': 'application/json' - } - - clean_function_args = stringify_web_args(function_args) - async with session.get(url, params=clean_function_args, headers=headers, ssl=False) as response: - web_response = await response.json() - return web_response["body"]["return"] - + raise requests.HTTPError(f"Recieved code {response.json()['statusCode']} from spice server, with error: {response.json()['body']}") def spiceql_call(function_name = "", function_args = {}, use_web=False): """ @@ -139,13 +89,12 @@ def spiceql_call(function_name = "", function_args = {}, use_web=False): # Convert any args being passed over the wire to strings clean_function_args = stringify_web_args(function_args) - response = requests.get(url, params=clean_function_args, headers=headers, verify=False) check_response(response) return response.json()["body"]["return"] -def get_ephem_data(times, function_name, batch_size=400, web=False, **kwargs): +def get_ephem_data(times, function_name, batch_size=400, web=False, function_args={}): """ This function provides access to ephemeris data aquisition in spiceql. For the web service there is a limited number of times that can be @@ -187,36 +136,23 @@ def get_ephem_data(times, function_name, batch_size=400, web=False, **kwargs): raise ValueError(f"The function name {function_name} is not supported " "by this function please pass one of the following: " + str(valid_functions)) if not web: - function_args = {**kwargs} - function_args["ets"] = times - ephemeris_data = spiceql_call(function_name, function_args, web) + func_args = {**function_args} + func_args["ets"] = times + ephemeris_data = spiceql_call(function_name, func_args, web) return ephemeris_data batches = math.ceil(len(times) / batch_size) job_args_list = [] for i in range(1, batches+1): batch_times = times[(i - 1) * batch_size: i * batch_size] - function_args = {**kwargs} - function_args["ets"] = batch_times - job_args_list.append(function_args) + func_args = {**function_args} + func_args["ets"] = batch_times + job_args_list.append([function_name, func_args, web]) with ThreadPool() as pool: jobs = pool.starmap_async(spiceql_call, job_args_list) results = jobs.get() - return results - - # tasks = [] - - # async with aiohttp.ClientSession() as session: - # for i in range(1, batches+1): - # batch_times = times[(i - 1) * batch_size: i * batch_size] - # function_args = {**kwargs} - # function_args["ets"] = batch_times - # tasks.append(asyncio.create_task(async_spiceql_call(session, function_name, function_args, use_web=web))) - # responses = await asyncio.gather(*tasks) - # results = [] - # for response in responses: - # results += response - - - # return results + flat_results = [] + for i in results: + flat_results.extend(i) + return flat_results diff --git a/ale/transformation.py b/ale/transformation.py index 8a463e72d..9af626165 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -6,9 +6,7 @@ from networkx.algorithms.shortest_paths.generic import shortest_path import spiceypy as spice -import pyspiceql - -from ale.spiceql_access import get_ephem_data, async_spiceql_call, spiceql_call +from ale.spiceql_access import get_ephem_data, spiceql_call from ale.rotation import ConstantRotation, TimeDependentRotation def create_rotations(rotation_table): @@ -148,10 +146,18 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, constant_frames.extend(target_constant_frames) - # Add all time dependent frame chains to the graph - frame_chain.generate_time_dependent_rotiations(sensor_time_dependent_frames, sensor_times, inst_time_bias, mission) - frame_chain.generate_time_dependent_rotiations(target_time_dependent_frames, target_times, 0, mission) - frame_chain.generate_constant_rotations(constant_frames, ephemeris_times[0], mission) + frame_tasks = [] + # Add all time dependent frame edges to the graph + frame_tasks.append([sensor_time_dependent_frames, sensor_times, inst_time_bias, mission]) + frame_tasks.append([target_time_dependent_frames, target_times, 0, mission]) + + # Add all constant frames to the graph + frame_tasks.append([constant_frames, [ephemeris_times[0]], 0, mission]) + + # Build graph async + with ThreadPool() as pool: + jobs = pool.starmap_async(frame_chain.generate_rotations, frame_tasks) + jobs.get() return frame_chain @@ -167,7 +173,7 @@ def frame_trace(self, time, sensorFrame, targetFrame, nadir=False, mission=""): "mission": mission, "searchKernels": self.search_kernels}) with ThreadPool() as pool: - jobs = pool.starmap_async(spiceql_call, [("frameTrace", job, self.use_web)for job in jobs]) + jobs = pool.starmap_async(spiceql_call, [("frameTrace", job, self.use_web) for job in jobs]) results = jobs.get() if nadir: @@ -360,7 +366,7 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): return times - def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=""): + def generate_rotations(self, frames, times, time_bias, mission=""): """ Computes the time dependent rotations based on a list of tuples that define the relationships between frames as (source, destination) and a list of times to @@ -373,13 +379,13 @@ def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=" times : list A list of times to compute the rotation at """ - quats_and_avs_per_frame = [] + frame_tasks = [] for s, d in frames: - kwargs = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} - quats_and_avs_per_frame.append(get_ephem_data(times, "getTargetOrientations", **kwargs, web=self.use_web)) - # with ThreadPool() as pool: - # jobs = pool.starmap_async(get_ephem_data, frame_tasks) - # quats_and_avs_per_frame = jobs.get() + function_args = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} + frame_tasks.append([times, "getTargetOrientations", 400, self.use_web, function_args]) + with ThreadPool() as pool: + jobs = pool.starmap_async(get_ephem_data, frame_tasks) + quats_and_avs_per_frame = jobs.get() for i, frame in enumerate(frames): quats_and_avs = quats_and_avs_per_frame[i] @@ -396,28 +402,8 @@ def generate_time_dependent_rotiations(self, frames, times, time_bias, mission=" if len(avs) == 0: avs = None biased_times = [time - time_bias for time in times] - rotation = TimeDependentRotation(quats, biased_times, frame[0], frame[1], av=avs) + if len(biased_times) > 1: + rotation = TimeDependentRotation(quats, biased_times, frame[0], frame[1], av=avs) + else: + rotation = ConstantRotation(quats[0], frame[0], frame[1]) self.add_edge(rotation=rotation) - - def generate_constant_rotations(self, frames, time, mission): - quats_and_avs_per_frame = [] - for s, d in frames: - kwargs = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels} - quats_and_avs_per_frame.append(get_ephem_data([time], "getTargetOrientations", **kwargs, web=self.use_web)) - # frame_tasks = [] - # for s, d in frames: - # frame_tasks.append([[time], "getTargetOrientations", d, s, mission, self.search_kernels, self.use_web]) - # with ThreadPool() as pool: - # jobs = pool.starmap_async(get_ephem_data, frame_tasks) - # quats_and_avs_per_frame = jobs.get() - - # Add all constant frame chains to the graph - for i, frame in enumerate(frames): - quats = np.zeros(4) - quat_and_av = quats_and_avs_per_frame[i][0] - quats[:3] = quat_and_av[1:4] - quats[3] = quat_and_av[0] - - rotation = ConstantRotation(quats, frame[0], frame[1]) - - self.add_edge(rotation=rotation) \ No newline at end of file From f6bdee848c9978559cccc39f55add29f2d5f59e1 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Tue, 7 Nov 2023 16:23:05 -0700 Subject: [PATCH 31/73] Removed all spice calls from new dawn driver --- ale/drivers/dawn_drivers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ale/drivers/dawn_drivers.py b/ale/drivers/dawn_drivers.py index 162c8f0db..6e9bffc69 100644 --- a/ale/drivers/dawn_drivers.py +++ b/ale/drivers/dawn_drivers.py @@ -320,7 +320,7 @@ def detector_center_sample(self): : float center detector sample """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)[0]) + 0.5 + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][0]) + 0.5 @property def detector_center_line(self): @@ -338,7 +338,7 @@ def detector_center_line(self): : float center detector line """ - return float(spice.gdpool('INS{}_CCD_CENTER'.format(self.ikid), 0, 2)[1]) + 0.5 + return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][1]) + 0.5 @property def ephemeris_start_time(self): @@ -353,8 +353,7 @@ def ephemeris_start_time(self): ephemeris start time """ if not hasattr(self, '_ephemeris_start_time'): - sclock = self.spacecraft_clock_start_count - self._ephemeris_start_time = spice.scs2e(self.spacecraft_id, sclock) + self._ephemeris_start_time = super().ephemeris_start_time self._ephemeris_start_time += 193.0 / 1000.0 return self._ephemeris_start_time From 079ccdd640dde32dce44fbf7662c66432a561516 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 13 Nov 2023 12:07:12 -0700 Subject: [PATCH 32/73] Only remove sensor_orietation if it exists --- ale/base/base.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ale/base/base.py b/ale/base/base.py index 88069df2e..3e9d546e9 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -71,7 +71,8 @@ def get_property(prop_name): if "fikid" in properties: properties.remove("fikid") spice_props.append("fikid") - properties.remove("sensor_orientation") + if "sensor_orientation" in properties: + properties.remove("sensor_orientation") data = {} From eb30bb3467220a1d30bc9c95e3c05727ad8f11df Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:33:37 -0700 Subject: [PATCH 33/73] Added new spiceql config keys --- ale/base/__init__.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ale/base/__init__.py b/ale/base/__init__.py index 7f4bec72b..5c5e7f08e 100644 --- a/ale/base/__init__.py +++ b/ale/base/__init__.py @@ -5,14 +5,14 @@ "CHANDRAYAAN-1_MRFFR": "mrffr", "CASSINI_ISS_NAC": "cassini", "CASSINI_ISS_WAC": "cassini", - "DAWN_FC2_FILTER_1": "", - "DAWN_FC2_FILTER_2": "", - "DAWN_FC2_FILTER_3": "", - "DAWN_FC2_FILTER_4": "", - "DAWN_FC2_FILTER_5": "", - "DAWN_FC2_FILTER_6": "", - "DAWN_FC2_FILTER_7": "", - "DAWN_FC2_FILTER_8": "", + "DAWN_FC2_FILTER_1": "fc2", + "DAWN_FC2_FILTER_2": "fc2", + "DAWN_FC2_FILTER_3": "fc2", + "DAWN_FC2_FILTER_4": "fc2", + "DAWN_FC2_FILTER_5": "fc2", + "DAWN_FC2_FILTER_6": "fc2", + "DAWN_FC2_FILTER_7": "fc2", + "DAWN_FC2_FILTER_8": "fc2", "GLL_SSI_PLATFORM": "galileo", "HAYABUSA_AMICA": "amica", "HAYABUSA_NIRS": "nirs", @@ -40,10 +40,10 @@ "NEAR EARTH ASTEROID RENDEZVOUS": "", "MSL_MASTCAM_RIGHT": "", "MSL_MASTCAM_LEFT": "", - "NH_LORRI": "", - "NH_RALPH_LEISA": "", - "NH_MVIC": "", - "ISIS_NH_RALPH_MVIC_METHANE": "", + "NH_LORRI": "lorri", + "NH_RALPH_LEISA": "leisa", + "NH_MVIC": "mvic_tdi", + "ISIS_NH_RALPH_MVIC_METHANE": "mvic_framing", "THEMIS_IR": "odyssey", "THEMIS_VIS": "odyssey", "ORX_OCAMS_MAPCAM": "", From 59c94a5a55f268105c6c4c019b1ea0071ed63c87 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:35:36 -0700 Subject: [PATCH 34/73] Ensured try excepts around gdal reads --- ale/base/base.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/ale/base/base.py b/ale/base/base.py index 3e9d546e9..5384e6649 100644 --- a/ale/base/base.py +++ b/ale/base/base.py @@ -408,13 +408,19 @@ def projection(self): with tempfile.NamedTemporaryFile() as tmp: tmp.write(pvl.dumps(self._file)) - geodata = gdal.Open(tempfile.name) + try: + geodata = gdal.Open(tempfile.name) + except: + geodata = None else: # should be a path if not os.path.exists(self._file): self._projection = "" else: - geodata = gdal.Open(self._file) + try: + geodata = gdal.Open(self._file) + except: + geodata = None # Try to get the projection, if we are unsuccessful set it @@ -427,26 +433,32 @@ def projection(self): @property def geotransform(self): - if not hasattr(self, "_geotransform"): + if not hasattr(self, "_geotransform"): + self._geotransform = (0.0, 1.0, 0.0, 0.0, 0.0, 1.0) try: - from osgeo import gdal + from osgeo import gdal except: - self._geotransform = (0.0, 1.0, 0.0, 0.0, 0.0, 1.0) return self._geotransform + geodata = None if isinstance(self._file, pvl.PVLModule): # save it to a temp folder with tempfile.NamedTemporaryFile() as tmp: tmp.write(pvl.dumps(self._file)) - - geodata = gdal.Open(tempfile.name) - self._geotransform = geodata.GetGeoTransform() + try: + geodata = gdal.Open(tempfile.name) + except: + geodata = None else: # should be a path if not os.path.exists(self._file): - self._geotransform = (0.0, 1.0, 0.0, 0.0, 0.0, 1.0) - else: - geodata = gdal.Open(self._file) - self._geotransform = geodata.GetGeoTransform() - + self._geotransform = (0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + else: + try: + geodata = gdal.Open(self._file) + except: + geodata = None + + if geodata != None: + self._geotransform = geodata.GetGeoTransform() return self._geotransform \ No newline at end of file From af88d3768ae0c613de76de43ea2bd064e9f3adcb Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:53:15 -0700 Subject: [PATCH 35/73] Fixed kernel access calls and pixel2focal properties --- ale/base/data_naif.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index fc8b51534..a3ca6d31f 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -11,6 +11,7 @@ from ale.base import spiceql_mission_map from ale.transformation import FrameChain from ale.rotation import TimeDependentRotation +from ale import kernel_access from ale import spiceql_access from ale import spice_root from ale import util @@ -74,11 +75,11 @@ def kernels(self): if not hasattr(self, '_kernels'): if 'kernels' in self._props.keys(): try: - self._kernels = util.get_kernels_from_isis_pvl(self._props['kernels']) + self._kernels = kernel_access.get_kernels_from_isis_pvl(self._props['kernels']) except Exception as e: self._kernels = self._props['kernels'] elif ale.spice_root: - search_results = util.get_metakernels(ale.spice_root, missions=self.short_mission_name, years=self.utc_start_time.year, versions='latest') + search_results = kernel_access.get_metakernels(ale.spice_root, missions=self.short_mission_name, years=self.utc_start_time.year, versions='latest') if search_results['count'] == 0: raise ValueError(f'Failed to find metakernels. mission: {self.short_mission_name}, year:{self.utc_start_time.year}, versions="latest" spice root = "{ale.spice_root}"') @@ -308,7 +309,7 @@ def pixel2focal_x(self): detector to focal plane x """ if not hasattr(self, "_pixel2focal_x"): - self._pixel2focal_x = self.naif_keywords['INS{}_ITRANSX'.format(self.ikid)] + self._pixel2focal_x = self.naif_keywords['INS{}_TRANSX'.format(self.ikid)] return self._pixel2focal_x @property @@ -322,7 +323,7 @@ def pixel2focal_y(self): detector to focal plane y """ if not hasattr(self, "_pixel2focal_y"): - self._pixel2focal_y = self.naif_keywords['INS{}_ITRANSY'.format(self.ikid)] + self._pixel2focal_y = self.naif_keywords['INS{}_TRANSY'.format(self.ikid)] return self._pixel2focal_y @property @@ -350,7 +351,7 @@ def pixel_size(self): : float pixel size """ if not hasattr(self, "_pixel_size"): - self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] * 0.001 + self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)][0] * 0.001 return self._pixel_size @property @@ -443,7 +444,9 @@ def sensor_position(self): : (positions, velocities, times) a tuple containing a list of positions, a list of velocities, and a list of times """ - if not hasattr(self, '_position'): + if not hasattr(self, '_position') or \ + not hasattr(self, '_velocity') or \ + not hasattr(self, '_ephem'): ephem = self.ephemeris_time if isinstance(ephem, np.ndarray): From cadd5bce4f4dcd0ceab1f04e0cb3fea03eb12d72 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:54:09 -0700 Subject: [PATCH 36/73] Added missing dict_merge import in kernel_access --- ale/kernel_access.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ale/kernel_access.py b/ale/kernel_access.py index 997f8bf0b..910c3b97f 100644 --- a/ale/kernel_access.py +++ b/ale/kernel_access.py @@ -14,6 +14,7 @@ from ale.util import get_isis_mission_translations from ale.util import read_pvl from ale.util import search_isis_db +from ale.util import dict_merge def get_metakernels(spice_dir=spice_root, missions=set(), years=set(), versions=set()): """ From bc95db1bcde400d331c62456ff4153346da59b1b Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:54:53 -0700 Subject: [PATCH 37/73] Change av arg to expect an empty list instead of None --- ale/rotation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ale/rotation.py b/ale/rotation.py index aa603d63b..3488a75d9 100644 --- a/ale/rotation.py +++ b/ale/rotation.py @@ -154,7 +154,7 @@ def from_euler(sequence, euler, times, source, dest, degrees=False): rot = Rotation.from_euler(sequence, np.asarray(euler), degrees=degrees) return TimeDependentRotation(rot.as_quat(), times, source, dest) - def __init__(self, quats, times, source, dest, av=None): + def __init__(self, quats, times, source, dest, av=[]): """ Construct a time dependent rotation @@ -181,10 +181,10 @@ def __init__(self, quats, times, source, dest, av=None): self.dest = dest self.quats = quats self.times = np.atleast_1d(times) - if av is not None: + if len(av) != 0: self.av = np.asarray(av) else: - self.av = av + self.av = None def __repr__(self): return f'Time Dependent Rotation Source: {self.source}, Destination: {self.dest}, Quats: {self.quats}, AV: {self.av}, Times: {self.times}' @@ -219,7 +219,7 @@ def inverse(self): if self.av is not None: new_av = -self._rots.apply(self.av) else: - new_av = None + new_av = [] return TimeDependentRotation(self._rots.inv().as_quat(), self.times, self.dest, self.source, av=new_av) def _slerp(self, times): @@ -328,7 +328,7 @@ def __mul__(self, other): other_inverse = other._rot.inv() new_av = np.asarray([other_inverse.apply(av) for av in self.av]) else: - new_av = None + new_av = [] return TimeDependentRotation((self._rots * other._rot).as_quat(), self.times, other.source, self.dest, av=new_av) elif isinstance(other, TimeDependentRotation): merged_times = np.union1d(np.asarray(self.times), np.asarray(other.times)) From ebfefdfa455cb62dffa94ce30b779ab4268c83e8 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:57:29 -0700 Subject: [PATCH 38/73] Fixed import in isis_formatter --- ale/formatters/isis_formatter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ale/formatters/isis_formatter.py b/ale/formatters/isis_formatter.py index fb1a99bf5..2625887f4 100644 --- a/ale/formatters/isis_formatter.py +++ b/ale/formatters/isis_formatter.py @@ -1,3 +1,5 @@ +import time + import json from ale.rotation import ConstantRotation, TimeDependentRotation From 67e65d3e9660802076ce68764bb8b14a69dcb0b1 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:58:10 -0700 Subject: [PATCH 39/73] Changed how driver loading is reported in load/loads --- ale/drivers/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ale/drivers/__init__.py b/ale/drivers/__init__.py index 3103ce65e..a3a6487d1 100644 --- a/ale/drivers/__init__.py +++ b/ale/drivers/__init__.py @@ -1,14 +1,15 @@ import pvl +import datetime +from datetime import datetime +from glob import glob import importlib import inspect from itertools import chain, compress -import os -from glob import glob import json import numpy as np -import datetime -from datetime import datetime +import os +import sys import traceback from ale.formatters.usgscsm_formatter import to_usgscsm @@ -147,7 +148,7 @@ def load(label, props={}, formatter='ale', verbose=False, only_isis_spice=False, for driver in drivers: if verbose: - print(f'Trying {driver}') + print(f'Trying {driver}', file=sys.stderr) try: res = driver(label, props=props, parsed_label=parsed_label) # get instrument_id to force early failure @@ -160,7 +161,6 @@ def load(label, props={}, formatter='ale', verbose=False, only_isis_spice=False, return isd except Exception as e: if verbose: - print(f'Failed: {e}\n') traceback.print_exc() raise Exception('No Such Driver for Label') From 01f6380b4ce807525a959ec087561858fe9e483c Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 16:59:05 -0700 Subject: [PATCH 40/73] Added time dependent and constant rotation flag to generate_rotations --- ale/transformation.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/ale/transformation.py b/ale/transformation.py index 9af626165..b04cfa6c7 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -42,7 +42,7 @@ def create_rotations(rotation_table): rotation_table['AV2'], rotation_table['AV3']]).T else: - av = None + av = [] time_dep_rot = TimeDependentRotation(quats, rotation_table['ET'], root_frame, @@ -148,11 +148,11 @@ def from_spice(cls, sensor_frame, target_frame, center_ephemeris_time, frame_tasks = [] # Add all time dependent frame edges to the graph - frame_tasks.append([sensor_time_dependent_frames, sensor_times, inst_time_bias, mission]) - frame_tasks.append([target_time_dependent_frames, target_times, 0, mission]) + frame_tasks.append([sensor_time_dependent_frames, sensor_times, inst_time_bias, TimeDependentRotation, mission]) + frame_tasks.append([target_time_dependent_frames, target_times, 0, TimeDependentRotation, mission]) # Add all constant frames to the graph - frame_tasks.append([constant_frames, [ephemeris_times[0]], 0, mission]) + frame_tasks.append([constant_frames, [ephemeris_times[0]], 0, ConstantRotation, mission]) # Build graph async with ThreadPool() as pool: @@ -366,9 +366,9 @@ def extract_exact_ck_times(observStart, observEnd, targetFrame): return times - def generate_rotations(self, frames, times, time_bias, mission=""): + def generate_rotations(self, frames, times, time_bias, rotation_type, mission=""): """ - Computes the time dependent rotations based on a list of tuples that define the + Computes the rotations based on a list of tuples that define the relationships between frames as (source, destination) and a list of times to compute the rotation at. The rotations are then appended to the frame chain object @@ -399,10 +399,8 @@ def generate_rotations(self, frames, times, time_bias, mission=""): if (len(quats_and_avs[0]) > 4): avs = np.array(quats_and_avs)[:, 4:] - if len(avs) == 0: - avs = None biased_times = [time - time_bias for time in times] - if len(biased_times) > 1: + if rotation_type == TimeDependentRotation: rotation = TimeDependentRotation(quats, biased_times, frame[0], frame[1], av=avs) else: rotation = ConstantRotation(quats[0], frame[0], frame[1]) From a9ef7e3d2c214bbb2ce5bda6777714fd83a1287e Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:01:41 -0700 Subject: [PATCH 41/73] Updated MRO drivers and tests --- ale/drivers/mro_drivers.py | 2 +- tests/pytests/data/isds/crism_isd.json | 222 +++++++++++++++++++++++- tests/pytests/data/isds/ctx_isd.json | 52 +++++- tests/pytests/data/isds/hirise_isd.json | 130 +++++++++++++- tests/pytests/data/isds/marci_isd.json | 130 +++++++++++++- tests/pytests/test_mro_drivers.py | 68 +++++--- 6 files changed, 564 insertions(+), 40 deletions(-) diff --git a/ale/drivers/mro_drivers.py b/ale/drivers/mro_drivers.py index ad377ba7c..df5744e44 100644 --- a/ale/drivers/mro_drivers.py +++ b/ale/drivers/mro_drivers.py @@ -244,7 +244,7 @@ def naif_keywords(self): : dict Dictionary of keywords and values that ISIS creates and attaches to the label """ - return {**super().naif_keywords, **util.query_kernel_pool(f"*{self.base_ikid}*")} + return {**super().naif_keywords, **self.spiceql_call("findMissionKeywords", {"key": f"*{self.base_ikid}*", "mission": self.spiceql_mission})} @property def sensor_name(self): diff --git a/tests/pytests/data/isds/crism_isd.json b/tests/pytests/data/isds/crism_isd.json index fa0f67e0c..c8ee35a22 100644 --- a/tests/pytests/data/isds/crism_isd.json +++ b/tests/pytests/data/isds/crism_isd.json @@ -327,7 +327,97 @@ 2.0, 0.0, 0.0, - 3.0 + 3.0, + 0.0, + 0.0, + 4.0, + 0.0, + 0.0, + 5.0, + 0.0, + 0.0, + 6.0, + 0.0, + 0.0, + 7.0, + 0.0, + 0.0, + 8.0, + 0.0, + 0.0, + 9.0, + 0.0, + 0.0, + 10.0, + 0.0, + 0.0, + 11.0, + 0.0, + 0.0, + 12.0, + 0.0, + 0.0, + 13.0, + 0.0, + 0.0, + 14.0, + 0.0, + 0.0, + 15.0, + 0.0, + 0.0, + 16.0, + 0.0, + 0.0, + 17.0, + 0.0, + 0.0, + 18.0, + 0.0, + 0.0, + 19.0, + 0.0, + 0.0, + 20.0, + 0.0, + 0.0, + 21.0, + 0.0, + 0.0, + 22.0, + 0.0, + 0.0, + 23.0, + 0.0, + 0.0, + 24.0, + 0.0, + 0.0, + 25.0, + 0.0, + 0.0, + 26.0, + 0.0, + 0.0, + 27.0, + 0.0, + 0.0, + 28.0, + 0.0, + 0.0, + 29.0, + 0.0, + 0.0, + 30.0, + 0.0, + 0.0, + 31.0, + 0.0, + 0.0, + 32.0, + 0.0, + 0.0, + 33.0 ], "FRAME_-74017_NAME": "MRO_CRISM_VNIR", "FRAME_-74017_CENTER": -74.0, @@ -381,7 +471,24 @@ 61339176915162.99, 61899057915627.0, 63521451859691.0, - 65622287643263.0 + 65622287643263.0, + 65888349770746.99, + 67842962942791.0, + 69529271265267.0, + 70724085076049.0, + 71692166304603.0, + 75099259007666.0, + 79809852390453.0, + 83047459403679.0, + 83339739513255.0, + 83670199669409.0, + 83696265279213.0, + 84370208048567.0, + 85222415648003.0, + 85242076343532.98, + 85281866692896.0, + 86114551008961.98, + 281474976710650.0 ], "SCLK01_N_FIELDS_74999": 2.0, "SCLK01_OUTPUT_DELIM_74999": 1.0, @@ -405,7 +512,97 @@ 5164027215872.0, -552398346.816, 1.0, - 7230770577408.0 + 7230770577408.0, + -520862345.816, + 1.0, + 11369919545344.0, + -457703944.816, + 1.0, + 16545271316480.0, + -378734343.816, + 1.0, + 20684420284416.0, + -315575942.816, + 1.0, + 22751163645952.0, + -284039941.816, + 1.0, + 25848447500288.0, + -236779140.816, + 1.0, + 27915190861824.0, + -205243139.81599998, + 1.0, + 29981934223360.0, + -173707138.81599998, + 1.0, + 33090542698496.004, + -126273537.81599998, + 1.0, + 36187826552832.0, + -79012736.816, + 1.0, + 39296435027968.0, + -31579135.816, + 0.99999999999999, + 52973626698957.0, + 177118246.859, + 0.99999852023164, + 52993689169101.0, + 177424375.406, + 1.0, + 52995043929293.01, + 177445047.406, + 1.0000000226389, + 53096363306188.99, + 178991058.44099998, + 1.0000000201904, + 53284625886413.0, + 181863717.499, + 1.0000000150408, + 53363055635660.99, + 183060460.517, + 1.0000000132783, + 53599962770637.0, + 186675376.565, + 1.0000000070773, + 53627742694605.0, + 187099264.568, + 1.0000000106838, + 53774962830541.0, + 189345665.592, + 0.99999997549027, + 53791006043341.0, + 189590465.586, + 1.0, + 53792386231501.01, + 189611525.586, + 0.99999872490489, + 53797217545421.0, + 189685245.49199998, + 1.0000000061688, + 53892831227085.0, + 191144194.501, + 1.0000000031304, + 54018442177741.0, + 193060865.507, + 1.0000000020774, + 54239272283341.0, + 196430465.514, + 1.0, + 54625917840589.01, + 202330208.514, + 0.9999990357606199, + 54630607531213.0, + 202401767.445, + 0.99999999979331, + 54947686296781.01, + 207240005.444, + 0.99999949258425, + 54952723393741.01, + 207316865.40499997, + 0.9999999952330499, + 55103951580365.01 ], "SCLK01_TIME_SYSTEM_74999": 2.0, "SCLK_PARTITION_START_74999": [ @@ -418,7 +615,24 @@ 61228279791616.0, 61339176927232.0, 61899057922048.0, - 63521451868160.0 + 63521451868160.0, + 65622287646719.99, + 65888349782016.0, + 67842962948096.0, + 69529271271424.01, + 70724085088256.0, + 71692166299648.0, + 75099259011072.0, + 79809852407808.0, + 83047459454976.02, + 83339739529216.0, + 83670199697408.0, + 83696265265152.0, + 84370208063487.98, + 85222415663104.0, + 85242076332032.02, + 85281866711040.02, + 86114551070720.0 ], "BODY499_POLE_RA": [ 317.68143, diff --git a/tests/pytests/data/isds/ctx_isd.json b/tests/pytests/data/isds/ctx_isd.json index abdb89adf..5005ad864 100644 --- a/tests/pytests/data/isds/ctx_isd.json +++ b/tests/pytests/data/isds/ctx_isd.json @@ -5086,7 +5086,57 @@ 177424375.406, 1.0, 52995043929293.01, - 177445047.406 + 177445047.406, + 1.0000000226389, + 53096363306188.99, + 178991058.44099998, + 1.0000000201904, + 53284625886413.0, + 181863717.499, + 1.0000000150408, + 53363055635660.99, + 183060460.517, + 1.0000000132783, + 53599962770637.0, + 186675376.565, + 1.0000000070773, + 53627742694605.0, + 187099264.568, + 1.0000000106838, + 53774962830541.0, + 189345665.592, + 0.99999997549027, + 53791006043341.0, + 189590465.586, + 1.0, + 53792386231501.01, + 189611525.586, + 0.99999872490489, + 53797217545421.0, + 189685245.49199998, + 1.0000000061688, + 53892831227085.0, + 191144194.501, + 1.0000000031304, + 54018442177741.0, + 193060865.507, + 1.0000000020774, + 54239272283341.0, + 196430465.514, + 1.0, + 54625917840589.01, + 202330208.514, + 0.9999990357606199, + 54630607531213.0, + 202401767.445, + 0.99999999979331, + 54947686296781.01, + 207240005.444, + 0.99999949258425, + 54952723393741.01, + 207316865.40499997, + 0.9999999952330499, + 55103951580365.01 ], "SCLK01_TIME_SYSTEM_74999": 2.0, "SCLK_PARTITION_START_74999": [ diff --git a/tests/pytests/data/isds/hirise_isd.json b/tests/pytests/data/isds/hirise_isd.json index d23e18cea..be4c94912 100644 --- a/tests/pytests/data/isds/hirise_isd.json +++ b/tests/pytests/data/isds/hirise_isd.json @@ -405,7 +405,24 @@ 61339176915162.99, 61899057915627.0, 63521451859691.0, - 65622287643263.0 + 65622287643263.0, + 65888349770746.99, + 67842962942791.0, + 69529271265267.0, + 70724085076049.0, + 71692166304603.0, + 75099259007666.0, + 79809852390453.0, + 83047459403679.0, + 83339739513255.0, + 83670199669409.0, + 83696265279213.0, + 84370208048567.0, + 85222415648003.0, + 85242076343532.98, + 85281866692896.0, + 86114551008961.98, + 281474976710650.0 ], "SCLK01_N_FIELDS_74999": 2.0, "SCLK01_OUTPUT_DELIM_74999": 1.0, @@ -429,7 +446,97 @@ 5164027215872.0, -552398346.816, 1.0, - 7230770577408.0 + 7230770577408.0, + -520862345.816, + 1.0, + 11369919545344.0, + -457703944.816, + 1.0, + 16545271316480.0, + -378734343.816, + 1.0, + 20684420284416.0, + -315575942.816, + 1.0, + 22751163645952.0, + -284039941.816, + 1.0, + 25848447500288.0, + -236779140.816, + 1.0, + 27915190861824.0, + -205243139.81599998, + 1.0, + 29981934223360.0, + -173707138.81599998, + 1.0, + 33090542698496.004, + -126273537.81599998, + 1.0, + 36187826552832.0, + -79012736.816, + 1.0, + 39296435027968.0, + -31579135.816, + 0.99999999999999, + 52973626698957.0, + 177118246.859, + 0.99999852023164, + 52993689169101.0, + 177424375.406, + 1.0, + 52995043929293.01, + 177445047.406, + 1.0000000226389, + 53096363306188.99, + 178991058.44099998, + 1.0000000201904, + 53284625886413.0, + 181863717.499, + 1.0000000150408, + 53363055635660.99, + 183060460.517, + 1.0000000132783, + 53599962770637.0, + 186675376.565, + 1.0000000070773, + 53627742694605.0, + 187099264.568, + 1.0000000106838, + 53774962830541.0, + 189345665.592, + 0.99999997549027, + 53791006043341.0, + 189590465.586, + 1.0, + 53792386231501.01, + 189611525.586, + 0.99999872490489, + 53797217545421.0, + 189685245.49199998, + 1.0000000061688, + 53892831227085.0, + 191144194.501, + 1.0000000031304, + 54018442177741.0, + 193060865.507, + 1.0000000020774, + 54239272283341.0, + 196430465.514, + 1.0, + 54625917840589.01, + 202330208.514, + 0.9999990357606199, + 54630607531213.0, + 202401767.445, + 0.99999999979331, + 54947686296781.01, + 207240005.444, + 0.99999949258425, + 54952723393741.01, + 207316865.40499997, + 0.9999999952330499, + 55103951580365.01 ], "SCLK01_TIME_SYSTEM_74999": 2.0, "SCLK_PARTITION_START_74999": [ @@ -442,7 +549,24 @@ 61228279791616.0, 61339176927232.0, 61899057922048.0, - 63521451868160.0 + 63521451868160.0, + 65622287646719.99, + 65888349782016.0, + 67842962948096.0, + 69529271271424.01, + 70724085088256.0, + 71692166299648.0, + 75099259011072.0, + 79809852407808.0, + 83047459454976.02, + 83339739529216.0, + 83670199697408.0, + 83696265265152.0, + 84370208063487.98, + 85222415663104.0, + 85242076332032.02, + 85281866711040.02, + 86114551070720.0 ], "BODY499_POLE_RA": [ 317.68143, diff --git a/tests/pytests/data/isds/marci_isd.json b/tests/pytests/data/isds/marci_isd.json index 79c80ebd1..36f466997 100644 --- a/tests/pytests/data/isds/marci_isd.json +++ b/tests/pytests/data/isds/marci_isd.json @@ -4956,7 +4956,24 @@ 61339176915162.99, 61899057915627.0, 63521451859691.0, - 65622287643263.0 + 65622287643263.0, + 65888349770746.99, + 67842962942791.0, + 69529271265267.0, + 70724085076049.0, + 71692166304603.0, + 75099259007666.0, + 79809852390453.0, + 83047459403679.0, + 83339739513255.0, + 83670199669409.0, + 83696265279213.0, + 84370208048567.0, + 85222415648003.0, + 85242076343532.98, + 85281866692896.0, + 86114551008961.98, + 281474976710650.0 ], "SCLK01_N_FIELDS_74999": 2.0, "SCLK01_OUTPUT_DELIM_74999": 1.0, @@ -4980,7 +4997,97 @@ 5164027215872.0, -552398346.816, 1.0, - 7230770577408.0 + 7230770577408.0, + -520862345.816, + 1.0, + 11369919545344.0, + -457703944.816, + 1.0, + 16545271316480.0, + -378734343.816, + 1.0, + 20684420284416.0, + -315575942.816, + 1.0, + 22751163645952.0, + -284039941.816, + 1.0, + 25848447500288.0, + -236779140.816, + 1.0, + 27915190861824.0, + -205243139.81599998, + 1.0, + 29981934223360.0, + -173707138.81599998, + 1.0, + 33090542698496.004, + -126273537.81599998, + 1.0, + 36187826552832.0, + -79012736.816, + 1.0, + 39296435027968.0, + -31579135.816, + 0.99999999999999, + 52973626698957.0, + 177118246.859, + 0.99999852023164, + 52993689169101.0, + 177424375.406, + 1.0, + 52995043929293.01, + 177445047.406, + 1.0000000226389, + 53096363306188.99, + 178991058.44099998, + 1.0000000201904, + 53284625886413.0, + 181863717.499, + 1.0000000150408, + 53363055635660.99, + 183060460.517, + 1.0000000132783, + 53599962770637.0, + 186675376.565, + 1.0000000070773, + 53627742694605.0, + 187099264.568, + 1.0000000106838, + 53774962830541.0, + 189345665.592, + 0.99999997549027, + 53791006043341.0, + 189590465.586, + 1.0, + 53792386231501.01, + 189611525.586, + 0.99999872490489, + 53797217545421.0, + 189685245.49199998, + 1.0000000061688, + 53892831227085.0, + 191144194.501, + 1.0000000031304, + 54018442177741.0, + 193060865.507, + 1.0000000020774, + 54239272283341.0, + 196430465.514, + 1.0, + 54625917840589.01, + 202330208.514, + 0.9999990357606199, + 54630607531213.0, + 202401767.445, + 0.99999999979331, + 54947686296781.01, + 207240005.444, + 0.99999949258425, + 54952723393741.01, + 207316865.40499997, + 0.9999999952330499, + 55103951580365.01 ], "SCLK01_TIME_SYSTEM_74999": 2.0, "SCLK_PARTITION_START_74999": [ @@ -4993,7 +5100,24 @@ 61228279791616.0, 61339176927232.0, 61899057922048.0, - 63521451868160.0 + 63521451868160.0, + 65622287646719.99, + 65888349782016.0, + 67842962948096.0, + 69529271271424.01, + 70724085088256.0, + 71692166299648.0, + 75099259011072.0, + 79809852407808.0, + 83047459454976.02, + 83339739529216.0, + 83670199697408.0, + 83696265265152.0, + 84370208063487.98, + 85222415663104.0, + 85242076332032.02, + 85281866711040.02, + 86114551070720.0 ], "BODY499_POLE_RA": [ 317.68143, diff --git a/tests/pytests/test_mro_drivers.py b/tests/pytests/test_mro_drivers.py index 37a8d6b90..3c400bd5a 100644 --- a/tests/pytests/test_mro_drivers.py +++ b/tests/pytests/test_mro_drivers.py @@ -52,7 +52,7 @@ def test_mro_ctx_load(test_ctx_kernels, label_type, kernel_type): isd_str = ale.loads(label_file) compare_isd = get_isd('ctx_isis') else: - isd_str = ale.loads(label_file, props={'kernels': test_ctx_kernels}, verbose=False) + isd_str = ale.loads(label_file, props={'kernels': test_ctx_kernels}, verbose=True) compare_isd = get_isd('ctx') isd_obj = json.loads(isd_str) @@ -69,7 +69,7 @@ def test_mro_ctx_load(test_ctx_kernels, label_type, kernel_type): def test_mro_hirise_load(test_hirise_kernels, label_type, kernel_type): label_file = get_image_label("PSP_001446_1790_BG12_0", label_type) - isd_str = ale.loads(label_file, props={'kernels': test_hirise_kernels}) + isd_str = ale.loads(label_file, props={'kernels': test_hirise_kernels}, verbose=True) compare_isd = get_isd('hirise') isd_obj = json.loads(isd_str) @@ -129,7 +129,7 @@ def test_sensor_name(self): def test_ephemeris_start_time(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[-74, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - calls = [call('translateNameToCode', {'frame': 'MRO', 'mission': 'ctx', 'searchKernels': False}, False), + calls = [call('NonMemo_translateNameToCode', {'frame': 'MRO', 'mission': 'ctx', 'searchKernels': False}, False), call('strSclkToEt', {'frameCode': -74, 'sclk': '0928283918:060', 'mission': 'ctx', 'searchKernels': False}, False)] spiceql_call.assert_has_calls(calls) spiceql_call.call_count == 2 @@ -137,7 +137,7 @@ def test_ephemeris_start_time(self): def test_ephemeris_stop_time(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[-74, 12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == (12345 + self.driver.exposure_duration * self.driver.image_lines) - calls = [call('translateNameToCode', {'frame': 'MRO', 'mission': 'ctx', 'searchKernels': False}, False), + calls = [call('NonMemo_translateNameToCode', {'frame': 'MRO', 'mission': 'ctx', 'searchKernels': False}, False), call('strSclkToEt', {'frameCode': -74, 'sclk': '0928283918:060', 'mission': 'ctx', 'searchKernels': False}, False)] spiceql_call.assert_has_calls(calls) spiceql_call.call_count == 2 @@ -151,9 +151,9 @@ def test_detector_start_sample(self): def test_detector_center_sample(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[-499, {"frameCode":[-499]}, -74021, {'INS-74021_BORESIGHT_SAMPLE': 12345}, {}]) as spiceql_call: assert self.driver.detector_center_sample == 12345 - .5 - calls = [call('translateNameToCode', {'frame': 'Mars', 'mission': 'ctx', 'searchKernels': False}, False), + calls = [call('NonMemo_translateNameToCode', {'frame': 'Mars', 'mission': 'ctx', 'searchKernels': False}, False), call('getTargetFrameInfo', {'targetId': -499, 'mission': 'ctx', 'searchKernels': False}, False), - call('translateNameToCode', {'frame': 'MRO_CTX', 'mission': 'ctx', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'MRO_CTX', 'mission': 'ctx', 'searchKernels': False}, False), call('findMissionKeywords', {'key': '*-74021*', 'mission': 'ctx', 'searchKernels': False}, False), call('findTargetKeywords', {'key': '*-499*', 'mission': 'ctx', 'searchKernels': False}, False)] spiceql_call.assert_has_calls(calls) @@ -181,9 +181,9 @@ def test_detector_start_sample(self): def test_detector_center_sample(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[-499, {"frameCode":[-499]}, -74021, {'INS-74021_BORESIGHT_SAMPLE': 12345}, {}]) as spiceql_call: assert self.driver.detector_center_sample == 12345 - .5 - calls = [call('translateNameToCode', {'frame': 'MARS', 'mission': 'ctx', 'searchKernels': False}, False), + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS', 'mission': 'ctx', 'searchKernels': False}, False), call('getTargetFrameInfo', {'targetId': -499, 'mission': 'ctx', 'searchKernels': False}, False), - call('translateNameToCode', {'frame': 'MRO_CTX', 'mission': 'ctx', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'MRO_CTX', 'mission': 'ctx', 'searchKernels': False}, False), call('findMissionKeywords', {'key': '*-74021*', 'mission': 'ctx', 'searchKernels': False}, False), call('findTargetKeywords', {'key': '*-499*', 'mission': 'ctx', 'searchKernels': False}, False)] spiceql_call.assert_has_calls(calls) @@ -216,6 +216,7 @@ def test_ephemeris_start_time(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12344.997489375 spiceql_call.assert_called_with('strSclkToEt', {'frameCode': -74999, 'sclk': '848201291:62546', 'mission': 'hirise', 'searchKernels': False}, False) + assert spiceql_call.call_count == 1 def test_exposure_duration(self): assert self.driver.exposure_duration == 0.00033475 @@ -223,7 +224,8 @@ def test_exposure_duration(self): def test_ccd_ikid(self): with patch('ale.spiceql_access.spiceql_call', return_value=12345) as spiceql_call: assert self.driver.ccd_ikid == 12345 - spiceql_call.assert_called_with('translateNameToCode', {'frame': 'MRO_HIRISE_CCD12', 'mission': 'hirise', 'searchKernels': False}, False) + spiceql_call.assert_called_with('NonMemo_translateNameToCode', {'frame': 'MRO_HIRISE_CCD12', 'mission': 'hirise', 'searchKernels': False}, False) + assert spiceql_call.call_count == 1 def test_sensor_frame_id(self): assert self.driver.sensor_frame_id == -74690 @@ -248,9 +250,10 @@ def test_instrument_id(self): assert self.driver.instrument_id == "MRO_MARCI_VIS" def test_base_ikid(self): - with patch('ale.drivers.mro_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', return_value=12345) as spiceql_call: assert self.driver.base_ikid == 12345 - bods2c.assert_called_with("MRO_MARCI") + spiceql_call.assert_called_with('NonMemo_translateNameToCode', {'frame': 'MRO_MARCI', 'mission': 'marci', 'searchKernels': False}, False) + assert spiceql_call.call_count == 1 def test_flipped_framelets(self): assert self.driver.flipped_framelets == True @@ -268,11 +271,12 @@ def test_compute_marci_time(self): assert times[4] == 62.31875 def test_start_time(self): - with patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c, \ - patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345, 12345]) as spiceql_call: assert self.driver.start_time == 12344.99999125 - bods2c.assert_called_with('MARS RECONNAISSANCE ORBITER') - scs2e.assert_called_with(-12345, '1322269479:177') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS RECONNAISSANCE ORBITER', 'mission': 'marci', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': 12345, 'sclk': '1322269479:177', 'mission': 'marci', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_ephemeris_start_time(self): with patch('ale.drivers.mro_drivers.MroMarciIsisLabelNaifSpiceDriver.compute_marci_time') as compute_marci_time: @@ -293,16 +297,16 @@ def test_detector_center_line(self): assert self.driver.detector_center_line == 0 def test_focal2pixel_samples(self): - with patch('ale.drivers.mro_drivers.spice.gdpool', return_value=[0.0, 111.11111111111, 0.0]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal2pixel_samples == [0.0, 111.11111111111, 0.0] - gdpool.assert_called_with('INS-12345_ITRANSS', 0, 3) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_ITRANSS": [0.0, 111.11111111111, 0.0]} + assert self.driver.focal2pixel_samples == [0.0, 111.11111111111, 0.0] def test_focal2pixel_lines(self): - with patch('ale.drivers.mro_drivers.spice.gdpool', return_value=[0.0, 0.0, 111.11111111111]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal2pixel_lines == [0.0, 0.0, 111.11111111111] - gdpool.assert_called_with('INS-12345_ITRANSL', 0, 3) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_ITRANSL": [0.0, 0.0, 111.11111111111]} + assert self.driver.focal2pixel_lines == [0.0, 0.0, 111.11111111111] def test_sensor_name(self): assert self.driver.sensor_name == "COLOR IMAGER CAMERA" @@ -321,14 +325,18 @@ def test_instrument_id(self): assert self.driver.instrument_id == "MRO_CRISM_VNIR" def test_ephemeris_start_time(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - scs2e.assert_called_with(-74999, '2/0852246631.07190') + calls = [call('strSclkToEt', {'frameCode': -74999, 'sclk': '2/0852246631.07190', 'mission': 'crism', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephemeris_stop_time(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == 12345 - scs2e.assert_called_with(-74999, '2/0852246634.55318') + calls = [call('strSclkToEt', {'frameCode': -74999, 'sclk': '2/0852246634.55318', 'mission': 'crism', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def spacecraft_name(self): assert self.driver.sensor_name == "MRO" @@ -340,5 +348,9 @@ def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 def test_line_exposure_duration(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345, 12345]) as spiceql_call: assert self.driver.line_exposure_duration == 0.0 + calls = [call('strSclkToEt', {'frameCode': -74999, 'sclk': '2/0852246634.55318', 'mission': 'crism', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -74999, 'sclk': '2/0852246631.07190', 'mission': 'crism', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 From 079392edb6e241d254208cbaec480d9767d430bd Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:03:23 -0700 Subject: [PATCH 42/73] Updated env var tests to not mess with other tests --- tests/pytests/test_env.py | 17 +++++++---- tests/pytests/test_load.py | 59 ++++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/tests/pytests/test_env.py b/tests/pytests/test_env.py index 67a07d160..324a4c0fd 100644 --- a/tests/pytests/test_env.py +++ b/tests/pytests/test_env.py @@ -1,15 +1,20 @@ +import os + import pytest import warnings from importlib import reload +from unittest.mock import patch + import ale -def test_env_not_set(monkeypatch): - monkeypatch.delenv('ALESPICEROOT', raising=False) - reload(ale) +def test_env_not_set(): assert not ale.spice_root -def test_env_set(monkeypatch): - monkeypatch.setenv('ALESPICEROOT', '/foo/bar') +def test_env_set(): + with patch.dict('os.environ', {'ALESPICEROOT': '/foo/bar'}): + reload(ale) + assert ale.spice_root == '/foo/bar' reload(ale) - assert ale.spice_root == '/foo/bar' + assert not ale.spice_root + diff --git a/tests/pytests/test_load.py b/tests/pytests/test_load.py index 8c7e291c3..bed704f35 100644 --- a/tests/pytests/test_load.py +++ b/tests/pytests/test_load.py @@ -1,4 +1,6 @@ import pytest +from unittest.mock import patch + from importlib import reload import json import os @@ -9,6 +11,8 @@ from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice +from ale.drivers.mess_drivers import MessengerMdisPds3NaifSpiceDriver + from conftest import get_image_label, get_image_kernels, convert_kernels @pytest.fixture() @@ -59,39 +63,44 @@ def test_load_invalid_spice_root(monkeypatch): def test_load_mes_from_metakernels(tmpdir, monkeypatch, mess_kernels): - monkeypatch.setenv('ALESPICEROOT', str(tmpdir)) - - # reload module to repopulate ale.spice_root - reload(ale) + with patch.dict('os.environ', {'ALESPICEROOT': str(tmpdir)}): + # reload module to repopulate ale.spice_root + reload(ale) + + updated_kernels = mess_kernels + print(updated_kernels) + label_file = get_image_label('EN1072174528M') + tmpdir.mkdir('mess') + with open(tmpdir.join('mess', 'mess_2015_v1.tm'), 'w+') as mk_file: + mk_str = util.write_metakernel_from_kernel_list(updated_kernels) + print(mk_str) + mk_file.write(mk_str) - updated_kernels = mess_kernels - label_file = get_image_label('EN1072174528M') - tmpdir.mkdir('mess') - with open(tmpdir.join('mess', 'mess_2015_v1.tm'), 'w+') as mk_file: - mk_str = util.write_metakernel_from_kernel_list(updated_kernels) - print(mk_str) - mk_file.write(mk_str) + usgscsm_isd_obj = ale.load(label_file, verbose=True) - usgscsm_isd_obj = ale.load(label_file, verbose=True) assert usgscsm_isd_obj['name_platform'] == 'MESSENGER' assert usgscsm_isd_obj['name_sensor'] == 'MERCURY DUAL IMAGING SYSTEM NARROW ANGLE CAMERA' assert usgscsm_isd_obj['name_model'] == 'USGS_ASTRO_FRAME_SENSOR_MODEL' + reload(ale) + assert not ale.spice_root def test_load_mes_with_no_metakernels(tmpdir, monkeypatch, mess_kernels): - monkeypatch.setenv('ALESPICEROOT', str(tmpdir)) + with patch.dict('os.environ', {'ALESPICEROOT': str(tmpdir)}): + # reload module to repopulate ale.spice_root + reload(ale) - # reload module to repopulate ale.spice_root - reload(ale) + updated_kernels = mess_kernels + label_file = get_image_label('EN1072174528M') + tmpdir.mkdir('mes') - updated_kernels = mess_kernels - label_file = get_image_label('EN1072174528M') - tmpdir.mkdir('mes') + # intentionally make an mk file with wrong year + with open(tmpdir.join('mes', 'mes_2016_v1.tm'), 'w+') as mk_file: + mk_str = util.write_metakernel_from_kernel_list(updated_kernels) + print(mk_str) + mk_file.write(mk_str) - # intentionally make an mk file with wrong year - with open(tmpdir.join('mes', 'mes_2016_v1.tm'), 'w+') as mk_file: - mk_str = util.write_metakernel_from_kernel_list(updated_kernels) - print(mk_str) - mk_file.write(mk_str) + with pytest.raises(Exception): + usgscsm_isd_obj = ale.load(label_file, verbose=True) - with pytest.raises(Exception): - usgscsm_isd_obj = ale.load(label_file, verbose=True) + reload(ale) + assert not ale.spice_root From f59549a60779365a78d5403af678d560eeaaf1da Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:03:54 -0700 Subject: [PATCH 43/73] Updated mixin tests --- tests/pytests/test_cahvor_mixin.py | 5 ++++- tests/pytests/test_data_naif.py | 34 ++++++++++++++++++------------ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/tests/pytests/test_cahvor_mixin.py b/tests/pytests/test_cahvor_mixin.py index ad9b3a68d..0e3a5bb7f 100644 --- a/tests/pytests/test_cahvor_mixin.py +++ b/tests/pytests/test_cahvor_mixin.py @@ -27,6 +27,9 @@ def setUp(self): self.driver.target_frame_id = 10014 self.driver.center_ephemeris_time = 0 self.driver.ephemeris_time = [0] + self.driver.spiceql_mission = "msl" + self.driver.use_web = False + self.driver.search_kernels = False self.driver._props = {} @patch("ale.base.type_sensor.Cahvor.cahvor_camera_dict", new_callable=PropertyMock, return_value=cahvor_camera_dict()) @@ -51,7 +54,7 @@ def test_cahvor_frame_chain(self, final_inst_frame, cahvor_camera_dict, from_spi assert len(frame_chain.nodes()) == 2 assert -76000 in frame_chain.nodes() assert -76562 in frame_chain.nodes() - from_spice.assert_called_with(center_ephemeris_time=0, ephemeris_times=[0], sensor_frame=-76000, target_frame=10014, nadir=False, exact_ck_times=False) + from_spice.assert_called_with(center_ephemeris_time=0, ephemeris_times=[0], sensor_frame=-76000, target_frame=10014, nadir=False, exact_ck_times=False, mission='msl', use_web=False, search_kernels=False) print(frame_chain[-76562][-76000]['rotation'].quat[3]) np.testing.assert_allclose(frame_chain[-76562][-76000]['rotation'].quat, [-0.09914206260782343, 0.3330938313054434, 0.8940825953723198, -0.28255205470925904]) diff --git a/tests/pytests/test_data_naif.py b/tests/pytests/test_data_naif.py index e8047d110..d5f674ff5 100644 --- a/tests/pytests/test_data_naif.py +++ b/tests/pytests/test_data_naif.py @@ -5,7 +5,7 @@ from unittest.mock import patch, PropertyMock import numpy as np -import spiceypy as spice +import pyspiceql from conftest import get_image_kernels, convert_kernels @@ -18,8 +18,9 @@ class test_data_naif(unittest.TestCase): def setUp(self): kernels = get_image_kernels('B10_013341_1010_XN_79S172W') self.updated_kernels, self.binary_kernels = convert_kernels(kernels) - spice.furnsh(self.updated_kernels) + [pyspiceql.KernelPool.getInstance().load(k) for k in self.updated_kernels] self.driver = NaifSpice() + self.driver._props = {} self.driver.instrument_id = 'MRO_CTX' self.driver.spacecraft_name = 'MRO' self.driver.target_name = 'Mars' @@ -29,7 +30,7 @@ def setUp(self): self.driver.center_ephemeris_time = 297088762.61698407 def tearDown(self): - spice.unload(self.updated_kernels) + [pyspiceql.KernelPool.getInstance().unload(k) for k in self.updated_kernels] for kern in self.binary_kernels: os.remove(kern) @@ -40,9 +41,7 @@ def test_spacecraft_id(self): assert self.driver.spacecraft_id == -74 def test_target_frame_id(self): - with patch('ale.base.data_naif.NaifSpice.target_id', new_callable=PropertyMock) as target_id: - target_id.return_value = 499 - assert self.driver.target_frame_id == 10014 + assert self.driver.target_frame_id == 10014 def test_sensor_frame_id(self): assert self.driver.sensor_frame_id == -74021 @@ -121,25 +120,32 @@ def test_nadir_sensor_orientation(self): orientation = self.driver.sensor_orientation np.testing.assert_allclose(orientation[0], [-0.08443224924851939, -0.017974644466439982, -0.9949019866167608, -0.052135827116906064]) + def test_naif_keywords(self): + assert len(self.driver.naif_keywords) == 51 + # Check that each keyword has the ikid, target_id, or the fikid + # or the two we manually add (BODY_FRAME_CODE and BODY_CODE) + for i in self.driver.naif_keywords.keys(): + assert "74999" in i or "-74021" in i or "499" in i or i is "BODY_FRAME_CODE" or i is "BODY_CODE" + def test_light_time_correction_keyword(): - with patch('ale.base.data_naif.spice.gcpool', return_value=['NONE']) as gcpool, \ + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ patch('ale.base.data_naif.NaifSpice.ikid', new_callable=PropertyMock) as ikid: ikid.return_value = -12345 + naif_keywords.return_value = {"INS-12345_LIGHTTIME_CORRECTION": "NONE"} assert NaifSpice().light_time_correction == 'NONE' - gcpool.assert_called_with('INS-12345_LIGHTTIME_CORRECTION', 0, 1) -@pytest.mark.parametrize(("key_val, return_val"), [(['TRUE'], True), (['FALSE'], False)]) +@pytest.mark.parametrize(("key_val, return_val"), [(True, True), (False, False)]) def test_swap_observer_target_keyword(key_val, return_val): - with patch('ale.base.data_naif.spice.gcpool', return_value=key_val) as gcpool, \ + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ patch('ale.base.data_naif.NaifSpice.ikid', new_callable=PropertyMock) as ikid: ikid.return_value = -12345 + naif_keywords.return_value = {"INS-12345_SWAP_OBSERVER_TARGET": key_val} assert NaifSpice().swap_observer_target == return_val - gcpool.assert_called_with('INS-12345_SWAP_OBSERVER_TARGET', 0, 1) -@pytest.mark.parametrize(("key_val, return_val"), [(['TRUE'], True), (['FALSE'], False)]) +@pytest.mark.parametrize(("key_val, return_val"), [(True, True), (False, False)]) def test_correct_lt_to_surface_keyword(key_val, return_val): - with patch('ale.base.data_naif.spice.gcpool', return_value=key_val) as gcpool, \ + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ patch('ale.base.data_naif.NaifSpice.ikid', new_callable=PropertyMock) as ikid: ikid.return_value = -12345 + naif_keywords.return_value = {"INS-12345_LT_SURFACE_CORRECT": key_val} assert NaifSpice().correct_lt_to_surface == return_val - gcpool.assert_called_with('INS-12345_LT_SURFACE_CORRECT', 0, 1) From f165826331171c37309f539627c7cf044ec8ec29 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:05:23 -0700 Subject: [PATCH 44/73] Updated cassini drivers and tests --- ale/drivers/co_drivers.py | 38 ++++--- tests/pytests/test_cassini_drivers.py | 141 ++++++++++++++++---------- 2 files changed, 109 insertions(+), 70 deletions(-) diff --git a/ale/drivers/co_drivers.py b/ale/drivers/co_drivers.py index e50b0d03d..056a681d1 100644 --- a/ale/drivers/co_drivers.py +++ b/ale/drivers/co_drivers.py @@ -4,7 +4,6 @@ import numpy as np import pvl -import spiceypy as spice from pyspiceql import pyspiceql from ale.base import Driver from ale.base.data_naif import NaifSpice @@ -213,10 +212,10 @@ def focal_length(self): """ # default focal defined by IAK kernel if not hasattr(self, "_focal_length"): - try: - default_focal_len = super(CassiniIssPds3LabelNaifSpiceDriver, self).focal_length - except: - default_focal_len = float(self.naif_keywords['INS{}_DEFAULT_FOCAL_LENGTH'.format(self.ikid)]) + try: + default_focal_len = float(self.naif_keywords['INS{}_FOCAL_LENGTH'.format(self.ikid)]) + except: + default_focal_len = float(self.naif_keywords['INS{}_FOV_CENTER_PIXEL'.format(self.ikid)][0]) filters = tuple(self.label["IsisCube"]["BandBin"]['FilterName'].split("/")) @@ -280,11 +279,14 @@ def frame_chain(self): _ = self.spiceql_call("getFrameInfo", {"frame": self.sensor_frame_id, "mission": self.spiceql_mission}) self._frame_chain = super().frame_chain except Exception as e: + nadir = self._props.get('nadir', False) + exact_ck_times = self._props.get('exact_ck_times', True) self._frame_chain = FrameChain.from_spice(sensor_frame=self._original_naif_sensor_frame_id, target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, ephemeris_times=self.ephemeris_time, - exact_ck_times=True, + nadir=nadir, exact_ck_times=exact_ck_times, + inst_time_bias=self.instrument_time_bias, mission=self.spiceql_mission, use_web=self.use_web, search_kernels=self.search_kernels) @@ -446,18 +448,21 @@ def focal_length(self): """ # default focal defined by IK kernel - try: - default_focal_len = super(CassiniIssPds3LabelNaifSpiceDriver, self).focal_length - except: + if not hasattr(self, "_focal_length"): + try: + default_focal_len = float(self.naif_keywords['INS{}_FOCAL_LENGTH'.format(self.ikid)]) + except: default_focal_len = float(self.naif_keywords['INS{}_FOV_CENTER_PIXEL'.format(self.ikid)][0]) - filters = tuple(self.label['FILTER_NAME']) + filters = tuple(self.label['FILTER_NAME']) - if self.instrument_id == "CASSINI_ISS_NAC": - return nac_filter_to_focal_length.get(filters, default_focal_len) + if self.instrument_id == "CASSINI_ISS_NAC": + self._focal_length = nac_filter_to_focal_length.get(filters, default_focal_len) - elif self.instrument_id == "CASSINI_ISS_WAC": - return wac_filter_to_focal_length.get(filters, default_focal_len) + elif self.instrument_id == "CASSINI_ISS_WAC": + self._focal_length = wac_filter_to_focal_length.get(filters, default_focal_len) + + return self._focal_length @property def _original_naif_sensor_frame_id(self): @@ -512,11 +517,14 @@ def frame_chain(self): _ = self.spiceql_call("getFrameInfo", {"frame": self.sensor_frame_id, "mission": self.spiceql_mission}) self._frame_chain = super().frame_chain except Exception as e: + nadir = self._props.get('nadir', False) + exact_ck_times = self._props.get('exact_ck_times', True) self._frame_chain = FrameChain.from_spice(sensor_frame=self._original_naif_sensor_frame_id, target_frame=self.target_frame_id, center_ephemeris_time=self.center_ephemeris_time, ephemeris_times=self.ephemeris_time, - exact_ck_times=True, + nadir=nadir, exact_ck_times=exact_ck_times, + inst_time_bias=self.instrument_time_bias, mission=self.spiceql_mission, use_web=self.use_web, search_kernels=self.search_kernels) diff --git a/tests/pytests/test_cassini_drivers.py b/tests/pytests/test_cassini_drivers.py index 79041a7fc..a4f1a7b64 100644 --- a/tests/pytests/test_cassini_drivers.py +++ b/tests/pytests/test_cassini_drivers.py @@ -6,7 +6,7 @@ import numpy as np from ale.drivers import co_drivers import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import json from conftest import get_image_label, get_image_kernels, get_isd, convert_kernels, compare_dicts, get_table_data @@ -67,16 +67,26 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name == "CASSINI" def test_focal2pixel_samples(self): - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[12.0]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal2pixel_samples == [0.0, 83.33333333333333, 0.0] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {"frameCode": -12345}, -12345, {"INS-12345_PIXEL_SIZE": 12}, {}]) as spiceql_call: + assert self.driver.focal2pixel_samples == [0.0, 83.33333333333333, 0.0] + calls = [call('NonMemo_translateNameToCode', {'frame': 'ENCELADUS', 'mission': 'cassini', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -12345, 'mission': 'cassini', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'CASSINI_ISS_NAC', 'mission': 'cassini', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-12345*', 'mission': 'cassini', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': "*-12345*", 'mission': 'cassini', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 5 def test_focal2pixel_lines(self): - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[12.0]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal2pixel_lines == [0.0, 0.0, 83.33333333333333] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {"frameCode": -12345}, -12345, {"INS-12345_PIXEL_SIZE": 12}, {}]) as spiceql_call: + assert self.driver.focal2pixel_lines == [0.0, 0.0, 83.33333333333333] + calls = [call('NonMemo_translateNameToCode', {'frame': 'ENCELADUS', 'mission': 'cassini', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -12345, 'mission': 'cassini', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'CASSINI_ISS_NAC', 'mission': 'cassini', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-12345*', 'mission': 'cassini', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': "*-12345*", 'mission': 'cassini', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 5 def test_odtk(self): assert self.driver.odtk == [0, -8e-06, 0] @@ -85,27 +95,33 @@ def test_instrument_id(self): assert self.driver.instrument_id == "CASSINI_ISS_NAC" def test_focal_epsilon(self): - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[0.03]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal_epsilon == 0.03 - gdpool.assert_called_with('INS-12345_FL_UNCERTAINTY', 0, 1) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {"frameCode": -12345}, -12345, {"INS-12345_FL_UNCERTAINTY": [0.03]}, {}]) as spiceql_call: + assert self.driver.focal_epsilon == 0.03 + calls = [call('NonMemo_translateNameToCode', {'frame': 'ENCELADUS', 'mission': 'cassini', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -12345, 'mission': 'cassini', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'CASSINI_ISS_NAC', 'mission': 'cassini', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-12345*', 'mission': 'cassini', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': "*-12345*", 'mission': 'cassini', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + spiceql_call.call_count == 5 def test_focal_length(self): # This value isn't used for anything in the test, as it's only used for the # default focal length calculation if the filter can't be found. - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[10.0]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal_length == 2003.09 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {"frameCode": -12345}, -12345, {"INS-12345_FOV_CENTER_PIXEL": [2003.09]}, {}]) as spiceql_call: + assert self.driver.focal_length == 2003.09 + calls = [call('NonMemo_translateNameToCode', {'frame': 'ENCELADUS', 'mission': 'cassini', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -12345, 'mission': 'cassini', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'CASSINI_ISS_NAC', 'mission': 'cassini', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-12345*', 'mission': 'cassini', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': "*-12345*", 'mission': 'cassini', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_detector_center_sample(self): - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[511.5, 511.5]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.detector_center_sample == 512 + assert self.driver.detector_center_sample == 512 def test_detector_center_line(self): - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[511.5, 511.5]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.detector_center_sample == 512 + assert self.driver.detector_center_line == 512 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -115,32 +131,33 @@ def test_sensor_frame_id(self): @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain()) def test_custom_frame_chain(self, from_spice): - with patch('ale.drivers.co_drivers.spice.bods2c', return_value=-12345) as bods2c, \ - patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.target_frame_id', \ - new_callable=PropertyMock) as target_frame_id, \ - patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.ephemeris_start_time', \ - new_callable=PropertyMock) as ephemeris_start_time: - ephemeris_start_time.return_value = .1 + with patch('ale.spiceql_access.spiceql_call', side_effect=[Exception()]) as spiceql_call, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.sensor_frame_id', new_callable=PropertyMock) as sensor_frame_id, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.target_frame_id', new_callable=PropertyMock) as target_frame_id, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver._original_naif_sensor_frame_id', new_callable=PropertyMock) as original_naif_sensor_frame_id, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.center_ephemeris_time', new_callable=PropertyMock) as center_ephemeris_time, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.ephemeris_time', new_callable=PropertyMock) as ephemeris_time: + sensor_frame_id.return_value = 14082360 target_frame_id.return_value = -800 + original_naif_sensor_frame_id.return_value = -12345 + center_ephemeris_time.return_value = 2.4 + ephemeris_time.return_value = [2.4] frame_chain = self.driver.frame_chain assert len(frame_chain.nodes()) == 2 assert 14082360 in frame_chain.nodes() assert -12345 in frame_chain.nodes() - from_spice.assert_called_with(center_ephemeris_time=2.4, ephemeris_times=[2.4], sensor_frame=-12345, target_frame=-800, exact_ck_times=True) + from_spice.assert_called_with(center_ephemeris_time=2.4, ephemeris_times=[2.4], sensor_frame=-12345, target_frame=-800, exact_ck_times=True, nadir=False, inst_time_bias=0, mission='cassini', use_web=False, search_kernels=False) @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain()) def test_custom_frame_chain_iak(self, from_spice): - with patch('ale.drivers.co_drivers.spice.bods2c', return_value=-12345) as bods2c, \ - patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.target_frame_id', \ - new_callable=PropertyMock) as target_frame_id, \ - patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.ephemeris_start_time', \ - new_callable=PropertyMock) as ephemeris_start_time, \ - patch('ale.drivers.co_drivers.spice.frinfo', return_value=True) as frinfo: + with patch('ale.spiceql_access.spiceql_call', side_effect=[0]) as spiceql_call, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.target_frame_id', new_callable=PropertyMock) as target_frame_id, \ + patch('ale.drivers.co_drivers.CassiniIssPds3LabelNaifSpiceDriver.ephemeris_start_time', new_callable=PropertyMock) as ephemeris_start_time: ephemeris_start_time.return_value = .1 target_frame_id.return_value = -800 frame_chain = self.driver.frame_chain assert len(frame_chain.nodes()) == 0 - from_spice.assert_called_with(center_ephemeris_time=2.4, ephemeris_times=[2.4], nadir=False, sensor_frame=14082360, target_frame=-800, exact_ck_times=True, inst_time_bias=0) + from_spice.assert_called_with(center_ephemeris_time=2.4, ephemeris_times=[2.4], nadir=False, sensor_frame=14082360, target_frame=-800, exact_ck_times=True, inst_time_bias=0, mission='cassini', use_web=False, search_kernels=False) # ========= Test cassini isislabel and naifspice driver ========= class test_cassini_isis_naif(unittest.TestCase): @@ -159,15 +176,16 @@ def test_sensor_name(self): assert self.driver.sensor_name == "Imaging Science Subsystem Narrow Angle Camera" def test_ephemeris_start_time(self): - with patch('ale.drivers.co_drivers.spice.str2et', return_value=[12345]) as str2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - str2et.assert_called_with('2011-12-12 05:02:19.773000') + calls = [call('utcToEt', {'utc': '2011-12-12 05:02:19.773000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_center_ephemeris_time(self): - with patch('ale.drivers.co_drivers.spice.str2et', return_value=[12345]) as str2et: - print(self.driver.exposure_duration) + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.center_ephemeris_time == 12347.3 - str2et.assert_called_with('2011-12-12 05:02:19.773000') + calls = [call('utcToEt', {'utc': '2011-12-12 05:02:19.773000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_odtk(self): assert self.driver.odtk == [0, -8e-06, 0] @@ -175,9 +193,14 @@ def test_odtk(self): def test_focal_length(self): # This value isn't used for anything in the test, as it's only used for the # default focal length calculation if the filter can't be found. - with patch('ale.drivers.co_drivers.spice.gdpool', return_value=[10.0]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.focal_length == 2003.09 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, {"frameCode": -12345}, -12345, {"INS-12345_FOV_CENTER_PIXEL": [2003.09]}, {}]) as spiceql_call: + assert self.driver.focal_length == 2003.09 + calls = [call('NonMemo_translateNameToCode', {'frame': 'Enceladus', 'mission': 'cassini', 'searchKernels': False}, False), + call('getTargetFrameInfo', {'targetId': -12345, 'mission': 'cassini', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'CASSINI_ISS_NAC', 'mission': 'cassini', 'searchKernels': False}, False), + call('findMissionKeywords', {'key': '*-12345*', 'mission': 'cassini', 'searchKernels': False}, False), + call('findTargetKeywords', {'key': "*-12345*", 'mission': 'cassini', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -187,29 +210,37 @@ def test_sensor_frame_id(self): @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain()) def test_custom_frame_chain(self, from_spice): - with patch('ale.drivers.co_drivers.spice.bods2c', return_value=-12345) as bods2c, \ + with patch('ale.spiceql_access.spiceql_call', side_effect=[Exception()]) as spiceql_call, \ + patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.sensor_frame_id', \ + new_callable=PropertyMock) as sensor_frame_id, \ patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.target_frame_id', \ - new_callable=PropertyMock) as target_frame_id, \ - patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.ephemeris_start_time', \ - new_callable=PropertyMock) as ephemeris_start_time: - ephemeris_start_time.return_value = .1 + new_callable=PropertyMock) as target_frame_id, \ + patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver._original_naif_sensor_frame_id', \ + new_callable=PropertyMock) as original_naif_sensor_frame_id, \ + patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.center_ephemeris_time', \ + new_callable=PropertyMock) as center_ephemeris_time, \ + patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.ephemeris_time', \ + new_callable=PropertyMock) as ephemeris_time: + sensor_frame_id.return_value = 14082360 target_frame_id.return_value = -800 + original_naif_sensor_frame_id.return_value = -12345 + center_ephemeris_time.return_value = 2.4 + ephemeris_time.return_value = [2.4] frame_chain = self.driver.frame_chain assert len(frame_chain.nodes()) == 2 assert 14082360 in frame_chain.nodes() assert -12345 in frame_chain.nodes() - from_spice.assert_called_with(center_ephemeris_time=2.4000000000000004, ephemeris_times=[2.4000000000000004], sensor_frame=-12345, target_frame=-800, exact_ck_times=True) + from_spice.assert_called_with(center_ephemeris_time=2.4, ephemeris_times=[2.4], sensor_frame=-12345, target_frame=-800, exact_ck_times=True, nadir=False, inst_time_bias=0, mission='cassini', use_web=False, search_kernels=False) @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain()) def test_custom_frame_chain_iak(self, from_spice): - with patch('ale.drivers.co_drivers.spice.bods2c', return_value=-12345) as bods2c, \ + with patch('ale.spiceql_access.spiceql_call', side_effect=[0]) as spiceql_call, \ patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.target_frame_id', \ - new_callable=PropertyMock) as target_frame_id, \ + new_callable=PropertyMock) as target_frame_id, \ patch('ale.drivers.co_drivers.CassiniIssIsisLabelNaifSpiceDriver.ephemeris_start_time', \ - new_callable=PropertyMock) as ephemeris_start_time, \ - patch('ale.drivers.co_drivers.spice.frinfo', return_value=True) as frinfo: + new_callable=PropertyMock) as ephemeris_start_time: ephemeris_start_time.return_value = .1 target_frame_id.return_value = -800 frame_chain = self.driver.frame_chain assert len(frame_chain.nodes()) == 0 - from_spice.assert_called_with(center_ephemeris_time=2.4000000000000004, ephemeris_times=[2.4000000000000004], nadir=False, sensor_frame=14082360, target_frame=-800, exact_ck_times=True, inst_time_bias=0) + from_spice.assert_called_with(center_ephemeris_time=2.4000000000000004, ephemeris_times=[2.4000000000000004], nadir=False, sensor_frame=14082360, target_frame=-800, exact_ck_times=True, inst_time_bias=0, mission='cassini', use_web=False, search_kernels=False) From 90d2913b36f481e3d13e3297e980fdb3c25edd0c Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:06:27 -0700 Subject: [PATCH 45/73] Updated cassis tests --- tests/pytests/test_cassis_drivers.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/pytests/test_cassis_drivers.py b/tests/pytests/test_cassis_drivers.py index b83a3be1c..2d7d3ebf5 100644 --- a/tests/pytests/test_cassis_drivers.py +++ b/tests/pytests/test_cassis_drivers.py @@ -10,7 +10,7 @@ from ale.drivers.tgo_drivers import TGOCassisIsisLabelNaifSpiceDriver import unittest -from unittest.mock import patch +from unittest.mock import patch, call from conftest import get_image_label, get_image_kernels, convert_kernels, compare_dicts, get_isd @@ -46,6 +46,9 @@ def test_instrument_id(self): assert self.driver.instrument_id == "TGO_CASSIS" def test_ephemeris_start_time(self): - with patch("ale.drivers.viking_drivers.spice.utc2et", return_value=12345) as utc2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - utc2et.assert_called_with("2016-11-26 22:32:14.582000") + calls = [call('utcToEt', {'utc': '2016-11-26 22:32:14.582000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 + From b0a4113d3b9d9b50a5b80f53939426a34b1286e6 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:07:24 -0700 Subject: [PATCH 46/73] Updated hayabusa drivers and tests --- ale/drivers/hayabusa_drivers.py | 13 ++++++++---- .../pytests/data/isds/hayabusaamica_isd.json | 8 ++++--- tests/pytests/data/isds/hayabusanirs_isd.json | 8 ++++--- tests/pytests/test_hayabusa_drivers.py | 21 +++++++++++-------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/ale/drivers/hayabusa_drivers.py b/ale/drivers/hayabusa_drivers.py index 04b28b8ee..ed130ff2f 100644 --- a/ale/drivers/hayabusa_drivers.py +++ b/ale/drivers/hayabusa_drivers.py @@ -86,15 +86,20 @@ def sensor_name(self): @property def ephemeris_stop_time(self): """ - Returns the exposure duration of the instrument + Returns the ephemeris stop time of the image. Expects spacecraft_id to + be defined. This must be the integer Naif Id code for the spacecraft. + Expects spacecraft_clock_stop_count to be defined. This must be a string + containing the stop clock count of the spacecraft Returns ------- - : str - Exposure Duration + : double + Ephemeris stop time of the image """ - return spice.scs2e(self.spacecraft_id, self.spacecraft_clock_stop_count) + if not hasattr(self, "_ephemeris_stop_time"): + self._ephemeris_stop_time = self.spiceql_call("strSclkToEt", {"frameCode": self.spacecraft_id, "sclk": self.spacecraft_clock_stop_count, "mission": self.spiceql_mission}) + return self._ephemeris_stop_time @property def exposure_duration(self): diff --git a/tests/pytests/data/isds/hayabusaamica_isd.json b/tests/pytests/data/isds/hayabusaamica_isd.json index 4f4812aa7..d6dda07d4 100644 --- a/tests/pytests/data/isds/hayabusaamica_isd.json +++ b/tests/pytests/data/isds/hayabusaamica_isd.json @@ -111,10 +111,10 @@ 511.5, 511.5 ], - "INS-130102_LT_SURFACE_CORRECT": "FALSE", + "INS-130102_LT_SURFACE_CORRECT": false, "INS-130102_F_NUMBER": 8.0, "INS-130102_PIXEL_SIZE": 1.2e-05, - "INS-130102_SWAP_OBSERVER_TARGET": "TRUE", + "INS-130102_SWAP_OBSERVER_TARGET": true, "INS-130102_PIXEL_SAMPLES": 1024.0, "FRAME_-130102_CLASS": 4.0, "INS-130102_ITRANSL": [ @@ -133,7 +133,9 @@ -0.006144, -0.006144, 0.1204711614, - 0.006144 + 0.006144, + -0.006144, + 0.1204711614 ], "INS-130102_ITRANSS": [ 0.0, diff --git a/tests/pytests/data/isds/hayabusanirs_isd.json b/tests/pytests/data/isds/hayabusanirs_isd.json index 2d80c5fea..b927da2b2 100644 --- a/tests/pytests/data/isds/hayabusanirs_isd.json +++ b/tests/pytests/data/isds/hayabusanirs_isd.json @@ -96,9 +96,9 @@ ], "BODY_FRAME_CODE": 2025143, "BODY_CODE": 2025143, - "INS-130200_SWAP_OBSERVER_TARGET": "TRUE", + "INS-130200_SWAP_OBSERVER_TARGET": true, "FRAME_-130200_CLASS": 4.0, - "INS-130200_LT_SURFACE_CORRECT": "FALSE", + "INS-130200_LT_SURFACE_CORRECT": false, "INS-130200_LIGHTTIME_CORRECTION": "NONE", "INS-130200_FOV_BOUNDARY_CORNERS": [ 0.000872664, @@ -110,7 +110,9 @@ -0.000872664, -0.000872664, 1.0, - 0.000872664 + 0.000872664, + -0.000872664, + 1.0 ], "INS-130200_BORESIGHT_SAMPLE": 0.0, "INS-130200_ITRANSL": [ diff --git a/tests/pytests/test_hayabusa_drivers.py b/tests/pytests/test_hayabusa_drivers.py index f36384cc6..6ce2a76c3 100644 --- a/tests/pytests/test_hayabusa_drivers.py +++ b/tests/pytests/test_hayabusa_drivers.py @@ -1,16 +1,12 @@ import pytest -import numpy as np import os import unittest -from unittest.mock import MagicMock, PropertyMock, patch -import spiceypy as spice +from unittest.mock import patch, call import json from conftest import get_image, get_image_label, get_isd, get_image_kernels, convert_kernels, compare_dicts import ale from ale.drivers.hayabusa_drivers import HayabusaAmicaIsisLabelNaifSpiceDriver, HayabusaNirsIsisLabelNaifSpiceDriver -from ale import util - # AMICA Tests @pytest.fixture(scope='module') @@ -78,11 +74,18 @@ def test_sensor_name(self): assert self.driver.sensor_name == "HAYABUSA_NIRS" def test_exposure_duration(self): - with patch('ale.drivers.hayabusa_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-130, 12345, 12345]) as spiceql_call: assert self.driver.exposure_duration == 0 - scs2e.assert_called_with(-130, '1/2392973413.133') + calls = [call('NonMemo_translateNameToCode', {'frame': 'HAYABUSA', 'mission': 'nirs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -130, 'sclk': '1/2392975548.000', 'mission': 'nirs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -130, 'sclk': '1/2392973413.133', 'mission': 'nirs', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 3 def test_ephemeris_stop_time(self): - with patch('ale.drivers.hayabusa_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-130, 12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == 12345 - scs2e.assert_called_with(-130, '1/2392975548.000') + calls = [call('NonMemo_translateNameToCode', {'frame': 'HAYABUSA', 'mission': 'nirs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -130, 'sclk': '1/2392975548.000', 'mission': 'nirs', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 \ No newline at end of file From dee9e37e3c244a649e4291555dd4ce9e1967a318 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:08:30 -0700 Subject: [PATCH 47/73] Updated juno drivers and tests --- ale/drivers/juno_drivers.py | 2 +- tests/pytests/test_juno_drivers.py | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ale/drivers/juno_drivers.py b/ale/drivers/juno_drivers.py index 1e05ce9c9..c5982a325 100644 --- a/ale/drivers/juno_drivers.py +++ b/ale/drivers/juno_drivers.py @@ -68,4 +68,4 @@ def naif_keywords(self): Dictionary of keywords and values that ISIS creates and attaches to the label """ filter_code = self.label['IsisCube']['BandBin']['NaifIkCode'] - return {**super().naif_keywords, **util.query_kernel_pool(f"*{filter_code}*")} + return {**super().naif_keywords, **self.spiceql_call("findMissionKeywords", {"key": f"*{filter_code}*", "mission": self.spiceql_mission})} diff --git a/tests/pytests/test_juno_drivers.py b/tests/pytests/test_juno_drivers.py index 01aa8271e..48b3643fa 100644 --- a/tests/pytests/test_juno_drivers.py +++ b/tests/pytests/test_juno_drivers.py @@ -1,15 +1,12 @@ import os import json import unittest -from unittest.mock import patch, PropertyMock +from unittest.mock import patch, PropertyMock, call import pytest -import numpy as np -import spiceypy as spice import ale from ale.drivers.juno_drivers import JunoJunoCamIsisLabelNaifSpiceDriver -from ale.base.data_naif import NaifSpice from conftest import get_image_kernels, convert_kernels, get_image_label, compare_dicts, get_isd @@ -42,12 +39,15 @@ def test_instrument_id(self): assert self.driver.instrument_id == "JUNO_JUNOCAM" def test_ephemeris_start_time(self): - with patch('ale.base.data_naif.spice.scs2e', return_value=12345) as scs2e, \ - patch('ale.drivers.juno_drivers.JunoJunoCamIsisLabelNaifSpiceDriver.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-61500) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-61, 12345, -61500]) as spiceql_call, \ + patch('ale.drivers.juno_drivers.JunoJunoCamIsisLabelNaifSpiceDriver.naif_keywords', new_callable=PropertyMock) as naif_keywords: naif_keywords.return_value = {'INS-61500_INTERFRAME_DELTA': .1, 'INS-61500_START_TIME_BIAS': .1} assert self.driver.ephemeris_start_time == 12348.446 - scs2e.assert_called_with(-61500, '525560580:87') + calls = [call('NonMemo_translateNameToCode', {'frame': 'JUNO', 'mission': 'juno', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -61, 'sclk': '525560580:87', 'mission': 'juno', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'JUNO_JUNOCAM', 'mission': 'juno', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 3 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 From 27ca1e739e4a1cfb2e0723335893cc14fb8e3bb4 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:09:44 -0700 Subject: [PATCH 48/73] Updated lunar orbiter drivers and tests --- ale/drivers/lo_drivers.py | 30 +------ tests/pytests/data/isds/lohighcamera_isd.json | 15 +++- tests/pytests/test_lo_drivers.py | 90 +++++-------------- 3 files changed, 37 insertions(+), 98 deletions(-) diff --git a/ale/drivers/lo_drivers.py b/ale/drivers/lo_drivers.py index 7150982c6..4f2889c96 100644 --- a/ale/drivers/lo_drivers.py +++ b/ale/drivers/lo_drivers.py @@ -1,4 +1,3 @@ -import spiceypy as spice import numpy as np from ale.base.data_naif import NaifSpice from ale.base.label_isis import IsisLabel @@ -65,8 +64,9 @@ def ephemeris_start_time(self): : float ephemeris time of the image """ - - return spice.utc2et(self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")) + if not hasattr(self, "_ephemeris_start_time"): + self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + return self._ephemeris_start_time @property def ephemeris_stop_time(self): @@ -83,21 +83,6 @@ def ephemeris_stop_time(self): return self.ephemeris_start_time - - - @property - def ikid(self): - """ - Overridden to grab the ikid from the Isis Cube since there is no way to - obtain this value with a spice bods2c call. - - Returns - ------- - : int - Naif ID used to for identifying the instrument in Spice kernels - """ - return spice.namfrm(self.instrument_id) - @property def detector_center_line(self): """ @@ -125,15 +110,6 @@ def detector_center_sample(self): Detector line of the principal point """ return 0 - - @property - def focal2pixel_samples(self): - return self.naif_keywords[f"INS{self.ikid}_ITRANSS"] - - @property - def focal2pixel_lines(self): - return self.naif_keywords[f"INS{self.ikid}_ITRANSL"] - @property def naif_keywords(self): diff --git a/tests/pytests/data/isds/lohighcamera_isd.json b/tests/pytests/data/isds/lohighcamera_isd.json index d5a1e36d1..54918fcd7 100644 --- a/tests/pytests/data/isds/lohighcamera_isd.json +++ b/tests/pytests/data/isds/lohighcamera_isd.json @@ -175,7 +175,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -187,7 +190,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -200,7 +206,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/test_lo_drivers.py b/tests/pytests/test_lo_drivers.py index 50010ad76..a7c247acb 100644 --- a/tests/pytests/test_lo_drivers.py +++ b/tests/pytests/test_lo_drivers.py @@ -1,17 +1,13 @@ import pytest -import numpy as np import os import unittest -from unittest.mock import MagicMock, PropertyMock, patch -import spiceypy as spice +from unittest.mock import PropertyMock, patch, call import json from conftest import get_image, get_image_label, get_isd, get_image_kernels, convert_kernels, compare_dicts + import ale from ale.drivers.lo_drivers import LoHighCameraIsisLabelNaifSpiceDriver -from ale import util -import pvl - @pytest.fixture(scope='module') def test_high_kernels(): @@ -26,7 +22,7 @@ def test_high_load(test_high_kernels): label_file = get_image_label('3133_high_res_1', 'isis') compare_dict = get_isd("lohighcamera") - isd_str = ale.loads(label_file, props={'kernels': test_high_kernels}, verbose=True) + isd_str = ale.loads(label_file, props={'kernels': test_high_kernels}, verbose=False) isd_obj = json.loads(isd_str) print(json.dumps(isd_obj, indent=2)) assert compare_dicts(isd_obj, compare_dict) == [] @@ -47,88 +43,46 @@ def test_sensor_name(self): assert self.driver.sensor_name == "LO3_HIGH_RESOLUTION_CAMERA" def test_ephemeris_start_time(self): - with patch('ale.drivers.lo_drivers.spice.utc2et', return_value=-1037072690.2047702) as utc2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-1037072690.2047702]) as spiceql_call: assert self.driver.ephemeris_start_time == -1037072690.2047702 - utc2et.assert_called_with("1967-02-20 08:14:28.610000") + calls = [call('utcToEt', {'utc': '1967-02-20 08:14:28.610000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephemeris_stop_time(self): - with patch('ale.drivers.lo_drivers.spice.utc2et', return_value=-1037072690.2047702) as utc2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-1037072690.2047702]) as spiceql_call: assert self.driver.ephemeris_stop_time == -1037072690.2047702 - utc2et.assert_called_with("1967-02-20 08:14:28.610000") + calls = [call('utcToEt', {'utc': '1967-02-20 08:14:28.610000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ikid(self): - with patch('ale.drivers.lo_drivers.spice.namfrm', return_value=-533001) as namfrm: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-533001]) as spiceql_call: assert self.driver.ikid == -533001 - namfrm.assert_called_with("LO3_HIGH_RESOLUTION_CAMERA") + calls = [call('NonMemo_translateNameToCode', {'frame': 'LO3_HIGH_RESOLUTION_CAMERA', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_line(self): assert self.driver.detector_center_line == 0 def test_detector_center_sample(self): assert self.driver.detector_center_sample == 0 - - def test_focal2pixel_samples(self): - with patch('ale.drivers.lo_drivers.LoHighCameraIsisLabelNaifSpiceDriver.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ - patch('ale.drivers.lo_drivers.spice.namfrm', return_value=-533001) as namfrm: - naif_keywords.return_value = {'INS-533001_ITRANSS': [ - 16608.04530570599, - -143.80299143001824, - -0.08167293419694324 - ]} - assert self.driver.focal2pixel_samples == [ - 16608.04530570599, - -143.80299143001824, - -0.08167293419694324 - ] - namfrm.assert_called_with("LO3_HIGH_RESOLUTION_CAMERA") - - def test_focal2pixel_lines(self): - with patch('ale.drivers.lo_drivers.LoHighCameraIsisLabelNaifSpiceDriver.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ - patch('ale.drivers.lo_drivers.spice.namfrm', return_value=-533001) as namfrm: - naif_keywords.return_value = {'INS-533001_ITRANSL': [ - 4541.692430539061, - -0.05845617762411283, - 143.95514969883214 - ]} - assert self.driver.focal2pixel_lines == [ - 4541.692430539061, - -0.05845617762411283, - 143.95514969883214 - ] - namfrm.assert_called_with("LO3_HIGH_RESOLUTION_CAMERA") def test_naif_keywords(self): - with patch('ale.drivers.lo_drivers.LoHighCameraIsisLabelNaifSpiceDriver.ikid', new_callable=PropertyMock) as ikid, \ - patch('ale.base.data_naif.spice.bodvrd', return_value=[1737.4, 1737.4, 1737.4]) as bodvrd: - - ikid.return_value = -533001 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-533001]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as data_naif_keywords: + data_naif_keywords.return_value = {} naif_keywords = { - "BODY_CODE" : 301, - "BODY301_RADII" : 1737.4, - "BODY_FRAME_CODE" : 10020, "INS-533001_TRANSX" : [115.50954565137394, -0.006953956655748381, -3.945326343250231e-06], "INS-533001_TRANSY" : [-31.50245193387461, -2.8238081535064857e-06, 0.0069466064358475335], "INS-533001_ITRANSS" : [16608.04530570599, -143.80299143001824, -0.08167293419694324], "INS-533001_ITRANSL" : [4541.692430539061, -0.05845617762411283, 143.95514969883214] } - assert self.driver.naif_keywords["BODY_CODE"] == naif_keywords["BODY_CODE"] - assert self.driver.naif_keywords["BODY301_RADII"] == naif_keywords["BODY301_RADII"] - assert self.driver.naif_keywords["BODY_FRAME_CODE"] == naif_keywords["BODY_FRAME_CODE"] - - np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_TRANSX"]), - np.asarray(naif_keywords["INS-533001_TRANSX"]), - decimal=10) - np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_TRANSY"]), - np.asarray(naif_keywords["INS-533001_TRANSY"]), - decimal=10) - np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_ITRANSS"]), - np.asarray(naif_keywords["INS-533001_ITRANSS"]), - decimal=10) - np.testing.assert_almost_equal(np.asarray(self.driver.naif_keywords["INS-533001_ITRANSL"]), - np.asarray(naif_keywords["INS-533001_ITRANSL"]), - decimal=10) - - bodvrd.assert_called_with('Moon', 'RADII', 3) + assert self.driver.naif_keywords == naif_keywords + calls = [call('NonMemo_translateNameToCode', {'frame': 'LO3_HIGH_RESOLUTION_CAMERA', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 From 42634998445afc187ac109f6baa189d0db4e925f Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:10:40 -0700 Subject: [PATCH 49/73] Updated clementine tests --- tests/pytests/data/isds/clem_hires_isd.json | 15 +++++-- tests/pytests/data/isds/clem_lwir_isd.json | 15 +++++-- tests/pytests/data/isds/clem_nir_isd.json | 15 +++++-- tests/pytests/data/isds/clem_uvvis_isd.json | 19 +++++--- tests/pytests/test_clementine_drivers.py | 48 +++++++++++++++------ 5 files changed, 85 insertions(+), 27 deletions(-) diff --git a/tests/pytests/data/isds/clem_hires_isd.json b/tests/pytests/data/isds/clem_hires_isd.json index a5ac3fa1e..c705048ae 100644 --- a/tests/pytests/data/isds/clem_hires_isd.json +++ b/tests/pytests/data/isds/clem_hires_isd.json @@ -174,7 +174,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -186,7 +189,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -199,7 +205,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/data/isds/clem_lwir_isd.json b/tests/pytests/data/isds/clem_lwir_isd.json index 982cc6073..ec1d877db 100644 --- a/tests/pytests/data/isds/clem_lwir_isd.json +++ b/tests/pytests/data/isds/clem_lwir_isd.json @@ -174,7 +174,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -186,7 +189,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -199,7 +205,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/data/isds/clem_nir_isd.json b/tests/pytests/data/isds/clem_nir_isd.json index 6ee443ed3..5b886315d 100644 --- a/tests/pytests/data/isds/clem_nir_isd.json +++ b/tests/pytests/data/isds/clem_nir_isd.json @@ -173,7 +173,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -185,7 +188,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -198,7 +204,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/data/isds/clem_uvvis_isd.json b/tests/pytests/data/isds/clem_uvvis_isd.json index 38db515e4..0a5d6127d 100644 --- a/tests/pytests/data/isds/clem_uvvis_isd.json +++ b/tests/pytests/data/isds/clem_uvvis_isd.json @@ -161,7 +161,7 @@ 2.1089410000000002e-05 ], "INS-40021_FILTER_BANDCENTER": 415.0, - "INS-40021_SWAP_OBSERVER_TARGET": "TRUE", + "INS-40021_SWAP_OBSERVER_TARGET": true, "INS-40021_F/RATIO": -999.9999, "INS-40021_BORESIGHT_LINE": 144.5, "INS-40021_FOV_SHAPE": "RECTANGLE", @@ -190,7 +190,7 @@ "INS-40021_CK_REFERENCE_ID": -40000.0, "INS-40021_FOV_FRAME": "CLEM_UVVIS_A", "INS-40021_FOV_ANGLE_UNITS": "DEGREES", - "INS-40021_LT_SURFACE_CORRECT": "TRUE", + "INS-40021_LT_SURFACE_CORRECT": true, "INS-40021_SPK_TIME_BIAS": 0.0, "INS-40021_CCD_CENTER": [ 512.5, @@ -222,7 +222,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -234,7 +237,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -247,7 +253,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/test_clementine_drivers.py b/tests/pytests/test_clementine_drivers.py index fe3449c41..f3232980e 100644 --- a/tests/pytests/test_clementine_drivers.py +++ b/tests/pytests/test_clementine_drivers.py @@ -1,7 +1,7 @@ import os import json import unittest -from unittest.mock import patch +from unittest.mock import patch, call import pytest @@ -88,12 +88,19 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name == "CLEMENTINE_1" def test_ephemeris_start_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 + calls = [call('utcToEt', {'utc': '1994-03-25 15:14:15.347000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephemeris_stop_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: - assert self.driver.ephemeris_stop_time >= 12345 + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: + assert self.driver.ephemeris_stop_time == 12345.0090624 + calls = [call('utcToEt', {'utc': '1994-03-25 15:14:15.347000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 + def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -119,12 +126,17 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name == "CLEMENTINE_1" def test_ephemeris_start_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 + calls = [call('utcToEt', {'utc': '1994-02-19 21:34:01.990000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_ephemeris_stop_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: - assert self.driver.ephemeris_stop_time >= 12345 + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: + assert self.driver.ephemeris_stop_time == 12345.0005015 + calls = [call('utcToEt', {'utc': '1994-02-19 21:34:01.990000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -147,12 +159,17 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name == "CLEMENTINE_1" def test_ephemeris_start_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 + calls = [call('utcToEt', {'utc': '1994-03-11 13:22:45.332000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_ephemeris_stop_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: - assert self.driver.ephemeris_stop_time >= 12345 + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: + assert self.driver.ephemeris_stop_time == 12345.011 + calls = [call('utcToEt', {'utc': '1994-03-11 13:22:45.332000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_sensor_name(self): assert self.driver.sensor_name == "NIR" @@ -184,12 +201,17 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name == "CLEMENTINE_1" def test_ephemeris_start_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 + calls = [call('utcToEt', {'utc': '1994-04-04 17:17:51.263000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) def test_ephemeris_stop_time(self): - with patch('ale.drivers.clementine_drivers.spice.utc2et', return_value=12345) as scs2e: - assert self.driver.ephemeris_stop_time >= 12345 + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: + assert self.driver.ephemeris_stop_time == 12345.000144 + calls = [call('utcToEt', {'utc': '1994-04-04 17:17:51.263000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 From c7c8c2937159a77ba9dcc5968fe260f51806eb7c Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:11:59 -0700 Subject: [PATCH 50/73] Updated chandrayaan tests --- .../data/isds/chandrayaan_mrffr_isd.json | 15 ++++++++++++--- tests/pytests/test_chandrayaan_driver.py | 17 +++++++++++------ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tests/pytests/data/isds/chandrayaan_mrffr_isd.json b/tests/pytests/data/isds/chandrayaan_mrffr_isd.json index 8a1a30102..7a4ca1f40 100644 --- a/tests/pytests/data/isds/chandrayaan_mrffr_isd.json +++ b/tests/pytests/data/isds/chandrayaan_mrffr_isd.json @@ -22976,7 +22976,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -22988,7 +22991,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -23001,7 +23007,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/test_chandrayaan_driver.py b/tests/pytests/test_chandrayaan_driver.py index 7410a73cf..da7376c71 100644 --- a/tests/pytests/test_chandrayaan_driver.py +++ b/tests/pytests/test_chandrayaan_driver.py @@ -8,7 +8,7 @@ from ale.drivers import co_drivers from ale.formatters.formatter import to_isd import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import json from conftest import get_image_label, get_image_kernels, get_isd, convert_kernels, compare_dicts, get_table_data @@ -34,7 +34,7 @@ def test_chandrayaan_load(m3_kernels): label_file = get_image_label("M3T20090630T083407_V03_RDN", label_type="isis") compare_dict = get_isd("chandrayannM3") - isd_str = ale.loads(label_file, props={"kernels": m3_kernels}, verbose=True) + isd_str = ale.loads(label_file, props={"kernels": m3_kernels}, verbose=False) isd_obj = json.loads(isd_str) x = compare_dicts(isd_obj, compare_dict) assert x == [] @@ -43,11 +43,10 @@ def test_chandrayaan_mrffr_load(mrffr_kernels): label_file = get_image_label("fsb_00720_1cd_xhu_84n209_v1", label_type="isis3") compare_dict = get_isd("chandrayaan_mrffr") - isd_str = ale.loads(label_file, props={"kernels": mrffr_kernels, "nadir": True}, verbose=False) + isd_str = ale.loads(label_file, props={"kernels": mrffr_kernels, "nadir": True}, verbose=True) isd_obj = json.loads(isd_str) x = compare_dicts(isd_obj, compare_dict) assert x == [] - assert False # ========= Test chandrayaan isislabel and naifspice driver ========= class test_chandrayaan_isis_naif(unittest.TestCase): @@ -82,12 +81,18 @@ def test_sensor_name(self): assert self.driver.sensor_name == "CHANDRAYAAN-1_MRFFR" def test_ephemeris_start_time(self): - with patch("ale.drivers.chandrayaan_drivers.spice.str2et", return_value=12345) as utc2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 + calls = [call('utcToEt', {'utc': '2009-01-07 16:35:29.466477', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephemeris_stop_time(self): - with patch("ale.drivers.chandrayaan_drivers.spice.str2et", return_value=12345) as utc2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == 12345 + calls = [call('utcToEt', {'utc': '2009-01-07 16:38:07.171000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ikid(self): assert self.driver.ikid == -86001 From 8c42530f23255db9960880726ab9892cfa817fb0 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:12:36 -0700 Subject: [PATCH 51/73] Updated dawn tests --- tests/pytests/test_dawn_drivers.py | 66 +++++++++++++++++++----------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/tests/pytests/test_dawn_drivers.py b/tests/pytests/test_dawn_drivers.py index 62f2e8b3f..e88b4bd20 100644 --- a/tests/pytests/test_dawn_drivers.py +++ b/tests/pytests/test_dawn_drivers.py @@ -6,7 +6,7 @@ import json import unittest -from unittest.mock import patch +from unittest.mock import PropertyMock, patch, call from ale.drivers import AleJsonEncoder from conftest import get_image_label, get_image_kernels, get_isd, convert_kernels, compare_dicts @@ -58,48 +58,61 @@ def test_target_name(self): assert self.driver.target_name == 'CERES' def test_ephemeris_start_time(self): - with patch('ale.drivers.dawn_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[54321, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345.193 - scs2e.assert_called_with(-203, '488002612:246') + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN', 'mission': 'fc2', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': 54321, 'sclk': '488002612:246', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_usgscsm_distortion_model(self): - with patch('ale.drivers.dawn_drivers.spice.gdpool', return_value=np.array([12345])) as gdpool, \ - patch('ale.drivers.dawn_drivers.spice.bods2c', return_value=54321) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_RAD_DIST_COEFF": [12345]} dist = self.driver.usgscsm_distortion_model assert dist['dawnfc']['coefficients'] == [12345] - bods2c.assert_called_with('DAWN_FC2_FILTER_6') - gdpool.assert_called_with('INS54321_RAD_DIST_COEFF', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN_FC2_FILTER_6', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_samples(self): - with patch('ale.drivers.dawn_drivers.spice.gdpool', return_value=np.array([1000])) as gdpool, \ - patch('ale.drivers.dawn_drivers.spice.bods2c', return_value=54321) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": [1000]} assert self.driver.focal2pixel_samples == [0, 1, 0] - bods2c.assert_called_with('DAWN_FC2_FILTER_6') - gdpool.assert_called_with('INS54321_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN_FC2_FILTER_6', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_lines(self): - with patch('ale.drivers.dawn_drivers.spice.gdpool', return_value=np.array([1000])) as gdpool, \ - patch('ale.drivers.dawn_drivers.spice.bods2c', return_value=54321) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": [1000]} assert self.driver.focal2pixel_lines == [0, 0, 1] - bods2c.assert_called_with('DAWN_FC2_FILTER_6') - gdpool.assert_called_with('INS54321_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN_FC2_FILTER_6', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def sensor_model_version(self): assert self.driver.sensor_model_version == 2 def test_detector_center_sample(self): - with patch('ale.drivers.dawn_drivers.spice.gdpool', return_value=np.array([12345, 100])) as gdpool, \ - patch('ale.drivers.dawn_drivers.spice.bods2c', return_value=54321) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_CCD_CENTER": [12345, 100]} assert self.driver.detector_center_sample == 12345.5 - bods2c.assert_called_with('DAWN_FC2_FILTER_6') - gdpool.assert_called_with('INS54321_CCD_CENTER', 0, 2) + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN_FC2_FILTER_6', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_line(self): - with patch('ale.drivers.dawn_drivers.spice.gdpool', return_value=np.array([12345, 100])) as gdpool, \ - patch('ale.drivers.dawn_drivers.spice.bods2c', return_value=54321) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_CCD_CENTER": [12345, 100]} assert self.driver.detector_center_line == 100.5 - bods2c.assert_called_with('DAWN_FC2_FILTER_6') - gdpool.assert_called_with('INS54321_CCD_CENTER', 0, 2) + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN_FC2_FILTER_6', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 # ========= Test isis3label and naifspice driver ========= class test_isis3_naif(unittest.TestCase): @@ -121,7 +134,10 @@ def test_target_name(self): assert self.driver.target_name == 'CERES' def test_ephemeris_start_time(self): - with patch('ale.drivers.dawn_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[54321, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345.193 - scs2e.assert_called_with(-203, '488002612:246') + calls = [call('NonMemo_translateNameToCode', {'frame': 'DAWN', 'mission': 'fc2', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': 54321, 'sclk': '488002612:246', 'mission': 'fc2', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 From 6681941d97a82dbcea987d3e91f764740beb54c7 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:13:14 -0700 Subject: [PATCH 52/73] Updated galileo tests --- tests/pytests/test_galileo_drivers.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/pytests/test_galileo_drivers.py b/tests/pytests/test_galileo_drivers.py index fe9957f0f..f39d72b9b 100644 --- a/tests/pytests/test_galileo_drivers.py +++ b/tests/pytests/test_galileo_drivers.py @@ -1,6 +1,6 @@ import os import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import pytest import json @@ -42,10 +42,13 @@ def setUp(self): self.driver = GalileoSsiIsisLabelNaifSpiceDriver(label) def test_odtk(self): - with patch('ale.base.data_naif.spice.bods2c', return_value=-77001) as bods2c, \ - patch('ale.base.data_naif.spice.gdpool', return_value=-2.4976983626e-05) as gdpool: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-77001]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-77001_K1": -2.4976983626e-05} assert self.driver.odtk == -2.4976983626e-05 - gdpool.assert_called_with("INS-77001_K1", 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'GLL_SSI_PLATFORM', 'mission': 'galileo', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_instrument_id(self): assert self.driver.instrument_id == "GLL_SSI_PLATFORM" @@ -54,14 +57,18 @@ def test_sensor_name(self): assert self.driver.sensor_name == "SOLID STATE IMAGING SYSTEM" def test_ephemeris_start_time(self): - with patch('ale.base.data_naif.spice.str2et', return_value=12345) as str2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - str2et.assert_called_with('1997-02-19 21:07:27.314000') + calls = [call('utcToEt', {'utc': '1997-02-19 21:07:27.314000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephemeris_stop_time(self): - with patch('ale.base.data_naif.spice.str2et', return_value=12345) as str2et: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == 12345.19583 - str2et.assert_called_with('1997-02-19 21:07:27.314000') + calls = [call('utcToEt', {'utc': '1997-02-19 21:07:27.314000', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 From 032a9940ee4a323d88053c66dffe15bef74a901b Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:13:52 -0700 Subject: [PATCH 53/73] Updated kaguya drivers and tests --- ale/drivers/selene_drivers.py | 77 ++++++++-- .../pytests/data/isds/kaguyami_isis_isd.json | 19 ++- tests/pytests/data/isds/kaguyatc_isd.json | 23 ++- .../pytests/data/isds/kaguyatc_isis_isd.json | 23 ++- tests/pytests/test_kaguya_drivers.py | 137 +++++++++++------- 5 files changed, 198 insertions(+), 81 deletions(-) diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index 6abec2d91..48d1e6324 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -307,6 +307,19 @@ def ephemeris_start_time(self): "mission": self.spiceql_mission}) return self._ephemeris_start_time + @property + def pixel_size(self): + """ + Expects ikid to be defined. This must be the integer Naif id code of the instrument + + Returns + ------- + : float pixel size + """ + if not hasattr(self, "_pixel_size"): + self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] + return self._pixel_size + @property def focal2pixel_samples(self): """ @@ -321,8 +334,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - self._focal2pixel_samples = [0, 0, -1/pixel_size] + self._focal2pixel_samples = [0, 0, -1/self.pixel_size] return self._focal2pixel_samples @property @@ -339,8 +351,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - self._focal2pixel_lines = [0, 1/pixel_size, 0] + self._focal2pixel_lines = [0, 1/self.pixel_size, 0] return self._focal2pixel_lines @property @@ -687,6 +698,19 @@ def detector_start_sample(self): start_sample = 1172; return start_sample - 0.5 + @property + def pixel_size(self): + """ + Expects ikid to be defined. This must be the integer Naif id code of the instrument + + Returns + ------- + : float pixel size + """ + if not hasattr(self, "_pixel_size"): + self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] + return self._pixel_size + @property def focal2pixel_lines(self): """ @@ -701,8 +725,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - self._focal2pixel_lines = [0, 1/pixel_size, 0] + self._focal2pixel_lines = [0, 1/self.pixel_size, 0] return self._focal2pixel_lines @property @@ -719,8 +742,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - self._focal2pixel_samples = [0, 0, -1/pixel_size] + self._focal2pixel_samples = [0, 0, -1/self.pixel_size] return self._focal2pixel_samples @property @@ -982,6 +1004,7 @@ def ephemeris_start_time(self): "sclk": self.spacecraft_clock_start_count, "mission": self.spiceql_mission}) return self._ephemeris_start_time + @property def detector_center_line(self): """ @@ -1018,6 +1041,19 @@ def detector_center_sample(self): self._detector_center_sample = self.naif_keywords['INS{}_CENTER'.format(self.ikid)][0] - 0.5 return self._detector_center_sample + @property + def pixel_size(self): + """ + Expects ikid to be defined. This must be the integer Naif id code of the instrument + + Returns + ------- + : float pixel size + """ + if not hasattr(self, "_pixel_size"): + self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] + return self._pixel_size + @property def focal2pixel_samples(self): """ @@ -1032,8 +1068,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] - self._focal2pixel_samples = [0, 0, -1/pixel_size] + self._focal2pixel_samples = [0, 0, -1/self.pixel_size] return self._focal2pixel_samples @property @@ -1050,8 +1085,7 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)[0]] - self._focal2pixel_lines = [0, 1/pixel_size, 0] + self._focal2pixel_lines = [0, 1/self.pixel_size, 0] return self._focal2pixel_lines @property @@ -1443,6 +1477,19 @@ def line_exposure_duration(self): except: return self.label['IsisCube']['Instrument']['CorrectedSamplingInterval'].value * 0.001 # Scale to seconds + @property + def pixel_size(self): + """ + Expects ikid to be defined. This must be the integer Naif id code of the instrument + + Returns + ------- + : float pixel size + """ + if not hasattr(self, "_pixel_size"): + self._pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] + return self._pixel_size + @property def focal2pixel_samples(self): """ @@ -1457,8 +1504,7 @@ def focal2pixel_samples(self): focal plane to detector samples """ if not hasattr(self, "_focal2pixel_samples"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - self._focal2pixel_samples = [0, 0, -1/pixel_size] + self._focal2pixel_samples = [0, 0, -1/self.pixel_size] return self._focal2pixel_samples @property @@ -1475,6 +1521,5 @@ def focal2pixel_lines(self): focal plane to detector lines """ if not hasattr(self, "_focal2pixel_lines"): - pixel_size = self.naif_keywords['INS{}_PIXEL_SIZE'.format(self.ikid)] - self._focal2pixel_lines = [0, 1/pixel_size, 0] + self._focal2pixel_lines = [0, 1/self.pixel_size, 0] return self._focal2pixel_lines diff --git a/tests/pytests/data/isds/kaguyami_isis_isd.json b/tests/pytests/data/isds/kaguyami_isis_isd.json index 7ebadaa72..c0598f2f0 100644 --- a/tests/pytests/data/isds/kaguyami_isis_isd.json +++ b/tests/pytests/data/isds/kaguyami_isis_isd.json @@ -3983,7 +3983,9 @@ -1.5314, -6.4284, 64.9, - -1.4914 + -1.4914, + -6.4284, + 64.9 ], "INS-131341_F_NUMBER": 3.7, "INS-131341_TRANSX": [ @@ -4048,7 +4050,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -4060,7 +4065,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -4073,7 +4081,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/data/isds/kaguyatc_isd.json b/tests/pytests/data/isds/kaguyatc_isd.json index a249a47ab..02a43ce2e 100644 --- a/tests/pytests/data/isds/kaguyatc_isd.json +++ b/tests/pytests/data/isds/kaguyatc_isd.json @@ -4957,14 +4957,14 @@ -142.857142857, 0.0 ], - "INS-131351_LT_SURFACE_CORRECT": "TRUE", + "INS-131351_LT_SURFACE_CORRECT": true, "INS-131351_ITRANSS": [ 0.0, 0.0, -142.857142857 ], "INS-131351_BORESIGHT_LINE": 0.0, - "INS-131351_SWAP_OBSERVER_TARGET": "TRUE", + "INS-131351_SWAP_OBSERVER_TARGET": true, "INS-131351_LIGHTTIME_CORRECTION": "LT+S", "INS-131351_FOV_BOUNDARY_CORNERS": [ -0.069, @@ -4976,7 +4976,9 @@ -0.076, -14.3146, 72.45, - -0.069 + -0.069, + -14.3146, + 72.45 ], "INS-131351_PIXEL_PITCH": 0.007, "INS-131351_CENTER": [ @@ -4998,7 +5000,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -5010,7 +5015,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -5023,7 +5031,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/data/isds/kaguyatc_isis_isd.json b/tests/pytests/data/isds/kaguyatc_isis_isd.json index 09218ad79..d2f20f2bb 100644 --- a/tests/pytests/data/isds/kaguyatc_isis_isd.json +++ b/tests/pytests/data/isds/kaguyatc_isis_isd.json @@ -4957,14 +4957,14 @@ -142.857142857, 0.0 ], - "INS-131351_LT_SURFACE_CORRECT": "TRUE", + "INS-131351_LT_SURFACE_CORRECT": true, "INS-131351_ITRANSS": [ 0.0, 0.0, -142.857142857 ], "INS-131351_BORESIGHT_LINE": 0.0, - "INS-131351_SWAP_OBSERVER_TARGET": "TRUE", + "INS-131351_SWAP_OBSERVER_TARGET": true, "INS-131351_LIGHTTIME_CORRECTION": "LT+S", "INS-131351_FOV_BOUNDARY_CORNERS": [ -0.069, @@ -4976,7 +4976,9 @@ -0.076, -14.3146, 72.45, - -0.069 + -0.069, + -14.3146, + 72.45 ], "INS-131351_PIXEL_PITCH": 0.007, "INS-131351_CENTER": [ @@ -4998,7 +5000,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -5010,7 +5015,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -5023,7 +5031,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/test_kaguya_drivers.py b/tests/pytests/test_kaguya_drivers.py index b67d7c3cd..101e28a67 100644 --- a/tests/pytests/test_kaguya_drivers.py +++ b/tests/pytests/test_kaguya_drivers.py @@ -2,12 +2,10 @@ import json from datetime import datetime, timezone import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import numpy as np import pytest -from ale.drivers import AleJsonEncoder -from ale.formatters.formatter import to_isd from conftest import get_isd, get_image_label, get_image_kernels, convert_kernels, compare_dicts import ale @@ -69,14 +67,18 @@ def test_instrument_id(self): assert self.driver.instrument_id == 'LISM_TC1_STF' def test_sensor_frame_id(self): - with patch('ale.drivers.selene_drivers.spice.namfrm', return_value=12345) as namfrm: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.sensor_frame_id == 12345 - namfrm.assert_called_with('LISM_TC1_HEAD') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1_HEAD', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ikid(self): - with patch('ale.drivers.selene_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ikid == 12345 - bods2c.assert_called_with('LISM_TC1') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_spacecraft_name(self): assert self.driver.spacecraft_name == 'SELENE' @@ -88,22 +90,30 @@ def test_spacecraft_clock_stop_count(self): assert self.driver.spacecraft_clock_stop_count == 922997410.431674 def test_ephemeris_start_time(self): - with patch('ale.drivers.selene_drivers.spice.sct2e', return_value=12345) as sct2e, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - sct2e.assert_called_with(-12345, 922997380.174174) + calls = [call('NonMemo_translateNameToCode', {'frame': 'SELENE', 'mission': 'kaguya', 'searchKernels': False}, False), + call('doubleSclkToEt', {'frameCode': -12345, 'sclk': 922997380.174174, 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_focal2pixel_samples(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([2])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": 2} assert self.driver.focal2pixel_samples == [0, 0, -1/2] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_lines(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([2])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": 2} assert self.driver.focal2pixel_lines == [0, 1/2, 0] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_start_line(self): assert self.driver.detector_start_line == 1 @@ -122,14 +132,18 @@ def test_instrument_id(self): assert self.driver.instrument_id == 'LISM_MI-NIR1' def test_sensor_frame_id(self): - with patch('ale.drivers.selene_drivers.spice.namfrm', return_value=12345) as namfrm: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.sensor_frame_id == 12345 - namfrm.assert_called_with('LISM_MI_N_HEAD') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_MI_N_HEAD', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ikid(self): - with patch('ale.drivers.selene_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ikid == 12345 - bods2c.assert_called_with('LISM_MI-NIR1') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_MI-NIR1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_spacecraft_name(self): assert self.driver.spacecraft_name == 'KAGUYA' @@ -141,35 +155,48 @@ def test_spacecraft_clock_stop_count(self): assert self.driver.spacecraft_clock_stop_count == 905631033.576935 def test_ephemeris_start_time(self): - with patch('ale.drivers.selene_drivers.spice.sct2e', return_value=12345) as sct2e, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - sct2e.assert_called_with(-12345, 905631021.135959) + calls = [call('NonMemo_translateNameToCode', {'frame': 'KAGUYA', 'mission': 'kaguya', 'searchKernels': False}, False), + call('doubleSclkToEt', {'frameCode': -12345, 'sclk': 905631021.135959, 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_detector_center_line(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([54321, 12345])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_CENTER": [54321, 12345]} assert self.driver.detector_center_line == 12344.5 - gdpool.assert_called_with('INS-12345_CENTER', 0, 2) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_MI-NIR1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_sample(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([54321, 12345])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_CENTER": [54321, 12345]} assert self.driver.detector_center_sample == 54320.5 - gdpool.assert_called_with('INS-12345_CENTER', 0, 2) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_MI-NIR1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_samples(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([2])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": 2} assert self.driver.focal2pixel_samples == [0, 0, -1/2] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_MI-NIR1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_lines(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([2])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": 2} assert self.driver.focal2pixel_lines == [0, 1/2, 0] - assert self.driver.focal2pixel_lines == [0, 1/2, 0] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_MI-NIR1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 # ========= Test kaguyatc isis3label and isisspice driver ========= class test_kaguyatc_isis_isis(unittest.TestCase): @@ -228,14 +255,18 @@ def test_instrument_id(self): assert self.driver.instrument_id == 'LISM_TC1_STF' def test_sensor_frame_id(self): - with patch('ale.drivers.selene_drivers.spice.namfrm', return_value=12345) as namfrm: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.sensor_frame_id == 12345 - namfrm.assert_called_with('LISM_TC1_HEAD') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1_HEAD', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ikid(self): - with patch('ale.drivers.selene_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ikid == 12345 - bods2c.assert_called_with('LISM_TC1') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_platform_name(self): assert self.driver.spacecraft_name == 'SELENE' @@ -244,10 +275,12 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name == 'SELENE' def test_ephemeris_start_time(self): - with patch('ale.drivers.selene_drivers.spice.sct2e', return_value=12345) as sct2e, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - sct2e.assert_called_with(-12345, 922997380.174174) + calls = [call('NonMemo_translateNameToCode', {'frame': 'SELENE', 'mission': 'kaguya', 'searchKernels': False}, False), + call('doubleSclkToEt', {'frameCode': -12345, 'sclk': 922997380.174174, 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_detector_start_line(self): assert self.driver.detector_start_line == 1 @@ -256,13 +289,19 @@ def test_detector_start_sample(self): assert self.driver.detector_start_sample == 0.5 def test_focal2pixel_samples(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([2])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": 2} assert self.driver.focal2pixel_samples == [0, 0, -1/2] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_lines(self): - with patch('ale.drivers.selene_drivers.spice.gdpool', return_value=np.array([2])) as gdpool, \ - patch('ale.drivers.selene_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_SIZE": 2} assert self.driver.focal2pixel_lines == [0, 1/2, 0] - gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LISM_TC1', 'mission': 'kaguya', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 From e8592fd40ac2d8ad57c22cd1acff2ea28ad2c9d1 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:14:23 -0700 Subject: [PATCH 54/73] Updated lro drivers and tests --- ale/drivers/lro_drivers.py | 49 ++++--- tests/pytests/data/isds/lrolroc_isd.json | 41 +++++- tests/pytests/test_lro_drivers.py | 174 ++++++++++++++--------- 3 files changed, 165 insertions(+), 99 deletions(-) diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index 326a3261e..0ac8b936d 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -2,7 +2,6 @@ import spiceypy as spice from pyspiceql import pyspiceql -from ale.util import query_kernel_pool from ale.base import Driver from ale.base.data_naif import NaifSpice from ale.base.data_isis import IsisSpice @@ -271,13 +270,15 @@ def spacecraft_direction(self): frame_chain = self.frame_chain lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) time = self.ephemeris_start_time - lt_state = self.spiceql_call("getTargetState", {'et': time, - 'target': self.target_name, - 'observer': self.spacecraft_name, - 'frame': 'J2000', - 'abcorr': 'None'}) - state = lt_state.starg - velocity = state[3:] + lt_states = self.spiceql_call("getTargetStates", {'ets': [time], + 'target': self.spacecraft_name, + 'observer': self.target_name, + 'frame': 'J2000', + 'abcorr': 'None', + 'mission': self.spiceql_mission, + 'ckQuality': "", + 'spkQuality': ""}) + velocity = lt_states[0][3:6] rotation = frame_chain.compute_rotation(1, lro_bus_id) rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) self._spacecraft_direction = rotated_velocity[0] @@ -515,16 +516,18 @@ def spacecraft_direction(self): frame_chain = self.frame_chain lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) time = self.ephemeris_start_time - states = self.spiceql_call("getTargetStates", {'ets': [time], - 'target': self.spacecraft_name, - 'observer': self.target_name, - 'frame': 'J2000', - 'abcorr': 'None', - 'mission': self.spiceql_mission, - 'ckQuality': "", - 'spkQuality': ""}) - velocity = states[0][3:6] + print(time) + lt_states = self.spiceql_call("getTargetStates", {'ets': [time], + 'target': self.spacecraft_name, + 'observer': self.target_name, + 'frame': 'J2000', + 'abcorr': 'None', + 'mission': self.spiceql_mission, + 'ckQuality': "", + 'spkQuality': ""}) + velocity = lt_states[0][3:6] rotation = frame_chain.compute_rotation(1, lro_bus_id) + print(rotation._rots.as_matrix()[0], velocity) rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) self._spacecraft_direction = rotated_velocity[0] return self._spacecraft_direction @@ -1158,12 +1161,12 @@ def naif_keywords(self): Dictionary of keywords and values that ISIS creates and attaches to the label """ _naifKeywords = {**super().naif_keywords, - **query_kernel_pool("*_FOCAL_LENGTH"), - **query_kernel_pool("*_BORESIGHT_SAMPLE"), - **query_kernel_pool("*_BORESIGHT_LINE"), - **query_kernel_pool("*_TRANS*"), - **query_kernel_pool("*_ITRANS*"), - **query_kernel_pool("*_OD_K")} + **self.spiceql_call("findMissionKeywords", {"key": f"*_FOCAL_LENGTH", "mission": self.spiceql_mission}), + **self.spiceql_call("findMissionKeywords", {"key": f"*_BORESIGHT_SAMPLE", "mission": self.spiceql_mission}), + **self.spiceql_call("findMissionKeywords", {"key": f"*_BORESIGHT_LINE", "mission": self.spiceql_mission}), + **self.spiceql_call("findMissionKeywords", {"key": f"*_TRANS*", "mission": self.spiceql_mission}), + **self.spiceql_call("findMissionKeywords", {"key": f"*_ITRANS*", "mission": self.spiceql_mission}), + **self.spiceql_call("findMissionKeywords", {"key": f"*_OD_K", "mission": self.spiceql_mission})} return _naifKeywords diff --git a/tests/pytests/data/isds/lrolroc_isd.json b/tests/pytests/data/isds/lrolroc_isd.json index e766beb30..fb08b16c2 100644 --- a/tests/pytests/data/isds/lrolroc_isd.json +++ b/tests/pytests/data/isds/lrolroc_isd.json @@ -4950,7 +4950,7 @@ 0.0, 0.007 ], - "INS-85600_SWAP_OBSERVER_TARGET": "TRUE", + "INS-85600_SWAP_OBSERVER_TARGET": true, "INS-85600_TRANSY": [ 0.0, 0.007, @@ -4973,7 +4973,27 @@ 5.0026999999999996e-06, 0.0, 1.0, - 4.975e-06 + 4.975e-06, + 0.024805, + 1.0, + 4.9744999999999996e-06, + 0.025032000000000002, + 1.0, + -4.9744999999999996e-06, + 0.025032000000000002, + 1.0, + -4.975e-06, + 0.024805, + 1.0, + -5.0026999999999996e-06, + 0.0, + 1.0, + -4.9747e-06, + -0.024943, + 1.0, + -4.9738e-06, + -0.025335999999999997, + 1.0 ], "FRAME_-85600_NAME": "LRO_LROCNACL", "CK_-85600_SPK": -85.0, @@ -5000,7 +5020,7 @@ "INS-85600_PIXEL_PITCH": 0.007, "INS-85600_ADDITIONAL_PREROLL": 1024.0, "INS-85600_CK_REFERENCE_ID": 1.0, - "INS-85600_LT_SURFACE_CORRECT": "TRUE", + "INS-85600_LT_SURFACE_CORRECT": true, "INS-85600_FOV_FRAME": "LRO_LROCNACL", "FRAME_-85600_CLASS_ID": -85600.0, "INS-85600_IFOV": 1.0005399999999999e-05, @@ -5024,7 +5044,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -5036,7 +5059,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -5049,7 +5075,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, diff --git a/tests/pytests/test_lro_drivers.py b/tests/pytests/test_lro_drivers.py index 22745f60f..602222edf 100644 --- a/tests/pytests/test_lro_drivers.py +++ b/tests/pytests/test_lro_drivers.py @@ -2,7 +2,7 @@ import numpy as np import os import unittest -from unittest.mock import MagicMock, PropertyMock, patch +from unittest.mock import MagicMock, PropertyMock, patch, call import spiceypy as spice import json @@ -43,7 +43,7 @@ def test_kernels(): def test_load(test_kernels, label_type, image, kernel_type): if kernel_type == 'naif': label_file = get_image_label(image, label_type) - isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}) + isd_str = ale.loads(label_file, props={'kernels': test_kernels[image]}, verbose=False) compare_isd = image_dict[image] else: label_file = get_image(image) @@ -87,10 +87,13 @@ def test_sensor_model_version(self): assert self.driver.sensor_model_version == 2 def test_odtk(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ - patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_OD_K": [1.0]} assert self.driver.odtk == [1.0] - gdpool.assert_called_with('INS-12345_OD_K', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_usgscsm_distortion_model(self): with patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.odtk', \ @@ -100,7 +103,7 @@ def test_usgscsm_distortion_model(self): assert distortion_model['lrolrocnac']['coefficients'] == [1.0] def test_ephemeris_start_time(self): - with patch('ale.drivers.lro_drivers.spice.scs2e', return_value=5) as scs2e, \ + with patch('ale.spiceql_access.spiceql_call', side_effect=[5]) as spiceql_call, \ patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.exposure_duration', \ new_callable=PropertyMock) as exposure_duration, \ patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.spacecraft_id', \ @@ -108,7 +111,9 @@ def test_ephemeris_start_time(self): exposure_duration.return_value = 0.1 spacecraft_id.return_value = 1234 assert self.driver.ephemeris_start_time == 107.4 - scs2e.assert_called_with(1234, "1/270649237:07208") + calls = [call('strSclkToEt', {'frameCode': 1234, 'sclk': '1/270649237:07208', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_exposure_duration(self): with patch('ale.base.label_pds3.Pds3Label.exposure_duration', \ @@ -120,31 +125,36 @@ def test_exposure_duration(self): @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain()) @patch('ale.transformation.FrameChain.compute_rotation', return_value=TimeDependentRotation([[0, 0, 1, 0]], [0], 0, 0)) def test_spacecraft_direction(self, compute_rotation, from_spice, frame_chain): - with patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.target_frame_id', \ + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, -12345, [[1, 1, 1, 1, 1, 1, 1]]]) as spiceql_call, \ + patch('ale.drivers.lro_drivers.spice.mxv', return_value=[1, 1, 1]) as mxv, \ + patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.target_frame_id', \ new_callable=PropertyMock) as target_frame_id, \ patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.ephemeris_start_time', \ - new_callable=PropertyMock) as ephemeris_start_time, \ - patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c, \ - patch('ale.drivers.lro_drivers.spice.spkezr', return_value=[[1, 1, 1, 1, 1, 1], 0]) as spkezr, \ - patch('ale.drivers.lro_drivers.spice.mxv', return_value=[1, 1, 1]) as mxv: + new_callable=PropertyMock) as ephemeris_start_time: ephemeris_start_time.return_value = 0 assert self.driver.spacecraft_direction > 0 - bods2c.assert_called_with('LRO_SC_BUS') - spkezr.assert_called_with(self.driver.spacecraft_name, 0, 'J2000', 'None', self.driver.target_name) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'LRO_SC_BUS', 'mission': 'lroc', 'searchKernels': False}, False), + call('getTargetStates', {'ets': [0], 'target': 'LRO', 'observer': 'MOON', 'frame': 'J2000', 'abcorr': 'None', 'mission': 'lroc', 'ckQuality': '', 'spkQuality': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 3 compute_rotation.assert_called_with(1, -12345) np.testing.assert_array_equal(np.array([[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]), mxv.call_args[0][0]) np.testing.assert_array_equal(np.array([1, 1, 1]), mxv.call_args[0][1]) def test_focal2pixel_lines(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=[0, 1, 0]) as gdpool, \ - patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.ikid', \ - new_callable=PropertyMock) as ikid, \ + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ + patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, 321]) as spiceql_call, \ patch('ale.drivers.lro_drivers.LroLrocNacPds3LabelNaifSpiceDriver.spacecraft_direction', \ new_callable=PropertyMock) as spacecraft_direction: + naif_keywords.return_value = {"INS-12345_ITRANSL": [0, 1, 0]} spacecraft_direction.return_value = -1 np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, -1, 0]) spacecraft_direction.return_value = 1 np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 # ========= Test isislabel and naifspice driver ========= @@ -161,37 +171,46 @@ def test_intrument_id(self): assert self.driver.instrument_id == 'LRO_LROCNACL' def test_usgscsm_distortion_model(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ - patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_OD_K": [1.0]} distortion_model = self.driver.usgscsm_distortion_model assert distortion_model['lrolrocnac']['coefficients'] == [1.0] - gdpool.assert_called_with('INS-12345_OD_K', 0, 1) - bods2c.assert_called_with('LRO_LROCNACL') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_odtk(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ - patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.odtk == [1.0] - gdpool.assert_called_with('INS-12345_OD_K', 0, 1) - bods2c.assert_called_with('LRO_LROCNACL') + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_OD_K": [1.0]} + assert self.driver.odtk == [1.0] + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_light_time_correction(self): assert self.driver.light_time_correction == 'NONE' def test_detector_center_sample(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool, \ - patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, 321]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_BORESIGHT_SAMPLE": 1.0} assert self.driver.detector_center_sample == 0.5 - gdpool.assert_called_with('INS-12345_BORESIGHT_SAMPLE', 0, 1) - bods2c.assert_called_with('LRO_LROCNACL') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_exposure_duration(self): np.testing.assert_almost_equal(self.driver.exposure_duration, .0010334296) def test_ephemeris_start_time(self): - with patch('ale.drivers.lro_drivers.spice.scs2e', return_value=321) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-85, 321]) as spiceql_call: np.testing.assert_almost_equal(self.driver.ephemeris_start_time, 322.05823191) - scs2e.assert_called_with(-85, '1/270649237:07208') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LUNAR RECONNAISSANCE ORBITER', 'mission': 'lroc', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -85, 'sclk': '1/270649237:07208', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_multiplicative_line_error(self): assert self.driver.multiplicative_line_error == 0.0045 @@ -212,33 +231,36 @@ def test_sampling_factor(self): @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain()) @patch('ale.transformation.FrameChain.compute_rotation', return_value=TimeDependentRotation([[0, 0, 1, 0]], [0], 0, 0)) def test_spacecraft_direction(self, compute_rotation, from_spice, frame_chain): - with patch('ale.drivers.lro_drivers.LroLrocNacIsisLabelNaifSpiceDriver.target_frame_id', \ + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, -12345, [[1, 1, 1, 1, 1, 1, 1]]]) as spiceql_call, \ + patch('ale.drivers.lro_drivers.spice.mxv', return_value=[1, 1, 1]) as mxv, \ + patch('ale.drivers.lro_drivers.LroLrocNacIsisLabelNaifSpiceDriver.target_frame_id', \ new_callable=PropertyMock) as target_frame_id, \ patch('ale.drivers.lro_drivers.LroLrocNacIsisLabelNaifSpiceDriver.ephemeris_start_time', \ - new_callable=PropertyMock) as ephemeris_start_time, \ - patch('ale.drivers.lro_drivers.spice.cidfrm', return_value=[-12345]) as cidfrm, \ - patch('ale.drivers.lro_drivers.spice.scs2e', return_value=0) as scs2e, \ - patch('ale.drivers.lro_drivers.spice.bods2c', return_value=-12345) as bods2c, \ - patch('ale.drivers.lro_drivers.spice.spkezr', return_value=[[1, 1, 1, 1, 1, 1], 0]) as spkezr, \ - patch('ale.drivers.lro_drivers.spice.mxv', return_value=[1, 1, 1]) as mxv: + new_callable=PropertyMock) as ephemeris_start_time: ephemeris_start_time.return_value = 0 assert self.driver.spacecraft_direction > 0 - spkezr.assert_called_with(self.driver.spacecraft_name, 0, 'J2000', 'None', self.driver.target_name) + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False), + call('NonMemo_translateNameToCode', {'frame': 'LRO_SC_BUS', 'mission': 'lroc', 'searchKernels': False}, False), + call('getTargetStates', {'ets': [0], 'target': 'LUNAR RECONNAISSANCE ORBITER', 'observer': 'MOON', 'frame': 'J2000', 'abcorr': 'None', 'mission': 'lroc', 'ckQuality': '', 'spkQuality': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 3 compute_rotation.assert_called_with(1, -12345) np.testing.assert_array_equal(np.array([[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]]), mxv.call_args[0][0]) np.testing.assert_array_equal(np.array([1, 1, 1]), mxv.call_args[0][1]) def test_focal2pixel_lines(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=[0, 1, 0]) as gdpool, \ - patch('ale.drivers.lro_drivers.LroLrocNacIsisLabelNaifSpiceDriver.ikid', \ - new_callable=PropertyMock) as ikid, \ + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords, \ + patch('ale.spiceql_access.spiceql_call', side_effect=[-12345, 321]) as spiceql_call, \ patch('ale.drivers.lro_drivers.LroLrocNacIsisLabelNaifSpiceDriver.spacecraft_direction', \ new_callable=PropertyMock) as spacecraft_direction: + naif_keywords.return_value = {"INS-12345_ITRANSL": [0, 1, 0]} spacecraft_direction.return_value = -1 np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, -1, 0]) spacecraft_direction.return_value = 1 np.testing.assert_array_equal(self.driver.focal2pixel_lines, [0, 1, 0]) - + calls = [call('NonMemo_translateNameToCode', {'frame': 'LRO_LROCNACL', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 # ========= Test MiniRf isislabel and naifspice driver ========= class test_miniRf(unittest.TestCase): @@ -256,21 +278,25 @@ def test_line_exposure_duration(self): np.testing.assert_almost_equal(self.driver.line_exposure_duration, 4.70442147400000e-03) def test_range_conversion_coefficients(self): - with patch('ale.drivers.lro_drivers.spice.str2et', return_value=12345) as str2et: - assert len(self.driver.range_conversion_coefficients) == 20 + assert len(self.driver.range_conversion_coefficients) == 20 def test_ephmeris_start_time(self): - with patch('ale.drivers.lro_drivers.spice.str2et', return_value=12345) as str2et: - assert self.driver.ephemeris_start_time == 12344.995295578527 + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: + assert self.driver.ephemeris_start_time == 12345 + calls = [call('utcToEt', {'utc': '2010-04-25 04:22:31.244874', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephmeris_stop_time(self): - with patch('ale.drivers.lro_drivers.spice.str2et', return_value=12345) as str2et: - assert self.driver.ephemeris_stop_time == 12348.297799453276 + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: + assert self.driver.ephemeris_stop_time == 12345 + calls = [call('utcToEt', {'utc': '2010-04-25 04:22:34.537874', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 @patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock, return_value={}) def test_naif_keywords(self, naif_keywords): - with patch("ale.base.data_naif.spice.bods2c", return_value=12345) as bods2c: - print(self.driver.naif_keywords["INS12345_ITRANSL"]) + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: np.testing.assert_array_almost_equal(self.driver.naif_keywords["INS12345_ITRANSL"], [0.0, 0.0, 0.0]) np.testing.assert_array_almost_equal(self.driver.naif_keywords["INS12345_ITRANSS"], [1.0, 0.13333333333333, 0]) np.testing.assert_array_almost_equal(self.driver.naif_keywords["INS12345_TRANSX"], [-7.5, 7.5, 0]) @@ -290,24 +316,30 @@ def test_intrument_id(self): assert self.driver.instrument_id == 'LRO_LROCWAC_UV' def test_ephemeris_start_time(self): - with patch('ale.drivers.lro_drivers.spice.scs2e', return_value=321) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-85, 321]) as spiceql_call: np.testing.assert_almost_equal(self.driver.ephemeris_start_time, 321) - scs2e.assert_called_with(-85, '1/274692469:15073') + calls = [call('NonMemo_translateNameToCode', {'frame': 'LUNAR RECONNAISSANCE ORBITER', 'mission': 'lroc', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -85, 'sclk': '1/274692469:15073', 'mission': 'lroc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_detector_center_sample(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool: + with patch('ale.spiceql_access.spiceql_call', side_effect=[{}, {"INS-85641_BORESIGHT_SAMPLE": [1.0]}, {}, {}, {}, {}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {} assert self.driver.detector_center_sample == 0.5 - gdpool.assert_called_with('INS-85641_BORESIGHT_SAMPLE', 0, 1) def test_detector_center_line(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool: + with patch('ale.spiceql_access.spiceql_call', side_effect=[{}, {}, {"INS-85641_BORESIGHT_LINE": [1.0]}, {}, {}, {}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {} assert self.driver.detector_center_line == 0.5 - gdpool.assert_called_with('INS-85641_BORESIGHT_LINE', 0, 1) def test_odtk(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([1.0])) as gdpool: - assert self.driver.odtk == [-1.0] - gdpool.assert_called_with('INS-85641_OD_K', 0, 3) + with patch('ale.spiceql_access.spiceql_call', side_effect=[{}, {}, {}, {}, {}, {"INS-85641_OD_K": [1.0]}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {} + assert self.driver.odtk == [-1.0] def test_light_time_correction(self): assert self.driver.light_time_correction == 'LT+S' @@ -337,19 +369,21 @@ def test_fikid(self): assert self.driver.fikid == -85641 def test_pixel2focal_x(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([0, 0, -0.009])) as gdpool: - assert self.driver.pixel2focal_x == [0, 0, -0.009] - gdpool.assert_called_with('INS-85641_TRANSX', 0, 3) + with patch('ale.spiceql_access.spiceql_call', side_effect=[{}, {}, {}, {"INS-85641_TRANSX": [0, 0, -0.009]}, {}, {}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {} + assert self.driver.pixel2focal_x == [0, 0, -0.009] def test_pixel2focal_y(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([0, 0.009, 0])) as gdpool: - assert self.driver.pixel2focal_y == [0, 0.009, 0] - gdpool.assert_called_with('INS-85641_TRANSY', 0, 3) + with patch('ale.spiceql_access.spiceql_call', side_effect=[{}, {}, {}, {"INS-85641_TRANSY": [0, 0.009, 0]}, {}, {}]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {} + assert self.driver.pixel2focal_y == [0, 0.009, 0] def test_detector_start_line(self): - with patch('ale.drivers.lro_drivers.spice.gdpool', return_value=np.array([244])) as gdpool: - assert self.driver.detector_start_line == 244 - gdpool.assert_called_with('INS-85641_FILTER_OFFSET', 0, 3) + with patch('ale.drivers.lro_drivers.LroLrocWacIsisLabelNaifSpiceDriver.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-85641_FILTER_OFFSET": [244]} + assert self.driver.detector_start_line == 244 # ========= Test WAC isislabel and isis spice driver ========= class test_wac_isis_isis(unittest.TestCase): From b965298beab2f0d95b8fa0293fc4cc43d6830603 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:15:10 -0700 Subject: [PATCH 55/73] Updated messenger drivers and tests --- ale/drivers/mess_drivers.py | 45 +++++++++----- tests/pytests/data/isds/messmdis_isd.json | 4 +- tests/pytests/test_mdis_drivers.py | 75 +++++++++++++++-------- 3 files changed, 82 insertions(+), 42 deletions(-) diff --git a/ale/drivers/mess_drivers.py b/ale/drivers/mess_drivers.py index e7b1ad19b..9dd8cd4a4 100644 --- a/ale/drivers/mess_drivers.py +++ b/ale/drivers/mess_drivers.py @@ -159,14 +159,16 @@ def focal_length(self): : double focal length in meters """ - coeffs = self.naif_keywords['INS{}_FL_TEMP_COEFFS'.format(self.fikid)] + if not hasattr(self, "_focal_length"): + coeffs = self.naif_keywords['INS{}_FL_TEMP_COEFFS'.format(self.fikid)] - # 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]) + # 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_temperature - return f_t(self.label['FOCAL_PLANE_TEMPERATURE'].value) + # eval at the focal_plane_temperature + self._focal_length = f_t(self.label['FOCAL_PLANE_TEMPERATURE'].value) + return self._focal_length @property def detector_center_sample(self): @@ -241,7 +243,9 @@ def pixel_size(self): ------- : float pixel size """ - return self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)] + if not hasattr(self, "_pixel_size"): + self._pixel_size = self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)] + return self._pixel_size class MessengerMdisIsisLabelNaifSpiceDriver(IsisLabel, NaifSpice, Framer, NoDistortion, Driver): """ @@ -335,13 +339,16 @@ def focal_length(self): : double focal length in meters """ - coeffs = self.naif_keywords['INS{}_FL_TEMP_COEFFS'.format(self.fikid)] - # 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]) + if not hasattr(self, "_focal_length"): - # eval at the focal_plane_temperature - return f_t(self.label['IsisCube']['Instrument']['FocalPlaneTemperature'].value) + coeffs = self.naif_keywords['INS{}_FL_TEMP_COEFFS'.format(self.fikid)] + # 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_temperature + self._focal_length = f_t(self.label['IsisCube']['Instrument']['FocalPlaneTemperature'].value) + return self._focal_length @property def detector_center_sample(self): @@ -358,7 +365,9 @@ def detector_center_sample(self): : float detector center sample """ - return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][0]) - 0.5 + if not hasattr(self, "_detector_center_sample"): + self._detector_center_sample = float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][0]) - 0.5 + return self._detector_center_sample @property @@ -376,7 +385,9 @@ def detector_center_line(self): : float detector center line """ - return float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][1]) - 0.5 + if not hasattr(self, "_detector_center_line"): + self._detector_center_line = float(self.naif_keywords['INS{}_CCD_CENTER'.format(self.ikid)][1]) - 0.5 + return self._detector_center_line @property def sensor_model_version(self): @@ -398,7 +409,9 @@ def pixel_size(self): ------- : float pixel size """ - return self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)] + if not hasattr(self, "_pixel_size"): + self._pixel_size = self.naif_keywords['INS{}_PIXEL_PITCH'.format(self.ikid)] + return self._pixel_size @property def sampling_factor(self): diff --git a/tests/pytests/data/isds/messmdis_isd.json b/tests/pytests/data/isds/messmdis_isd.json index a2bedc26e..00034e16b 100644 --- a/tests/pytests/data/isds/messmdis_isd.json +++ b/tests/pytests/data/isds/messmdis_isd.json @@ -47,7 +47,7 @@ "INS-236820_FOV_ANGLE_UNITS": "DEGREES", "FRAME_-236820_CLASS": 4.0, "INS-236820_BORESIGHT_LINE": 512.5, - "INS-236820_SWAP_OBSERVER_TARGET": "TRUE", + "INS-236820_SWAP_OBSERVER_TARGET": true, "INS-236820_LIGHTTIME_CORRECTION": "LT+S", "INS-236820_FOV_FRAME": "MSGR_MDIS_NAC", "INS-236820_PIXEL_SAMPLES": 1024.0, @@ -77,7 +77,7 @@ "FRAME_-236820_NAME": "MSGR_MDIS_NAC", "INS-236820_FRAME": "MSGR_MDIS_NAC", "INS-236820_PLATFORM_ID": -236000.0, - "INS-236820_LT_SURFACE_CORRECT": "FALSE", + "INS-236820_LT_SURFACE_CORRECT": false, "INS-236820_TRANSX": [ 0.0, 0.014, diff --git a/tests/pytests/test_mdis_drivers.py b/tests/pytests/test_mdis_drivers.py index a89f51b2e..9b43786fc 100644 --- a/tests/pytests/test_mdis_drivers.py +++ b/tests/pytests/test_mdis_drivers.py @@ -5,7 +5,7 @@ from importlib import reload import json import unittest -from unittest.mock import patch +from unittest.mock import PropertyMock, patch, call from conftest import get_image, get_image_label, get_isd, get_image_kernels, convert_kernels, compare_dicts import ale @@ -65,10 +65,13 @@ def test_sampling_factor(self): assert self.driver.sampling_factor == 2 def test_focal_length(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', return_value=np.array([pow(4.07, -x) for x in np.arange(6)])) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_FL_TEMP_COEFFS": np.array([pow(4.07, -x) for x in np.arange(6)])} assert self.driver.focal_length == pytest.approx(6.0) - gdpool.assert_called_with('INS-12345_FL_TEMP_COEFFS', 0, 6) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_sample(self): assert self.driver.detector_center_sample == 512 @@ -80,19 +83,26 @@ def test_sensor_model_version(self): assert self.driver.sensor_model_version == 2 def test_usgscsm_distortion_model(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', side_effect=[np.array([1, 2, 3, 4, 5]), np.array([-1, -2, -3, -4, -5])]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_OD_T_X": [1, 2, 3, 4, 5], + "INS-12345_OD_T_Y": [-1, -2, -3, -4, -5]} assert self.driver.usgscsm_distortion_model == {"transverse" : { "x" : [1, 2, 3, 4, 5], "y" : [-1, -2, -3, -4, -5]}} - + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_pixel_size(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', return_value=np.array([0.1])) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_PITCH": np.array([0.1])} assert self.driver.pixel_size == 0.1 - gdpool.assert_called_with('INS-12345_PIXEL_PITCH', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 # ========= Test ISIS3 Label and NAIF Spice driver ========= class test_isis3_naif(unittest.TestCase): @@ -118,37 +128,54 @@ def test_sampling_factor(self): assert self.driver.sampling_factor == 2 def test_focal_length(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', return_value=np.array([pow(4.07, -x) for x in np.arange(6)])) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_FL_TEMP_COEFFS": np.array([pow(4.07, -x) for x in np.arange(6)])} assert self.driver.focal_length == pytest.approx(6.0) - gdpool.assert_called_with('INS-12345_FL_TEMP_COEFFS', 0, 6) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_sample(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', return_value=np.array([512.5, 512.5, 1])) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_CCD_CENTER": np.array([512.5, 512.5, 1])} assert self.driver.detector_center_sample == 512 - gdpool.assert_called_with('INS-12345_CCD_CENTER', 0, 3) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_line(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', return_value=np.array([512.5, 512.5, 1])) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_CCD_CENTER": np.array([512.5, 512.5, 1])} assert self.driver.detector_center_line == 512 - gdpool.assert_called_with('INS-12345_CCD_CENTER', 0, 3) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 2 def test_usgscsm_distortion_model(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', side_effect=[np.array([1, 2, 3, 4, 5]), np.array([-1, -2, -3, -4, -5])]) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_OD_T_X": [1, 2, 3, 4, 5], + "INS-12345_OD_T_Y": [-1, -2, -3, -4, -5]} assert self.driver.usgscsm_distortion_model == {"transverse" : { "x" : [1, 2, 3, 4, 5], "y" : [-1, -2, -3, -4, -5]}} + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_pixel_size(self): - with patch('ale.drivers.mess_drivers.spice.gdpool', return_value=np.array([0.1])) as gdpool, \ - patch('ale.base.data_naif.spice.bods2c', return_value=-12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-12345]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-12345_PIXEL_PITCH": np.array([0.1])} assert self.driver.pixel_size == 0.1 - gdpool.assert_called_with('INS-12345_PIXEL_PITCH', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSGR_MDIS_NAC', 'mission': 'mdis', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 From f6f0c61980ae27d46029b2c38b19319ded9b048a Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:15:52 -0700 Subject: [PATCH 56/73] Updated mex drivers and tests --- ale/drivers/mex_drivers.py | 3 +- tests/pytests/data/isds/mexhrsc_isd.json | 8 +- tests/pytests/data/isds/mexhrsc_isis_isd.json | 8 +- tests/pytests/test_mex_drivers.py | 97 ++++++++++++------- 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/ale/drivers/mex_drivers.py b/ale/drivers/mex_drivers.py index b35804d9f..ed03eb356 100644 --- a/ale/drivers/mex_drivers.py +++ b/ale/drivers/mex_drivers.py @@ -497,7 +497,6 @@ def sensor_model_version(self): """ return 1 - class MexHrscIsisLabelNaifSpiceDriver(LineScanner, IsisLabel, NaifSpice, NoDistortion, Driver): @property @@ -685,7 +684,6 @@ def focal2pixel_lines(self): """ return FILTER_SPECIFIC_LOOKUP[self.fikid][4] - @property def focal2pixel_samples(self): """ @@ -716,6 +714,7 @@ def sampling_factor(self): summing = self.label['IsisCube']['Instrument'].get("Summing", 1) return summing + class MexSrcPds3NaifSpiceDriver(Framer, Pds3Label, NaifSpice, NoDistortion, Driver): """ Driver for a PDS3 Mars Express (Mex) High Resolution Stereo Camera (HRSC) - Super Resolution diff --git a/tests/pytests/data/isds/mexhrsc_isd.json b/tests/pytests/data/isds/mexhrsc_isd.json index 083aa6a25..7bc113378 100644 --- a/tests/pytests/data/isds/mexhrsc_isd.json +++ b/tests/pytests/data/isds/mexhrsc_isd.json @@ -194,7 +194,9 @@ -18.1862, -60.0435, 175.0, - -18.142 + -18.142, + 60.0476, + 175.0 ], "INS-41210_FOV_SHAPE": "RECTANGLE", "TKFRAME_-41210_RELATIVE": "MEX_HRSC_BASE", @@ -269,7 +271,9 @@ -18.1693, 49.8901, 175.0, - -18.1693 + -18.1693, + 49.8971, + 175.0 ], "INS-41218_BORESIGHT": [ 0.0151, diff --git a/tests/pytests/data/isds/mexhrsc_isis_isd.json b/tests/pytests/data/isds/mexhrsc_isis_isd.json index 4fe3c7cc1..88eb82968 100644 --- a/tests/pytests/data/isds/mexhrsc_isis_isd.json +++ b/tests/pytests/data/isds/mexhrsc_isis_isd.json @@ -199,7 +199,9 @@ -18.1862, -60.0435, 175.0, - -18.142 + -18.142, + 60.0476, + 175.0 ], "INS-41210_FOV_SHAPE": "RECTANGLE", "TKFRAME_-41210_RELATIVE": "MEX_HRSC_BASE", @@ -274,7 +276,9 @@ -18.1693, 49.8901, 175.0, - -18.1693 + -18.1693, + 49.8971, + 175.0 ], "INS-41218_BORESIGHT": [ 0.0151, diff --git a/tests/pytests/test_mex_drivers.py b/tests/pytests/test_mex_drivers.py index ce85b8f73..285618b28 100644 --- a/tests/pytests/test_mex_drivers.py +++ b/tests/pytests/test_mex_drivers.py @@ -3,7 +3,7 @@ import numpy as np import spiceypy as spice import json -from unittest.mock import patch, PropertyMock +from unittest.mock import patch, PropertyMock, call import unittest from conftest import get_image_label, get_image_kernels, convert_kernels, get_isd, compare_dicts import ale @@ -79,14 +79,18 @@ def test_short_mission_name(self): assert self.driver.short_mission_name=='mex' def test_ikid(self): - with patch('ale.drivers.mex_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ikid == 12345 - bods2c.assert_called_with('MEX_HRSC_HEAD') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_HEAD', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_fikid(self): - with patch('ale.drivers.mex_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.fikid == 12345 - bods2c.assert_called_with('MEX_HRSC_IR') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_instrument_id(self): assert self.driver.instrument_id == 'MEX_HRSC_IR' @@ -95,38 +99,43 @@ def test_spacecraft_name(self): assert self.driver.spacecraft_name =='MEX' def test_focal_length(self): - with patch('ale.drivers.mex_drivers.MexHrscPds3NaifSpiceDriver.fikid', \ - new_callable=PropertyMock) as fikid: - fikid.return_value = -41218 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: assert self.driver.focal_length == 174.82 + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_lines(self): - with patch('ale.drivers.mex_drivers.MexHrscPds3NaifSpiceDriver.fikid', \ - new_callable=PropertyMock) as fikid: - fikid.return_value = -41218 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: np.testing.assert_almost_equal(self.driver.focal2pixel_lines, [-7113.11359717265, 0.062856784318668, 142.857129028729]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_samples(self): - with patch('ale.drivers.mex_drivers.MexHrscPds3NaifSpiceDriver.fikid', \ - new_callable=PropertyMock) as fikid: - fikid.return_value = -41218 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: np.testing.assert_almost_equal(self.driver.focal2pixel_samples, [-0.778052433438109, -142.857129028729, 0.062856784318668]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_pixel2focal_x(self): - with patch('ale.drivers.mex_drivers.MexHrscPds3NaifSpiceDriver.fikid', \ - new_callable=PropertyMock) as fikid: - fikid.return_value = -41218 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: np.testing.assert_almost_equal(self.driver.pixel2focal_x, [0.016461898406507, -0.006999999322408, 3.079982431615e-06]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_pixel2focal_y(self): - with patch('ale.drivers.mex_drivers.MexHrscPds3NaifSpiceDriver.fikid', \ - new_callable=PropertyMock) as fikid: - fikid.return_value = -41218 + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: np.testing.assert_almost_equal(self.driver.pixel2focal_y, [49.7917927568053, 3.079982431615e-06, 0.006999999322408]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_start_line(self): assert self.driver.detector_start_line == 0.0 @@ -189,14 +198,41 @@ def test_instrument_id(self): assert self.driver.instrument_id == 'MEX_HRSC_IR' def test_ikid(self): - with patch('ale.drivers.mex_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ikid == 12345 - bods2c.assert_called_with('MEX_HRSC_HEAD') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_HEAD', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_fikid(self): - with patch('ale.drivers.mex_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.fikid == 12345 - bods2c.assert_called_with('MEX_HRSC_IR') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 + + def test_focal_length(self): + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: + assert self.driver.focal_length == 174.82 + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 + + def test_focal2pixel_lines(self): + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: + np.testing.assert_almost_equal(self.driver.focal2pixel_lines, + [-7113.11359717265, 0.062856784318668, 142.857129028729]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 + + def test_focal2pixel_samples(self): + with patch('ale.spiceql_access.spiceql_call', side_effect=[-41218]) as spiceql_call: + np.testing.assert_almost_equal(self.driver.focal2pixel_samples, + [-0.778052433438109, -142.857129028729, 0.062856784318668]) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_IR', 'mission': 'hrsc', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_ephemeris_start_time(self): with patch('ale.drivers.mex_drivers.read_table_data', return_value=12345) as read_table_data, \ @@ -244,22 +280,17 @@ def test_short_mission_name(self): assert self.driver.short_mission_name=='mex' def test_ikid(self): - with patch('ale.drivers.mex_drivers.spice.bods2c', return_value=12345) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: assert self.driver.ikid == 12345 - bods2c.assert_called_with('MEX_HRSC_SRC') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MEX_HRSC_SRC', 'mission': 'src', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_instrument_id(self): assert self.driver.instrument_id == 'MEX_HRSC_SRC' def test_spacecraft_name(self): assert self.driver.spacecraft_name =='MEX' - - def test_focal_length(self): - with patch('ale.drivers.mex_drivers.spice.gdpool', return_value=[10.0]) as gdpool, \ - patch('ale.drivers.mex_drivers.spice.bods2c', return_value=-12345) as bods2c: - assert self.driver.ikid == -12345 - bods2c.assert_called_with('MEX_HRSC_SRC') - assert self.driver.focal_length == 10.0 def test_focal2pixel_lines(self): np.testing.assert_almost_equal(self.driver.focal2pixel_lines, From a9145252c4d9156b1cc5c1ddb7114bb52bbc8a36 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:16:30 -0700 Subject: [PATCH 57/73] Updated MGS drivers and tests --- tests/pytests/data/isds/mgsmocna_isd.json | 4 +- tests/pytests/data/isds/mgsmocwa_isd.json | 7 +++- tests/pytests/test_mgs_drivers.py | 49 ++++++++++++++--------- 3 files changed, 37 insertions(+), 23 deletions(-) diff --git a/tests/pytests/data/isds/mgsmocna_isd.json b/tests/pytests/data/isds/mgsmocna_isd.json index 5f507381d..267cf4618 100644 --- a/tests/pytests/data/isds/mgsmocna_isd.json +++ b/tests/pytests/data/isds/mgsmocna_isd.json @@ -18576,7 +18576,9 @@ -1.857138381e-06, 0.0038015622659203, 0.9999927740343374, - -1.857138381e-06 + -1.857138381e-06, + -0.0038015622659203, + 0.9999927740343374 ], "INS-94031_CK_TIME_BIAS": -1.15, "INS-94031_PIXEL_SIZE": 1.3e-05, diff --git a/tests/pytests/data/isds/mgsmocwa_isd.json b/tests/pytests/data/isds/mgsmocwa_isd.json index b43e203af..d54fc0042 100644 --- a/tests/pytests/data/isds/mgsmocwa_isd.json +++ b/tests/pytests/data/isds/mgsmocwa_isd.json @@ -1086,7 +1086,9 @@ 0.0033750005332111, -0.9575626662157566, 0.2882053948856133, - 0.0034601379682684 + 0.0034601379682684, + 0.9223636076439348, + 0.3863073941038482 ], "INS-94032_PIXEL_PITCH": 0.007, "INS-94032_CK_REFERENCE_ID": 1.0, @@ -1129,7 +1131,8 @@ 0.2145501, 0.0, -0.093066, - 0.0 + 0.0, + 0.0154483 ], "INS-94032_RD_S": 1.0, "INS-94032_RD_PB": 1673.65, diff --git a/tests/pytests/test_mgs_drivers.py b/tests/pytests/test_mgs_drivers.py index cf171670b..2bae93193 100644 --- a/tests/pytests/test_mgs_drivers.py +++ b/tests/pytests/test_mgs_drivers.py @@ -2,7 +2,7 @@ import numpy as np import os import unittest -from unittest.mock import MagicMock, PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import spiceypy as spice import json @@ -58,14 +58,20 @@ def test_sensor_name(self): assert self.driver.sensor_name == "MGS_MOC_WA_RED" def test_ephemeris_start_time(self): - with patch('ale.drivers.mgs_drivers.spice.scs2e', return_value=1234) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-94, 1234]) as spiceql_call: assert self.driver.ephemeris_start_time == 1234 - scs2e.assert_called_with(-94, "561812335:32") + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS GLOBAL SURVEYOR', 'mission': 'mgs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -94, 'sclk': '561812335:32', 'mission': 'mgs', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_ephemeris_stop_time(self): - with patch('ale.drivers.mgs_drivers.spice.scs2e', return_value=1234) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-94, 1234]) as spiceql_call: assert self.driver.ephemeris_stop_time == 1541.2 - scs2e.assert_called_with(-94, "561812335:32") + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS GLOBAL SURVEYOR', 'mission': 'mgs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -94, 'sclk': '561812335:32', 'mission': 'mgs', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_detector_start_sample(self): @@ -73,15 +79,14 @@ def test_detector_start_sample(self): def test_detector_center_sample(self): - with patch('ale.drivers.mgs_drivers.spice.gdpool', return_value=[1727.5]) as gdpool: + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-94032_CENTER": [1727.5, 0]} assert self.driver.detector_center_sample == 1727.5 - gdpool.assert_called_with('INS-94032_CENTER', 0, 1) - def test_detector_center_line(self): - with patch('ale.drivers.mgs_drivers.spice.gdpool', return_value=[0, 1727.5]) as gdpool: + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-94032_CENTER": [0, 1727.5]} assert self.driver.detector_center_line == 1727.5 - gdpool.assert_called_with('INS-94032_CENTER', 0, 2) def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -107,30 +112,34 @@ def test_sensor_name(self): assert self.driver.sensor_name == "MGS_MOC_NA" def test_ephemeris_start_time(self): - with patch('ale.drivers.mgs_drivers.spice.scs2e', return_value=1234) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-94, 1234]) as spiceql_call: assert self.driver.ephemeris_start_time == 1234 - scs2e.assert_called_with(-94, "619971158:28") + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS GLOBAL SURVEYOR', 'mission': 'mgs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -94, 'sclk': '619971158:28', 'mission': 'mgs', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_ephemeris_stop_time(self): - with patch('ale.drivers.mgs_drivers.spice.scs2e', return_value=1234) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-94, 1234]) as spiceql_call: assert self.driver.ephemeris_stop_time == 1239.9240448 - scs2e.assert_called_with(-94, "619971158:28") - + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS GLOBAL SURVEYOR', 'mission': 'mgs', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -94, 'sclk': '619971158:28', 'mission': 'mgs', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_detector_start_sample(self): assert self.driver.detector_start_sample == 1 def test_detector_center_sample(self): - with patch('ale.drivers.mgs_drivers.spice.gdpool', return_value=[1727.5]) as gdpool: + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-94031_CENTER": [1727.5, 0]} assert self.driver.detector_center_sample == 1727.5 - gdpool.assert_called_with('INS-94031_CENTER', 0, 1) - def test_detector_center_line(self): - with patch('ale.drivers.mgs_drivers.spice.gdpool', return_value=[0, 1727.5]) as gdpool: + with patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-94031_CENTER": [0, 1727.5]} assert self.driver.detector_center_line == 1727.5 - gdpool.assert_called_with('INS-94031_CENTER', 0, 2) def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 From 0883096dcb3bf240dcd3eff58f6555bd6131bf52 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:16:52 -0700 Subject: [PATCH 58/73] Updated msl drivers and tests --- ale/drivers/msl_drivers.py | 5 ++-- tests/pytests/data/isds/msl_isd.json | 16 ++++++++++++- tests/pytests/test_msl_drivers.py | 36 +++++++++++++++++----------- 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/ale/drivers/msl_drivers.py b/ale/drivers/msl_drivers.py index 9f830dc85..99a88f63b 100644 --- a/ale/drivers/msl_drivers.py +++ b/ale/drivers/msl_drivers.py @@ -1,5 +1,4 @@ import numpy as np -import spiceypy as spice from ale.base.data_naif import NaifSpice from ale.base.label_pds3 import Pds3Label @@ -97,7 +96,9 @@ def final_inst_frame(self): : int Naif frame code for MSL_ROVER """ - return spice.bods2c("MSL_ROVER") + if not hasattr(self, "_final_inst_frame"): + self._final_inst_frame = self.spiceql_call("translateNameToCode", {"frame": "MSL_ROVER", "mission": self.spiceql_mission}) + return self._final_inst_frame @property def sensor_frame_id(self): diff --git a/tests/pytests/data/isds/msl_isd.json b/tests/pytests/data/isds/msl_isd.json index 87194f8e8..a5a1d40f0 100644 --- a/tests/pytests/data/isds/msl_isd.json +++ b/tests/pytests/data/isds/msl_isd.json @@ -154,7 +154,21 @@ -0.17476887, 0.12719345, 0.9763594, - -0.17553059 + -0.17553059, + -5.566e-05, + 0.98447398, + -0.17480715, + -0.12735688, + 0.97633124, + 1.62e-05, + -0.12838394, + 0.99172454, + 0.1749107, + -0.12728511, + 0.97632205, + 0.17557293, + 3.78e-05, + 0.98446643 ], "INS-76210_PIXEL_LINES": 1200.0, "INS-76210_CAHVOR_MODEL": " CAHVOR", diff --git a/tests/pytests/test_msl_drivers.py b/tests/pytests/test_msl_drivers.py index c12d308c1..5d635705c 100644 --- a/tests/pytests/test_msl_drivers.py +++ b/tests/pytests/test_msl_drivers.py @@ -9,7 +9,7 @@ from ale.drivers.msl_drivers import MslMastcamPds3NaifSpiceDriver from conftest import get_image_label -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call @pytest.fixture(scope='module') @@ -53,9 +53,11 @@ def test_exposure_duration(self): np.testing.assert_almost_equal(self.driver.exposure_duration, 0.0102) def test_final_inst_frame(self): - with patch('ale.drivers.msl_drivers.spice.bods2c', new_callable=PropertyMock, return_value=-76000) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-76000]) as spiceql_call: assert self.driver.final_inst_frame == -76000 - bods2c.assert_called_with("MSL_ROVER") + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSL_ROVER', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_cahvor_camera_dict(self): cahvor_camera_dict = self.driver.cahvor_camera_dict @@ -66,20 +68,26 @@ def test_cahvor_camera_dict(self): np.testing.assert_allclose(cahvor_camera_dict['V'], [5.843885e+03, -8.213856e+03, 9.438374e+03]) def test_sensor_frame_id(self): - with patch('ale.drivers.msl_drivers.spice.bods2c', return_value=-76562) as bods2c: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-76562]) as spiceql_call: assert self.driver.sensor_frame_id == -76562 - bods2c.assert_called_with("MSL_SITE_62") - + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSL_SITE_62', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 + def test_focal2pixel_lines(self): - with patch('ale.drivers.msl_drivers.spice.bods2c', new_callable=PropertyMock, return_value=-76220) as bods2c, \ - patch('ale.drivers.msl_drivers.spice.gdpool', new_callable=PropertyMock, return_value=[100]) as gdpool: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-76220]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-76220_FOCAL_LENGTH": 100} np.testing.assert_allclose(self.driver.focal2pixel_lines, [0, 0, -137.96844341513602]) - bods2c.assert_called_with('MSL_MASTCAM_RIGHT') - gdpool.assert_called_with('INS-76220_FOCAL_LENGTH', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSL_MASTCAM_RIGHT', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_focal2pixel_samples(self): - with patch('ale.drivers.msl_drivers.spice.bods2c', new_callable=PropertyMock, return_value=-76220) as bods2c, \ - patch('ale.drivers.msl_drivers.spice.gdpool', new_callable=PropertyMock, return_value=[100]) as gdpool: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-76220]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-76220_FOCAL_LENGTH": 100} np.testing.assert_allclose(self.driver.focal2pixel_samples, [0, -137.96844341513602, 0]) - bods2c.assert_called_with('MSL_MASTCAM_RIGHT') - gdpool.assert_called_with('INS-76220_FOCAL_LENGTH', 0, 1) + calls = [call('NonMemo_translateNameToCode', {'frame': 'MSL_MASTCAM_RIGHT', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 From ff3421238f89704083cc34b44efeeb265accb8c0 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:17:48 -0700 Subject: [PATCH 59/73] Updated new horizons tests --- tests/pytests/data/isds/nhmvic_tdi_isd.json | 19 ++++++- tests/pytests/test_newhorizons_drivers.py | 61 +++++++++++++++++---- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/tests/pytests/data/isds/nhmvic_tdi_isd.json b/tests/pytests/data/isds/nhmvic_tdi_isd.json index 06d7ea805..9d377e5dd 100644 --- a/tests/pytests/data/isds/nhmvic_tdi_isd.json +++ b/tests/pytests/data/isds/nhmvic_tdi_isd.json @@ -4990,7 +4990,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 5e-05, + 0.000404, + 0.000617, + -1.3e-05, + 0.000926 ], "BODY599_NUT_PREC_PM": [ 0.0, @@ -5002,6 +5007,11 @@ 0.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0 ], "BODY599_POLE_RA": [ @@ -5024,7 +5034,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 0.000117, + 0.000938, + 0.001432, + 3e-05, + 0.00215 ], "INS-98900_DISTORTION_COEF_X": [ -2.184e-05, diff --git a/tests/pytests/test_newhorizons_drivers.py b/tests/pytests/test_newhorizons_drivers.py index c97d56085..d5bc8f5ce 100644 --- a/tests/pytests/test_newhorizons_drivers.py +++ b/tests/pytests/test_newhorizons_drivers.py @@ -5,7 +5,7 @@ import numpy as np import unittest -from unittest.mock import patch +from unittest.mock import patch, call from conftest import get_image_label, get_image_kernels, convert_kernels, compare_dicts, get_isd @@ -84,14 +84,20 @@ def test_ikid(self): assert self.driver.ikid == -98901 def test_ephemeris_start_time(self): - with patch('ale.drivers.nh_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-98, 12345]) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - scs2e.assert_called_with(-98, '0296962438:00000') + calls = [call('NonMemo_translateNameToCode', {'frame': 'NEW HORIZONS', 'mission': 'leisa', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -98, 'sclk': '0296962438:00000', 'mission': 'leisa', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_ephemeris_stop_time(self): - with patch('ale.drivers.nh_drivers.spice.scs2e', return_value=12345) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-98, 12345]) as spiceql_call: assert self.driver.ephemeris_stop_time == (12345 + self.driver.exposure_duration * self.driver.image_lines) - scs2e.assert_called_with(-98, '0296962438:00000') + calls = [call('NonMemo_translateNameToCode', {'frame': 'NEW HORIZONS', 'mission': 'leisa', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -98, 'sclk': '0296962438:00000', 'mission': 'leisa', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_detector_center_sample(self): assert self.driver.detector_center_sample == 0 @@ -121,14 +127,34 @@ def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 def test_ephemeris_start_time(self): - with patch('ale.drivers.nh_drivers.spice.utc2et', return_value=12345) as utc2et: + with patch('ale.spiceql_access.spiceql_call', return_value=12345) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - utc2et.assert_called_with("2015-06-03 04:06:32.848000") + calls = [call('utcToEt', {'utc': '2015-06-03 04:05:59.624000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:03.777000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:07.930000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:12.083000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:16.236000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:20.389000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:24.542000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:28.695000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:32.848000', 'searchKernels': False}, False),] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 9 def test_ephemeris_stop_time(self): - with patch('ale.drivers.nh_drivers.spice.utc2et', return_value=12345) as utc2et: + with patch('ale.spiceql_access.spiceql_call', return_value=12345) as spiceql_call: assert self.driver.ephemeris_start_time == 12345 - utc2et.assert_called_with("2015-06-03 04:06:32.848000") + calls = [call('utcToEt', {'utc': '2015-06-03 04:05:59.624000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:03.777000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:07.930000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:12.083000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:16.236000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:20.389000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:24.542000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:28.695000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:32.848000', 'searchKernels': False}, False),] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 9 def test_detector_center_line(self): assert self.driver.detector_center_line == -1 @@ -140,9 +166,20 @@ def test_sensor_name(self): assert self.driver.sensor_name == 'NEW HORIZONS' def test_band_times(self): - with patch('ale.drivers.nh_drivers.spice.utc2et', return_value=12345) as utc2et: - assert self.driver.ephemeris_start_time == 12345 - utc2et.assert_called_with("2015-06-03 04:06:32.848000") + with patch('ale.spiceql_access.spiceql_call', return_value=12345) as spiceql_call: + assert len(self.driver.band_times) == 9 + assert sum(self.driver.band_times)/len(self.driver.band_times) == 12345 + calls = [call('utcToEt', {'utc': '2015-06-03 04:05:59.624000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:03.777000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:07.930000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:12.083000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:16.236000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:20.389000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:24.542000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:28.695000', 'searchKernels': False}, False), + call('utcToEt', {'utc': '2015-06-03 04:06:32.848000', 'searchKernels': False}, False),] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 9 class test_mvictdi_isis_naif(unittest.TestCase): def setUp(self): From d07a6e95abddc528db1462be2a939b9f456e178d Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:19:14 -0700 Subject: [PATCH 60/73] Updated orex drivers and tests --- tests/pytests/data/isds/osirisrex_isd.json | 324 ++++++++++++++++++++- tests/pytests/test_osirisrex_drivers.py | 38 ++- 2 files changed, 345 insertions(+), 17 deletions(-) diff --git a/tests/pytests/data/isds/osirisrex_isd.json b/tests/pytests/data/isds/osirisrex_isd.json index 5a14bf766..4c4eccfd2 100644 --- a/tests/pytests/data/isds/osirisrex_isd.json +++ b/tests/pytests/data/isds/osirisrex_isd.json @@ -1 +1,323 @@ -{"isis_camera_version": 1, "image_lines": 1024, "image_samples": 1024, "name_platform": "OSIRIS-REX", "name_sensor": "MapCam", "reference_height": {"maxheight": 1000, "minheight": -1000, "unit": "m"}, "name_model": "USGS_ASTRO_FRAME_SENSOR_MODEL", "center_ephemeris_time": 604882849.4327942, "radii": {"semimajor": 0.283065, "semiminor": 0.24972, "unit": "km"}, "body_rotation": {"time_dependent_frames": [10106, 1], "ck_table_start_time": 604882849.4327942, "ck_table_end_time": 604882849.4327942, "ck_table_original_size": 1, "ephemeris_times": [604882849.4327942], "quaternions": [[-0.24468662154888665, -0.8995476917306681, 0.3540944064834505, 0.07456244922312974]], "angular_velocities": [[1.5901075118354376e-05, 0.00020029780775859552, -0.0003531029098106748]], "reference_frame": 1}, "instrument_pointing": {"time_dependent_frames": [-64000, 1], "ck_table_start_time": 604882849.4327942, "ck_table_end_time": 604882849.4327942, "ck_table_original_size": 1, "ephemeris_times": [604882849.4327942], "quaternions": [[-0.49481036455664573, 0.4609332756246706, -0.3664592415687433, -0.6390702956780986]], "angular_velocities": [[5.395053026508693e-06, -5.108637996042997e-06, 2.277063782852625e-06]], "reference_frame": 1, "constant_frames": [-64000], "constant_rotation": [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]}, "naif_keywords": {"BODY2101955_RADII": [0.283065, 0.271215, 0.24972], "BODY_FRAME_CODE": 10106, "BODY_CODE": 2101955, "INS-64361_TOLERANCE": 1e-10, "INS-64361_ITRANSL": [0.0, 117.64705882353, 0.0], "INS-64361_ITRANSS": [0.0, 0.0, 117.64705882353], "FRAME_-64361_CLASS": 3.0, "INS-64361_FOCAL_LENGTH": 125.2, "FRAME_-64361_CENTER": -64.0, "INS-64361_WAVELENGTH_RANGE": [440.0, 890.0], "CK_-64361_SPK": -64.0, "INS-64361_OD_CENTER_PAN": [486.2, 450.3], "INS-64361_PIXEL_LINES": 1024.0, "INS-64361_OD_CENTER_B": [497.3, 456.8], "INS-64361_TRANSX": [0.0, 0.0, 0.0085], "INS-64361_TRANSY": [0.0, 0.0085, 0.0], "INS-64361_OD_CENTER_V": [494.3, 473.8], "INS-64361_OD_CENTER_W": [510.3, 461.2], "INS-64361_OD_CENTER_X": [504.5, 450.5], "INS-64361_F/NUMBER": 3.295, "INS-64361_LT_SURFACE_CORRECT": "FALSE", "INS-64361_FOV_ANGLE_UNITS": "DEGREES", "INS-64361_SWAP_OBSERVER_TARGET": "TRUE", "INS-64361_FOV_REF_ANGLE": 1.9849999999999999, "INS-64361_DEBUG_MODEL": "FALSE", "INS-64361_BORESIGHT": [0.0, 0.0, 1.0], "INS-64361_LIGHTTIME_CORRECTION": "LT+S", "INS-64361_FOV_CLASS_SPEC": "ANGLES", "INS-64361_FOV_REF_VECTOR": [1.0, 0.0, 0.0], "INS-64361_IFOV": 67.675, "INS-64361_FOV_CENTER_PIXEL": [511.5, 511.5], "INS-64361_DISTORTION_MODEL": "OPENCV", "INS-64361_FOV_SHAPE": "RECTANGLE", "INS-64361_FOV_CROSS_ANGLE": 1.9849999999999999, "INS-64361_PIXEL_SIZE": 8.5, "INS-64361_FL_UNCERTAINTY": 0.5, "INS-64361_FOV_FRAME": "ORX_OCAMS_MAPCAM", "INS-64361_OD_K_PAN": [2.21e-05, 0.000171, 5.96e-05, 0.0, 0.0], "FRAME_-64361_NAME": "ORX_OCAMS_MAPCAM", "INS-64361_OD_K_B": [5.06e-05, 0.00016299999999999998, 6e-05, 0.0, 0.0], "INS-64361_PIXEL_SAMPLES": 1024.0, "INS-64361_OD_K_V": [7.450000000000001e-05, 0.00022, 6.22e-05, 0.0, 0.0], "INS-64361_OD_K_W": [2.21e-05, 0.000132, 6.08e-05, 0.0, 0.0], "INS-64361_OD_K_X": [2.44e-05, -3.6099999999999997e-05, 8.869999999999999e-05, 0.0, 0.0], "INS-64361_CCD_CENTER": [511.5, 511.5], "FRAME_-64361_CLASS_ID": -64361.0, "CK_-64361_SCLK": -64.0, "INS-64361_SPOC_FITS_NAXIS1": [0.0, 1.0, 0.0], "INS-64361_SPOC_FITS_NAXIS2": [1.0, 0.0, 0.0], "BODY2101955_PM": [140.68835, 2011.145755336826, 1.815e-06], "BODY2101955_POLE_DEC": [-60.3586, 0.0, 0.0], "BODY2101955_POLE_RA": [85.46097, 0.0, 0.0], "BODY2101955_LONG_AXIS": 0.0, "OBJECT_2101955_FRAME": "IAU_BENNU"}, "detector_sample_summing": 1, "detector_line_summing": 1, "focal_length_model": {"focal_length": 125.2}, "detector_center": {"line": 511.5, "sample": 511.5}, "focal2pixel_lines": [0.0, 117.64705882353, 0.0], "focal2pixel_samples": [0.0, 0.0, 117.64705882353], "optical_distortion": {"radial": {"coefficients": [2.21e-05, 0.000171, 5.96e-05]}}, "starting_detector_line": 0, "starting_detector_sample": 0, "instrument_position": {"spk_table_start_time": 604882849.4327942, "spk_table_end_time": 604882849.4327942, "spk_table_original_size": 1, "ephemeris_times": [604882849.4327942], "positions": [[6.263896259086776, -0.17789034115912727, -2.0516825743917164]], "velocities": [[-1.6329228503551952e-05, 5.936927842752571e-06, -2.2327914272865625e-05]], "reference_frame": 1}, "sun_position": {"spk_table_start_time": 604882849.4327942, "spk_table_end_time": 604882849.4327942, "spk_table_original_size": 1, "ephemeris_times": [604882849.4327942], "positions": [[94633635.43566033, -98012563.34059505, -55786970.073704116]], "velocities": [[27.39074526770413, 14.215569043304772, 7.916498653173447]], "reference_frame": 1}} \ No newline at end of file +{ + "isis_camera_version": 1, + "image_lines": 1024, + "image_samples": 1024, + "name_platform": "OSIRIS-REX", + "name_sensor": "MapCam", + "reference_height": { + "maxheight": 1000, + "minheight": -1000, + "unit": "m" + }, + "name_model": "USGS_ASTRO_FRAME_SENSOR_MODEL", + "center_ephemeris_time": 604882849.4327942, + "radii": { + "semimajor": 0.283065, + "semiminor": 0.24972, + "unit": "km" + }, + "body_rotation": { + "time_dependent_frames": [ + 10106, + 1 + ], + "ck_table_start_time": 604882849.4327942, + "ck_table_end_time": 604882849.4327942, + "ck_table_original_size": 1, + "ephemeris_times": [ + 604882849.4327942 + ], + "quaternions": [ + [ + -0.24468662154888665, + -0.8995476917306681, + 0.3540944064834505, + 0.07456244922312974 + ] + ], + "angular_velocities": [ + [ + 1.5901075118354376e-05, + 0.00020029780775859552, + -0.0003531029098106748 + ] + ], + "reference_frame": 1 + }, + "instrument_pointing": { + "time_dependent_frames": [ + -64000, + 1 + ], + "ck_table_start_time": 604882849.4327942, + "ck_table_end_time": 604882849.4327942, + "ck_table_original_size": 1, + "ephemeris_times": [ + 604882849.4327942 + ], + "quaternions": [ + [ + -0.49481036455664573, + 0.4609332756246706, + -0.3664592415687433, + -0.6390702956780986 + ] + ], + "angular_velocities": [ + [ + 5.395053026508693e-06, + -5.108637996042997e-06, + 2.277063782852625e-06 + ] + ], + "reference_frame": 1, + "constant_frames": [ + -64000 + ], + "constant_rotation": [ + 1.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + "naif_keywords": { + "BODY2101955_RADII": [ + 0.283065, + 0.271215, + 0.24972 + ], + "BODY_FRAME_CODE": 10106, + "BODY_CODE": 2101955, + "INS-64361_TOLERANCE": 1e-10, + "INS-64361_ITRANSL": [ + 0.0, + 117.64705882353, + 0.0 + ], + "INS-64361_ITRANSS": [ + 0.0, + 0.0, + 117.64705882353 + ], + "FRAME_-64361_CLASS": 3.0, + "INS-64361_FOCAL_LENGTH": 125.2, + "FRAME_-64361_CENTER": -64.0, + "INS-64361_WAVELENGTH_RANGE": [ + 440.0, + 890.0 + ], + "CK_-64361_SPK": -64.0, + "INS-64361_OD_CENTER_PAN": [ + 486.2, + 450.3 + ], + "INS-64361_PIXEL_LINES": 1024.0, + "INS-64361_OD_CENTER_B": [ + 497.3, + 456.8 + ], + "INS-64361_TRANSX": [ + 0.0, + 0.0, + 0.0085 + ], + "INS-64361_TRANSY": [ + 0.0, + 0.0085, + 0.0 + ], + "INS-64361_OD_CENTER_V": [ + 494.3, + 473.8 + ], + "INS-64361_OD_CENTER_W": [ + 510.3, + 461.2 + ], + "INS-64361_OD_CENTER_X": [ + 504.5, + 450.5 + ], + "INS-64361_F/NUMBER": 3.295, + "INS-64361_LT_SURFACE_CORRECT": false, + "INS-64361_FOV_ANGLE_UNITS": "DEGREES", + "INS-64361_SWAP_OBSERVER_TARGET": true, + "INS-64361_FOV_REF_ANGLE": 1.9849999999999999, + "INS-64361_DEBUG_MODEL": false, + "INS-64361_BORESIGHT": [ + 0.0, + 0.0, + 1.0 + ], + "INS-64361_LIGHTTIME_CORRECTION": "LT+S", + "INS-64361_FOV_CLASS_SPEC": "ANGLES", + "INS-64361_FOV_REF_VECTOR": [ + 1.0, + 0.0, + 0.0 + ], + "INS-64361_IFOV": 67.675, + "INS-64361_FOV_CENTER_PIXEL": [ + 511.5, + 511.5 + ], + "INS-64361_DISTORTION_MODEL": "OPENCV", + "INS-64361_FOV_SHAPE": "RECTANGLE", + "INS-64361_FOV_CROSS_ANGLE": 1.9849999999999999, + "INS-64361_PIXEL_SIZE": 8.5, + "INS-64361_FL_UNCERTAINTY": 0.5, + "INS-64361_FOV_FRAME": "ORX_OCAMS_MAPCAM", + "INS-64361_OD_K_PAN": [ + 2.21e-05, + 0.000171, + 5.96e-05, + 0.0, + 0.0 + ], + "FRAME_-64361_NAME": "ORX_OCAMS_MAPCAM", + "INS-64361_OD_K_B": [ + 5.06e-05, + 0.00016299999999999998, + 6e-05, + 0.0, + 0.0 + ], + "INS-64361_PIXEL_SAMPLES": 1024.0, + "INS-64361_OD_K_V": [ + 7.450000000000001e-05, + 0.00022, + 6.22e-05, + 0.0, + 0.0 + ], + "INS-64361_OD_K_W": [ + 2.21e-05, + 0.000132, + 6.08e-05, + 0.0, + 0.0 + ], + "INS-64361_OD_K_X": [ + 2.44e-05, + -3.6099999999999997e-05, + 8.869999999999999e-05, + 0.0, + 0.0 + ], + "INS-64361_CCD_CENTER": [ + 511.5, + 511.5 + ], + "FRAME_-64361_CLASS_ID": -64361.0, + "CK_-64361_SCLK": -64.0, + "INS-64361_SPOC_FITS_NAXIS1": [ + 0.0, + 1.0, + 0.0 + ], + "INS-64361_SPOC_FITS_NAXIS2": [ + 1.0, + 0.0, + 0.0 + ], + "BODY2101955_PM": [ + 140.68835, + 2011.145755336826, + 1.815e-06 + ], + "BODY2101955_POLE_DEC": [ + -60.3586, + 0.0, + 0.0 + ], + "BODY2101955_POLE_RA": [ + 85.46097, + 0.0, + 0.0 + ], + "BODY2101955_LONG_AXIS": 0.0, + "OBJECT_2101955_FRAME": "IAU_BENNU" + }, + "detector_sample_summing": 1, + "detector_line_summing": 1, + "focal_length_model": { + "focal_length": 125.2 + }, + "detector_center": { + "line": 511.5, + "sample": 511.5 + }, + "focal2pixel_lines": [ + 0.0, + 117.64705882353, + 0.0 + ], + "focal2pixel_samples": [ + 0.0, + 0.0, + 117.64705882353 + ], + "optical_distortion": { + "radial": { + "coefficients": [ + 2.21e-05, + 0.000171, + 5.96e-05 + ] + } + }, + "starting_detector_line": 0, + "starting_detector_sample": 0, + "instrument_position": { + "spk_table_start_time": 604882849.4327942, + "spk_table_end_time": 604882849.4327942, + "spk_table_original_size": 1, + "ephemeris_times": [ + 604882849.4327942 + ], + "positions": [ + [ + 6.263896259086776, + -0.17789034115912727, + -2.0516825743917164 + ] + ], + "velocities": [ + [ + -1.6329228503551952e-05, + 5.936927842752571e-06, + -2.2327914272865625e-05 + ] + ], + "reference_frame": 1 + }, + "sun_position": { + "spk_table_start_time": 604882849.4327942, + "spk_table_end_time": 604882849.4327942, + "spk_table_original_size": 1, + "ephemeris_times": [ + 604882849.4327942 + ], + "positions": [ + [ + 94633635.43566033, + -98012563.34059505, + -55786970.073704116 + ] + ], + "velocities": [ + [ + 27.39074526770413, + 14.215569043304772, + 7.916498653173447 + ] + ], + "reference_frame": 1 + } +} \ No newline at end of file diff --git a/tests/pytests/test_osirisrex_drivers.py b/tests/pytests/test_osirisrex_drivers.py index 74b60dbfa..275a410a1 100644 --- a/tests/pytests/test_osirisrex_drivers.py +++ b/tests/pytests/test_osirisrex_drivers.py @@ -1,6 +1,6 @@ import os import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import pytest import json @@ -48,25 +48,31 @@ def test_sensor_frame_id(self): assert self.driver.sensor_frame_id == -64000 def test_detector_center_sample(self): - with patch('ale.drivers.osirisrex_drivers.spice.gdpool', return_value=np.array([12345, 100])) as gdpool, \ - patch('ale.drivers.osirisrex_drivers.spice.bods2c', return_value=54321) as bods2c: - assert self.driver.detector_center_sample == 12345 - bods2c.assert_called_with('ORX_OCAMS_MAPCAM') - gdpool.assert_called_with('INS54321_CCD_CENTER', 0, 2) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-54321]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-54321_CCD_CENTER": [12345, 100]} + assert self.driver.detector_center_sample == 12345 + calls = [call('NonMemo_translateNameToCode', {'frame': 'ORX_OCAMS_MAPCAM', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_detector_center_line(self): - with patch('ale.drivers.osirisrex_drivers.spice.gdpool', return_value=np.array([12345, 100])) as gdpool, \ - patch('ale.drivers.osirisrex_drivers.spice.bods2c', return_value=54321) as bods2c: - assert self.driver.detector_center_line == 100 - bods2c.assert_called_with('ORX_OCAMS_MAPCAM') - gdpool.assert_called_with('INS54321_CCD_CENTER', 0, 2) - + with patch('ale.spiceql_access.spiceql_call', side_effect=[-54321]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-54321_CCD_CENTER": [12345, 100]} + assert self.driver.detector_center_line == 100 + calls = [call('NonMemo_translateNameToCode', {'frame': 'ORX_OCAMS_MAPCAM', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 def test_filter_name(self): assert self.driver.filter_name == "PAN" def test_odtk(self): - with patch('ale.drivers.osirisrex_drivers.spice.bods2c', return_value=54321) as bods2c, \ - patch('ale.drivers.osirisrex_drivers.spice.gdpool', return_value=np.array([2.21e-05, 1.71e-04, 5.96e-05])) as gdpool: - assert self.driver.odtk == [2.21e-05, 1.71e-04, 5.96e-05] - gdpool.assert_called_with("INS54321_OD_K_PAN", 0, 3) + with patch('ale.spiceql_access.spiceql_call', side_effect=[-54321]) as spiceql_call, \ + patch('ale.base.data_naif.NaifSpice.naif_keywords', new_callable=PropertyMock) as naif_keywords: + naif_keywords.return_value = {"INS-54321_OD_K_PAN": [2.21e-05, 1.71e-04, 5.96e-05]} + assert self.driver.odtk == [2.21e-05, 1.71e-04, 5.96e-05] + calls = [call('NonMemo_translateNameToCode', {'frame': 'ORX_OCAMS_MAPCAM', 'mission': '', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 \ No newline at end of file From 289620d1f8a074317d24d6989938dec05b1314d8 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:19:32 -0700 Subject: [PATCH 61/73] Updated themis tests --- tests/pytests/test_themis_drivers.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/pytests/test_themis_drivers.py b/tests/pytests/test_themis_drivers.py index 195b244ea..29fec5d1f 100644 --- a/tests/pytests/test_themis_drivers.py +++ b/tests/pytests/test_themis_drivers.py @@ -2,12 +2,11 @@ import numpy as np import os import unittest -from unittest.mock import PropertyMock, patch +from unittest.mock import PropertyMock, patch, call import json import ale -from ale import util from ale.formatters.formatter import to_isd from ale.drivers.ody_drivers import OdyThemisVisIsisLabelNaifSpiceDriver, OdyThemisIrIsisLabelNaifSpiceDriver @@ -57,10 +56,13 @@ def test_line_exposure_duration(self): assert self.driver.line_exposure_duration == 0.0332871 def test_ephemeris_start_time(self): - with patch('ale.drivers.ody_drivers.spice.scs2e', return_value=0) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-53, 0]) as spiceql_call: self.driver.label["IsisCube"]["Instrument"]["SpacecraftClockOffset"] = 10 assert self.driver.ephemeris_start_time == 10 - scs2e.assert_called_with(-53, '1220641481.102') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS ODYSSEY', 'mission': 'odyssey', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -53, 'sclk': '1220641481.102', 'mission': 'odyssey', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 @@ -81,10 +83,13 @@ def test_line_exposure_duration(self): assert self.driver.line_exposure_duration == 0.0048 def test_ephemeris_start_time(self): - with patch('ale.drivers.mro_drivers.spice.scs2e', return_value=0) as scs2e: + with patch('ale.spiceql_access.spiceql_call', side_effect=[-53, 0]) as spiceql_call: self.driver.label["IsisCube"]["Instrument"]["SpacecraftClockOffset"] = 10 assert self.driver.ephemeris_start_time == (10 - self.driver.line_exposure_duration/2) - scs2e.assert_called_with(-53, '1023406812.23') + calls = [call('NonMemo_translateNameToCode', {'frame': 'MARS ODYSSEY', 'mission': 'odyssey', 'searchKernels': False}, False), + call('strSclkToEt', {'frameCode': -53, 'sclk': '1023406812.23', 'mission': 'odyssey', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 2 def test_sensor_model_version(self): assert self.driver.sensor_model_version == 1 From 8dbcfdbc3ae30bb717b2f0d64fd9714a98cde7fe Mon Sep 17 00:00:00 2001 From: acpaquette Date: Fri, 8 Dec 2023 17:20:17 -0700 Subject: [PATCH 62/73] Updated viking drivers and tests --- tests/pytests/data/isds/c1637937_isd.json | 23 ++++++++++++++++++++--- tests/pytests/data/isds/c1638610_isd.json | 23 ++++++++++++++++++++--- tests/pytests/data/isds/c2065022_isd.json | 4 +++- tests/pytests/data/isds/c2065801_isd.json | 23 ++++++++++++++++++++--- tests/pytests/test_viking_drivers.py | 20 +++++++++++--------- 5 files changed, 74 insertions(+), 19 deletions(-) diff --git a/tests/pytests/data/isds/c1637937_isd.json b/tests/pytests/data/isds/c1637937_isd.json index 33d4075aa..b2b8721f0 100644 --- a/tests/pytests/data/isds/c1637937_isd.json +++ b/tests/pytests/data/isds/c1637937_isd.json @@ -111,7 +111,9 @@ -0.003700098, -0.003700098, 1.0, - 0.003700098 + 0.003700098, + -0.003700098, + 1.0 ], "INS-31101_SPK_TIME_BIAS": 0.0, "TKFRAME_-31101_RELATIVE": "VG1_SCAN_PLATFORM", @@ -176,7 +178,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 5e-05, + 0.000404, + 0.000617, + -1.3e-05, + 0.000926 ], "BODY599_NUT_PREC_PM": [ 0.0, @@ -188,6 +195,11 @@ 0.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0 ], "BODY599_POLE_RA": [ @@ -210,7 +222,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 0.000117, + 0.000938, + 0.001432, + 3e-05, + 0.00215 ] }, "detector_sample_summing": 1, diff --git a/tests/pytests/data/isds/c1638610_isd.json b/tests/pytests/data/isds/c1638610_isd.json index ab438d371..f7b3a3db8 100644 --- a/tests/pytests/data/isds/c1638610_isd.json +++ b/tests/pytests/data/isds/c1638610_isd.json @@ -123,7 +123,9 @@ -0.02765, -0.02765, 1.0, - 0.02765 + 0.02765, + -0.02765, + 1.0 ], "INS-31102_TRANSX": [ 0.0, @@ -176,7 +178,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 5e-05, + 0.000404, + 0.000617, + -1.3e-05, + 0.000926 ], "BODY599_NUT_PREC_PM": [ 0.0, @@ -188,6 +195,11 @@ 0.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0 ], "BODY599_POLE_RA": [ @@ -210,7 +222,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 0.000117, + 0.000938, + 0.001432, + 3e-05, + 0.00215 ] }, "detector_sample_summing": 1, diff --git a/tests/pytests/data/isds/c2065022_isd.json b/tests/pytests/data/isds/c2065022_isd.json index 4af2c99f9..fcb646225 100644 --- a/tests/pytests/data/isds/c2065022_isd.json +++ b/tests/pytests/data/isds/c2065022_isd.json @@ -151,7 +151,9 @@ -0.003700098, -0.003700098, 1.0, - 0.003700098 + 0.003700098, + -0.003700098, + 1.0 ], "INS-32101_CK_FRAME_ID": -32100.0, "TKFRAME_-32101_UNITS": "DEGREES", diff --git a/tests/pytests/data/isds/c2065801_isd.json b/tests/pytests/data/isds/c2065801_isd.json index 97a41d971..626e4b87a 100644 --- a/tests/pytests/data/isds/c2065801_isd.json +++ b/tests/pytests/data/isds/c2065801_isd.json @@ -134,7 +134,9 @@ -0.02765, -0.02765, 1.0, - 0.02765 + 0.02765, + -0.02765, + 1.0 ], "FRAME_-32102_NAME": "VG2_ISSWA", "TKFRAME_-32102_AXES": [ @@ -176,7 +178,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 5e-05, + 0.000404, + 0.000617, + -1.3e-05, + 0.000926 ], "BODY599_NUT_PREC_PM": [ 0.0, @@ -188,6 +195,11 @@ 0.0, 0.0, 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, 0.0 ], "BODY599_POLE_RA": [ @@ -210,7 +222,12 @@ 0.0, 0.0, 0.0, - 0.0 + 0.0, + 0.000117, + 0.000938, + 0.001432, + 3e-05, + 0.00215 ] }, "detector_sample_summing": 1, diff --git a/tests/pytests/test_viking_drivers.py b/tests/pytests/test_viking_drivers.py index 38e3da2c2..56ae7be20 100644 --- a/tests/pytests/test_viking_drivers.py +++ b/tests/pytests/test_viking_drivers.py @@ -1,12 +1,10 @@ import pytest import os import numpy as np -import spiceypy as spice -from importlib import reload import json import unittest -from unittest.mock import patch +from unittest.mock import patch, call from conftest import data_root, get_image, get_isd, get_image_label, get_image_kernels, convert_kernels, compare_dicts import ale @@ -301,12 +299,16 @@ def test_alt_ikid(self): assert self.driver.alt_ikid == -27999 def test_ephemeris_start_time(self): - with patch('ale.drivers.viking_drivers.spice.scs2e', return_value=54321) as scs2e: - assert self.driver.ephemeris_start_time == 54324.99 - scs2e.assert_called_with(-27999, '40031801') + with patch('ale.spiceql_access.spiceql_call', side_effect=[54321]) as spiceql_call: + assert self.driver.ephemeris_start_time == 54324.99 + calls = [call('strSclkToEt', {'frameCode': -27999, 'sclk': '40031801', 'mission': 'viking1', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 @patch('ale.base.label_isis.IsisLabel.exposure_duration', 0.43) def test_ephemeris_start_time_different_exposure(self): - with patch('ale.drivers.viking_drivers.spice.scs2e', return_value=54321) as scs2e: - assert self.driver.ephemeris_start_time == 54322.75 - scs2e.assert_called_with(-27999, '40031801') + with patch('ale.spiceql_access.spiceql_call', side_effect=[54321]) as spiceql_call: + assert self.driver.ephemeris_start_time == 54322.75 + calls = [call('strSclkToEt', {'frameCode': -27999, 'sclk': '40031801', 'mission': 'viking1', 'searchKernels': False}, False)] + spiceql_call.assert_has_calls(calls) + assert spiceql_call.call_count == 1 From 8e58f896714ba4d0a77152d83935acdd7758e983 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 11 Dec 2023 10:29:41 -0700 Subject: [PATCH 63/73] Fixed up last chandrayaan isd --- .../pytests/data/isds/chandrayannM3_isd.json | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/pytests/data/isds/chandrayannM3_isd.json b/tests/pytests/data/isds/chandrayannM3_isd.json index 7a338edab..4003e62a6 100644 --- a/tests/pytests/data/isds/chandrayannM3_isd.json +++ b/tests/pytests/data/isds/chandrayannM3_isd.json @@ -188,8 +188,8 @@ "INS-86520_CK_REFERENCE_ID": 1.0, "INS-86520_PLATFORM_ID": -86000.0, "TKFRAME_-86520_UNITS": "DEGREES", - "INS-86520_LT_SURFACE_CORRECT": "TRUE", - "INS-86520_SWAP_OBSERVER_TARGET": "TRUE", + "INS-86520_LT_SURFACE_CORRECT": true, + "INS-86520_SWAP_OBSERVER_TARGET": true, "TKFRAME_-86520_ANGLES": [ 0.0, 0.0, @@ -243,7 +243,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -255,7 +258,10 @@ 0.0, 0.0, 0.0, - -0.0052 + -0.0052, + 0.0, + 0.0, + 0.0043 ], "BODY301_LONG_AXIS": 0.0, "BODY301_NUT_PREC_DEC": [ @@ -268,7 +274,10 @@ 0.0009, 0.0, 0.0, - 0.0008 + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_POLE_DEC": [ 66.5392, From 8aed7550af2e418a6f8975791c2240d24c6c9c55 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 11 Dec 2023 10:40:18 -0700 Subject: [PATCH 64/73] Moved kernel_access tests to test_kernel_access --- ale/kernel_access.py | 26 +--- ale/util.py | 22 +++ tests/pytests/test_kernel_access.py | 224 ++++++++++++++++++++++++++++ tests/pytests/test_util.py | 219 +-------------------------- 4 files changed, 249 insertions(+), 242 deletions(-) create mode 100644 tests/pytests/test_kernel_access.py diff --git a/ale/kernel_access.py b/ale/kernel_access.py index 910c3b97f..e197544b2 100644 --- a/ale/kernel_access.py +++ b/ale/kernel_access.py @@ -15,6 +15,8 @@ from ale.util import read_pvl from ale.util import search_isis_db from ale.util import dict_merge +from ale.util import dict_to_lower +from ale.util import expandvars def get_metakernels(spice_dir=spice_root, missions=set(), years=set(), versions=set()): """ @@ -147,30 +149,6 @@ def generate_kernels_from_cube(cube, expand=False, format_as='list'): return get_kernels_from_isis_pvl(kernel_group, expand, format_as) -def dict_to_lower(d): - return {k.lower():v if not isinstance(v, dict) else dict_to_lower(v) for k,v in d.items()} - - -def expandvars(path, env_dict=os.environ, default=None, case_sensitive=True): - if env_dict != os.environ: - env_dict = dict_merge(env_dict, os.environ) - - while "$" in path: - user_dict = env_dict if case_sensitive else dict_to_lower(env_dict) - - def replace_var(m): - group1 = m.group(1) if case_sensitive else m.group(1).lower() - val = user_dict.get(m.group(2) or group1 if default is None else default) - if not val: - raise KeyError(f"Failed to evaluate {m.group(0)} from env_dict. " + - f"Should {m.group(0)} be an environment variable?") - - return val - reVar = r'\$(\w+|\{([^}]*)\})' - path = re.sub(reVar, replace_var, path) - return path - - def get_kernels_from_isis_pvl(kernel_group, expand=True, format_as="list"): # enforce key order mk_paths = OrderedDict.fromkeys( diff --git a/ale/util.py b/ale/util.py index eecac5747..27c22bb08 100644 --- a/ale/util.py +++ b/ale/util.py @@ -184,6 +184,8 @@ def dict_merge(dct, merge_dct): return new_dct +def dict_to_lower(d): + return {k.lower():v if not isinstance(v, dict) else dict_to_lower(v) for k,v in d.items()} def get_isis_preferences(isis_preferences=None): """ @@ -687,3 +689,23 @@ def search_isis_db(dbobj, labelobj, isis_data): if any(types): kernels["types"] = types return kernels + + +def expandvars(path, env_dict=os.environ, default=None, case_sensitive=True): + if env_dict != os.environ: + env_dict = dict_merge(env_dict, os.environ) + + while "$" in path: + user_dict = env_dict if case_sensitive else dict_to_lower(env_dict) + + def replace_var(m): + group1 = m.group(1) if case_sensitive else m.group(1).lower() + val = user_dict.get(m.group(2) or group1 if default is None else default) + if not val: + raise KeyError(f"Failed to evaluate {m.group(0)} from env_dict. " + + f"Should {m.group(0)} be an environment variable?") + + return val + reVar = r'\$(\w+|\{([^}]*)\})' + path = re.sub(reVar, replace_var, path) + return path \ No newline at end of file diff --git a/tests/pytests/test_kernel_access.py b/tests/pytests/test_kernel_access.py new file mode 100644 index 000000000..b1ba06dd3 --- /dev/null +++ b/tests/pytests/test_kernel_access.py @@ -0,0 +1,224 @@ +from importlib import reload +from os.path import join + +import pytest +import tempfile +import pvl +from unittest.mock import MagicMock, patch + +from collections import OrderedDict + +import ale +from ale import kernel_access + +@pytest.fixture +def cube_kernels(): + return """ + Object = IsisCube + Group = Instrument + StartTime = 2016-332T05:40:45.020 + StopTime = 2016-332T05:40:46.820 + InstrumentId = fake + SpacecraftName = fake + End_Group + + Group = Kernels + TargetAttitudeShape = $base/attitudeshape + TargetPosition = ($messenger/targetposition0, $messenger/targetposition1) + Instrument = $messenger/instrument + InstrumentPointing = (Table, $messenger/instrumentpointing0, $messenger/instrumentpointing1) + SpacecraftClock = $base/clock + InstrumentPosition = $messenger/instrumentposition + InstrumentAddendum = Null + ShapeModel = Null + End_Group + End_Object + End + """ + +@pytest.fixture +def pvl_four_group(): + # Mock of the DataDirectory group + return """ + Group = DataDirectory + Base = $ISIS3DATA/base + Messenger = $ISIS3DATA/messenger + EndGroup + """ + +def test_find_kernels(cube_kernels, tmpdir): + ck_db = """ + Object = Pointing + Group = Selection + Time = ( "2016 JAN 01 00:00:00.000000 TDB", "2016 DEC 31 00:00:00.000000 TDB" ) + Type = Reconstructed + File = $MRO/fake + End_Group + End_Object + """ + + ik_db = """ + Object = instrument + Group = Selection + Match = ("Instrument", "InstrumentId", "fake") + File = ("fake", "not/a/real/file") + End_Group + End_Object + """ + translation = """ + Group = MissionName + InputKey = SpacecraftName + InputGroup = "IsisCube,Instrument" + InputPosition = (IsisCube, Instrument) + Translation = (fake, "fake") + End_Group + """ + + tmpdir.mkdir("fake").mkdir("kernels").mkdir("ik") + tmpdir.mkdir("base").mkdir("kernels").mkdir("ck") + tmpdir.mkdir("base", "translations") + + ck_db_file = tmpdir.join("base", "kernels", "ck", "kernel.01.db") + ik_db_file = tmpdir.join("fake", "kernels", "ik", "kernel.01.db") + translation_file = tmpdir.join("base", "translations", "MissionName2DataDir.trn") + cube_file = tmpdir.join("test.cub") + + with open(translation_file, "w") as f: + f.write(translation) + + with open(ck_db_file, "w") as f: + f.write(ck_db) + + with open(ik_db_file, "w") as f: + f.write(ik_db) + + with open(cube_file, "w") as cube: + cube.write(cube_kernels) + + print(pvl.load(str(cube_file))) + kernels = kernel_access.find_kernels(str(cube_file), str(tmpdir)) + assert kernels == {'Pointing': {'kernels': [str(tmpdir / 'MRO/fake')], 'types': ['Reconstructed']}, 'instrument': {'kernels': [str(tmpdir / 'fake/not/a/real/file')]}} + +def test_kernel_from_cube_list(cube_kernels): + with tempfile.NamedTemporaryFile('r+') as cube: + cube.write(cube_kernels) + cube.flush() + kernels = kernel_access.generate_kernels_from_cube(cube.name) + assert kernels == ['$messenger/targetposition0', '$messenger/targetposition1','$messenger/instrumentposition', '$messenger/instrumentpointing0', '$messenger/instrumentpointing1', '$base/attitudeshape', '$messenger/instrument', '$base/clock'] + +def test_kernel_from_cube_list_expanded(monkeypatch, tmpdir, pvl_four_group, cube_kernels): + with patch.dict('os.environ', {'ISISROOT': str(tmpdir), 'ISIS3DATA': '$ISISDATA', 'ISISDATA': '/test/path'}): + + with open(tmpdir.join('IsisPreferences'), 'w+') as pvl_isisroot_file: + pvl_isisroot_file.write(pvl_four_group) + pvl_isisroot_file.flush() + + with tempfile.NamedTemporaryFile('r+') as cube: + cube.write(cube_kernels) + cube.flush() + kernels = kernel_access.generate_kernels_from_cube(cube.name, expand=True) + assert kernels == ['/test/path/messenger/targetposition0', '/test/path/messenger/targetposition1', '/test/path/messenger/instrumentposition', '/test/path/messenger/instrumentpointing0', '/test/path/messenger/instrumentpointing1', '/test/path/base/attitudeshape', '/test/path/messenger/instrument', '/test/path/base/clock'] + +def test_kernel_from_cube_dict(cube_kernels): + with tempfile.NamedTemporaryFile('r+') as cube: + cube.write(cube_kernels) + cube.flush() + kernels = kernel_access.generate_kernels_from_cube(cube.name, format_as='dict') + assert kernels == OrderedDict([('TargetPosition', ['$messenger/targetposition0', '$messenger/targetposition1']), ('InstrumentPosition', ['$messenger/instrumentposition']), ('InstrumentPointing', ['$messenger/instrumentpointing0', '$messenger/instrumentpointing1']), ('Frame', [None]), ('TargetAttitudeShape', ['$base/attitudeshape']), ('Instrument', ['$messenger/instrument']), ('InstrumentAddendum', [None]), ('LeapSecond', [None]), ('SpacecraftClock', ['$base/clock']), ('Extra', [None]), ('Clock', [None])]) + +def test_kernel_from_cube_dict_expanded(monkeypatch, tmpdir, pvl_four_group, cube_kernels): + with patch.dict('os.environ', {'ISISROOT': str(tmpdir), 'ISIS3DATA': '$ISISDATA', 'ISISDATA': '/test/path'}): + + with open(tmpdir.join('IsisPreferences'), 'w+') as pvl_isisroot_file: + pvl_isisroot_file.write(pvl_four_group) + pvl_isisroot_file.flush() + + with tempfile.NamedTemporaryFile('r+') as cube: + cube.write(cube_kernels) + cube.flush() + kernels = kernel_access.generate_kernels_from_cube(cube.name, expand=True, format_as='dict') + assert kernels == OrderedDict([('TargetPosition', ['/test/path/messenger/targetposition0', '/test/path/messenger/targetposition1']), ('InstrumentPosition', ['/test/path/messenger/instrumentposition']), ('InstrumentPointing', ['/test/path/messenger/instrumentpointing0', '/test/path/messenger/instrumentpointing1']), ('Frame', [None]), ('TargetAttitudeShape', ['/test/path/base/attitudeshape']), ('Instrument', ['/test/path/messenger/instrument']), ('InstrumentAddendum', [None]), ('LeapSecond', [None]), ('SpacecraftClock', ['/test/path/base/clock']), ('Extra', [None]), ('Clock', [None])]) + +def test_kernel_from_cube_no_kernel_group(): + with pytest.raises(KeyError): + with tempfile.NamedTemporaryFile('w+') as cube: + cube.write('') + cube.flush() + kernel_access.generate_kernels_from_cube(cube.name) + +@pytest.mark.parametrize('search_kwargs,expected', + [({'years':'2009', 'versions':'v01'}, {'count':1, 'data':[{'path':join('foo-b-v01', 'foo_2009_v01.tm'), 'year':'2009', 'mission':'foo', 'version':'v01'}]}), + ({'versions':'v02', 'years':2010}, {'count': 1, 'data': [{'path':join('bar-b-v01', 'bar_2010_v02.tm'), 'year':'2010', 'mission':'bar', 'version': 'v02'}]})]) +def test_get_metakernels(tmpdir, search_kwargs, expected): + tmpdir.mkdir('foo-b-v01') + tmpdir.mkdir('bar-b-v01') + + open(tmpdir.join('foo-b-v01', 'foo_2009_v01.tm'), 'w').close() + open(tmpdir.join('bar-b-v01', 'bar_2010_v02.tm'), 'w').close() + + search_result = kernel_access.get_metakernels(str(tmpdir), **search_kwargs) + # we can't know the tmpdir at parameterization, append it here + for r in expected['data']: + r['path'] = str(tmpdir.join(r['path'])) + + assert search_result == expected + +@pytest.mark.parametrize('search_kwargs, expected', + [({'years':'2009', 'versions':'v01'}, {'count':0, 'data':[]})]) +def test_get_metakernels_no_alespiceroot(monkeypatch, search_kwargs, expected): + with pytest.warns(UserWarning, match="Unable to search mission directories without" + + "ALESPICEROOT being set. Defaulting to empty list"): + search_result = ale.kernel_access.get_metakernels(**search_kwargs) + print(search_result) + with patch.dict('os.environ', {'ALESPICEROOT': '/foo/bar'}): + reload(ale) + + assert search_result == expected + reload(ale) + assert not ale.spice_root + +@pytest.mark.parametrize('search_kwargs', [{'years':'2010'}, {'years':2010}, {'years': [2010]}, {'years': ['2010']}, {'years': set(['2010', '1999', '1776'])}, + {'missions':'bar', 'versions':'v20'}, {'missions': ['bar'], 'versions':'v20'}, {'missions': 'bar', 'versions':['v20', 'v03']}, {'missions':set(['bar']),'years': 2010, 'versions': 'latest'} ]) +def test_get_metakernels_search_args(tmpdir, search_kwargs): + tmpdir.mkdir('foo-b-v01') + tmpdir.mkdir('bar-b-v01') + + open(tmpdir.join('foo-b-v01', 'foo_2009_v01.tm'), 'w').close() + open(tmpdir.join('bar-b-v01', 'bar_9009_v01.tm'), 'w').close() + open(tmpdir.join('bar-b-v01', 'bar_2009_v10.tm'), 'w').close() + + test_mk = tmpdir.join('bar-b-v01', 'bar_2010_v20.tm') + open(test_mk, 'w').close() + + search_result = kernel_access.get_metakernels(str(tmpdir), **search_kwargs) + + expected = { + 'count' : 1, + 'data' : [{ + 'year' : '2010', + 'mission' : 'bar', + 'version': 'v20', + 'path': test_mk + }] + } + + assert search_result == expected + +@pytest.mark.parametrize('search_kwargs,expected_count', [({'years':'2010'}, 2), ({'years': ['1990', '2009']}, 4), ({'years':'9009'}, 1), ({'years':'all'}, 7), ({'years':[]},7), ({'versions':'latest'}, 6), ({'versions':'all'},7), ({'versions':[]}, 7), ({'versions':None}, 7), ({'versions':['v20']}, 2), ({'versions':['v10', 'v01']}, 4), ({'missions': 'foo'}, 3), ({'missions':'bar'},3), ({'missions':'baz'},1), ({'missions':'all'}, 7), ({'missions':['foo', 'bar'], 'versions': 'v01', 'years': + 2009}, 1), ({}, 7), ({'versions': 'latest', 'missions':'foo'}, 2), ({'missions': 'not_real'}, 0)]) +def test_get_metakernels_search_counts(tmpdir, search_kwargs, expected_count): + tmpdir.mkdir('foo-b-v01') + tmpdir.mkdir('bar-b-v01') + tmpdir.mkdir('baz-b-v100') + + open(tmpdir.join('foo-b-v01', 'foo_2009_v01.tm'), 'w').close() + open(tmpdir.join('foo-b-v01', 'foo_2009_v20.tm'), 'w').close() + open(tmpdir.join('foo-b-v01', 'foo_2010_v20.tm'), 'w').close() + open(tmpdir.join('bar-b-v01', 'bar_9009_v01.tm'), 'w').close() + open(tmpdir.join('bar-b-v01', 'bar_2009_v10.tm'), 'w').close() + open(tmpdir.join('bar-b-v01', 'bar_2010_v02.tm'), 'w').close() + open(tmpdir.join('baz-b-v100', 'baz_1990_v10.tm'), 'w').close() + + + search_result = kernel_access.get_metakernels(str(tmpdir), **search_kwargs) + assert search_result['count'] == expected_count \ No newline at end of file diff --git a/tests/pytests/test_util.py b/tests/pytests/test_util.py index 9fe3685dd..568fc8d3b 100644 --- a/tests/pytests/test_util.py +++ b/tests/pytests/test_util.py @@ -14,32 +14,6 @@ import ale from ale import util -@pytest.fixture -def cube_kernels(): - return """ - Object = IsisCube - Group = Instrument - StartTime = 2016-332T05:40:45.020 - StopTime = 2016-332T05:40:46.820 - InstrumentId = fake - SpacecraftName = fake - End_Group - - Group = Kernels - TargetAttitudeShape = $base/attitudeshape - TargetPosition = ($messenger/targetposition0, $messenger/targetposition1) - Instrument = $messenger/instrument - InstrumentPointing = (Table, $messenger/instrumentpointing0, $messenger/instrumentpointing1) - SpacecraftClock = $base/clock - InstrumentPosition = $messenger/instrumentposition - InstrumentAddendum = Null - ShapeModel = Null - End_Group - End_Object - End - """ - - @pytest.fixture def pvl_one_group(): return """ @@ -82,126 +56,12 @@ def pvl_three_group(): End_Group """ -@pytest.fixture -def pvl_four_group(): - # Mock of the DataDirectory group - return """ - Group = DataDirectory - Base = $ISIS3DATA/base - Messenger = $ISIS3DATA/messenger - EndGroup - """ - def test_pvl_parser(pvl_three_group): obj = util.JBFPvlParser(pvl_three_group) assert obj["Data"]["a"] == "a3" assert obj["Test"]["t"] == "t3" assert obj["Settings"]["delsystem32"] == "yes" - -def test_find_kernels(cube_kernels, tmpdir): - ck_db = """ - Object = Pointing - Group = Selection - Time = ( "2016 JAN 01 00:00:00.000000 TDB", "2016 DEC 31 00:00:00.000000 TDB" ) - Type = Reconstructed - File = $MRO/fake - End_Group - End_Object - """ - - ik_db = """ - Object = instrument - Group = Selection - Match = ("Instrument", "InstrumentId", "fake") - File = ("fake", "not/a/real/file") - End_Group - End_Object - """ - translation = """ - Group = MissionName - InputKey = SpacecraftName - InputGroup = "IsisCube,Instrument" - InputPosition = (IsisCube, Instrument) - Translation = (fake, "fake") - End_Group - """ - - tmpdir.mkdir("fake").mkdir("kernels").mkdir("ik") - tmpdir.mkdir("base").mkdir("kernels").mkdir("ck") - tmpdir.mkdir("base", "translations") - - ck_db_file = tmpdir.join("base", "kernels", "ck", "kernel.01.db") - ik_db_file = tmpdir.join("fake", "kernels", "ik", "kernel.01.db") - translation_file = tmpdir.join("base", "translations", "MissionName2DataDir.trn") - cube_file = tmpdir.join("test.cub") - - with open(translation_file, "w") as f: - f.write(translation) - - with open(ck_db_file, "w") as f: - f.write(ck_db) - - with open(ik_db_file, "w") as f: - f.write(ik_db) - - with open(cube_file, "w") as cube: - cube.write(cube_kernels) - - print(pvl.load(str(cube_file))) - kernels = util.find_kernels(str(cube_file), str(tmpdir)) - assert kernels == {'Pointing': {'kernels': [str(tmpdir / 'MRO/fake')], 'types': ['Reconstructed']}, 'instrument': {'kernels': [str(tmpdir / 'fake/not/a/real/file')]}} - - -def test_kernel_from_cube_list(cube_kernels): - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name) - assert kernels == ['$messenger/targetposition0', '$messenger/targetposition1','$messenger/instrumentposition', '$messenger/instrumentpointing0', '$messenger/instrumentpointing1', '$base/attitudeshape', '$messenger/instrument', '$base/clock'] - -def test_kernel_from_cube_list_expanded(monkeypatch, tmpdir, pvl_four_group, cube_kernels): - monkeypatch.setenv('ISISROOT', str(tmpdir)) - monkeypatch.setenv('ISIS3DATA', '/test/path') - - with open(tmpdir.join('IsisPreferences'), 'w+') as pvl_isisroot_file: - pvl_isisroot_file.write(pvl_four_group) - pvl_isisroot_file.flush() - - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name, expand=True) - assert kernels == ['/test/path/messenger/targetposition0', '/test/path/messenger/targetposition1', '/test/path/messenger/instrumentposition', '/test/path/messenger/instrumentpointing0', '/test/path/messenger/instrumentpointing1', '/test/path/base/attitudeshape', '/test/path/messenger/instrument', '/test/path/base/clock'] - -def test_kernel_from_cube_dict(cube_kernels): - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name, format_as='dict') - assert kernels == OrderedDict([('TargetPosition', ['$messenger/targetposition0', '$messenger/targetposition1']), ('InstrumentPosition', ['$messenger/instrumentposition']), ('InstrumentPointing', ['$messenger/instrumentpointing0', '$messenger/instrumentpointing1']), ('Frame', [None]), ('TargetAttitudeShape', ['$base/attitudeshape']), ('Instrument', ['$messenger/instrument']), ('InstrumentAddendum', [None]), ('LeapSecond', [None]), ('SpacecraftClock', ['$base/clock']), ('Extra', [None]), ('Clock', [None])]) - -def test_kernel_from_cube_dict_expanded(monkeypatch, tmpdir, pvl_four_group, cube_kernels): - monkeypatch.setenv('ISISROOT', str(tmpdir)) - monkeypatch.setenv('ISIS3DATA', '/test/path') - - with open(tmpdir.join('IsisPreferences'), 'w+') as pvl_isisroot_file: - pvl_isisroot_file.write(pvl_four_group) - pvl_isisroot_file.flush() - - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name, expand=True, format_as='dict') - assert kernels == OrderedDict([('TargetPosition', ['/test/path/messenger/targetposition0', '/test/path/messenger/targetposition1']), ('InstrumentPosition', ['/test/path/messenger/instrumentposition']), ('InstrumentPointing', ['/test/path/messenger/instrumentpointing0', '/test/path/messenger/instrumentpointing1']), ('Frame', [None]), ('TargetAttitudeShape', ['/test/path/base/attitudeshape']), ('Instrument', ['/test/path/messenger/instrument']), ('InstrumentAddendum', [None]), ('LeapSecond', [None]), ('SpacecraftClock', ['/test/path/base/clock']), ('Extra', [None]), ('Clock', [None])]) - -def test_kernel_from_cube_no_kernel_group(): - with pytest.raises(KeyError): - with tempfile.NamedTemporaryFile('w+') as cube: - cube.write('') - cube.flush() - util.generate_kernels_from_cube(cube.name) - def test_get_preferences_arg(tmpdir, pvl_one_group): with open(tmpdir.join('IsisPrefrences'), 'w+') as pvl_file: pvl_file.write(pvl_one_group) @@ -275,90 +135,13 @@ def test_get_prefrences_malformed_files(monkeypatch, tmpdir, filename): util.get_isis_preferences(tmpdir.join(filename)) -@pytest.mark.parametrize('string,expected,case_sensitive', [('$bar/baz', '/bar/baz', False), ('$bar/$foo/baz', '/bar//foo/baz', True), ('$BAR/$FOO/baz', '/bar//foo/baz', False)]) +@pytest.mark.parametrize('string,expected,case_sensitive', [('$bar/baz', '/bar/baz', False), ('$bar/$foo/baz', '/bar//foo/baz', True), ('$BAR/$FOO/baz', '/bar//foo/baz', False), ('$foo/$bar/$foo/baz', '/foo//bar//foo/baz', True)]) def test_expand_vars(string, expected, case_sensitive): user_vars = {'foo': '/foo', 'bar': '/bar'} result = util.expandvars(string, env_dict=user_vars, case_sensitive=case_sensitive) assert result == expected -@pytest.mark.parametrize('search_kwargs,expected', - [({'years':'2009', 'versions':'v01'}, {'count':1, 'data':[{'path':join('foo-b-v01', 'foo_2009_v01.tm'), 'year':'2009', 'mission':'foo', 'version':'v01'}]}), - ({'versions':'v02', 'years':2010}, {'count': 1, 'data': [{'path':join('bar-b-v01', 'bar_2010_v02.tm'), 'year':'2010', 'mission':'bar', 'version': 'v02'}]})]) -def test_get_metakernels(tmpdir, search_kwargs, expected): - tmpdir.mkdir('foo-b-v01') - tmpdir.mkdir('bar-b-v01') - - open(tmpdir.join('foo-b-v01', 'foo_2009_v01.tm'), 'w').close() - open(tmpdir.join('bar-b-v01', 'bar_2010_v02.tm'), 'w').close() - - search_result = util.get_metakernels(str(tmpdir), **search_kwargs) - # we can't know the tmpdir at parameterization, append it here - for r in expected['data']: - r['path'] = str(tmpdir.join(r['path'])) - - assert search_result == expected - -@pytest.mark.parametrize('search_kwargs, expected', - [({'years':'2009', 'versions':'v01'}, {'count':0, 'data':[]})]) -def test_get_metakernels_no_alespiceroot(monkeypatch, search_kwargs, expected): - monkeypatch.delenv('ALESPICEROOT', raising=False) - reload(ale) - with pytest.warns(UserWarning, match="Unable to search mission directories without" + - "ALESPICEROOT being set. Defaulting to empty list"): - search_result = ale.util.get_metakernels(**search_kwargs) - print(search_result) - monkeypatch.setenv('ALESPICEROOT', '/foo/bar') - reload(ale) - - assert search_result == expected - -@pytest.mark.parametrize('search_kwargs', [{'years':'2010'}, {'years':2010}, {'years': [2010]}, {'years': ['2010']}, {'years': set(['2010', '1999', '1776'])}, - {'missions':'bar', 'versions':'v20'}, {'missions': ['bar'], 'versions':'v20'}, {'missions': 'bar', 'versions':['v20', 'v03']}, {'missions':set(['bar']),'years': 2010, 'versions': 'latest'} ]) -def test_get_metakernels_search_args(tmpdir, search_kwargs): - tmpdir.mkdir('foo-b-v01') - tmpdir.mkdir('bar-b-v01') - - open(tmpdir.join('foo-b-v01', 'foo_2009_v01.tm'), 'w').close() - open(tmpdir.join('bar-b-v01', 'bar_9009_v01.tm'), 'w').close() - open(tmpdir.join('bar-b-v01', 'bar_2009_v10.tm'), 'w').close() - - test_mk = tmpdir.join('bar-b-v01', 'bar_2010_v20.tm') - open(test_mk, 'w').close() - - search_result = util.get_metakernels(str(tmpdir), **search_kwargs) - - expected = { - 'count' : 1, - 'data' : [{ - 'year' : '2010', - 'mission' : 'bar', - 'version': 'v20', - 'path': test_mk - }] - } - - assert search_result == expected - -@pytest.mark.parametrize('search_kwargs,expected_count', [({'years':'2010'}, 2), ({'years': ['1990', '2009']}, 4), ({'years':'9009'}, 1), ({'years':'all'}, 7), ({'years':[]},7), ({'versions':'latest'}, 6), ({'versions':'all'},7), ({'versions':[]}, 7), ({'versions':None}, 7), ({'versions':['v20']}, 2), ({'versions':['v10', 'v01']}, 4), ({'missions': 'foo'}, 3), ({'missions':'bar'},3), ({'missions':'baz'},1), ({'missions':'all'}, 7), ({'missions':['foo', 'bar'], 'versions': 'v01', 'years': - 2009}, 1), ({}, 7), ({'versions': 'latest', 'missions':'foo'}, 2), ({'missions': 'not_real'}, 0)]) -def test_get_metakernels_search_counts(tmpdir, search_kwargs, expected_count): - tmpdir.mkdir('foo-b-v01') - tmpdir.mkdir('bar-b-v01') - tmpdir.mkdir('baz-b-v100') - - open(tmpdir.join('foo-b-v01', 'foo_2009_v01.tm'), 'w').close() - open(tmpdir.join('foo-b-v01', 'foo_2009_v20.tm'), 'w').close() - open(tmpdir.join('foo-b-v01', 'foo_2010_v20.tm'), 'w').close() - open(tmpdir.join('bar-b-v01', 'bar_9009_v01.tm'), 'w').close() - open(tmpdir.join('bar-b-v01', 'bar_2009_v10.tm'), 'w').close() - open(tmpdir.join('bar-b-v01', 'bar_2010_v02.tm'), 'w').close() - open(tmpdir.join('baz-b-v100', 'baz_1990_v10.tm'), 'w').close() - - - search_result = util.get_metakernels(str(tmpdir), **search_kwargs) - assert search_result['count'] == expected_count - def test_create_spk_dependency_tree(): de430_output =""" BRIEF -- Version 4.0.0, September 8, 2010 -- Toolkit Version N0066 From c366767732b60ed445f331f614ff31319b9e48b0 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 11 Dec 2023 13:48:29 -0700 Subject: [PATCH 65/73] Minor fixes after rebase --- ale/drivers/lro_drivers.py | 27 +- ale/formatters/formatter.py | 4 +- tests/pytests/data/isds/lrominirf_isd.json | 8926 +++++++++++++++++++- tests/pytests/data/isds/msl_nadir_isd.json | 16 +- tests/pytests/test_lo_drivers.py | 8 +- tests/pytests/test_lro_drivers.py | 7 +- 6 files changed, 8699 insertions(+), 289 deletions(-) diff --git a/ale/drivers/lro_drivers.py b/ale/drivers/lro_drivers.py index 0ac8b936d..c4713e285 100644 --- a/ale/drivers/lro_drivers.py +++ b/ale/drivers/lro_drivers.py @@ -516,7 +516,6 @@ def spacecraft_direction(self): frame_chain = self.frame_chain lro_bus_id = self.spiceql_call("translateNameToCode", {'frame': 'LRO_SC_BUS', 'mission': self.spiceql_mission}) time = self.ephemeris_start_time - print(time) lt_states = self.spiceql_call("getTargetStates", {'ets': [time], 'target': self.spacecraft_name, 'observer': self.target_name, @@ -527,7 +526,6 @@ def spacecraft_direction(self): 'spkQuality': ""}) velocity = lt_states[0][3:6] rotation = frame_chain.compute_rotation(1, lro_bus_id) - print(rotation._rots.as_matrix()[0], velocity) rotated_velocity = spice.mxv(rotation._rots.as_matrix()[0], velocity) self._spacecraft_direction = rotated_velocity[0] return self._spacecraft_direction @@ -838,6 +836,7 @@ def ephemeris_start_time(self): """ if not hasattr(self, "_ephemeris_start_time"): self._ephemeris_start_time = self.spiceql_call("utcToEt", {"utc": self.utc_start_time.strftime("%Y-%m-%d %H:%M:%S.%f")}) + self._ephemeris_start_time -= self.line_exposure_duration return self._ephemeris_start_time @property @@ -868,18 +867,18 @@ def look_direction(self): """ return self.label['IsisCube']['Instrument']['LookDirection'].lower() - @property - def sensor_frame_id(self): - """ - Returns the Naif ID code for the sensor reference frame - We replace this with the target frame ID because the sensor operates - entirely in the target reference frame - Returns - ------- - : int - Naif ID code for the sensor frame - """ - return self.target_frame_id + # @property + # def sensor_frame_id(self): + # """ + # Returns the Naif ID code for the sensor reference frame + # We replace this with the target frame ID because the sensor operates + # entirely in the target reference frame + # Returns + # ------- + # : int + # Naif ID code for the sensor frame + # """ + # return self.target_frame_id @property def naif_keywords(self): diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py index fbbc22dd0..2e0f1d2ac 100644 --- a/ale/formatters/formatter.py +++ b/ale/formatters/formatter.py @@ -156,8 +156,8 @@ def to_isd(driver): isd['focal2pixel_samples'] = driver_data["focal2pixel_samples"] isd['optical_distortion'] = driver_data["usgscsm_distortion_model"] - isd['starting_detector_line'] = driver_data.detector_start_line - isd['starting_detector_sample'] = driver_data.detector_start_sample + isd['starting_detector_line'] = driver_data["detector_start_line"] + isd['starting_detector_sample'] = driver_data["detector_start_sample"] j2000_rotation = frame_chain.compute_rotation(target_frame, J2000) diff --git a/tests/pytests/data/isds/lrominirf_isd.json b/tests/pytests/data/isds/lrominirf_isd.json index 08363a8b8..19237111c 100644 --- a/tests/pytests/data/isds/lrominirf_isd.json +++ b/tests/pytests/data/isds/lrominirf_isd.json @@ -224,75 +224,8466 @@ }, "instrument_pointing": { "time_dependent_frames": [ - 31006, + -85000, 1 ], "ck_table_start_time": 325441417.4257179, "ck_table_end_time": 325441420.7282218, - "ck_table_original_size": 2, + "ck_table_original_size": 701, "ephemeris_times": [ 325441417.4257179, - 325441420.7282218 - ], - "quaternions": [ + 325441417.4304358, + 325441417.4351536, + 325441417.4398715, + 325441417.4445893, + 325441417.4493072, + 325441417.4540251, + 325441417.4587429, + 325441417.4634608, + 325441417.46817863, + 325441417.4728965, + 325441417.4776144, + 325441417.4823322, + 325441417.4870501, + 325441417.49176794, + 325441417.4964858, + 325441417.5012037, + 325441417.50592154, + 325441417.5106394, + 325441417.51535726, + 325441417.52007514, + 325441417.524793, + 325441417.52951086, + 325441417.53422874, + 325441417.53894657, + 325441417.54366446, + 325441417.54838234, + 325441417.55310017, + 325441417.55781806, + 325441417.5625359, + 325441417.56725377, + 325441417.57197165, + 325441417.5766895, + 325441417.58140737, + 325441417.5861252, + 325441417.5908431, + 325441417.59556097, + 325441417.6002788, + 325441417.6049967, + 325441417.6097145, + 325441417.6144324, + 325441417.6191503, + 325441417.6238681, + 325441417.628586, + 325441417.6333038, + 325441417.6380217, + 325441417.6427396, + 325441417.6474574, + 325441417.6521753, + 325441417.65689313, + 325441417.661611, + 325441417.6663289, + 325441417.67104673, + 325441417.6757646, + 325441417.68048245, + 325441417.68520033, + 325441417.6899182, + 325441417.69463605, + 325441417.69935393, + 325441417.70407176, + 325441417.70878965, + 325441417.71350753, + 325441417.71822536, + 325441417.72294325, + 325441417.7276611, + 325441417.73237896, + 325441417.73709685, + 325441417.7418147, + 325441417.74653256, + 325441417.7512504, + 325441417.7559683, + 325441417.76068616, + 325441417.765404, + 325441417.7701219, + 325441417.77483976, + 325441417.7795576, + 325441417.7842755, + 325441417.7889933, + 325441417.7937112, + 325441417.7984291, + 325441417.8031469, + 325441417.8078648, + 325441417.8125826, + 325441417.8173005, + 325441417.8220184, + 325441417.8267362, + 325441417.8314541, + 325441417.8361719, + 325441417.8408898, + 325441417.8456077, + 325441417.8503255, + 325441417.8550434, + 325441417.85976124, + 325441417.8644791, + 325441417.869197, + 325441417.87391484, + 325441417.8786327, + 325441417.88335055, + 325441417.88806844, + 325441417.8927863, + 325441417.89750415, + 325441417.90222204, + 325441417.90693986, + 325441417.91165775, + 325441417.91637564, + 325441417.92109346, + 325441417.92581135, + 325441417.9305292, + 325441417.93524706, + 325441417.93996495, + 325441417.9446828, + 325441417.94940066, + 325441417.9541185, + 325441417.9588364, + 325441417.96355426, + 325441417.9682721, + 325441417.97299, + 325441417.9777078, + 325441417.9824257, + 325441417.9871436, + 325441417.9918614, + 325441417.9965793, + 325441418.0012971, + 325441418.006015, + 325441418.0107329, + 325441418.0154507, + 325441418.0201686, + 325441418.0248864, + 325441418.0296043, + 325441418.0343222, + 325441418.03904, + 325441418.0437579, + 325441418.04847574, + 325441418.0531936, + 325441418.0579115, + 325441418.06262934, + 325441418.0673472, + 325441418.07206506, + 325441418.07678294, + 325441418.0815008, + 325441418.08621866, + 325441418.09093654, + 325441418.09565437, + 325441418.10037225, + 325441418.10509014, + 325441418.10980797, + 325441418.11452585, + 325441418.1192437, + 325441418.12396157, + 325441418.12867945, + 325441418.1333973, + 325441418.13811517, + 325441418.142833, + 325441418.1475509, + 325441418.15226877, + 325441418.1569866, + 325441418.1617045, + 325441418.1664223, + 325441418.1711402, + 325441418.1758581, + 325441418.1805759, + 325441418.1852938, + 325441418.1900116, + 325441418.1947295, + 325441418.1994474, + 325441418.2041652, + 325441418.2088831, + 325441418.21360093, + 325441418.2183188, + 325441418.2230367, + 325441418.22775453, + 325441418.2324724, + 325441418.23719025, + 325441418.24190813, + 325441418.246626, + 325441418.25134385, + 325441418.25606173, + 325441418.26077956, + 325441418.26549745, + 325441418.27021533, + 325441418.27493316, + 325441418.27965105, + 325441418.2843689, + 325441418.28908676, + 325441418.29380465, + 325441418.2985225, + 325441418.30324036, + 325441418.3079582, + 325441418.3126761, + 325441418.31739396, + 325441418.3221118, + 325441418.3268297, + 325441418.3315475, + 325441418.3362654, + 325441418.3409833, + 325441418.3457011, + 325441418.350419, + 325441418.3551368, + 325441418.3598547, + 325441418.3645726, + 325441418.3692904, + 325441418.3740083, + 325441418.3787261, + 325441418.383444, + 325441418.3881619, + 325441418.3928797, + 325441418.3975976, + 325441418.40231544, + 325441418.4070333, + 325441418.4117512, + 325441418.41646904, + 325441418.4211869, + 325441418.4259048, + 325441418.43062264, + 325441418.4353405, + 325441418.44005835, + 325441418.44477624, + 325441418.4494941, + 325441418.45421195, + 325441418.45892984, + 325441418.46364766, + 325441418.46836555, + 325441418.47308344, + 325441418.47780126, + 325441418.48251915, + 325441418.487237, + 325441418.49195486, + 325441418.49667275, + 325441418.5013906, + 325441418.50610846, + 325441418.5108263, + 325441418.5155442, + 325441418.52026206, + 325441418.5249799, + 325441418.5296978, + 325441418.5344156, + 325441418.5391335, + 325441418.5438514, + 325441418.5485692, + 325441418.5532871, + 325441418.5580049, + 325441418.5627228, + 325441418.5674407, + 325441418.5721585, + 325441418.5768764, + 325441418.5815942, + 325441418.5863121, + 325441418.59103, + 325441418.5957478, + 325441418.6004657, + 325441418.60518354, + 325441418.6099014, + 325441418.6146193, + 325441418.61933714, + 325441418.624055, + 325441418.62877285, + 325441418.63349074, + 325441418.6382086, + 325441418.64292645, + 325441418.64764434, + 325441418.65236217, + 325441418.65708005, + 325441418.66179794, + 325441418.66651577, + 325441418.67123365, + 325441418.6759515, + 325441418.68066937, + 325441418.68538725, + 325441418.6901051, + 325441418.69482297, + 325441418.6995408, + 325441418.7042587, + 325441418.70897657, + 325441418.7136944, + 325441418.7184123, + 325441418.7231301, + 325441418.727848, + 325441418.7325659, + 325441418.7372837, + 325441418.7420016, + 325441418.7467194, + 325441418.7514373, + 325441418.7561552, + 325441418.760873, + 325441418.7655909, + 325441418.77030873, + 325441418.7750266, + 325441418.7797445, + 325441418.78446233, + 325441418.7891802, + 325441418.79389805, + 325441418.79861593, + 325441418.8033338, + 325441418.80805165, + 325441418.81276953, + 325441418.81748736, + 325441418.82220525, + 325441418.82692313, + 325441418.83164096, + 325441418.83635885, + 325441418.8410767, + 325441418.84579456, + 325441418.85051244, + 325441418.8552303, + 325441418.85994816, + 325441418.864666, + 325441418.8693839, + 325441418.87410176, + 325441418.8788196, + 325441418.8835375, + 325441418.8882553, + 325441418.8929732, + 325441418.8976911, + 325441418.9024089, + 325441418.9071268, + 325441418.9118446, + 325441418.9165625, + 325441418.9212804, + 325441418.9259982, + 325441418.9307161, + 325441418.9354339, + 325441418.9401518, + 325441418.9448697, + 325441418.9495875, + 325441418.9543054, + 325441418.95902324, + 325441418.9637411, + 325441418.968459, + 325441418.97317684, + 325441418.9778947, + 325441418.98261255, + 325441418.98733044, + 325441418.9920483, + 325441418.99676615, + 325441419.00148404, + 325441419.00620186, + 325441419.01091975, + 325441419.01563764, + 325441419.02035546, + 325441419.02507335, + 325441419.0297912, + 325441419.03450906, + 325441419.03922695, + 325441419.0439448, + 325441419.04866266, + 325441419.0533805, + 325441419.0580984, + 325441419.06281626, + 325441419.0675341, + 325441419.072252, + 325441419.07696986, + 325441419.0816877, + 325441419.0864056, + 325441419.0911234, + 325441419.0958413, + 325441419.1005592, + 325441419.105277, + 325441419.1099949, + 325441419.1147127, + 325441419.1194306, + 325441419.1241485, + 325441419.1288663, + 325441419.1335842, + 325441419.138302, + 325441419.1430199, + 325441419.1477378, + 325441419.1524556, + 325441419.1571735, + 325441419.16189134, + 325441419.1666092, + 325441419.1713271, + 325441419.17604494, + 325441419.1807628, + 325441419.18548065, + 325441419.19019854, + 325441419.1949164, + 325441419.19963425, + 325441419.20435214, + 325441419.20906997, + 325441419.21378785, + 325441419.21850574, + 325441419.22322357, + 325441419.22794145, + 325441419.2326593, + 325441419.23737717, + 325441419.24209505, + 325441419.2468129, + 325441419.25153077, + 325441419.2562486, + 325441419.2609665, + 325441419.26568437, + 325441419.2704022, + 325441419.2751201, + 325441419.2798379, + 325441419.2845558, + 325441419.2892737, + 325441419.2939915, + 325441419.2987094, + 325441419.3034272, + 325441419.3081451, + 325441419.312863, + 325441419.3175808, + 325441419.3222987, + 325441419.32701653, + 325441419.3317344, + 325441419.3364523, + 325441419.34117013, + 325441419.345888, + 325441419.35060585, + 325441419.35532373, + 325441419.3600416, + 325441419.36475945, + 325441419.36947733, + 325441419.37419516, + 325441419.37891304, + 325441419.38363093, + 325441419.38834876, + 325441419.39306664, + 325441419.3977845, + 325441419.40250236, + 325441419.40722024, + 325441419.4119381, + 325441419.41665596, + 325441419.4213738, + 325441419.4260917, + 325441419.43080956, + 325441419.4355274, + 325441419.4402453, + 325441419.4449631, + 325441419.449681, + 325441419.4543989, + 325441419.4591167, + 325441419.4638346, + 325441419.4685524, + 325441419.4732703, + 325441419.4779882, + 325441419.482706, + 325441419.4874239, + 325441419.4921417, + 325441419.4968596, + 325441419.5015775, + 325441419.5062953, + 325441419.5110132, + 325441419.51573104, + 325441419.5204489, + 325441419.5251668, + 325441419.52988464, + 325441419.5346025, + 325441419.53932035, + 325441419.54403824, + 325441419.5487561, + 325441419.55347395, + 325441419.55819184, + 325441419.56290966, + 325441419.56762755, + 325441419.57234544, + 325441419.57706326, + 325441419.58178115, + 325441419.586499, + 325441419.59121686, + 325441419.59593475, + 325441419.6006526, + 325441419.60537046, + 325441419.6100883, + 325441419.6148062, + 325441419.61952406, + 325441419.6242419, + 325441419.6289598, + 325441419.6336776, + 325441419.6383955, + 325441419.6431134, + 325441419.6478312, + 325441419.6525491, + 325441419.6572669, + 325441419.6619848, + 325441419.6667027, + 325441419.6714205, + 325441419.6761384, + 325441419.6808562, + 325441419.6855741, + 325441419.690292, + 325441419.6950098, + 325441419.6997277, + 325441419.70444554, + 325441419.7091634, + 325441419.7138813, + 325441419.71859914, + 325441419.723317, + 325441419.72803485, + 325441419.73275274, + 325441419.7374706, + 325441419.74218845, + 325441419.74690634, + 325441419.7516242, + 325441419.75634205, + 325441419.76105994, + 325441419.76577777, + 325441419.77049565, + 325441419.77521354, + 325441419.77993137, + 325441419.78464925, + 325441419.7893671, + 325441419.79408497, + 325441419.79880285, + 325441419.8035207, + 325441419.80823857, + 325441419.8129564, + 325441419.8176743, + 325441419.82239217, + 325441419.82711, + 325441419.8318279, + 325441419.8365457, + 325441419.8412636, + 325441419.8459815, + 325441419.8506993, + 325441419.8554172, + 325441419.860135, + 325441419.8648529, + 325441419.8695708, + 325441419.8742886, + 325441419.8790065, + 325441419.88372433, + 325441419.8884422, + 325441419.8931601, + 325441419.89787793, + 325441419.9025958, + 325441419.90731364, + 325441419.91203153, + 325441419.9167494, + 325441419.92146724, + 325441419.92618513, + 325441419.93090296, + 325441419.93562084, + 325441419.94033873, + 325441419.94505656, + 325441419.94977444, + 325441419.9544923, + 325441419.95921016, + 325441419.96392804, + 325441419.9686459, + 325441419.97336376, + 325441419.9780816, + 325441419.9827995, + 325441419.98751736, + 325441419.9922352, + 325441419.99695307, + 325441420.0016709, + 325441420.0063888, + 325441420.01110667, + 325441420.0158245, + 325441420.0205424, + 325441420.0252602, + 325441420.0299781, + 325441420.034696, + 325441420.0394138, + 325441420.0441317, + 325441420.0488495, + 325441420.0535674, + 325441420.0582853, + 325441420.0630031, + 325441420.067721, + 325441420.07243884, + 325441420.0771567, + 325441420.0818746, + 325441420.08659244, + 325441420.0913103, + 325441420.09602815, + 325441420.10074604, + 325441420.1054639, + 325441420.11018175, + 325441420.11489964, + 325441420.11961746, + 325441420.12433535, + 325441420.12905324, + 325441420.13377106, + 325441420.13848895, + 325441420.1432068, + 325441420.14792466, + 325441420.15264255, + 325441420.1573604, + 325441420.16207826, + 325441420.1667961, + 325441420.171514, + 325441420.17623186, + 325441420.1809497, + 325441420.1856676, + 325441420.1903854, + 325441420.1951033, + 325441420.1998212, + 325441420.204539, + 325441420.2092569, + 325441420.2139747, + 325441420.2186926, + 325441420.2234105, + 325441420.2281283, + 325441420.2328462, + 325441420.237564, + 325441420.2422819, + 325441420.2469998, + 325441420.2517176, + 325441420.2564355, + 325441420.26115334, + 325441420.2658712, + 325441420.2705891, + 325441420.27530694, + 325441420.2800248, + 325441420.28474265, + 325441420.28946054, + 325441420.2941784, + 325441420.29889625, + 325441420.30361414, + 325441420.30833197, + 325441420.31304985, + 325441420.31776774, + 325441420.32248557, + 325441420.32720345, + 325441420.3319213, + 325441420.33663917, + 325441420.34135705, + 325441420.3460749, + 325441420.35079277, + 325441420.3555106, + 325441420.3602285, + 325441420.36494637, + 325441420.3696642, + 325441420.3743821, + 325441420.3790999, + 325441420.3838178, + 325441420.3885357, + 325441420.3932535, + 325441420.3979714, + 325441420.4026893, + 325441420.4074071, + 325441420.412125, + 325441420.4168428, + 325441420.4215607, + 325441420.4262786, + 325441420.4309964, + 325441420.4357143, + 325441420.44043213, + 325441420.44515, + 325441420.4498679, + 325441420.45458573, + 325441420.4593036, + 325441420.46402144, + 325441420.46873933, + 325441420.4734572, + 325441420.47817504, + 325441420.48289293, + 325441420.48761076, + 325441420.49232864, + 325441420.49704653, + 325441420.50176436, + 325441420.50648224, + 325441420.5112001, + 325441420.51591796, + 325441420.52063584, + 325441420.52535367, + 325441420.53007156, + 325441420.5347894, + 325441420.53950727, + 325441420.54422516, + 325441420.548943, + 325441420.55366087, + 325441420.5583787, + 325441420.5630966, + 325441420.56781447, + 325441420.5725323, + 325441420.5772502, + 325441420.581968, + 325441420.5866859, + 325441420.5914038, + 325441420.5961216, + 325441420.6008395, + 325441420.6055573, + 325441420.6102752, + 325441420.6149931, + 325441420.6197109, + 325441420.6244288, + 325441420.62914664, + 325441420.6338645, + 325441420.6385824, + 325441420.64330024, + 325441420.6480181, + 325441420.65273595, + 325441420.65745384, + 325441420.6621717, + 325441420.66688955, + 325441420.67160743, + 325441420.67632526, + 325441420.68104315, + 325441420.68576103, + 325441420.69047886, + 325441420.69519675, + 325441420.6999146, + 325441420.70463246, + 325441420.70935035, + 325441420.7140682, + 325441420.71878606, + 325441420.7235039, + 325441420.7282218 + ], + "quaternions": [ + [ + -0.2092343188818965, + -0.8195798964915978, + 0.052229157159269, + -0.530831336877622 + ], + [ + -0.20923420518543795, + -0.819578742567477, + 0.052229607623814706, + -0.530833118973745 + ], + [ + -0.2092340914894275, + -0.8195775886540634, + 0.05223005808242261, + -0.5308349010448461 + ], + [ + -0.20923397779099243, + -0.8195764347222004, + 0.0522305085464749, + -0.5308366831359546 + ], + [ + -0.20923386569937194, + -0.8195753085764607, + 0.052230944627812796, + -0.5308384231002715 + ], + [ + -0.20923375657850912, + -0.819574233819895, + 0.05223135410580041, + -0.5308400851620493 + ], + [ + -0.20923364745678905, + -0.8195731590599716, + 0.052231763583574044, + -0.530841747221652 + ], + [ + -0.20923353833559036, + -0.8195720843102685, + 0.052232173055960396, + -0.5308434092580819 + ], + [ + -0.2092334292121558, + -0.8195710095436293, + 0.052232582533306, + -0.5308450713133348 + ], + [ + -0.2092333200892426, + -0.8195699347872105, + 0.05223299200526437, + -0.530846733345415 + ], + [ + -0.20923321096409356, + -0.8195688600138556, + 0.052233401482181994, + -0.530848395396318 + ], + [ + -0.20923310183808724, + -0.8195677852371428, + 0.05223381095888558, + -0.5308500574450461 + ], + [ + -0.20923299271260234, + -0.8195667104706506, + 0.05223422043020193, + -0.5308517194706014 + ], + [ + -0.20923288358488148, + -0.8195656356872221, + 0.05223462990647755, + -0.5308533815149795 + ], + [ + -0.2092327744576822, + -0.8195645609140142, + 0.052235039377365886, + -0.5308550435361851 + ], + [ + -0.20923266532824686, + -0.81956348612387, + 0.05223544885321342, + -0.5308567055762133 + ], + [ + -0.2092325561979543, + -0.8195624113303679, + 0.05223585832884698, + -0.5308583676140666 + ], + [ + -0.20923244706818317, + -0.8195613365470867, + 0.05223626779909329, + -0.5308600296287471 + ], + [ + -0.2092323379361761, + -0.8195602617468689, + 0.05223667727429879, + -0.5308616916622505 + ], + [ + -0.20923222880469058, + -0.8195591869568721, + 0.0522370867441171, + -0.5308633536725812 + ], + [ + -0.20923211967096902, + -0.8195581121499388, + 0.05223749621889453, + -0.5308650157017345 + ], + [ + -0.20923201053639023, + -0.8195570373396476, + 0.052237905693458, + -0.5308666777287128 + ], + [ + -0.20923190140233297, + -0.8195559625395774, + 0.05223831516263421, + -0.5308683397325185 + ], + [ + -0.2092317922660396, + -0.8195548877225706, + 0.05223872463676958, + -0.5308700017551466 + ], + [ + -0.20923168313026785, + -0.819553812915785, + 0.05223913410551777, + -0.5308716637546024 + ], + [ + -0.20923157399226006, + -0.8195527380920625, + 0.05223954357922511, + -0.5308733257728806 + ], + [ + -0.20923146485339503, + -0.8195516632649822, + 0.05223995305271842, + -0.5308749877889838 + ], + [ + -0.2092313557150516, + -0.8195505884481232, + 0.05224036252082452, + -0.5308766497819144 + ], + [ + -0.20923124657447212, + -0.8195495136143275, + 0.05224077199388974, + -0.5308783117936674 + ], + [ + -0.20923113743441427, + -0.819548438790753, + 0.05224118146156779, + -0.530879973782248 + ], + [ + -0.2092310282921202, + -0.8195473639502417, + 0.05224159093420493, + -0.5308816357896509 + ], + [ + -0.20923091914896894, + -0.8195462891063724, + 0.05224200040662806, + -0.5308832977948788 + ], + [ + -0.20923081000633934, + -0.8195452142727249, + 0.05224240987366397, + -0.530884959776934 + ], + [ + -0.20923070086147358, + -0.8195441394221401, + 0.052242819345659004, + -0.5308866217778117 + ], + [ + -0.20923059171712952, + -0.8195430645817771, + 0.05224322881226684, + -0.5308882837555169 + ], + [ + -0.2092304825705493, + -0.8195419897244769, + 0.05224363828383378, + -0.5308899457520443 + ], + [ + -0.20923037342311185, + -0.8195409148638189, + 0.05224404775518669, + -0.5308916077463967 + ], + [ + -0.20923026427619612, + -0.8195398400133826, + 0.05224445722115238, + -0.5308932697175767 + ], + [ + -0.20923015512704418, + -0.8195387651460092, + 0.05224486669207717, + -0.5308949317075786 + ], + [ + -0.20923004597841394, + -0.8195376902888577, + 0.052245276157614776, + -0.5308965936744083 + ], + [ + -0.2092299368275475, + -0.8195366154147687, + 0.052245685628111486, + -0.5308982556600602 + ], + [ + -0.20922982767582385, + -0.8195355405373219, + 0.05224609509839413, + -0.5308999176435368 + ], + [ + -0.20922971852462197, + -0.8195344656700974, + 0.052246504563289546, + -0.5309015796038412 + ], + [ + -0.20922960937118384, + -0.8195333907859352, + 0.05224691403314407, + -0.5309032415829675 + ], + [ + -0.20922950021826753, + -0.8195323159119952, + 0.05224732349761139, + -0.5309049035389218 + ], + [ + -0.20922939106311492, + -0.8195312410211176, + 0.05224773296703778, + -0.5309065655136976 + ], + [ + -0.20922928190710507, + -0.8195301661268823, + 0.0522481424362501, + -0.5309082274862985 + ], + [ + -0.20922917275161707, + -0.8195290912428693, + 0.05224855190007521, + -0.5309098894357271 + ], + [ + -0.2092290635938927, + -0.8195280163419186, + 0.05224896136885943, + -0.5309115514039775 + ], + [ + -0.20922894876665424, + -0.8195268716958581, + 0.052249402086953195, + -0.5309133201832076 + ], + [ + -0.20922882601688472, + -0.8195256295955395, + 0.05224988646753473, + -0.5309152382101692 + ], + [ + -0.2092287032659704, + -0.819524387490737, + 0.05225037084783034, + -0.5309171562342258 + ], + [ + -0.2092285805154621, + -0.8195231453971431, + 0.05225085522172055, + -0.5309190742311457 + ], + [ + -0.2092284577622582, + -0.8195219032833727, + 0.05225133960144441, + -0.5309209922493927 + ], + [ + -0.2092283350094605, + -0.8195206611808113, + 0.052251823974762864, + -0.5309229102405031 + ], + [ + -0.20922821225396718, + -0.8195194190580734, + 0.05225230835391499, + -0.5309248282529405 + ], + [ + -0.20922808949732902, + -0.8195181769308515, + 0.05225279273278117, + -0.530926746262473 + ], + [ + -0.2092279667410971, + -0.8195169348148387, + 0.05225327710524194, + -0.5309286642448691 + ], + [ + -0.20922784398216954, + -0.8195156926786492, + 0.05225376148353641, + -0.5309305822485918 + ], + [ + -0.20922772122364808, + -0.8195144505536689, + 0.05225424585542542, + -0.530932500225178 + ], + [ + -0.20922759846243105, + -0.8195132084085117, + 0.052254730233148076, + -0.5309344182230911 + ], + [ + -0.20922747570006914, + -0.8195119662588708, + 0.05225521461058477, + -0.5309363362180991 + ], + [ + -0.2092273529381135, + -0.819510724120439, + 0.05225569898161607, + -0.5309382541859707 + ], + [ + -0.2092272301734622, + -0.8195094819618306, + 0.05225618335848101, + -0.5309401721751691 + ], + [ + -0.2092271074092171, + -0.8195082398144315, + 0.05225666772894053, + -0.5309420901372309 + ], + [ + -0.20922698464227626, + -0.8195069976468554, + 0.05225715210523362, + -0.5309440081206194 + ], + [ + -0.20922686187419068, + -0.8195057554747955, + 0.05225763648124079, + -0.5309459261011026 + ], + [ + -0.20922673910651146, + -0.8195045133139454, + 0.052258120850842575, + -0.5309478440544498 + ], + [ + -0.20922661633613635, + -0.8195032711329178, + 0.052258605226277906, + -0.5309497620291233 + ], + [ + -0.20922649356616763, + -0.8195020289631002, + 0.052259089595307874, + -0.5309516799766606 + ], + [ + -0.20922637079350312, + -0.8195007867731054, + 0.05225957397017138, + -0.530953597945524 + ], + [ + -0.20922624801969383, + -0.8194995445786268, + 0.052260058344748936, + -0.5309555159114825 + ], + [ + -0.20922612524629086, + -0.8194983023953581, + 0.0522605427129211, + -0.5309574338503048 + ], + [ + -0.20922600247019216, + -0.8194970601919119, + 0.0522610270869268, + -0.5309593518104533 + ], + [ + -0.2092258796929486, + -0.8194958179839822, + 0.052261511460646545, + -0.5309612697676965 + ], + [ + -0.20922575691611153, + -0.8194945757872626, + 0.05226199582796095, + -0.5309631876978038 + ], + [ + -0.20922563413657852, + -0.8194933335703651, + 0.05226248020110881, + -0.530965105649237 + ], + [ + -0.20922551135745193, + -0.8194920913646782, + 0.05226296456785133, + -0.5309670235735343 + ], + [ + -0.20922538857562953, + -0.8194908491388136, + 0.05226344894042731, + -0.5309689415191575 + ], + [ + -0.20922526579266226, + -0.8194896069084653, + 0.05226393331271738, + -0.5309708594618754 + ], + [ + -0.2092251430101016, + -0.8194883646893274, + 0.052264417678601995, + -0.5309727773774576 + ], + [ + -0.20922502022484493, + -0.8194871224500118, + 0.05226490205032013, + -0.5309746953143654 + ], + [ + -0.20922489743999487, + -0.8194858802219068, + 0.05226538641563292, + -0.5309766132241374 + ], + [ + -0.20922477465244874, + -0.8194846379736239, + 0.05226587078677914, + -0.5309785311552347 + ], + [ + -0.20922465186375788, + -0.8194833957208572, + 0.05226635515763941, + -0.5309804490834273 + ], + [ + -0.20922452907547356, + -0.8194821534793013, + 0.05226683952209425, + -0.5309823669844838 + ], + [ + -0.2092244062844932, + -0.8194809112175674, + 0.05226732389238258, + -0.5309842849068659 + ], + [ + -0.20922428349391944, + -0.8194796689670445, + 0.052267808256265536, + -0.5309862028021122 + ], + [ + -0.20922416070064967, + -0.8194784266963432, + 0.052268292625981906, + -0.5309881207186838 + ], + [ + -0.20922403519645008, + -0.8194772419156817, + 0.05226875777136638, + -0.5309899528610877 + ], + [ + -0.20922390763126325, + -0.8194761008870077, + 0.05226920828525654, + -0.5309917197242947 + ], + [ + -0.20922378006349332, + -0.8194749598401132, + 0.05226965880459578, + -0.5309934866073586 + ], + [ + -0.2092236524963637, + -0.8194738188038295, + 0.052270109318000586, + -0.5309952534656348 + ], + [ + -0.20922352492665092, + -0.8194726777493252, + 0.05227055983685444, + -0.5309970203437677 + ], + [ + -0.2092233973559667, + -0.8194715366910159, + 0.05227101035546558, + -0.5309987872194353 + ], + [ + -0.20922326978592273, + -0.8194703956433177, + 0.052271460868142314, + -0.5310005540703152 + ], + [ + -0.20922314221329563, + -0.8194692545773987, + 0.05227191138626806, + -0.5310023209410518 + ], + [ + -0.20922301464130885, + -0.8194681135220909, + 0.052272361898459394, + -0.5310040877870007 + ], + [ + -0.20922288706673892, + -0.8194669724485621, + 0.05227281241609975, + -0.5310058546528065 + ], + [ + -0.20922275949119748, + -0.8194658313712286, + 0.05227326293349737, + -0.5310076215161466 + ], + [ + -0.20922263191629636, + -0.8194646903045064, + 0.052273713444960575, + -0.5310093883546991 + ], + [ + -0.20922250433881207, + -0.8194635492195632, + 0.0522741639618728, + -0.5310111552131082 + ], + [ + -0.20922237676196814, + -0.8194624081452313, + 0.052274614472850575, + -0.5310129220467298 + ], + [ + -0.20922224918254095, + -0.8194612670526784, + 0.05227506498927737, + -0.5310146889002079 + ], + [ + -0.2092221216021424, + -0.8194601259563207, + 0.052275515505461466, + -0.5310164557512204 + ], + [ + -0.20922199402238414, + -0.8194589848705746, + 0.0522759660157111, + -0.5310182225774454 + ], + [ + -0.20922186644004262, + -0.8194578437666072, + 0.05227641653140973, + -0.5310199894235266 + ], + [ + -0.20922173885834164, + -0.8194567026732515, + 0.052276867041173944, + -0.5310217562448206 + ], + [ + -0.2092216112740573, + -0.8194555615616745, + 0.052277317556387135, + -0.5310235230859709 + ], + [ + -0.20922148368880153, + -0.8194544204462928, + 0.0522777680713576, + -0.5310252899246555 + ], + [ + -0.20922135610418624, + -0.8194532793415228, + 0.05227821858039363, + -0.5310270567385529 + ], + [ + -0.20922122851698755, + -0.8194521382185315, + 0.05227866909487862, + -0.5310288235723062 + ], + [ + -0.2092211009304294, + -0.8194509971061521, + 0.05227911960342917, + -0.5310305903812723 + ], + [ + -0.20922097334128784, + -0.819449855975551, + 0.05227957011742871, + -0.5310323572100946 + ], + [ + -0.20922084575117497, + -0.8194487148411455, + 0.05228002063118549, + -0.5310341240364512 + ], + [ + -0.20922071816170254, + -0.8194475737173519, + 0.052280471139007856, + -0.5310358908380205 + ], + [ + -0.20922059056964673, + -0.8194464325753367, + 0.05228092165227915, + -0.5310376576594458 + ], + [ + -0.20922046297823155, + -0.8194452914439336, + 0.05228137215961606, + -0.531039424456084 + ], + [ + -0.2092203353842329, + -0.819444150294309, + 0.05228182267240185, + -0.531041191272578 + ], + [ + -0.2092202077892628, + -0.8194430091408794, + 0.05228227318494495, + -0.5310429580866064 + ], + [ + -0.20922008019493332, + -0.8194418679980624, + 0.052282723691553554, + -0.5310447248758475 + ], + [ + -0.2092199525980204, + -0.8194407268370234, + 0.05228317420361115, + -0.5310464916849444 + ], + [ + -0.20921982500174816, + -0.8194395856865969, + 0.05228362470973428, + -0.5310482584692544 + ], + [ + -0.20921969740289237, + -0.8194384445179486, + 0.052284075221306334, + -0.53105002527342 + ], + [ + -0.2092195698030651, + -0.8194373033454955, + 0.05228452573263563, + -0.5310517920751199 + ], + [ + -0.2092194422038786, + -0.8194361621836549, + 0.05228497623803049, + -0.5310535588520328 + ], + [ + -0.20921931460210855, + -0.8194350210035923, + 0.05228542674887425, + -0.5310553256488012 + ], + [ + -0.2092191870009792, + -0.8194338798341426, + 0.052285877253783655, + -0.5310570924207827 + ], + [ + -0.20921905939726626, + -0.8194327386464706, + 0.05228632776414185, + -0.5310588592126196 + ], + [ + -0.20921893179258197, + -0.819431597454994, + 0.05228677827425732, + -0.5310606260019908 + ], + [ + -0.2092188041885384, + -0.8194304562741302, + 0.05228722877843837, + -0.5310623927665751 + ], + [ + -0.20921867800288602, + -0.8194293133575037, + 0.052287676834732066, + -0.5310641618829135 + ], + [ + -0.20921855844793072, + -0.8194281624376679, + 0.052288113438177714, + -0.5310659418547505 + ], + [ + -0.209218438890482, + -0.8194270114994416, + 0.05228855004689368, + -0.5310677218465807 + ], + [ + -0.20921831933205043, + -0.8194258605573659, + 0.05228898665536404, + -0.5310695018359157 + ], + [ + -0.20921819977414646, + -0.8194247096259814, + 0.05228942325807271, + -0.531071281800268 + ], + [ + -0.20921808021374907, + -0.8194235586762064, + 0.052289859866051724, + -0.5310730617846133 + ], + [ + -0.20921796065387938, + -0.8194224077371227, + 0.052290296468269125, + -0.5310748417439759 + ], + [ + -0.2092178410915163, + -0.8194212567796486, + 0.05229073307575685, + -0.5310766217233314 + ], + [ + -0.20921772152817025, + -0.8194201058183248, + 0.052291169682998906, + -0.5310784017001917 + ], + [ + -0.20921760196535188, + -0.8194189548676926, + 0.05229160628447933, + -0.5310801816520694 + ], + [ + -0.20921748240004007, + -0.8194178038986697, + 0.05229204289123008, + -0.53108196162394 + ], + [ + -0.20921736283525597, + -0.8194166529403384, + 0.05229247949221916, + -0.5310837415708277 + ], + [ + -0.20921724326797836, + -0.8194155019636165, + 0.052292916098478574, + -0.5310855215377083 + ], + [ + -0.20921712369971793, + -0.8194143509830448, + 0.052293352704492334, + -0.5310873015020939 + ], + [ + -0.2092170041319852, + -0.819413200013165, + 0.05229378930474442, + -0.5310890814414968 + ], + [ + -0.209216884561759, + -0.8194120490248945, + 0.052294225910266855, + -0.5310908614008922 + ], + [ + -0.20921676499206043, + -0.8194108980473157, + 0.0522946625100276, + -0.5310926413353052 + ], + [ + -0.20921664541986845, + -0.819409747051346, + 0.05229509911505866, + -0.5310944212897105 + ], + [ + -0.20921652584669354, + -0.8194085960515267, + 0.052295535719844, + -0.5310962012416209 + ], + [ + -0.20921640627404642, + -0.8194074450623994, + 0.05229597231886775, + -0.5310979811685489 + ], + [ + -0.20921628669890585, + -0.8194062940548812, + 0.05229640892316177, + -0.5310997611154693 + ], + [ + -0.20921616712429295, + -0.819405143058055, + 0.05229684552169414, + -0.531101541037407 + ], + [ + -0.20921604754718648, + -0.8194039920428378, + 0.052297282125496745, + -0.531103320979337 + ], + [ + -0.20921592796909724, + -0.8194028410237708, + 0.05229771872905374, + -0.5311051009187723 + ], + [ + -0.2092158083915357, + -0.8194016900153964, + 0.05229815532684904, + -0.5311068808332248 + ], + [ + -0.2092156888114807, + -0.8194005389886306, + 0.0522985919299146, + -0.5311086607676696 + ], + [ + -0.20921556923195347, + -0.8193993879725572, + 0.05229902852721853, + -0.5311104406771322 + ], + [ + -0.20921544964993266, + -0.8193982369380924, + 0.05229946512979271, + -0.5311122206065869 + ], + [ + -0.2092153300669289, + -0.8193970858997782, + 0.05229990173212121, + -0.5311140005335464 + ], + [ + -0.20921521048445313, + -0.8193959348721566, + 0.052300338328688044, + -0.5311157804355237 + ], + [ + -0.20921509089948367, + -0.8193947838261434, + 0.05230077493052511, + -0.5311175603574929 + ], + [ + -0.20921497131655298, + -0.819393632805365, + 0.052301211521084634, + -0.5311193402319928 + ], + [ + -0.2092148517296178, + -0.8193924817516531, + 0.052301648122430267, + -0.5311211201489718 + ], + [ + -0.20921473214169967, + -0.8193913306940916, + 0.05230208472353024, + -0.5311229000634554 + ], + [ + -0.2092146125543096, + -0.8193901796472229, + 0.052302521318868575, + -0.5311246799529571 + ], + [ + -0.2092144929644258, + -0.8193890285819626, + 0.0523029579194771, + -0.5311264598624506 + ], + [ + -0.20921437337506993, + -0.8193878775273953, + 0.05230339451432398, + -0.5311282397469618 + ], + [ + -0.2092142537832204, + -0.8193867264544362, + 0.0523038311144411, + -0.5311300196514649 + ], + [ + -0.20921413419038792, + -0.8193855753776276, + 0.05230426771431246, + -0.5311317995534728 + ], + [ + -0.2092140145980835, + -0.8193844243115119, + 0.052304704308422205, + -0.5311335794304984 + ], + [ + -0.20921389500328524, + -0.8193832732270045, + 0.05230514090780215, + -0.5311353593275158 + ], + [ + -0.2092137754090152, + -0.8193821221531904, + 0.05230557750142046, + -0.5311371391995513 + ], + [ + -0.20921365581225124, + -0.8193809710609841, + 0.05230601410030893, + -0.5311389190915781 + ], + [ + -0.20921354356077404, + -0.8193798114832579, + 0.052306469442246456, + -0.5311407073261212 + ], + [ + -0.2092134368157333, + -0.8193786455592577, + 0.052306938826256824, + -0.5311425017901051 + ], + [ + -0.20921333006833742, + -0.8193774796165849, + 0.052307408215945705, + -0.531144296274205 + ], + [ + -0.20921322332128356, + -0.8193763136847002, + 0.05230787759945275, + -0.5311460907330782 + ], + [ + -0.20921311657187439, + -0.819375147734143, + 0.05230834698863822, + -0.5311478852120669 + ], + [ + -0.20921300982145874, + -0.8193739817796435, + 0.05230881637757208, + -0.5311496796885001 + ], + [ + -0.20921290307138515, + -0.8193728158359321, + 0.05230928576032409, + -0.5311514741397068 + ], + [ + -0.20921279631895628, + -0.8193716498735482, + 0.052309755148754605, + -0.531153268611029 + ], + [ + -0.20921268956686953, + -0.8193704839219526, + 0.05231022453100331, + -0.5311550630571247 + ], + [ + -0.20921258281242752, + -0.8193693179516841, + 0.05231069391893044, + -0.5311568575233359 + ], + [ + -0.20921247605697896, + -0.8193681519774734, + 0.052311163306605894, + -0.5311586519869913 + ], + [ + -0.20921236930187248, + -0.8193669860140512, + 0.052311632688099526, + -0.5311604464254205 + ], + [ + -0.2092122625444107, + -0.8193658200319561, + 0.05231210207527161, + -0.5311622408839649 + ], + [ + -0.20921215578729116, + -0.8193646540606496, + 0.05231257145626189, + -0.5311640353172831 + ], + [ + -0.2092120490278162, + -0.81936348807067, + 0.052313040842930626, + -0.5311658297707164 + ], + [ + -0.20921194226733472, + -0.8193623220767483, + 0.05231351022934762, + -0.5311676242215939 + ], + [ + -0.20921183550719535, + -0.8193611560936154, + 0.05231397960958283, + -0.5311694186472453 + ], + [ + -0.20921172874470076, + -0.8193599900918092, + 0.05231444899549644, + -0.5311712130930119 + ], + [ + -0.20921162198254833, + -0.819358824100792, + 0.05231491837522826, + -0.531173007513552 + ], + [ + -0.20921151521804052, + -0.8193576580911015, + 0.0523153877606385, + -0.5311748019542073 + ], + [ + -0.2092114084525261, + -0.819356492077469, + 0.052315857145796986, + -0.5311765963923069 + ], + [ + -0.209211301687354, + -0.8193553260746252, + 0.052316326524773714, + -0.5311783908051803 + ], + [ + -0.20921119491982643, + -0.8193541600531083, + 0.05231679590942881, + -0.5311801852381685 + ], + [ + -0.20921108815264114, + -0.8193529940423806, + 0.052317265287902086, + -0.5311819796459306 + ], + [ + -0.20921098138310049, + -0.8193518280129793, + 0.05231773467205378, + -0.5311837740738077 + ], + [ + -0.20921087461255322, + -0.8193506619796359, + 0.052318204055953714, + -0.5311855684991288 + ], + [ + -0.2092107678423482, + -0.8193494959570818, + 0.052318673433671865, + -0.531187362899224 + ], + [ + -0.2092106610697878, + -0.8193483299158542, + 0.052319142817068384, + -0.5311891573194338 + ], + [ + -0.2092105542975698, + -0.819347163885416, + 0.052319612194283105, + -0.5311909517144177 + ], + [ + -0.20921044752299614, + -0.8193459978363041, + 0.052320081577176186, + -0.5311927461295162 + ], + [ + -0.209210340747416, + -0.81934483178325, + 0.05232055095981753, + -0.5311945405420588 + ], + [ + -0.2092102339721782, + -0.8193436657409854, + 0.052321020336277044, + -0.5311963349293757 + ], + [ + -0.209210127194585, + -0.8193424996800474, + 0.052321489718414944, + -0.5311981293368069 + ], + [ + -0.2092100204173341, + -0.8193413336298989, + 0.05232195909437105, + -0.5311999237190123 + ], + [ + -0.2092099136377277, + -0.8193401675610764, + 0.05232242847600543, + -0.531201718121332 + ], + [ + -0.20920980685711466, + -0.819339001488312, + 0.052322897857388126, + -0.531203512521096 + ], + [ + -0.20920970007684414, + -0.8193378354263373, + 0.05232336723258897, + -0.531205306895634 + ], + [ + -0.20920959329421804, + -0.8193366693456887, + 0.05232383661346819, + -0.5312071012902866 + ], + [ + -0.20920948651058527, + -0.8193355032610979, + 0.052324305994095655, + -0.5312088956823832 + ], + [ + -0.2092093797272951, + -0.8193343371872972, + 0.05232477536854129, + -0.531210690049254 + ], + [ + -0.20920927294164923, + -0.8193331710948223, + 0.05232524474866521, + -0.531212484436239 + ], + [ + -0.2092091661563459, + -0.8193320050131376, + 0.0523257141226074, + -0.5312142787979984 + ], + [ + -0.20920905708768123, + -0.819330847955124, + 0.052326176195580096, + -0.5312160608512979 + ], + [ + -0.2092089444560507, + -0.8193297050136695, + 0.05232662685835048, + -0.5312178236499838 + ], + [ + -0.20920883182487457, + -0.8193285620828616, + 0.05232707751518506, + -0.5312195864239397 + ], + [ + -0.2092087191913069, + -0.8193274191338211, + 0.052327528177471, + -0.5312213492177069 + ], + [ + -0.20920860655819368, + -0.8193262761954273, + 0.052327978833821065, + -0.531223111986744 + ], + [ + -0.20920849392268895, + -0.8193251332388002, + 0.052328429495622455, + -0.5312248747755928 + ], + [ + -0.20920838128621566, + -0.8193239902783802, + 0.052328880157181595, + -0.5312266375619821 + ], + [ + -0.2092082686501969, + -0.8193228473286072, + 0.05232933081280491, + -0.5312284003236414 + ], + [ + -0.20920815601178647, + -0.819321704360601, + 0.052329781473879546, + -0.531230163105112 + ], + [ + -0.20920804337383075, + -0.8193205614032419, + 0.05233023212901837, + -0.5312319258618529 + ], + [ + -0.20920793073348334, + -0.8193194184276497, + 0.052330682789608465, + -0.5312336886384048 + ], + [ + -0.20920781809216732, + -0.8193182754482643, + 0.05233113344995627, + -0.5312354514124971 + ], + [ + -0.20920770545130593, + -0.819317132479526, + 0.0523315841043683, + -0.53123721416186 + ], + [ + -0.2092075928080529, + -0.8193159894925547, + 0.05233203476423157, + -0.5312389769310337 + ], + [ + -0.20920748016525442, + -0.8193148465162304, + 0.052332485418159054, + -0.5312407396754777 + ], + [ + -0.2092073675200644, + -0.8193137035216731, + 0.052332936077537806, + -0.5312425024397327 + ], + [ + -0.20920725487390573, + -0.8193125605233222, + 0.052333386736674245, + -0.5312442652015283 + ], + [ + -0.2092071422282017, + -0.8193114175356191, + 0.052333837389874925, + -0.5312460279385941 + ], + [ + -0.2092070295801061, + -0.8193102745296824, + 0.052334288048526856, + -0.5312477906954711 + ], + [ + -0.209206916932465, + -0.8193091315343932, + 0.05233473870124295, + -0.5312495534276183 + ], + [ + -0.2092068042824323, + -0.8193079885208705, + 0.05233518935941026, + -0.5312513161795762 + ], + [ + -0.209206691631431, + -0.8193068455035548, + 0.05233564001733531, + -0.5312530789290745 + ], + [ + -0.20920657898088438, + -0.8193057024968867, + 0.05233609066932456, + -0.5312548416538435 + ], + [ + -0.20920646632794612, + -0.8193045594719851, + 0.05233654132676504, + -0.5312566043984229 + ], + [ + -0.20920635367546242, + -0.8193034164577311, + 0.05233699197826972, + -0.531258367118273 + ], + [ + -0.209206241020587, + -0.8193022734252434, + 0.052337442635225585, + -0.5312601298579335 + ], + [ + -0.20920612836474312, + -0.8193011303889626, + 0.05233789329193916, + -0.5312618925951347 + ], + [ + -0.2092060157093539, + -0.8192999873633299, + 0.052338343942716935, + -0.5312636553076063 + ], + [ + -0.20920590305157297, + -0.8192988443194631, + 0.05233879459894592, + -0.5312654180398884 + ], + [ + -0.20920579039424672, + -0.8192977012862445, + 0.052339245249239094, + -0.5312671807474411 + ], + [ + -0.20920567773452878, + -0.8192965582347921, + 0.05233969590498347, + -0.5312689434748041 + ], + [ + -0.20920556507384214, + -0.8192954151795463, + 0.052340146560485495, + -0.5312707061997076 + ], + [ + -0.2092054524136104, + -0.8192942721349489, + 0.0523405972100518, + -0.5312724688998818 + ], + [ + -0.20920533975098682, + -0.8192931290721176, + 0.052341047865069226, + -0.5312742316198663 + ], + [ + -0.20920522708881806, + -0.8192919860199342, + 0.05234149851415086, + -0.5312759943151215 + ], + [ + -0.20920511442425743, + -0.8192908429495169, + 0.05234194916868365, + -0.5312777570301869 + ], + [ + -0.2092050017587282, + -0.8192896998753066, + 0.05234239982297414, + -0.5312795197427926 + ], + [ + -0.20920488909365395, + -0.8192885568117448, + 0.05234285047132885, + -0.5312812824306693 + ], + [ + -0.2092047764261878, + -0.8192874137299487, + 0.05234330112513467, + -0.5312830451383558 + ], + [ + -0.2092046637591765, + -0.8192862706588012, + 0.052343751773004765, + -0.5312848078213133 + ], + [ + -0.2092045510897732, + -0.8192851275694192, + 0.052344202426325946, + -0.5312865705240808 + ], + [ + -0.20920443841940142, + -0.8192839844762443, + 0.05234465307940481, + -0.5312883332243886 + ], + [ + -0.20920432574948458, + -0.819282841393718, + 0.05234510372654788, + -0.5312900958999672 + ], + [ + -0.2092042140005553, + -0.8192816825174367, + 0.052345543052655215, + -0.5312918836744362 + ], + [ + -0.20920410250420288, + -0.8192805193438384, + 0.05234597927986962, + -0.5312936782725096 + ], + [ + -0.2092039910054426, + -0.8192793561516314, + 0.05234641551234527, + -0.5312954728907183 + ], + [ + -0.2092038795056831, + -0.8192781929555112, + 0.05234685174457086, + -0.5312972675063893 + ], + [ + -0.209203768006333, + -0.8192770297701735, + 0.052347287971035224, + -0.5312990620968499 + ], + [ + -0.20920365650457498, + -0.819275866566227, + 0.052347724202760765, + -0.5313008567074454 + ], + [ + -0.20920354500322644, + -0.819274703373063, + 0.052348160428725046, + -0.5313026512928308 + ], + [ + -0.20920343349946996, + -0.8192735401612902, + 0.052348596659950536, + -0.5313044458983509 + ], + [ + -0.20920332199471425, + -0.8192723769456042, + 0.05234903289092601, + -0.5313062405013333 + ], + [ + -0.20920321049036808, + -0.8192712137407008, + 0.05234946911614019, + -0.5313080350791057 + ], + [ + -0.20920309898361392, + -0.8192700505171884, + 0.05234990534661556, + -0.5313098296770127 + ], + [ + -0.20920298747726934, + -0.8192688873044589, + 0.05235034157132964, + -0.5313116242497096 + ], + [ + -0.20920287596851667, + -0.8192677240731203, + 0.05235077780130493, + -0.5313134188425411 + ], + [ + -0.20920276445876476, + -0.8192665608378685, + 0.052351214031030185, + -0.5313152134328349 + ], + [ + -0.2092026529494225, + -0.8192653976133998, + 0.05235165025499416, + -0.5313170079979187 + ], + [ + -0.2092025414376722, + -0.8192642343703218, + 0.05235208648421931, + -0.5313188025831369 + ], + [ + -0.20920242992633142, + -0.8192630711380269, + 0.052352522707683175, + -0.5313205971431452 + ], + [ + -0.2092023184125826, + -0.8192619078871227, + 0.05235295893640819, + -0.5313223917232879 + ], + [ + -0.2092022068978346, + -0.8192607446323054, + 0.05235339516488317, + -0.5313241863008927 + ], + [ + -0.20920209538349627, + -0.8192595813882713, + 0.05235383138759691, + -0.5313259808532877 + ], + [ + -0.20920198386674976, + -0.8192584181256278, + 0.05235426761557172, + -0.531327775425817 + ], + [ + -0.20920187235041293, + -0.8192572548737677, + 0.05235470383778533, + -0.5313295699731363 + ], + [ + -0.20920176083166803, + -0.819256091603298, + 0.052355140065260056, + -0.5313313645405898 + ], + [ + -0.2092016493119239, + -0.8192549283289152, + 0.05235557629248468, + -0.5313331591055058 + ], + [ + -0.20920153779258946, + -0.819253765065316, + 0.0523560125139481, + -0.5313349536452118 + ], + [ + -0.20920142627084684, + -0.8192526017831071, + 0.052356448740672586, + -0.5313367482050518 + ], + [ + -0.20920131474951398, + -0.8192514385116818, + 0.05235688496163585, + -0.5313385427396821 + ], + [ + -0.20920120322577287, + -0.8192502752216468, + 0.052357321187860226, + -0.5313403372944465 + ], + [ + -0.20920109170103257, + -0.8192491119276989, + 0.05235775741383451, + -0.5313421318466729 + ], + [ + -0.20920098017670208, + -0.8192479486445345, + 0.05235819363404754, + -0.5313439263736895 + ], + [ + -0.20920086864996337, + -0.8192467853427604, + 0.05235862985952165, + -0.5313457209208403 + ], + [ + -0.20920075712363448, + -0.8192456220517702, + 0.05235906607923453, + -0.5313475154427812 + ], + [ + -0.20920064559489723, + -0.8192444587421701, + 0.05235950230420849, + -0.5313493099848561 + ], + [ + -0.20920053406516087, + -0.8192432954286569, + 0.05235993852893236, + -0.531351104524393 + ], + [ + -0.20920042253583435, + -0.8192421321259277, + 0.05236037474789495, + -0.5313528990387204 + ], + [ + -0.20920031100409944, + -0.8192409688045885, + 0.052360810972118615, + -0.5313546935731814 + ], + [ + -0.20920019947277452, + -0.8192398054940334, + 0.05236124719058105, + -0.531356488082433 + ], + [ + -0.2092000879390412, + -0.8192386421648682, + 0.052361683414304534, + -0.5313582826118181 + ], + [ + -0.2091999764043087, + -0.81923747883179, + 0.05236211963777791, + -0.5313600771386652 + ], + [ + -0.20919986486998615, + -0.819236315509496, + 0.052362555855490066, + -0.531361871640303 + ], + [ + -0.20919975333325522, + -0.8192351521685919, + 0.05236299207846326, + -0.5313636661620741 + ], + [ + -0.20919964179693418, + -0.819233988838472, + 0.05236342829567518, + -0.5313654606586358 + ], + [ + -0.20919952537873038, + -0.8192328406983117, + 0.052363874732462935, + -0.5313672326420699 + ], + [ + -0.20919940580723334, + -0.8192317023796566, + 0.05236432776783709, + -0.5313689900657103 + ], + [ + -0.20919928623628384, + -0.8192305640716112, + 0.05236478079724666, + -0.5313707474647014 + ], + [ + -0.20919916666286054, + -0.8192294257454129, + 0.05236523383213864, + -0.5313725048834491 + ], + [ + -0.20919904708998488, + -0.8192282874298245, + 0.05236568686106605, + -0.5313742622775478 + ], + [ + -0.2091989275146354, + -0.819227149096083, + 0.0523661398954759, + -0.5313760196914028 + ], + [ + -0.2091988079383227, + -0.8192260107585699, + 0.05236659292964462, + -0.5313777771028114 + ], + [ + -0.2091986883625577, + -0.8192248724316669, + 0.0523670459578488, + -0.531379534489571 + ], + [ + -0.2091985687843189, + -0.8192237340866108, + 0.05236749899153538, + -0.5313812918960868 + ], + [ + -0.20919844920662767, + -0.8192225957521646, + 0.052367952019257355, + -0.5313830492779539 + ], + [ + -0.20919832962646265, + -0.8192214573995653, + 0.05236840505246178, + -0.5313848066795771 + ], + [ + -0.20919821004533443, + -0.8192203190431945, + 0.05236885808542505, + -0.5313865640787537 + ], + [ + -0.20919809046475393, + -0.8192191806974339, + 0.05236931111242377, + -0.5313883214532816 + ], + [ + -0.2091979708816995, + -0.81921804233352, + 0.052369764144904844, + -0.5313900788475654 + ], + [ + -0.20919785129919283, + -0.8192169039802163, + 0.05237021717142135, + -0.5313918362172005 + ], + [ + -0.2091977317142122, + -0.8192157656087594, + 0.05237067020342023, + -0.5313935936065914 + ], + [ + -0.20919761212826846, + -0.8192146272335309, + 0.05237112323517806, + -0.5313953509935361 + ], + [ + -0.20919749254287245, + -0.8192134888689129, + 0.052371576260971296, + -0.5313971083558319 + ], + [ + -0.2091973729550025, + -0.8192123504861414, + 0.05237202929224685, + -0.5313988657378835 + ], + [ + -0.2091972533676803, + -0.8192112121139804, + 0.05237248231755784, + -0.5314006230952865 + ], + [ + -0.20919713377788418, + -0.8192100737236658, + 0.0523729353483512, + -0.5314023804724453 + ], + [ + -0.20919701418712489, + -0.8192089353295798, + 0.05237338837890343, + -0.5314041378471576 + ], + [ + -0.2091968945969134, + -0.8192077969461045, + 0.052373841403491064, + -0.531405895197221 + ], + [ + -0.20919677500422793, + -0.8192066585444755, + 0.05237429443356109, + -0.5314076525670404 + ], + [ + -0.20919665541209026, + -0.8192055201534574, + 0.0523747474576665, + -0.531409409912211 + ], + [ + -0.20919653581747857, + -0.8192043817442853, + 0.05237520048725425, + -0.5314111672771372 + ], + [ + -0.20919641622190382, + -0.8192032433313419, + 0.05237565351660088, + -0.531412924639617 + ], + [ + -0.20919629662687694, + -0.8192021049290095, + 0.05237610653998293, + -0.5314146819774483 + ], + [ + -0.20919617702937587, + -0.8192009665085231, + 0.052376559568847306, + -0.5314164393350349 + ], + [ + -0.20919605743242276, + -0.8191998280986478, + 0.05237701259174709, + -0.531418196667973 + ], + [ + -0.2091959378329955, + -0.8191986896706184, + 0.05237746562012917, + -0.5314199540206666 + ], + [ + -0.20919581823260527, + -0.8191975512388178, + 0.052377918648270176, + -0.5314217113709135 + ], + [ + -0.20919569863276286, + -0.8191964128176284, + 0.05237837167044653, + -0.531423468696512 + ], + [ + -0.20919557903044636, + -0.8191952743782848, + 0.05237882469810525, + -0.5314252260418659 + ], + [ + -0.20919545942867782, + -0.8191941359495525, + 0.05237927771979936, + -0.5314269833625713 + ], + [ + -0.20919533982443514, + -0.819192997502666, + 0.052379730746975765, + -0.531428740703032 + ], + [ + -0.2091952202192293, + -0.8191918590520082, + 0.052380183773910995, + -0.5314304980410461 + ], + [ + -0.20919510061457153, + -0.8191907206119619, + 0.05238063679488168, + -0.5314322553544119 + ], + [ + -0.20919498100743952, + -0.819189582153761, + 0.05238108982133464, + -0.5314340126875328 + ], + [ + -0.2091948614008555, + -0.8191884437061722, + 0.052381542841823024, + -0.5314357699960052 + ], + [ + -0.2091947417917973, + -0.8191873052404286, + 0.05238199586779367, + -0.5314375273242328 + ], + [ + -0.209194622181776, + -0.8191861667709138, + 0.05238244889352315, + -0.5314392846500136 + ], + [ + -0.2091945025645864, + -0.8191850282457499, + 0.05238290195029393, + -0.5314410420526731 + ], + [ + -0.20919438001618296, + -0.8191838645535782, + 0.05238336905787349, + -0.5314428380088084 + ], + [ + -0.20919425746832093, + -0.8191827008721657, + 0.052383836159299604, + -0.5314446339396961 + ], + [ + -0.20919413491790384, + -0.8191815371721086, + 0.05238430326637492, + -0.5314464298907158 + ], + [ + -0.20919401236647997, + -0.8191803734681091, + 0.052384770373198164, + -0.531448225839178 + ], + [ + -0.20919388981559756, + -0.8191792097748689, + 0.05238523747386795, + -0.5314500217623924 + ], + [ + -0.20919376726216007, + -0.8191780460629843, + 0.052385704580186924, + -0.5314518177057389 + ], + [ + -0.20919364470771573, + -0.819176882347157, + 0.05238617168625377, + -0.5314536136465277 + ], + [ + -0.20919352215381293, + -0.8191757186420893, + 0.05238663878616721, + -0.5314554095620689 + ], + [ + -0.20919339959735497, + -0.819174554918377, + 0.05238710589172982, + -0.5314572054977421 + ], + [ + -0.20919327704143853, + -0.8191733912054243, + 0.052387572991138956, + -0.5314590014081678 + ], + [ + -0.20919315448296702, + -0.8191722274738268, + 0.052388040096197325, + -0.5314607973387253 + ], + [ + -0.20919303192348856, + -0.819171063738287, + 0.05238850720100351, + -0.531462593266725 + ], + [ + -0.2091929093645518, + -0.8191699000135068, + 0.052388974299656284, + -0.5314643891694775 + ], + [ + -0.20919278680305983, + -0.8191687362700817, + 0.05238944140395821, + -0.5314661850923613 + ], + [ + -0.20919266424210942, + -0.8191675725374168, + 0.05238990850210672, + -0.5314679809899981 + ], + [ + -0.20919254167860385, + -0.8191664087861068, + 0.052390375605904385, + -0.5314697769077664 + ], + [ + -0.20919241911409145, + -0.8191652450308542, + 0.05239084270944988, + -0.5314715728229769 + ], + [ + -0.20919229655012064, + -0.8191640812863619, + 0.05239130980684198, + -0.53147336871294 + ], + [ + -0.20919217398359458, + -0.8191629175232243, + 0.05239177690988315, + -0.5314751646230346 + ], + [ + -0.20919205141761027, + -0.8191617537708471, + 0.052392244006770936, + -0.5314769605078823 + ], + [ + -0.20919192884907062, + -0.8191605899998247, + 0.052392711109307835, + -0.5314787564128611 + ], + [ + -0.20919180627952422, + -0.8191594262248597, + 0.05239317821159258, + -0.531480552315282 + ], + [ + -0.20919168371051952, + -0.8191582624606553, + 0.052393645307723904, + -0.5314823481924559 + ], + [ + -0.20919156113895943, + -0.8191570986778053, + 0.05239411240950432, + -0.531484144089761 + ], + [ + -0.20919143856794112, + -0.8191559349057159, + 0.052394579505131315, + -0.5314859399618191 + ], + [ + -0.2091913159943675, + -0.8191547711149813, + 0.05239504660640743, + -0.5314877358540082 + ], + [ + -0.20919119341978704, + -0.819153607320304, + 0.052395513707431327, + -0.5314895317436394 + ], + [ + -0.20919107084574834, + -0.8191524435363873, + 0.052395980802301824, + -0.5314913276080239 + ], + [ + -0.2091909482691543, + -0.8191512797338252, + 0.0523964479028214, + -0.5314931234925391 + ], + [ + -0.20919082569310202, + -0.8191501159420239, + 0.052396914997187585, + -0.5314949193518076 + ], + [ + -0.20919070311449448, + -0.819148952131577, + 0.052397382097202815, + -0.531496715231207 + ], + [ + -0.20919058053487993, + -0.8191477883171877, + 0.05239784919696586, + -0.5314985111080481 + ], + [ + -0.20919045795580746, + -0.8191466245135592, + 0.05239831629057552, + -0.5315003069596429 + ], + [ + -0.20919033537417933, + -0.8191454606912849, + 0.05239878338983418, + -0.531502102831368 + ], + [ + -0.20919021279309322, + -0.819144296879772, + 0.05239925048293946, + -0.5315038986778468 + ], + [ + -0.20919009020945162, + -0.819143133049613, + 0.05239971758169377, + -0.531505694544456 + ], + [ + -0.20918996762480324, + -0.8191419692155115, + 0.05240018468019592, + -0.5315074904085072 + ], + [ + -0.20918984504069668, + -0.8191408053921714, + 0.0524006517725446, + -0.5315092862473116 + ], + [ + -0.2091897224540346, + -0.8191396415501853, + 0.05240111887054231, + -0.5315110821062466 + ], + [ + -0.2091895998679146, + -0.8191384777189605, + 0.05240158596238668, + -0.5315128779399354 + ], + [ + -0.209189477279239, + -0.8191373138690897, + 0.052402053059879994, + -0.5315146737937542 + ], + [ + -0.20918935468955657, + -0.8191361500152764, + 0.05240252015712112, + -0.5315164696450149 + ], + [ + -0.20918924933031424, + -0.8191349952632029, + 0.05240298002125918, + -0.531518245392069 + ], + [ + -0.20918915492910758, + -0.8191338462756952, + 0.05240343529372861, + -0.5315200083863707 + ], + [ + -0.209189060528122, + -0.8191326972988993, + 0.052403890560202844, + -0.5315217713559307 + ], + [ + -0.20918896612497218, + -0.8191315483037824, + 0.0524043458321855, + -0.5315235343452952 + ], + [ + -0.20918887172085077, + -0.8191303993048613, + 0.05240480110392474, + -0.5315252973321909 + ], + [ + -0.2091887773169505, + -0.819129250316652, + 0.052405256369668814, + -0.531527060294345 + ], + [ + -0.20918868291088594, + -0.819128101310122, + 0.052405711640921275, + -0.5315288232763035 + ], + [ + -0.20918858850504254, + -0.819126952314304, + 0.05240616690617852, + -0.5315305862335203 + ], + [ + -0.20918849409703483, + -0.8191258033001654, + 0.05240662217694417, + -0.5315323492105413 + ], + [ + -0.20918839968805555, + -0.819124654282222, + 0.052407077447466456, + -0.5315341121850938 + ], + [ + -0.20918830527929752, + -0.8191235052749909, + 0.052407532711993575, + -0.5315358751349045 + ], + [ + -0.2091882108683751, + -0.8191223562494387, + 0.05240798798202901, + -0.5315376381045195 + ], + [ + -0.20918811645767388, + -0.819121207234599, + 0.05240844324606927, + -0.5315394010493929 + ], + [ + -0.20918802204480835, + -0.8191200582014383, + 0.052408898515617905, + -0.5315411640140704 + ], + [ + -0.20918792763097122, + -0.819118909164473, + 0.05240935378492316, + -0.5315429269762791 + ], + [ + -0.20918783321735537, + -0.8191177601382201, + 0.05240980904823318, + -0.5315446899137465 + ], + [ + -0.2091877388015751, + -0.8191166110936462, + 0.05241026431705158, + -0.5315464528710179 + ], + [ + -0.2091876443860161, + -0.8191154620597847, + 0.052410719579874775, + -0.5315482158035477 + ], + [ + -0.2091875499682927, + -0.819114313007602, + 0.05241117484820633, + -0.5315499787558815 + ], + [ + -0.2091874555495978, + -0.8191131639516148, + 0.05241163011629449, + -0.5315517417057466 + ], + [ + -0.2091873611311241, + -0.8191120149063404, + 0.05241208537838744, + -0.5315535046308701 + ], + [ + -0.209187266710486, + -0.8191108658427447, + 0.0524125406459887, + -0.5315552675757977 + ], + [ + -0.20918717229006925, + -0.8191097167898617, + 0.05241299590759481, + -0.5315570304959838 + ], + [ + -0.20918707786748797, + -0.8191085677186571, + 0.05241345117470926, + -0.5315587934359736 + ], + [ + -0.20918698344393521, + -0.8191074186436483, + 0.052413906441580234, + -0.5315605563734946 + ], + [ + -0.2091868890206038, + -0.8191062695793524, + 0.05241436170245604, + -0.5315623192862743 + ], + [ + -0.2091867945951079, + -0.8191051204967349, + 0.05241481696884017, + -0.5315640822188576 + ], + [ + -0.20918670016983335, + -0.8191039714248304, + 0.052415272229229114, + -0.5315658451266999 + ], + [ + -0.20918660574239434, + -0.8191028223346043, + 0.05241572749512634, + -0.5315676080543456 + ], + [ + -0.2091865113139836, + -0.819101673240574, + 0.052416182760780125, + -0.5315693709795223 + ], + [ + -0.2091864168857945, + -0.8191005241572566, + 0.05241663802043876, + -0.5315711338799581 + ], + [ + -0.20918632245544072, + -0.8190993750556177, + 0.05241709328560563, + -0.5315728968001971 + ], + [ + -0.20918622802530842, + -0.819098225964692, + 0.05241754854477738, + -0.5315746596956951 + ], + [ + -0.20918613359301158, + -0.8190970768554444, + 0.05241800380945736, + -0.5315764226109964 + ], + [ + -0.20918603915974318, + -0.8190959277423925, + 0.052418459073893885, + -0.531578185523829 + ], + [ + -0.2091859447266963, + -0.819094778640054, + 0.0524189143323353, + -0.5315799484119204 + ], + [ + -0.20918585029148468, + -0.8190936295193937, + 0.05241936959628489, + -0.5315817113198148 + ], + [ + -0.20918575585649465, + -0.8190924804094468, + 0.05241982485423937, + -0.5315834742029684 + ], + [ + -0.20918566141934003, + -0.8190913312811778, + 0.052420280117702084, + -0.5315852371059252 + ], + [ + -0.20918556698121382, + -0.8190901821491046, + 0.05242073538092129, + -0.5315870000064131 + ], + [ + -0.20918547254330913, + -0.819089033027745, + 0.05242119063814538, + -0.53158876288216 + ], + [ + -0.20918537810323978, + -0.8190878838880634, + 0.05242164590087767, + -0.5315905257777098 + ], + [ + -0.20918527591377645, + -0.8190867358073701, + 0.052422099600980744, + -0.5315922902363519 + ], + [ + -0.2091851462084493, + -0.8190855914300674, + 0.05242254778002589, + -0.5315940603521239 + ], + [ + -0.20918501650214716, + -0.8190844470489472, + 0.05242299595882667, + -0.5315958304654183 + ], + [ + -0.20918488679650885, + -0.8190833026784675, + 0.052423444131721, + -0.5315976005538721 + ], + [ + -0.20918475708825696, + -0.8190821582897128, + 0.0524238923100332, + -0.5315993706622114 + ], + [ + -0.2091846273806688, + -0.8190810139115984, + 0.052424340482438846, + -0.53160114074571 + ], + [ + -0.20918449767046704, + -0.8190798695152086, + 0.05242478866026241, + -0.5316029108490943 + ], + [ + -0.20918436795929038, + -0.8190787251150015, + 0.05242523683784158, + -0.531604680950001 + ], + [ + -0.20918423824877752, + -0.8190775807254352, + 0.05242568500951429, + -0.531606451026067 + ], + [ + -0.20918410853565095, + -0.8190764363175933, + 0.05242613318660478, + -0.5316082211220184 + ], + [ + -0.20918397882318834, + -0.8190752919203924, + 0.052426581357788826, + -0.5316099911931293 + ], + [ + -0.20918384910811197, + -0.8190741475049158, + 0.052427029534390684, + -0.5316117612841257 + ], + [ + -0.20918371939206065, + -0.8190730030856219, + 0.052427477710748176, + -0.5316135313726443 + ], + [ + -0.20918358967667322, + -0.8190718586769691, + 0.05242792588119924, + -0.5316153014363224 + ], + [ + -0.20918345995867219, + -0.8190707142500404, + 0.05242837405706805, + -0.5316170715198859 + ], + [ + -0.209183330241335, + -0.819069569833753, + 0.05242882222703035, + -0.5316188415786088 + ], + [ + -0.20918320052138403, + -0.8190684253991897, + 0.052429270402410494, + -0.531620611657217 + ], + [ + -0.20918307080045825, + -0.819067280960809, + 0.052429718577546275, + -0.5316223817333474 + ], + [ + -0.20918294108019636, + -0.8190661365330697, + 0.05243016674677558, + -0.5316241517846374 + ], + [ + -0.2091828113573207, + -0.8190649920870544, + 0.05243061492142266, + -0.5316259218558126 + ], + [ + -0.20918268163510897, + -0.8190638476516807, + 0.05243106309016325, + -0.5316276919021474 + ], + [ + -0.20918255191028348, + -0.8190627031980308, + 0.052431511264321586, + -0.5316294619683671 + ], + [ + -0.20918242218448305, + -0.8190615587405636, + 0.05243195943823558, + -0.531631232032109 + ], + [ + -0.2091822924593467, + -0.819060414293738, + 0.05243240760624312, + -0.5316330020710108 + ], + [ + -0.20918216273159645, + -0.8190592698286362, + 0.05243285577966836, + -0.5316347721297976 + ], + [ + -0.20918203300451024, + -0.8190581253741761, + 0.05243330394718717, + -0.531636542163744 + ], + [ + -0.2091819032748102, + -0.8190569809014397, + 0.05243375212012368, + -0.5316383122175752 + ], + [ + -0.20918177354413528, + -0.8190558364248862, + 0.052434200292815834, + -0.5316400822689286 + ], + [ + -0.20918164381412446, + -0.8190546919589743, + 0.052434648459601545, + -0.5316418522954419 + ], + [ + -0.20918151408149965, + -0.8190535474747862, + 0.05243509663180494, + -0.5316436223418398 + ], + [ + -0.20918138434953895, + -0.81905240300124, + 0.052435544798101884, + -0.5316453923633976 + ], + [ + -0.2091812546149644, + -0.8190512585094176, + 0.05243599296981656, + -0.53164716240484 + ], + [ + -0.20918112487941495, + -0.8190501140137775, + 0.0524364411412868, + -0.5316489324438046 + ], + [ + -0.2091809951445296, + -0.8190489695287797, + 0.05243688930685062, + -0.5316507024579291 + ], + [ + -0.2091808654070303, + -0.8190478250255053, + 0.05243733747783209, + -0.5316524724919381 + ], + [ + -0.2091807356701952, + -0.8190466805328731, + 0.05243778564290714, + -0.5316542425011073 + ], + [ + -0.20918060593074614, + -0.8190455360219643, + 0.052438233813399876, + -0.5316560125301607 + ], + [ + -0.20918047619032212, + -0.8190443915072382, + 0.05243868198364818, + -0.5316577825567363 + ], + [ + -0.20918034645056227, + -0.8190432470031546, + 0.052439130147990065, + -0.5316595525584719 + ], + [ + -0.20918021670818857, + -0.8190421024807939, + 0.052439578317749626, + -0.5316613225800919 + ], + [ + -0.20918008696647894, + -0.819040957969076, + 0.052440026481602696, + -0.5316630925768719 + ], + [ + -0.20917995722215546, + -0.8190398134390812, + 0.05244047465087344, + -0.5316648625935362 + ], + [ + -0.20917982747685687, + -0.819038668905269, + 0.05244092281989979, + -0.5316666326077224 + ], + [ + -0.2091797269858757, + -0.8190375072455041, + 0.05244136518860798, + -0.5316684180580415 + ], + [ + -0.2091796326933603, + -0.8190363419348247, + 0.05244180633444755, + -0.5316702068055651 + ], + [ + -0.20917953840104025, + -0.8190351766349679, + 0.052442247474464077, + -0.5316719955279589 + ], + [ + -0.20917944410653305, + -0.8190340113164893, + 0.05244268861980429, + -0.5316737842704199 + ], + [ + -0.2091793498110298, + -0.8190328459941115, + 0.05244312976489479, + -0.5316755730103494 + ], + [ + -0.20917925551572203, + -0.8190316806825566, + 0.052443570904162295, + -0.5316773617251491 + ], + [ + -0.20917916121822705, + -0.8190305153523798, + 0.05244401204875342, + -0.5316791504600161 + ], + [ + -0.20917906692092753, + -0.819029350033026, + 0.05244445318752158, + -0.5316809391697533 + ], + [ + -0.20917897262144072, + -0.8190281846950503, + 0.052444894331613374, + -0.5316827278995577 + ], + [ + -0.209178878320958, + -0.8190270193531753, + 0.05244533547545546, + -0.5316845166268305 + ], + [ + -0.20917878402067072, + -0.8190258540221234, + 0.052445776613474514, + -0.5316863053289737 + ], + [ + -0.20917868971819623, + -0.8190246886724494, + 0.05244621775681723, + -0.5316880940511839 + ], + [ + -0.2091785954159172, + -0.8190235233335988, + 0.05244665889433692, + -0.5316898827482645 + ], + [ + -0.20917850111145087, + -0.819022357976126, + 0.052447100037180186, + -0.5316916714654116 + ], + [ + -0.20917840680598856, + -0.8190211926147538, + 0.05244754117977376, + -0.5316934601800277 + ], + [ + -0.20917831250072186, + -0.8190200272642052, + 0.05244798231654434, + -0.5316952488695139 + ], + [ + -0.20917821819326776, + -0.8190188618950343, + 0.052448423458638545, + -0.5316970375790671 + ], + [ + -0.20917812388600923, + -0.819017696536687, + 0.0524488645949097, + -0.5316988262634906 + ], + [ + -0.20917802957656328, + -0.8190165311597173, + 0.05244930573650445, + -0.5317006149679808 + ], + [ + -0.20917793526612152, + -0.8190153657788479, + 0.05244974687784949, + -0.5317024036699397 + ], + [ + -0.20917784095587535, + -0.8190142004088028, + 0.052450188013371556, + -0.531704192346769 + ], + [ + -0.20917774664344174, + -0.819013035020135, + 0.052450629154217165, + -0.5317059810436648 + ], + [ + -0.20917765233001223, + -0.8190118696275678, + 0.05245107029481304, + -0.5317077697380291 + ], + [ + -0.2091775580179699, + -0.8190107042605479, + 0.05245151142401265, + -0.5317095583846663 + ], + [ + -0.20917746370254856, + -0.8190095388601821, + 0.05245195256410911, + -0.5317113470739677 + ], + [ + -0.20917736938732295, + -0.8190083734706405, + 0.05245239369838256, + -0.5317131357381398 + ], + [ + -0.2091772750699098, + -0.8190072080624758, + 0.05245283483797956, + -0.5317149244223781 + ], + [ + -0.20917718075150088, + -0.819006042650412, + 0.05245327597732681, + -0.5317167131040853 + ], + [ + -0.2091770864332875, + -0.8190048772491724, + 0.052453717110851054, + -0.5317185017606627 + ], + [ + -0.20917699211288673, + -0.81900371182931, + 0.05245415824969888, + -0.5317202904373066 + ], + [ + -0.2091768977926816, + -0.8190025464202718, + 0.052454599382723684, + -0.5317220790888212 + ], + [ + -0.20917680347028902, + -0.8190013809926107, + 0.052455040521072006, + -0.5317238677604019 + ], + [ + -0.20917670914690042, + -0.8190002155610503, + 0.052455481659170584, + -0.5317256564294511 + ], + [ + -0.20917661482370775, + -0.8189990501403145, + 0.052455922791446154, + -0.5317274450733712 + ], + [ + -0.2091765204983274, + -0.8189978847009554, + 0.052456363929045284, + -0.5317292337373573 + ], + [ + -0.20917642617314292, + -0.818996719272421, + 0.05245680506082134, + -0.5317310223762142 + ], + [ + -0.20917633184577075, + -0.8189955538252636, + 0.05245724619792096, + -0.531732811035137 + ], + [ + -0.20917623751740283, + -0.8189943883742067, + 0.05245768733477081, + -0.5317345996915284 + ], + [ + -0.20917614318923058, + -0.8189932229339746, + 0.05245812846579769, + -0.5317363883227905 + ], + [ + -0.20917604885887073, + -0.8189920574751193, + 0.052458569602147995, + -0.5317381769741184 + ], + [ + -0.20917595452870688, + -0.8189908920270889, + 0.05245901073267537, + -0.5317399656003176 + ], + [ + -0.20917586019635526, + -0.818989726560435, + 0.05245945186852617, + -0.5317417542465823 + ], + [ + -0.20917574840746483, + -0.818988563804587, + 0.0524599032180809, + -0.5317435445680808 + ], + [ + -0.2091756138237371, + -0.8189874046046544, + 0.05246036790011757, + -0.5317453370554172 + ], + [ + -0.2091754792373068, + -0.818986245386153, + 0.05246083258777357, + -0.5317471295628522 + ], + [ + -0.20917534465157472, + -0.8189850861783732, + 0.05246129726930755, + -0.5317489220450936 + ], + [ + -0.20917521006314022, + -0.8189839269520245, + 0.05246176195646091, + -0.5317507145474335 + ], + [ + -0.20917507547370354, + -0.8189827677217519, + 0.052462226643362954, + -0.5317525070472259 + ], + [ + -0.20917494088496497, + -0.8189816085022013, + 0.05246269132414287, + -0.5317542995218245 + ], + [ + -0.20917480629352406, + -0.8189804492640815, + 0.05246315601054222, + -0.5317560920165217 + ], + [ + -0.2091746717027814, + -0.8189792900366838, + 0.052463620690819474, + -0.5317578844860255 + ], + [ + -0.20917453710933617, + -0.8189781307907166, + 0.05246408537671613, + -0.5317596769756275 + ], + [ + -0.20917440251488878, + -0.8189769715408259, + 0.05246455006236142, + -0.5317614694626818 + ], + [ + -0.20917426792113974, + -0.8189758123016572, + 0.052465014741884655, + -0.5317632619245428 + ], + [ + -0.20917413332468807, + -0.8189746530439193, + 0.05246547942702724, + -0.5317650544065019 + ], + [ + -0.20917399872893486, + -0.8189734937969035, + 0.05246594410604777, + -0.5317668468632678 + ], + [ + -0.20917386413047895, + -0.8189723345313183, + 0.052466408790687646, + -0.5317686393401316 + ], + [ + -0.20917372953102095, + -0.8189711752618096, + 0.05246687347507618, + -0.5317704318144478 + ], + [ + -0.20917359493226123, + -0.818970016003023, + 0.052467338153342584, + -0.5317722242635706 + ], + [ + -0.209173460330799, + -0.8189688567256669, + 0.0524678028372284, + -0.5317740167327917 + ], + [ + -0.2091733257300351, + -0.8189676974590335, + 0.05246826751499212, + -0.5317758091768193 + ], + [ + -0.2091731911265686, + -0.8189665381738302, + 0.05246873219837515, + -0.5317776016409449 + ], + [ + -0.20917305652209991, + -0.8189653788847036, + 0.05246919688150683, + -0.5317793941025227 + ], + [ + -0.20917292191832973, + -0.8189642196062994, + 0.05246966155851645, + -0.5317811865389075 + ], + [ + -0.20917278731185687, + -0.8189630603093254, + 0.052470126241145366, + -0.5317829789953901 + ], + [ + -0.20917265270608237, + -0.8189619010230742, + 0.05247059091765222, + -0.5317847714266793 + ], + [ + -0.20917251809760523, + -0.8189607417182531, + 0.0524710555997784, + -0.5317865638780663 + ], + [ + -0.2091723834881259, + -0.8189595824095085, + 0.052471520281653194, + -0.5317883563269056 + ], + [ + -0.2091722488793451, + -0.8189584231114868, + 0.0524719849574059, + -0.5317901487505517 + ], + [ + -0.20917211426786167, + -0.8189572637948952, + 0.052472449638777924, + -0.5317919411942956 + ], + [ + -0.20917197965707662, + -0.8189561044890266, + 0.052472914314027855, + -0.5317937336128464 + ], + [ + -0.20917184504358888, + -0.8189549451645878, + 0.05247337899489708, + -0.5317955260514946 + ], + [ + -0.20917171042909902, + -0.8189537858362255, + 0.05247384367551491, + -0.5317973184875951 + ], + [ + -0.2091715758153077, + -0.8189526265185865, + 0.05247430835001071, + -0.5317991108985026 + ], + [ + -0.20917144119881353, + -0.818951467182377, + 0.05247477303012573, + -0.5318009033295075 + ], + [ + -0.20917130658301797, + -0.8189503078568909, + 0.05247523770411871, + -0.5318026957353196 + ], + [ + -0.20917117196451968, + -0.8189491485128347, + 0.052475702383730956, + -0.5318044881612288 + ], + [ + -0.2091710373450192, + -0.8189479891648549, + 0.0524761670630918, + -0.5318062805845905 + ], + [ + -0.2091709027262174, + -0.8189468298275984, + 0.05247663173633058, + -0.5318080729827591 + ], + [ + -0.20917076810471258, + -0.8189456704717716, + 0.05247709641518859, + -0.5318098654010247 + ], + [ + -0.20917063348390655, + -0.8189445111266682, + 0.05247756108792452, + -0.5318116577940979 + ], + [ + -0.20917049886039765, + -0.8189433517629945, + 0.05247802576627972, + -0.531813450207268 + ], + [ + -0.20917036423588659, + -0.8189421923953972, + 0.052478490444383484, + -0.5318152426178903 + ], + [ + -0.2091702296120743, + -0.8189410330385238, + 0.05247895511636521, + -0.5318170350033199 + ], + [ + -0.2091700968898386, + -0.8189398743150552, + 0.05247941870086256, + -0.5318188257637714 + ], + [ + -0.20917000735155272, + -0.8189387303872111, + 0.052479857491002695, + -0.5318205791938275 + ], + [ + -0.2091699178111769, + -0.8189375864411609, + 0.05248029628644593, + -0.5318223326435987 + ], + [ + -0.2091698282698422, + -0.8189364424913569, + 0.052480735081648626, + -0.5318240860909321 + ], + [ + -0.2091697387286801, + -0.8189352985522514, + 0.05248117387106712, + -0.531825839513675 + ], + [ + -0.20916964918542788, + -0.8189341545949399, + 0.052481612665788664, + -0.5318275929561329 + ], + [ + -0.20916955964234826, + -0.8189330106483272, + 0.05248205145472606, + -0.5318293463740006 + ], + [ + -0.20916947009717846, + -0.8189318666835079, + 0.0524824902489665, + -0.5318310998115829 + ], + [ + -0.20916938055105, + -0.8189307227149349, + 0.052482929042966385, + -0.5318328532467277 + ], + [ + -0.209169291005094, + -0.8189295787570611, + 0.05248336783118208, + -0.531834606657282 + ], + [ + -0.20916920145704793, + -0.8189284347809805, + 0.052483806624700834, + -0.5318363600875511 + ], + [ + -0.20916911190917448, + -0.8189272908155992, + 0.05248424541243537, + -0.53183811349323 + ], + [ + -0.20916902235921084, + -0.8189261468320114, + 0.05248468420547297, + -0.5318398669186233 + ], + [ + -0.2091689328082884, + -0.8189250028446696, + 0.05248512299826997, + -0.5318416203415789 + ], + [ + -0.20916884325753862, + -0.8189238588680271, + 0.052485561785282804, + -0.5318433737399444 + ], + [ + -0.20916875370469865, + -0.818922714873178, + 0.052486000577598675, + -0.5318451271580243 + ], + [ + -0.20916866415203134, + -0.8189215708890282, + 0.05248643936413037, + -0.5318468805515142 + ], + [ + -0.20916857459727387, + -0.8189204268866717, + 0.052486878155965054, + -0.5318486339647186 + ], + [ + -0.2091684850415576, + -0.8189192828805613, + 0.052487316947559155, + -0.531850387375485 + ], + [ + -0.20916839548601399, + -0.8189181388851505, + 0.052487755733369064, + -0.5318521407616614 + ], + [ + -0.20916830592838015, + -0.8189169948715328, + 0.052488194524482, + -0.5318538941675521 + ], + [ + -0.209168216370919, + -0.8189158508686146, + 0.05248863330981076, + -0.5318556475488528 + ], + [ + -0.20916812681136768, + -0.8189147068474896, + 0.052489072100442506, + -0.5318574009498679 + ], + [ + -0.20916803725085756, + -0.8189135628226107, + 0.05248951089083366, + -0.5318591543484449 + ], + [ + -0.20916794769052013, + -0.8189124188084317, + 0.05248994967544062, + -0.531860907722432 + ], + [ + -0.20916785812809252, + -0.8189112747760455, + 0.05249038846535056, + -0.5318626611161332 + ], + [ + -0.20916776856583758, + -0.8189101307543594, + 0.052490827249476374, + -0.5318644144852447 + ], + [ + -0.20916767900149236, + -0.8189089867144658, + 0.052491266038905096, + -0.5318661678740702 + ], + [ + -0.20916758943618843, + -0.8189078426708186, + 0.05249170482809325, + -0.5318679212604577 + ], + [ + -0.2091674998710572, + -0.8189066986378715, + 0.052492143611497205, + -0.5318696746222552 + ], + [ + -0.2091674103038357, + -0.818905554586717, + 0.052492582400204144, + -0.5318714280037667 + ], + [ + -0.20916732073678698, + -0.8189044105462626, + 0.0524930211831269, + -0.5318731813606886 + ], + [ + -0.20916723116764793, + -0.8189032664876009, + 0.052493459971352574, + -0.5318749347373243 + ], + [ + -0.20916714159755012, + -0.8189021224251856, + 0.05249389875933767, + -0.531876688111522 + ], + [ + -0.2091670520276252, + -0.8189009783734705, + 0.05249433754153858, + -0.5318784414611301 + ], + [ + -0.20916696245560984, + -0.8188998343035477, + 0.05249477632904242, + -0.5318801948304518 + ], + [ + -0.20916687288376734, + -0.8188986902443256, + 0.05249521511076208, + -0.5318819481751836 + ], + [ + -0.2091667833098345, + -0.8188975461668958, + 0.052495653897784704, + -0.5318837015396295 + ], + [ + -0.20916669373494282, + -0.8188964020857122, + 0.052496092684566655, + -0.5318854549016373 + ], + [ + -0.20916660416022412, + -0.8188952580152292, + 0.052496531465564496, + -0.5318872082390554 + ], + [ + -0.20916651458341493, + -0.8188941139265387, + 0.0524969702518652, + -0.531888961596187 + ], + [ + -0.2091664250067787, + -0.8188929698485485, + 0.052497409032381745, + -0.5318907149287292 + ], + [ + -0.20916633542805196, + -0.8188918257523508, + 0.05249784781820118, + -0.5318924682809848 + ], + [ + -0.20916621971560062, + -0.8188906675492802, + 0.05249829427144143, + -0.5318942528634509 + ], + [ + -0.20916608998189745, + -0.8188895017898019, + 0.052498744832926145, + -0.5318960541789178 + ], + [ + -0.20916596024554637, + -0.8188883360116452, + 0.05249919539985005, + -0.5318978555145768 + ], + [ + -0.2091658305098254, + -0.8188871702442669, + 0.05249964596082833, + -0.5318996568249126 + ], + [ + -0.2091657007714564, + -0.8188860044582104, + 0.05250009652724572, + -0.5319014581554402 + ], + [ + -0.20916557103207847, + -0.8188848386682036, + 0.052500547093409886, + -0.5319032594834021 + ], + [ + -0.2091654412933307, + -0.8188836728889753, + 0.052500997653628444, + -0.5319050607860407 + ], + [ + -0.2091653115519349, + -0.8188825070910687, + 0.0525014482192861, + -0.5319068621088712 + ], + [ + -0.20916518181116928, + -0.8188813413039404, + 0.05250189877899818, + -0.5319086634063784 + ], + [ + -0.2091650520677555, + -0.8188801754981337, + 0.05250234934414933, + -0.5319104647240773 + ], + [ + -0.20916492232333286, + -0.8188790096883769, + 0.05250279990904722, + -0.5319122660392105 + ], + [ + -0.20916479257954043, + -0.8188778438893989, + 0.05250325046799954, + -0.5319140673290206 + ], + [ + -0.20916466283309992, + -0.818876678071742, + 0.05250370103239092, + -0.5319158686390222 + ], + [ + -0.20916453308728958, + -0.8188755122648641, + 0.05250415159083674, + -0.5319176699237007 + ], + [ + -0.20916440333883113, + -0.8188743464393075, + 0.05250460215472158, + -0.5319194712285706 + ], + [ + -0.20916427358936382, + -0.8188731806098007, + 0.052505052718353186, + -0.531921272530875 + ], + [ + -0.20916414384052673, + -0.818872014791073, + 0.052505503276039214, + -0.5319230738078562 + ], + [ + -0.20916401408904148, + -0.8188708489536664, + 0.05250595383916427, + -0.531924875105029 + ], + [ + -0.20916388433818664, + -0.8188696831270388, + 0.05250640439634377, + -0.5319266763768786 + ], + [ + -0.20916375458468353, + -0.8188685172817324, + 0.05250685495896231, + -0.5319284776689196 + ], + [ + -0.20916362483017145, + -0.8188673514324757, + 0.05250730552132754, + -0.5319302789583946 + ], + [ + -0.20916349507628978, + -0.8188661855939985, + 0.052507756077747214, + -0.5319320802225468 + ], + [ + -0.20916336531975988, + -0.8188650197368421, + 0.052508206639605905, + -0.5319338815068901 + ], + [ + -0.2091632355638603, + -0.8188638538904651, + 0.052508657195519, + -0.5319356827659109 + ], + [ + -0.20916310580531253, + -0.8188626880254088, + 0.05250910775687113, + -0.5319374840451224 + ], + [ + -0.20916297604575584, + -0.8188615221564027, + 0.052509558317969975, + -0.5319392853217683 + ], + [ + -0.20916284628682955, + -0.8188603562981761, + 0.05251000887312326, + -0.5319410865730911 + ], + [ + -0.20916271652525492, + -0.8188591904212702, + 0.0525104594337155, + -0.5319428878446051 + ], + [ + -0.20916258676431077, + -0.8188580245551438, + 0.052510909988362206, + -0.5319446890907964 + ], + [ + -0.2091624570007184, + -0.8188568586703379, + 0.05251136054844784, + -0.5319464903571784 + ], + [ + -0.20916232723611694, + -0.8188556927815823, + 0.05251181110828024, + -0.5319482916209946 + ], + [ + -0.20916219747214615, + -0.8188545269036065, + 0.05251226166216705, + -0.5319500928594882 + ], + [ + -0.20916206770552687, + -0.8188533610069512, + 0.05251271222149281, + -0.5319518941181725 + ], + [ + -0.20916193793789875, + -0.8188521951063455, + 0.05251316278056525, + -0.5319536953742908 + ], + [ + -0.20916180817090105, + -0.8188510292165202, + 0.05251361333369217, + -0.5319554966050865 + ], + [ + -0.20916167840125502, + -0.8188498633080152, + 0.052514063892258, + -0.5319572978560728 + ], + [ + -0.20916154863223957, + -0.8188486974102902, + 0.05251451444487829, + -0.5319590990817366 + ], + [ + -0.20916141886057574, + -0.8188475314938857, + 0.05251496500293752, + -0.531960900327591 + ], + [ + -0.20916128908790296, + -0.8188463655735311, + 0.05251541556074346, + -0.5319627015708794 + ], + [ + -0.2091611593158607, + -0.8188451996639565, + 0.05251586611260381, + -0.5319645027888456 + ], + [ + -0.20916102954117016, + -0.8188440337357021, + 0.05251631666990308, + -0.531966304027002 + ], + [ + -0.2091608997671101, + -0.8188428678182283, + 0.052516767221256797, + -0.5319681052398357 + ], + [ + -0.20916077291401, + -0.818841705667575, + 0.05251721652000822, + -0.5319698996206658 + ], + [ + -0.2091606544082237, + -0.8188405543224622, + 0.05251766222619967, + -0.5319716744326727 + ], + [ + -0.20916053590295386, + -0.8188394029880562, + 0.05251810792651393, + -0.5319734492197632 + ], + [ + -0.2091604173952063, + -0.8188382516352657, + 0.05251855363221288, + -0.531975224026782 + ], + [ + -0.20916029888797533, + -0.8188371002931821, + 0.05251899933203474, + -0.5319769988088845 + ], + [ + -0.20916018037826664, + -0.8188359489327138, + 0.05251944503724126, + -0.5319787736109154 + ], + [ + -0.20916006186757732, + -0.8188347975684065, + 0.05251989074220162, + -0.5319805484104522 + ], + [ + -0.20915994335740457, + -0.8188336462148064, + 0.052520336441284746, + -0.5319823231850727 + ], + [ + -0.20915982484475412, + -0.8188324948428213, + 0.052520782145752634, + -0.5319840979796214 + ], + [ + -0.20915970633262024, + -0.8188313434815436, + 0.052521227844343335, + -0.5319858727492537 + ], + [ + -0.20915958781800856, + -0.8188301921018807, + 0.052521673548318736, + -0.5319876475388142 + ], + [ + -0.20915946930241627, + -0.8188290407183791, + 0.052522119252047916, + -0.5319894223258809 + ], + [ + -0.20915935078734066, + -0.8188278893455849, + 0.05252256494989995, + -0.531991197088031 + ], + [ + -0.20915923226978728, + -0.8188267379544056, + 0.052523010653136665, + -0.5319929718701094 + ], + [ + -0.20915911375275054, + -0.8188255865739338, + 0.05252345635049619, + -0.5319947466272714 + ], + [ + -0.2091589952332359, + -0.8188244351750769, + 0.052523902053240444, + -0.5319965214043616 + ], + [ + -0.20915887671274072, + -0.8188232837723809, + 0.05252434775573838, + -0.5319982961789577 + ], + [ + -0.20915875819276228, + -0.8188221323803929, + 0.05252479345235919, + -0.5320000709286373 + ], + [ + -0.20915863967030587, + -0.8188209809700192, + 0.052525239154364696, + -0.532001845698245 + ], + [ + -0.2091585211483664, + -0.8188198295703537, + 0.052525684850493054, + -0.5320036204429367 + ], + [ + -0.20915840262394875, + -0.8188186781523025, + 0.052526130552006015, + -0.532005395207556 + ], + [ + -0.2091582840985506, + -0.8188175267304125, + 0.05252657625327275, + -0.5320071699696814 + ], + [ + -0.20915816557366934, + -0.8188163753192305, + 0.05252702194866232, + -0.5320089447068905 + ], + [ + -0.2091580470463101, + -0.818815223889663, + 0.05252746764943653, + -0.5320107194640276 + ], + [ + -0.2091579285194677, + -0.8188140724708035, + 0.05252791334433361, + -0.5320124941962485 + ], + [ + -0.20915780999014721, + -0.8188129210335585, + 0.05252835904461527, + -0.532014268948397 + ], + [ + -0.2091576914598462, + -0.8188117695924746, + 0.05252880474465071, + -0.5320160436980512 + ], + [ + -0.20915757293006207, + -0.8188106181620988, + 0.052529250438808996, + -0.5320178184227898 + ], + [ + -0.20915745439779992, + -0.8188094667133374, + 0.052529696138351865, + -0.5320195931674555 + ], + [ + -0.20915733586605464, + -0.8188083152752843, + 0.05253014183201764, + -0.5320213678872056 + ], + [ + -0.20915721733183135, + -0.8188071638188452, + 0.05253058753106797, + -0.5320231426268831 + ], + [ + -0.20915709879662736, + -0.8188060123585674, + 0.05253103322987202, + -0.5320249173640662 + ], + [ + -0.20915698026194043, + -0.8188048609089983, + 0.05253147892279895, + -0.5320266920763336 + ], + [ + -0.20915686172477535, + -0.8188037094410431, + 0.05253192462111044, + -0.5320284668085282 + ], + [ + -0.2091567431881273, + -0.8188025579837964, + 0.052532370313544845, + -0.5320302415158071 + ], + [ + -0.20915662464900112, + -0.8188014065081637, + 0.05253281601136381, + -0.5320320162430132 + ], + [ + -0.20915650610889433, + -0.8188002550286921, + 0.052533261708936435, + -0.5320337909677251 + ], + [ + -0.20915638756930455, + -0.8187991035599297, + 0.052533707400632, + -0.5320355656675213 + ], + [ + -0.20915626902723664, + -0.8187979520727809, + 0.05253415309771206, + -0.5320373403872445 + ], + [ + -0.20915615048568578, + -0.8187968005963409, + 0.052534598788915046, + -0.5320391150820521 + ], + [ + -0.20915603194165666, + -0.8187956491015145, + 0.05253504448550251, + -0.5320408897967867 + ], + [ + -0.20915591339664705, + -0.8187944976028497, + 0.05253549018184371, + -0.5320426645090269 + ], + [ + -0.20915579655543018, + -0.8187933462023625, + 0.05253593680532998, + -0.5320444383000239 + ], + [ + -0.209155699799215, + -0.8187921958150642, + 0.052536394437741184, + -0.5320462015401748 + ], + [ + -0.20915560304324934, + -0.8187910454384915, + 0.0525368520641265, + -0.5320479647555745 + ], + [ + -0.20915550628508847, + -0.8187898950435766, + 0.052537309696048994, + -0.5320497279907759 + ], + [ + -0.20915540952595482, + -0.8187887446448533, + 0.05253776732772716, + -0.5320514912235027 + ], + [ + -0.20915531276707078, + -0.8187875942568557, + 0.05253822495337935, + -0.5320532544314784 + ], + [ + -0.20915521600599152, + -0.8187864438505157, + 0.052538682584568806, + -0.532055017659256 + ], + [ + -0.20915511924516186, + -0.8187852934549016, + 0.05253914020973227, + -0.5320567808622826 + ], + [ + -0.20915502248213685, + -0.818784143040945, + 0.05253959784043298, + -0.5320585440851106 + ], + [ + -0.20915492571813915, + -0.8187829926231803, + 0.05254005547088931, + -0.532060307305464 + ], + [ + -0.2091548289543911, + -0.8187818422161413, + 0.05254051309531968, + -0.5320620705010666 + ], + [ + -0.20915473218844766, + -0.8187806917907599, + 0.05254097072528725, + -0.5320638337164705 + ], + [ + -0.20915463542275403, + -0.8187795413761043, + 0.0525414283492289, + -0.5320655969071237 + ], + [ + -0.20915453865486505, + -0.8187783909431063, + 0.05254188597870772, + -0.5320673601175784 + ], + [ + -0.20915444188600324, + -0.8187772405063001, + 0.05254234360794219, + -0.5320691233255581 + ], + [ + -0.20915434511739112, + -0.8187760900802199, + 0.05254280123115068, + -0.5320708865087872 + ], + [ + -0.2091542483465837, + -0.8187749396357971, + 0.052543258859896344, + -0.5320726497118174 + ], + [ + -0.20915415157602604, + -0.8187737892021005, + 0.05254371648261607, + -0.5320744128900973 + ], + [ + -0.20915405480327293, + -0.8187726387500612, + 0.05254417411087297, + -0.5320761760881778 + ] + ], + "angular_velocities": [ + [ + 0.00011379960385463027, + -0.0007854003132670582, + -0.0003404344392466544 + ], + [ + 0.00011351516680504009, + -0.0007840778588928445, + -0.00033977846895758495 + ], + [ + 0.00011323073334895932, + -0.0007827554212262019, + -0.0003391225069558864 + ], + [ + 0.00011294629629936906, + -0.000781432966851988, + -0.00033846653666681667 + ], + [ + 0.00011292788786374979, + -0.000781508420814244, + -0.0003384739331189884 + ], + [ + 0.00011340184009723464, + -0.0007841711029825191, + -0.000339709077964051 + ], + [ + 0.00011387579233071946, + -0.0007868337851507942, + -0.00034094422280911386 + ], + [ + 0.00011434973857640574, + -0.0007894964336793819, + -0.00034217935204965307 + ], + [ + 0.00011482369080989058, + -0.0007921591158476567, + -0.0003434144968947156 + ], + [ + 0.0001152976370555768, + -0.0007948217643762446, + -0.0003446496261352549 + ], + [ + 0.00011577158928906163, + -0.0007974844465445193, + -0.00034588477098031764 + ], + [ + 0.00011624554152254654, + -0.0008001471287127945, + -0.00034711991582538033 + ], + [ + 0.00011671948776823268, + -0.0008028097772413819, + -0.00034835504506591927 + ], + [ + 0.00011719344000171749, + -0.000805472459409657, + -0.00034959018991098206 + ], + [ + 0.00011766738624740377, + -0.0008081351079382445, + -0.0003508253191515213 + ], + [ + 0.00011814133848088868, + -0.0008107977901065199, + -0.00035206046399658395 + ], + [ + 0.00011861529071437356, + -0.0008134604722747949, + -0.0003532956088416468 + ], + [ + 0.00011908923696005962, + -0.0008161231208033824, + -0.0003545307380821859 + ], + [ + 0.00011956318919354456, + -0.0008187858029716573, + -0.00035576588292724853 + ], + [ + 0.00012003713543923072, + -0.0008214484515002449, + -0.0003570010121677878 + ], + [ + 0.00012051108767271563, + -0.00082411113366852, + -0.0003582361570128504 + ], + [ + 0.00012098503990620057, + -0.0008267738158367951, + -0.0003594713018579133 + ], + [ + 0.00012145898615188673, + -0.0008294364643653829, + -0.0003607064310984524 + ], + [ + 0.00012193293838537155, + -0.0008320991465336576, + -0.00036194157594351495 + ], + [ + 0.00012240688463105765, + -0.0008347617950622454, + -0.0003631767051840543 + ], + [ + 0.00012288083686454258, + -0.0008374244772305204, + -0.0003644118500291169 + ], + [ + 0.00012335478909802748, + -0.0008400871593987953, + -0.00036564699487417964 + ], + [ + 0.0001238287353437137, + -0.0008427498079273833, + -0.00036688212411471884 + ], + [ + 0.00012430268757719862, + -0.0008454124900956582, + -0.00036811726895978153 + ], + [ + 0.00012477663382288486, + -0.0008480751386242459, + -0.00036935239820032095 + ], + [ + 0.0001252505860563696, + -0.0008507378207925206, + -0.0003705875430453834 + ], + [ + 0.0001257245382898546, + -0.0008534005029607959, + -0.00037182268789044605 + ], + [ + 0.00012619848453554062, + -0.0008560631514893833, + -0.00037305781713098537 + ], + [ + 0.00012667243676902558, + -0.0008587258336576582, + -0.00037429296197604805 + ], + [ + 0.00012714638301471168, + -0.0008613884821862458, + -0.0003755280912165871 + ], + [ + 0.00012762033524819658, + -0.0008640511643545211, + -0.00037676323606164995 + ], + [ + 0.0001280942874816815, + -0.000866713846522796, + -0.0003779983809067126 + ], + [ + 0.00012856823372736767, + -0.0008693764950513837, + -0.0003792335101472518 + ], + [ + 0.00012904218596085254, + -0.0008720391772196586, + -0.0003804686549923146 + ], + [ + 0.00012951613220653864, + -0.0008747018257482463, + -0.00038170378423285373 + ], + [ + 0.0001299900844400235, + -0.0008773645079165213, + -0.0003829389290779164 + ], + [ + 0.00013046403667350842, + -0.000880027190084796, + -0.00038417407392297905 + ], + [ + 0.00013093798291919455, + -0.0008826898386133839, + -0.00038540920316351837 + ], + [ + 0.00013141193515267953, + -0.0008853525207816591, + -0.0003866443480085808 + ], + [ + 0.00013188588139836574, + -0.0008880151693102471, + -0.0003878794772491203 + ], + [ + 0.00013235983363185056, + -0.0008906778514785217, + -0.0003891146220941829 + ], + [ + 0.00013283378586533551, + -0.0008933405336467968, + -0.0003903497669392456 + ], + [ + 0.00013330773211102164, + -0.0008960031821753843, + -0.0003915848961797847 + ], + [ + 0.00013378168434450644, + -0.0008986658643436591, + -0.0003928200410248474 + ], + [ + 0.00013390178689241916, + -0.0008994600296867975, + -0.0003932642437177217 + ], + [ + 0.00013352763501344502, + -0.0008976442704313262, + -0.0003926036700239258 + ], + [ + 0.00013315348313447067, + -0.000895828511175854, + -0.0003919430963301294 + ], + [ + 0.00013277933598244133, + -0.0008940127748602489, + -0.0003912825309818625 + ], + [ + 0.00013240518410346705, + -0.0008921970156047773, + -0.0003906219572880662 + ], + [ + 0.00013203103695143766, + -0.0008903812792891719, + -0.0003899613919397994 + ], + [ + 0.00013165688507246336, + -0.0008885655200336998, + -0.0003893008182460031 + ], + [ + 0.0001312827331934891, + -0.0008867497607782283, + -0.00038864024455220677 + ], + [ + 0.0001309085860414599, + -0.0008849340244626229, + -0.0003879796792039399 + ], + [ + 0.00013053443416248571, + -0.0008831182652071516, + -0.00038731910551014387 + ], + [ + 0.0001301602870104563, + -0.0008813025288915459, + -0.000386658540161877 + ], + [ + 0.00012978613513148205, + -0.0008794867696360743, + -0.00038599796646808076 + ], + [ + 0.00012941198325250775, + -0.0008776710103806023, + -0.00038533739277428437 + ], + [ + 0.0001290378361004785, + -0.0008758552740649971, + -0.00038467682742601765 + ], + [ + 0.0001286636842215042, + -0.0008740395148095253, + -0.0003840162537322213 + ], + [ + 0.0001282895370694749, + -0.0008722237784939205, + -0.00038335568838395454 + ], + [ + 0.00012791538519050063, + -0.0008704080192384481, + -0.00038269511469015815 + ], + [ + 0.00012754123331152627, + -0.0008685922599829765, + -0.000382034540996362 + ], + [ + 0.00012716708615949704, + -0.0008667765236673712, + -0.00038137397564809515 + ], + [ + 0.00012679293428052277, + -0.0008649607644118995, + -0.00038071340195429876 + ], + [ + 0.00012641878712849337, + -0.0008631450280962939, + -0.00038005283660603204 + ], + [ + 0.00012604463524951918, + -0.0008613292688408224, + -0.00037939226291223586 + ], + [ + 0.00012567048337054485, + -0.0008595135095853505, + -0.0003787316892184396 + ], + [ + 0.00012529633621851562, + -0.0008576977732697454, + -0.0003780711238701727 + ], + [ + 0.0001249221843395413, + -0.0008558820140142731, + -0.0003774105501763763 + ], + [ + 0.00012454803246056702, + -0.0008540662547588016, + -0.0003767499764825801 + ], + [ + 0.0001241738853085377, + -0.0008522505184431966, + -0.00037608941113431347 + ], + [ + 0.00012379973342956349, + -0.0008504347591877243, + -0.0003754288374405169 + ], + [ + 0.00012342558627753407, + -0.000848619022872119, + -0.0003747682720922502 + ], + [ + 0.00012305143439855987, + -0.0008468032636166474, + -0.0003741076983984539 + ], + [ + 0.0001226772825195855, + -0.0008449875043611755, + -0.00037344712470465763 + ], + [ + 0.00012230313536755637, + -0.0008431717680455707, + -0.0003727865593563909 + ], + [ + 0.00012192898348858205, + -0.0008413560087900987, + -0.00037212598566259446 + ], + [ + 0.00012155483633655274, + -0.0008395402724744937, + -0.00037146542031432796 + ], + [ + 0.00012118068445757848, + -0.0008377245132190217, + -0.00037080484662053157 + ], + [ + 0.00012080653257860426, + -0.00083590875396355, + -0.00037014427292673534 + ], + [ + 0.00012043238542657484, + -0.0008340930176479441, + -0.0003694837075784683 + ], + [ + 0.0001200582335476006, + -0.0008322772583924724, + -0.0003688231338846719 + ], + [ + 0.00011968408639557125, + -0.0008304615220768673, + -0.00036816256853640524 + ], + [ + 0.00011930993451659703, + -0.0008286457628213954, + -0.0003675019948426089 + ], + [ + 0.00011915145573118362, + -0.0008279709627033975, + -0.00036714619235417686 + ], + [ + 0.00011915705980157615, + -0.0008281641957035068, + -0.00036702225972112324 + ], + [ + 0.00011916266394277002, + -0.0008283574311449055, + -0.0003668983255223143 + ], + [ + 0.00011916826801316267, + -0.0008285506641450146, + -0.00036677439288926045 + ], + [ + 0.00011917387215435657, + -0.000828743899586414, + -0.00036665045869045177 + ], + [ + 0.00011917947629555046, + -0.0008289371350278127, + -0.0003665265244916429 + ], + [ + 0.00011918508036594304, + -0.0008291303680279217, + -0.00036640259185858904 + ], + [ + 0.00011919068450713698, + -0.000829323603469321, + -0.00036627865765978036 + ], + [ + 0.00011919628857752944, + -0.0008295168364694297, + -0.0003661547250267265 + ], + [ + 0.00011920189271872349, + -0.000829710071910829, + -0.00036603079082791774 + ], + [ + 0.00011920749685991745, + -0.0008299033073522281, + -0.00036590685662910905 + ], + [ + 0.00011921310093030991, + -0.0008300965403523369, + -0.0003657829239960551 + ], + [ + 0.00011921870507150385, + -0.0008302897757937362, + -0.0003656589897972465 + ], + [ + 0.0001192243091418965, + -0.0008304830087938448, + -0.00036553505716419244 + ], + [ + 0.00011922991328309042, + -0.0008306762442352441, + -0.0003654111229653837 + ], + [ + 0.00011923551742428437, + -0.0008308694796766435, + -0.0003652871887665752 + ], + [ + 0.0001192411214946769, + -0.0008310627126767525, + -0.0003651632561335212 + ], + [ + 0.00011924672563587072, + -0.0008312559481181513, + -0.0003650393219347122 + ], + [ + 0.00011925232970626337, + -0.0008314491811182605, + -0.00036491538930165856 + ], + [ + 0.00011925793384745732, + -0.0008316424165596594, + -0.0003647914551028497 + ], + [ + 0.00011926353798865119, + -0.0008318356520010583, + -0.00036466752090404104 + ], + [ + 0.0001192691420590439, + -0.0008320288850011676, + -0.0003645435882709874 + ], + [ + 0.00011927474620023769, + -0.0008322221204425668, + -0.0003644196540721784 + ], + [ + 0.00011928035027063026, + -0.0008324153534426755, + -0.0003642957214391245 + ], + [ + 0.0001192859544118241, + -0.0008326085888840745, + -0.00036417178724031584 + ], + [ + 0.00011929155855301816, + -0.0008328018243254739, + -0.00036404785304150705 + ], + [ + 0.00011929716262341065, + -0.0008329950573255829, + -0.0003639239204084531 + ], + [ + 0.00011930276676460456, + -0.0008331882927669817, + -0.00036379998620964443 + ], + [ + 0.00011930837083499717, + -0.000833381525767091, + -0.00036367605357659065 + ], + [ + 0.00011931397497619119, + -0.0008335747612084902, + -0.00036355211937778186 + ], + [ + 0.00011931957911738504, + -0.000833767996649889, + -0.00036342818517897307 + ], + [ + 0.00011932518318777768, + -0.0008339612296499984, + -0.00036330425254591924 + ], + [ + 0.00011933078732897147, + -0.0008341544650913967, + -0.00036318031834711045 + ], + [ + 0.00011933639139936414, + -0.000834347698091506, + -0.0003630563857140567 + ], + [ + 0.00011934199554055807, + -0.0008345409335329052, + -0.00036293245151524793 + ], + [ + 0.00011934759968175198, + -0.0008347341689743047, + -0.00036280851731643903 + ], + [ + 0.00011935320375214453, + -0.0008349274019744131, + -0.00036268458468338526 + ], + [ + 0.00011935880789333847, + -0.000835120637415812, + -0.00036256065048457647 + ], + [ + 0.00011936441196373105, + -0.0008353138704159215, + -0.0003624367178515227 + ], + [ + 0.00011937001610492495, + -0.0008355071058573206, + -0.0003623127836527139 + ], + [ + 0.00011937562024611893, + -0.0008357003412987198, + -0.00036218884945390527 + ], + [ + 0.00011938122431651143, + -0.0008358935742988285, + -0.00036206491682085144 + ], + [ + 0.00011943903007521355, + -0.0008360766874374202, + -0.0003620047804594832 + ], + [ + 0.00011974040096228544, + -0.0008362125689334638, + -0.00036224231714848557 + ], + [ + 0.00012004177565685286, + -0.0008363484521462231, + -0.00036247985683850685 + ], + [ + 0.00012034315035142017, + -0.0008364843353589821, + -0.0003627173965285283 + ], + [ + 0.00012064452123849203, + -0.0008366202168550258, + -0.00036295493321753046 + ], + [ + 0.00012094589593305953, + -0.0008367561000677854, + -0.000363192472907552 + ], + [ + 0.00012124726682013146, + -0.0008368919815638289, + -0.00036343000959655406 + ], + [ + 0.00012154864151469889, + -0.0008370278647765877, + -0.00036366754928657567 + ], + [ + 0.00012185001620926632, + -0.0008371637479893474, + -0.00036390508897659685 + ], + [ + 0.00012215138709633817, + -0.0008372996294853908, + -0.00036414262566559927 + ], + [ + 0.00012245276179090564, + -0.0008374355126981502, + -0.00036438016535562067 + ], + [ + 0.00012275413267797745, + -0.0008375713941941933, + -0.00036461770204462255 + ], + [ + 0.00012305550737254484, + -0.0008377072774069529, + -0.00036485524173464416 + ], + [ + 0.00012335688206711241, + -0.0008378431606197123, + -0.00036509278142466577 + ], + [ + 0.0001236582529541843, + -0.0008379790421157557, + -0.00036533031811366776 + ], + [ + 0.0001239596276487516, + -0.0008381149253285148, + -0.0003655678578036892 + ], + [ + 0.00012426099853582342, + -0.0008382508068245584, + -0.00036580539449269103 + ], + [ + 0.00012456237323039095, + -0.0008383866900373179, + -0.0003660429341827128 + ], + [ + 0.00012486374792495834, + -0.0008385225732500771, + -0.00036628047387273426 + ], + [ + 0.00012516511881203028, + -0.0008386584547461205, + -0.0003665180105617363 + ], + [ + 0.0001254664935065978, + -0.0008387943379588801, + -0.0003667555502517579 + ], + [ + 0.00012576786439366953, + -0.0008389302194549234, + -0.0003669930869407599 + ], + [ + 0.0001260692390882369, + -0.0008390661026676825, + -0.00036723062663078114 + ], + [ + 0.00012637061378280447, + -0.000839201985880442, + -0.0003674681663208029 + ], + [ + 0.00012667198466987623, + -0.0008393378673764855, + -0.000367705703009805 + ], + [ + 0.0001269733593644437, + -0.0008394737505892447, + -0.00036794324269982646 + ], + [ + 0.00012727473025151556, + -0.000839609632085288, + -0.0003681807793888284 + ], + [ + 0.00012757610494608306, + -0.0008397455152980476, + -0.00036841831907884984 + ], + [ + 0.00012787747964065037, + -0.0008398813985108069, + -0.00036865585876887146 + ], + [ + 0.00012817885052772229, + -0.0008400172800068503, + -0.00036889339545787355 + ], + [ + 0.00012848022522228978, + -0.0008401531632196095, + -0.000369130935147895 + ], + [ + 0.00012878159230186604, + -0.0008402890429989373, + -0.00036936846883587775 + ], + [ + 0.00012908296699643356, + -0.0008404249262116967, + -0.00036960600852589925 + ], + [ + 0.00012938434169100082, + -0.0008405608094244558, + -0.00036984354821592054 + ], + [ + 0.00012968571257807276, + -0.0008406966909204992, + -0.00037008108490492263 + ], + [ + 0.00012998708727264023, + -0.0008408325741332586, + -0.0003703186245949443 + ], + [ + 0.00013028845815971204, + -0.0008409684556293021, + -0.00037055616128394634 + ], + [ + 0.00013058983285427949, + -0.0008411043388420615, + -0.0003707937009739679 + ], + [ + 0.00013089120754884693, + -0.0008412402220548212, + -0.0003710312406639893 + ], + [ + 0.00013119257843591887, + -0.0008413761035508643, + -0.00037126877735299134 + ], + [ + 0.00013149395313048615, + -0.0008415119867636233, + -0.00037150631704301274 + ], + [ + 0.00013179532401755815, + -0.0008416478682596676, + -0.000371743853732015 + ], + [ + 0.00013209669871212554, + -0.0008417837514724262, + -0.00037198139342203634 + ], + [ + 0.00013212285131460294, + -0.0008416433818598772, + -0.0003719679802965244 + ], + [ + 0.00013194272497485258, + -0.0008412959628756503, + -0.00037176647852089906 + ], + [ + 0.00013176259635940086, + -0.0008409485395021612, + -0.00037156497419951696 + ], + [ + 0.0001315824700196506, + -0.0008406011205179346, + -0.0003713634724238921 + ], + [ + 0.0001314023414041986, + -0.0008402536971444447, + -0.00037116196810250973 + ], + [ + 0.00013122221278874676, + -0.0008399062737709548, + -0.0003709604637811275 + ], + [ + 0.00013104208644899653, + -0.0008395588547867283, + -0.00037075896200550244 + ], + [ + 0.00013086195783354457, + -0.0008392114314132385, + -0.0003705574576841201 + ], + [ + 0.0001306818314937943, + -0.0008388640124290122, + -0.00037035595590849516 + ], + [ + 0.00013050170287834251, + -0.0008385165890555229, + -0.0003701544515871129 + ], + [ + 0.00013032157426289052, + -0.0008381691656820327, + -0.0003699529472657306 + ], + [ + 0.00013014144792314032, + -0.0008378217466978064, + -0.0003697514454901058 + ], + [ + 0.00012996131930768833, + -0.0008374743233243163, + -0.0003695499411687232 + ], + [ + 0.0001297811929679382, + -0.0008371269043400903, + -0.0003693484393930985 + ], + [ + 0.00012960106435248628, + -0.0008367794809666004, + -0.0003691469350717162 + ], + [ + 0.00012942093573703434, + -0.0008364320575931103, + -0.00036894543075033376 + ], + [ + 0.00012924080939728406, + -0.0008360846386088843, + -0.00036874392897470883 + ], + [ + 0.00012906068078183218, + -0.0008357372152353941, + -0.0003685424246533266 + ], + [ + 0.000128880554442082, + -0.0008353897962511679, + -0.00036834092287770165 + ], + [ + 0.00012870042582663007, + -0.0008350423728776781, + -0.0003681394185563193 + ], + [ + 0.00012852029721117822, + -0.0008346949495041886, + -0.00036793791423493714 + ], + [ + 0.00012834017087142788, + -0.0008343475305199618, + -0.00036773641245931217 + ], + [ + 0.00012816004225597597, + -0.0008340001071464721, + -0.0003675349081379298 + ], + [ + 0.00012797991591622575, + -0.0008336526881622459, + -0.0003673334063623048 + ], + [ + 0.0001277997873007739, + -0.000833305264788756, + -0.00036713190204092257 + ], + [ + 0.000127619658685322, + -0.0008329578414152662, + -0.0003669303977195403 + ], + [ + 0.00012743953234557162, + -0.0008326104224310397, + -0.00036672889594391517 + ], + [ + 0.0001272594037301198, + -0.0008322629990575499, + -0.000366527391622533 + ], + [ + 0.00012707927739036957, + -0.0008319155800733235, + -0.000366325889846908 + ], + [ + 0.00012689914877491774, + -0.0008315681566998343, + -0.0003661243855255258 + ], + [ + 0.00012671902015946567, + -0.000831220733326344, + -0.0003659228812041435 + ], + [ + 0.00012653889381971558, + -0.0008308733143421173, + -0.00036572137942851823 + ], + [ + 0.00012635876520426364, + -0.0008305258909686277, + -0.00036551987510713625 + ], + [ + 0.0001261786388645133, + -0.0008301784719844015, + -0.00036531837333151116 + ], + [ + 0.00012599851024906145, + -0.0008298310486109115, + -0.00036511686901012885 + ], + [ + 0.0001258183816336096, + -0.000829483625237422, + -0.0003649153646887467 + ], + [ + 0.00012563825529385931, + -0.0008291362062531955, + -0.0003647138629131215 + ], + [ + 0.00012545812667840743, + -0.0008287887828797058, + -0.00036451235859173947 + ], + [ + 0.0001252779980629555, + -0.0008284413595062161, + -0.0003643108542703572 + ], + [ + 0.00012509787172320532, + -0.0008280939405219897, + -0.00036410935249473224 + ], + [ + 0.00012491774310775336, + -0.0008277465171484997, + -0.00036390784817334987 + ], + [ + 0.00012473761676800316, + -0.0008273990981642735, + -0.0003637063463977249 + ], + [ + 0.00012461161901945744, + -0.000827342312679569, + -0.00036356522022853625 + ], + [ + 0.00012457015126187752, + -0.0008277393831834593, + -0.0003635183797220604 + ], + [ + 0.0001245286840281912, + -0.0008281364486708565, + -0.0003634715398073561 + ], + [ + 0.00012448721627061104, + -0.0008285335191747467, + -0.00036342469930088016 + ], + [ + 0.0001244457490369246, + -0.0008289305846621442, + -0.00036337785938617595 + ], + [ + 0.00012440428127934473, + -0.0008293276551660343, + -0.00036333101887970015 + ], + [ + 0.00012436281352176461, + -0.0008297247256699252, + -0.0003632841783732243 + ], + [ + 0.00012432134628807836, + -0.000830121791157322, + -0.00036323733845851987 + ], + [ + 0.00012427987853049814, + -0.0008305188616612122, + -0.000363190497952044 + ], + [ + 0.00012423841129681191, + -0.0008309159271486094, + -0.0003631436580373398 + ], + [ + 0.00012419694353923188, + -0.0008313129976525003, + -0.00036309681753086406 + ], + [ + 0.0001241554757816517, + -0.0008317100681563904, + -0.00036304997702438793 + ], + [ + 0.00012411400854796546, + -0.0008321071336437877, + -0.0003630031371096839 + ], + [ + 0.00012407254079038527, + -0.0008325042041476778, + -0.0003629562966032077 + ], + [ + 0.00012403107355669893, + -0.0008329012696350752, + -0.0003629094566885036 + ], + [ + 0.00012398960579911898, + -0.0008332983401389659, + -0.0003628626161820278 + ], + [ + 0.00012394813804153892, + -0.0008336954106428562, + -0.00036281577567555184 + ], + [ + 0.0001239066708078524, + -0.0008340924761302531, + -0.0003627689357608476 + ], + [ + 0.00012386520305027247, + -0.0008344895466341435, + -0.00036272209525437167 + ], + [ + 0.00012382373581658608, + -0.0008348866121215406, + -0.0003626752553396675 + ], + [ + 0.00012378226805900616, + -0.0008352836826254314, + -0.00036262841483319155 + ], + [ + 0.00012374080030142607, + -0.000835680753129322, + -0.0003625815743267157 + ], + [ + 0.00012369933306773966, + -0.0008360778186167187, + -0.00036253473441201137 + ], + [ + 0.00012365786531015962, + -0.0008364748891206092, + -0.00036248789390553557 + ], + [ + 0.00012361639807647324, + -0.0008368719546080063, + -0.00036244105399083136 + ], + [ + 0.00012357493031889304, + -0.0008372690251118965, + -0.00036239421348435523 + ], + [ + 0.00012353346256131325, + -0.0008376660956157872, + -0.0003623473729778795 + ], + [ + 0.00012349199532762678, + -0.0008380631611031841, + -0.0003623005330631751 + ], + [ + 0.00012345052757004678, + -0.0008384602316070747, + -0.0003622536925566993 + ], + [ + 0.00012340906033636042, + -0.0008388572970944721, + -0.0003622068526419951 + ], + [ + 0.00012336759257878038, + -0.0008392543675983627, + -0.0003621600121355193 + ], + [ + 0.00012332612482120024, + -0.0008396514381022526, + -0.0003621131716290432 + ], + [ + 0.00012328465758751385, + -0.0008400485035896495, + -0.00036206633171433886 + ], + [ + 0.0001232431898299338, + -0.0008404455740935404, + -0.00036201949120786306 + ], + [ + 0.00012320172259624751, + -0.0008408426395809374, + -0.0003619726512931589 + ], + [ + 0.00012316025483866748, + -0.0008412397100848278, + -0.0003619258107866829 + ], + [ + 0.00012311878708108742, + -0.0008416367805887185, + -0.0003618789702802069 + ], + [ + 0.00012307731984740112, + -0.0008420338460761155, + -0.00036183213036550287 + ], + [ + 0.00012303585208982092, + -0.0008424309165800055, + -0.0003617852898590268 + ], + [ + 0.00012299438485613467, + -0.000842827982067403, + -0.00036173844994432286 + ], + [ + 0.00012295291709855455, + -0.0008432250525712935, + -0.0003616916094378468 + ], + [ + 0.00012291144934097455, + -0.0008436221230751844, + -0.000361644768931371 + ], + [ + 0.00012286998210728824, + -0.0008440191885625811, + -0.00036159792901666656 + ], + [ + 0.00012285365901379029, + -0.0008437283673403944, + -0.00036165870954276645 + ], + [ + 0.00012284420275657983, + -0.0008432496968947243, + -0.00036174887898841234 + ], + [ + 0.00012283474637989997, + -0.0008427710204015709, + -0.00036183904957325195 + ], + [ + 0.00012282529000321997, + -0.0008422923439084168, + -0.0003619292201580914 + ], + [ + 0.0001228158337460096, + -0.0008418136734627473, + -0.0003620193896037375 + ], + [ + 0.0001228063773693296, + -0.0008413349969695937, + -0.000362109560188577 + ], + [ + 0.0001227969211121193, + -0.0008408563265239242, + -0.0003621997296342231 + ], + [ + 0.00012278746473543925, + -0.0008403776500307702, + -0.00036228990021906256 + ], + [ + 0.0001227780083587593, + -0.0008398989735376167, + -0.00036238007080390206 + ], + [ + 0.00012276855210154904, + -0.0008394203030919471, + -0.0003624702402495484 + ], + [ + 0.00012275909572486898, + -0.0008389416265987932, + -0.00036256041083438767 + ], + [ + 0.0001227496394676587, + -0.0008384629561531233, + -0.0003626505802800338 + ], + [ + 0.00012274018309097872, + -0.0008379842796599696, + -0.00036274075086487333 + ], + [ + 0.00012273072671429872, + -0.0008375056031668158, + -0.0003628309214497128 + ], + [ + 0.0001227212704570884, + -0.0008370269327211459, + -0.0003629210908953589 + ], + [ + 0.00012271181408040846, + -0.0008365482562279924, + -0.0003630112614801985 + ], + [ + 0.00012270235782319808, + -0.0008360695857823227, + -0.00036310143092584444 + ], + [ + 0.0001226929014465181, + -0.000835590909289169, + -0.0003631916015106839 + ], + [ + 0.0001226834450698381, + -0.0008351122327960153, + -0.0003632817720955235 + ], + [ + 0.0001226739888126278, + -0.0008346335623503457, + -0.00036337194154116966 + ], + [ + 0.00012266453243594785, + -0.0008341548858571919, + -0.0003634621121260091 + ], + [ + 0.00012265507617873747, + -0.000833676215411522, + -0.0003635522815716551 + ], + [ + 0.00012264561980205747, + -0.0008331975389183684, + -0.0003636424521564947 + ], + [ + 0.00012263616342537764, + -0.0008327188624252148, + -0.0003637326227413342 + ], + [ + 0.00012262670716816731, + -0.000832240191979545, + -0.00036382279218698043 + ], + [ + 0.0001226172507914873, + -0.0008317615154863913, + -0.0003639129627718197 + ], + [ + 0.00012260779453427694, + -0.0008312828450407215, + -0.00036400313221746577 + ], + [ + 0.00012259833815759697, + -0.0008308041685475678, + -0.0003640933028023053 + ], + [ + 0.00012258888178091697, + -0.0008303254920544145, + -0.00036418347338714504 + ], + [ + 0.00012257942552370657, + -0.0008298468216087441, + -0.0003642736428327908 + ], + [ + 0.0001225699691470267, + -0.0008293681451155906, + -0.00036436381341763043 + ], + [ + 0.00012256051288981638, + -0.0008288894746699209, + -0.00036445398286327654 + ], + [ + 0.00012255105651313628, + -0.0008284107981767675, + -0.00036454415344811604 + ], + [ + 0.0001225416001364564, + -0.0008279321216836136, + -0.0003646343240329556 + ], + [ + 0.0001225321438792461, + -0.0008274534512379437, + -0.0003647244934786016 + ], + [ + 0.00012252268750256602, + -0.0008269747747447899, + -0.0003648146640634412 + ], + [ + 0.00012251323124535572, + -0.0008264961042991205, + -0.0003649048335090872 + ], + [ + 0.0001225037748686757, + -0.0008260174278059662, + -0.0003649950040939266 + ], + [ + 0.00012249431849199567, + -0.0008255387513128125, + -0.0003650851746787662 + ], + [ + 0.0001224848622347855, + -0.0008250600808671431, + -0.0003651753441244123 + ], + [ + 0.00012247540585810543, + -0.0008245814043739892, + -0.0003652655147092517 + ], + [ + 0.0001224659496008951, + -0.0008241027339283194, + -0.00036535568415489765 + ], + [ + 0.0001225125885290912, + -0.0008241684442344867, + -0.0003655270817240269 + ], + [ + 0.0001225954671216722, + -0.0008245858487679441, + -0.0003657509549621297 + ], + [ + 0.00012267834466718483, + -0.0008250032480280123, + -0.00036597482537187184 + ], + [ + 0.0001227612232597658, + -0.0008254206525614697, + -0.0003661986986099746 + ], + [ + 0.00012284410080527867, + -0.0008258380518215388, + -0.00036642256901971685 + ], + [ + 0.00012292697939785964, + -0.0008262554563549957, + -0.0003666464422578196 + ], + [ + 0.00012300985799044054, + -0.0008266728608884528, + -0.0003668703154959224 + ], + [ + 0.00012309273553595324, + -0.0008270902601485217, + -0.00036709418590566466 + ], + [ + 0.00012317561412853427, + -0.0008275076646819791, + -0.00036731805914376757 + ], + [ + 0.00012325849167404708, + -0.0008279250639420476, + -0.0003675419295535096 + ], + [ + 0.0001233413702666281, + -0.0008283424684755048, + -0.00036776580279161263 + ], + [ + 0.00012342424885920908, + -0.0008287598730089623, + -0.00036798967602971543 + ], + [ + 0.00012350712640472178, + -0.0008291772722690308, + -0.0003682135464394576 + ], + [ + 0.00012359000499730278, + -0.0008295946768024882, + -0.0003684374196775604 + ], + [ + 0.00012367288254281562, + -0.0008300120760625568, + -0.00036866129008730254 + ], + [ + 0.00012375576113539657, + -0.0008304294805960141, + -0.0003688851633254053 + ], + [ + 0.00012383863972797752, + -0.0008308468851294714, + -0.00036910903656350814 + ], + [ + 0.0001239215172734902, + -0.0008312642843895402, + -0.00036933290697325046 + ], + [ + 0.00012400439586607122, + -0.0008316816889229974, + -0.00036955678021135315 + ], + [ + 0.00012408727341158395, + -0.0008320990881830663, + -0.0003697806506210954 + ], + [ + 0.000124170152004165, + -0.0008325164927165231, + -0.0003700045238591982 + ], + [ + 0.000124253030596746, + -0.0008329338972499808, + -0.00037022839709730107 + ], + [ + 0.0001243359081422587, + -0.0008333512965100491, + -0.0003704522675070431 + ], + [ + 0.00012441878673483963, + -0.0008337687010435068, + -0.00037067614074514624 + ], + [ + 0.0001245016642803524, + -0.0008341861003035752, + -0.0003709000111548881 + ], + [ + 0.00012458454287293339, + -0.0008346035048370324, + -0.0003711238843929911 + ], + [ + 0.0001246674214655144, + -0.00083502090937049, + -0.00037134775763109394 + ], + [ + 0.00012475029901102728, + -0.0008354383086305585, + -0.0003715716280408361 + ], + [ + 0.00012483317760360812, + -0.0008358557131640156, + -0.0003717955012789389 + ], + [ + 0.00012491605514912093, + -0.0008362731124240845, + -0.00037201937168868094 + ], + [ + 0.0001249989337417019, + -0.0008366905169575417, + -0.00037224324492678384 + ], + [ + 0.00012508181233428293, + -0.000837107921490999, + -0.00037246711816488675 + ], + [ + 0.00012516468987979558, + -0.0008375253207510677, + -0.0003726909885746287 + ], + [ + 0.00012524756847237664, + -0.0008379427252845252, + -0.0003729148618127317 + ], + [ + 0.00012533044601788936, + -0.0008383601245445934, + -0.0003731387322224738 + ], + [ + 0.00012541332461047037, + -0.0008387775290780511, + -0.0003733626054605768 + ], + [ + 0.0001254962032030514, + -0.0008391949336115084, + -0.00037358647869867957 + ], + [ + 0.00012557908074856404, + -0.0008396123328715765, + -0.00037381034910842156 + ], + [ + 0.00012566195934114513, + -0.0008400297374050343, + -0.0003740342223465245 + ], + [ + 0.0001257448368866577, + -0.0008404471366651028, + -0.0003742580927562665 + ], + [ + 0.0001258277154792388, + -0.0008408645411985604, + -0.0003744819659943696 + ], + [ + 0.0001259105940718196, + -0.0008412819457320172, + -0.0003747058392324722 + ], + [ + 0.0001259936589656682, + -0.0008416974370313676, + -0.000374928271988946 + ], + [ + 0.00012614783170636885, + -0.0008413887799554907, + -0.0003746050559522913 + ], + [ + 0.0001263020024992881, + -0.0008410801267791134, + -0.0003742818439990705 + ], + [ + 0.00012645617523998886, + -0.0008407714697032368, + -0.0003739586279624157 + ], + [ + 0.00012661034798068955, + -0.00084046281262736, + -0.0003736354119257612 + ], + [ + 0.00012676451877360876, + -0.0008401541594509825, + -0.00037331219997254026 + ], + [ + 0.00012691869151430947, + -0.0008398455023751056, + -0.0003729889839358857 + ], + [ + 0.0001270728642550103, + -0.0008395368452992295, + -0.0003726657678992312 + ], + [ + 0.00012722703504792953, + -0.0008392281921228517, + -0.0003723425559460103 + ], + [ + 0.00012738120778863017, + -0.0008389195350469749, + -0.0003720193399093557 + ], + [ + 0.00012753537858154954, + -0.0008386108818705978, + -0.0003716961279561348 + ], + [ + 0.00012768955132225025, + -0.000838302224794721, + -0.0003713729119194803 + ], + [ + 0.0001278437240629508, + -0.0008379935677188437, + -0.00037104969588282546 + ], + [ + 0.00012799789485587023, + -0.0008376849145424668, + -0.0003707264839296048 + ], + [ + 0.000128152067596571, + -0.00083737625746659, + -0.00037040326789295006 + ], + [ + 0.0001283062383894902, + -0.0008370676042902127, + -0.0003700800559397293 + ], + [ + 0.00012846041113019082, + -0.0008367589472143358, + -0.00036975683990307466 + ], + [ + 0.00012861458387089167, + -0.000836450290138459, + -0.00036943362386641996 + ], + [ + 0.00012876875466381088, + -0.000836141636962082, + -0.00036911041191319926 + ], + [ + 0.0001289229274045115, + -0.0008358329798862047, + -0.0003687871958765445 + ], + [ + 0.00012907709819743096, + -0.000835524326709828, + -0.0003684639839233237 + ], + [ + 0.00012923127093813157, + -0.0008352156696339508, + -0.00036814076788666895 + ], + [ + 0.00012938544367883234, + -0.0008349070125580741, + -0.0003678175518500145 + ], + [ + 0.00012953961447175163, + -0.0008345983593816969, + -0.0003674943398967936 + ], + [ + 0.00012969378721245232, + -0.00083428970230582, + -0.0003671711238601391 + ], + [ + 0.00012984795800537156, + -0.0008339810491294423, + -0.0003668479119069181 + ], + [ + 0.00013000213074607225, + -0.000833672392053566, + -0.00036652469587026355 + ], + [ + 0.0001301563034867729, + -0.0008333637349776887, + -0.00036620147983360875 + ], + [ + 0.0001303104742796923, + -0.0008330550818013117, + -0.000365878267880388 + ], + [ + 0.00013046464702039302, + -0.0008327464247254349, + -0.0003655550518437334 + ], + [ + 0.0001306188178133123, + -0.0008324377715490578, + -0.0003652318398905125 + ], + [ + 0.000130772990554013, + -0.0008321291144731809, + -0.0003649086238538579 + ], + [ + 0.00013092716329471355, + -0.0008318204573973039, + -0.00036458540781720303 + ], + [ + 0.0001310813340876331, + -0.000831511804220927, + -0.0003642621958639826 + ], + [ + 0.0001312355068283337, + -0.0008312031471450499, + -0.0003639389798273278 + ], + [ + 0.000131389677621253, + -0.0008308944939686727, + -0.00036361576787410704 + ], + [ + 0.00013154385036195373, + -0.0008305858368927962, + -0.0003632925518374524 + ], + [ + 0.00013169802310265447, + -0.0008302771798169193, + -0.00036296933580079785 + ], + [ + 0.00013185219389557376, + -0.0008299685266405422, + -0.00036264612384757694 + ], + [ + 0.00013200636663627432, + -0.000829659869564665, + -0.00036232290781092235 + ], + [ + 0.00013216053742919374, + -0.000829351216388288, + -0.0003619996958577015 + ], + [ + 0.00013231471016989443, + -0.0008290425593124113, + -0.0003616764798210468 + ], + [ + 0.00013246888291059496, + -0.0008287339022365344, + -0.00036135326378439214 + ], + [ + 0.00013232085725964422, + -0.0008286323297912384, + -0.0003613144236279272 + ], + [ + 0.00013198059544080007, + -0.0008286624850082902, + -0.0003614564785993467 + ], + [ + 0.00013164033792074226, + -0.0008286926398443685, + -0.0003615985317760778 + ], + [ + 0.0001313000761018982, + -0.0008287227950614202, + -0.00036174058674749737 + ], + [ + 0.00013095981428305422, + -0.0008287529502784717, + -0.00036188264171891667 + ], + [ + 0.00013061955676299633, + -0.0008287831051145497, + -0.0003620246948956478 + ], + [ + 0.00013027929494415226, + -0.0008288132603316014, + -0.0003621667498670673 + ], + [ + 0.00012993903742409445, + -0.0008288434151676796, + -0.00036230880304379833 + ], + [ + 0.00012959877560525033, + -0.0008288735703847316, + -0.00036245085801521785 + ], + [ + 0.00012925851378640628, + -0.0008289037256017832, + -0.00036259291298663737 + ], + [ + 0.0001289182562663484, + -0.0008289338804378609, + -0.00036273496616336847 + ], + [ + 0.00012857799444750443, + -0.0008289640356549127, + -0.0003628770211347878 + ], + [ + 0.00012823773692744643, + -0.0008289941904909907, + -0.0003630190743115189 + ], + [ + 0.00012789747510860236, + -0.0008290243457080424, + -0.0003631611292829384 + ], + [ + 0.00012755721328975832, + -0.0008290545009250942, + -0.00036330318425435785 + ], + [ + 0.00012721695576970045, + -0.0008290846557611718, + -0.0003634452374310888 + ], + [ + 0.00012687669395085644, + -0.000829114810978224, + -0.00036358729240250836 + ], + [ + 0.00012653643643079855, + -0.0008291449658143021, + -0.00036372934557923957 + ], + [ + 0.00012619617461195453, + -0.0008291751210313536, + -0.0003638714005506588 + ], + [ + 0.00012585591279311054, + -0.0008292052762484055, + -0.0003640134555220785 + ], + [ + 0.00012551565527305262, + -0.0008292354310844835, + -0.00036415550869880943 + ], + [ + 0.00012517539345420852, + -0.000829265586301535, + -0.0003642975636702289 + ], + [ + 0.00012483513593415063, + -0.0008292957411376134, + -0.00036443961684696005 + ], + [ + 0.00012449487411530662, + -0.000829325896354665, + -0.00036458167181837946 + ], + [ + 0.00012415461229646252, + -0.0008293560515717165, + -0.00036472372678979904 + ], + [ + 0.0001238143547764047, + -0.0008293862064077944, + -0.00036486577996653 + ], + [ + 0.0001234740929575606, + -0.000829416361624846, + -0.00036500783493794933 + ], + [ + 0.00012313383543750275, + -0.0008294465164609242, + -0.00036514988811468064 + ], + [ + 0.00012279357361865876, + -0.0008294766716779759, + -0.00036529194308610005 + ], + [ + 0.0001224533117998146, + -0.0008295068268950281, + -0.0003654339980575195 + ], + [ + 0.00012211305427975682, + -0.000829536981731106, + -0.00036557605123425067 + ], + [ + 0.00012177279246091278, + -0.0008295671369481574, + -0.00036571810620567 + ], + [ + 0.00012143253494085478, + -0.0008295972917842352, + -0.00036586015938240113 + ], + [ + 0.00012109227312201075, + -0.0008296274470012871, + -0.00036600221435382054 + ], + [ + 0.00012075201130316687, + -0.0008296576022183392, + -0.0003661442693252403 + ], + [ + 0.00012041175378310897, + -0.0008296877570544172, + -0.0003662863225019712 + ], + [ + 0.00012007149196426479, + -0.0008297179122714687, + -0.0003664283774733905 + ], + [ + 0.00011973123444420688, + -0.0008297480671075468, + -0.0003665704306501217 + ], + [ + 0.00011939097262536295, + -0.0008297782223245984, + -0.0003667124856215412 + ], + [ + 0.00011905071080651893, + -0.00082980837754165, + -0.00036685454059296065 + ], + [ + 0.00011871045328646103, + -0.0008298385323777282, + -0.0003669965937696917 + ], + [ + 0.00011837019146761701, + -0.0008298686875947798, + -0.0003671386487411111 + ], + [ + 0.0001181677068917704, + -0.0008299575196141659, + -0.0003672064266742582 + ], + [ + 0.00011845435751058963, + -0.0008302546754112904, + -0.0003670105047353346 + ], + [ + 0.00011874100812940892, + -0.000830551831208415, + -0.0003668145827964111 + ], + [ + 0.00011902765512675322, + -0.0008308489832513447, + -0.0003666186633327184 + ], + [ + 0.00011931430574557239, + -0.0008311461390484692, + -0.0003664227413937949 + ], + [ + 0.00011960095274291663, + -0.000831443291091399, + -0.00036622682193010215 + ], + [ + 0.00011988760336173598, + -0.0008317404468885237, + -0.00036603089999117885 + ], + [ + 0.00012017425398055536, + -0.0008320376026856484, + -0.00036583497805225544 + ], + [ + 0.0001204609009778995, + -0.000832334754728578, + -0.0003656390585885626 + ], + [ + 0.00012074755159671886, + -0.0008326319105257026, + -0.000365443136649639 + ], + [ + 0.00012103419859406306, + -0.0008329290625686323, + -0.0003652472171859465 + ], + [ + 0.00012132084921288233, + -0.0008332262183657566, + -0.00036505129524702277 + ], + [ + 0.00012160749983170168, + -0.0008335233741628815, + -0.00036485537330809947 + ], + [ + 0.00012189414682904573, + -0.0008338205262058112, + -0.0003646594538444067 + ], + [ + 0.00012218079744786517, + -0.0008341176820029357, + -0.0003644635319054833 + ], + [ + 0.00012246744444520933, + -0.000834414834045865, + -0.00036426761244179025 + ], + [ + 0.0001227540950640287, + -0.0008347119898429903, + -0.00036407169050286706 + ], + [ + 0.00012304074568284808, + -0.0008350091456401146, + -0.00036387576856394355 + ], + [ + 0.00012332739268019224, + -0.0008353062976830442, + -0.00036367984910025094 + ], + [ + 0.00012361404329901154, + -0.0008356034534801686, + -0.00036348392716132737 + ], + [ + 0.00012390069029635564, + -0.0008359006055230984, + -0.0003632880076976346 + ], + [ + 0.00012418734091517513, + -0.0008361977613202236, + -0.0003630920857587113 + ], + [ + 0.00012447399153399437, + -0.0008364949171173479, + -0.00036289616381978773 + ], + [ + 0.0001247606385313385, + -0.0008367920691602773, + -0.00036270024435609496 + ], + [ + 0.00012504728915015796, + -0.0008370892249574023, + -0.00036250432241717156 + ], + [ + 0.00012533393614750212, + -0.0008373863770003319, + -0.0003623084029534789 + ], + [ + 0.00012562058676632144, + -0.0008376835327974564, + -0.0003621124810145551 + ], + [ + 0.00012590723738514076, + -0.0008379806885945814, + -0.0003619165590756318 + ], + [ + 0.00012619388438248505, + -0.0008382778406375106, + -0.00036172063961193904 + ], + [ + 0.0001264805350013043, + -0.0008385749964346359, + -0.0003615247176730157 + ], + [ + 0.00012676718199864843, + -0.000838872148477565, + -0.0003613287982093229 + ], + [ + 0.00012705383261746767, + -0.0008391693042746897, + -0.0003611328762703995 + ], + [ + 0.00012734048323628715, + -0.0008394664600718144, + -0.0003609369543314761 + ], + [ + 0.00012762713023363126, + -0.0008397636121147439, + -0.0003607410348677833 + ], + [ + 0.00012791378085245063, + -0.0008400607679118685, + -0.0003605451129288598 + ], + [ + 0.00012820042784979484, + -0.0008403579199547984, + -0.0003603491934651671 + ], + [ + 0.0001284870784686142, + -0.0008406550757519231, + -0.0003601532715262436 + ], + [ + 0.00012877372908743357, + -0.0008409522315490478, + -0.0003599573495873202 + ], + [ + 0.0001290603760847776, + -0.000841249383591977, + -0.0003597614301236273 + ], + [ + 0.00012934702670359702, + -0.0008415465393891018, + -0.00035956550818470396 + ], + [ + 0.0001296336737009412, + -0.0008418436914320316, + -0.0003593695887210112 + ], + [ + 0.0001299203243197607, + -0.0008421408472291566, + -0.0003591736667820878 + ], + [ + 0.00013020697493857977, + -0.000842438003026281, + -0.0003589777448431644 + ], + [ + 0.0001300759656976878, + -0.0008424305829655565, + -0.0003592832082637262 + ], + [ + 0.00012985642659954442, + -0.0008423586044056933, + -0.0003596949508034721 + ], + [ + 0.0001296368902750055, + -0.0008422866267551899, + -0.0003601066881413614 + ], + [ + 0.00012941735117686233, + -0.0008422146481953269, + -0.0003605184306811076 + ], + [ + 0.0001291978120787189, + -0.0008421426696354639, + -0.00036093017322085316 + ], + [ + 0.00012897827575417985, + -0.0008420706919849605, + -0.0003613419105587425 + ], + [ + 0.00012875873665603658, + -0.0008419987134250975, + -0.0003617536530984884 + ], + [ + 0.00012853920033149756, + -0.0008419267357745939, + -0.00036216539043637763 + ], + [ + 0.0001283196612333543, + -0.0008418547572147309, + -0.0003625771329761237 + ], + [ + 0.00012810012213521082, + -0.0008417827786548673, + -0.00036298887551586934 + ], + [ + 0.00012788058581067184, + -0.000841710801004364, + -0.00036340061285375884 + ], + [ + 0.0001276610467125286, + -0.000841638822444501, + -0.0003638123553935047 + ], + [ + 0.00012744151038798958, + -0.0008415668447939974, + -0.0003642240927313941 + ], + [ + 0.00012722197128984625, + -0.0008414948662341341, + -0.00036463583527113983 + ], + [ + 0.00012700243219170303, + -0.0008414228876742716, + -0.00036504757781088574 + ], + [ + 0.00012678289586716396, + -0.0008413509100237678, + -0.000365459315148775 + ], + [ + 0.00012656335676902066, + -0.0008412789314639047, + -0.00036587105768852093 + ], + [ + 0.00012634382044448162, + -0.0008412069538134017, + -0.0003662827950264104 + ], + [ + 0.00012612428134633818, + -0.0008411349752535383, + -0.00036669453756615623 + ], + [ + 0.00012590474224819501, + -0.0008410629966936749, + -0.000367106280105902 + ], + [ + 0.00012568520592365595, + -0.0008409910190431718, + -0.00036751801744379126 + ], + [ + 0.0001254656668255126, + -0.0008409190404833086, + -0.0003679297599835372 + ], + [ + 0.0001252461277273693, + -0.0008408470619234452, + -0.0003683415025232829 + ], + [ + 0.00012502659417643454, + -0.0008407750851823017, + -0.000368753234659316 + ], + [ + 0.00012480705507829113, + -0.0008407031066224389, + -0.0003691649771990619 + ], + [ + 0.00012458751875375214, + -0.0008406311289719351, + -0.0003695767145369512 + ], + [ + 0.00012436797965560884, + -0.000840559150412072, + -0.0003699884570766969 + ], + [ + 0.00012414844055746576, + -0.0008404871718522093, + -0.000370400199616443 + ], + [ + 0.00012392890423292658, + -0.0008404151942017058, + -0.00037081193695433223 + ], + [ + 0.0001237093651347834, + -0.0008403432156418427, + -0.0003712236794940782 + ], + [ + 0.0001234898288102442, + -0.0008402712379913393, + -0.00037163541683196753 + ], + [ + 0.00012327028971210097, + -0.0008401992594314759, + -0.00037204715937171333 + ], + [ + 0.00012305075061395764, + -0.0008401272808716133, + -0.0003724589019114591 + ], + [ + 0.00012283121428941865, + -0.0008400553032211096, + -0.0003728706392493485 + ], + [ + 0.00012261167519127532, + -0.0008399833246612464, + -0.00037328238178909443 + ], + [ + 0.00012239213886673634, + -0.0008399113470107432, + -0.0003736941191269837 + ], + [ + 0.000122172599768593, + -0.0008398393684508802, + -0.0003741058616667295 + ], + [ + 0.00012195306067044969, + -0.0008397673898910166, + -0.00037451760420647537 + ], + [ + 0.0001217335243459106, + -0.000839695412240513, + -0.00037492934154436465 + ], + [ + 0.00012151398524776723, + -0.0008396234336806502, + -0.00037534108408411056 + ], + [ + 0.00012129444892322824, + -0.0008395514560301467, + -0.0003757528214219999 + ], + [ + 0.00012107490982508501, + -0.000839479477470284, + -0.0003761645639617459 + ], + [ + 0.00012104587811739645, + -0.0008392985149139492, + -0.0003761629930164741 + ], + [ + 0.00012126563098965515, + -0.000838975232092768, + -0.0003756216746832665 + ], + [ + 0.00012148538663825401, + -0.0008386519451872585, + -0.0003750803495110863 + ], + [ + 0.00012170513951051259, + -0.0008383286623660771, + -0.00037453903117787843 + ], + [ + 0.00012192489515911156, + -0.0008380053754605679, + -0.00037399770600569866 + ], + [ + 0.00012214465080771027, + -0.0008376820885550577, + -0.00037345638083351846 + ], + [ + 0.00012236440367996884, + -0.000837358805733877, + -0.0003729150625003106 + ], + [ + 0.00012258415932856764, + -0.0008370355188283669, + -0.00037237373732813036 + ], + [ + 0.00012280391220082643, + -0.0008367122360071862, + -0.0003718324189949227 + ], + [ + 0.00012302366784942528, + -0.0008363889491016761, + -0.00037129109382274265 + ], + [ + 0.00012324342349802402, + -0.0008360656621961662, + -0.00037074976865056233 + ], + [ + 0.00012346317637028275, + -0.0008357423793749854, + -0.0003702084503173547 + ], + [ + 0.00012368293201888152, + -0.0008354190924694755, + -0.0003696671251451744 + ], + [ + 0.0001239026848911402, + -0.0008350958096482945, + -0.0003691258068119666 + ], + [ + 0.000124122440539739, + -0.0008347725227427846, + -0.00036858448163978663 + ], + [ + 0.00012434219618833782, + -0.0008344492358372748, + -0.00036804315646760675 + ], + [ + 0.00012456194906059636, + -0.0008341259530160936, + -0.00036750183813439875 + ], + [ + 0.00012478170470919535, + -0.000833802666110584, + -0.0003669605129622187 + ], + [ + 0.0001250014575814539, + -0.0008334793832894029, + -0.00036641919462901076 + ], + [ + 0.00012522121323005282, + -0.0008331560963838932, + -0.00036587786945683077 + ], + [ + 0.00012544096887865153, + -0.000832832809478383, + -0.0003653365442846506 + ], + [ + 0.0001256607217509103, + -0.0008325095266572024, + -0.0003647952259514429 + ], + [ + 0.00012588047739950912, + -0.0008321862397516924, + -0.0003642539007792629 + ], + [ + 0.0001261002302717678, + -0.0008318629569305118, + -0.00036371258244605507 + ], + [ + 0.00012631998592036665, + -0.0008315396700250016, + -0.00036317125727387497 + ], + [ + 0.00012653974156896536, + -0.0008312163831194918, + -0.00036262993210169477 + ], + [ + 0.00012675949444122402, + -0.000830893100298311, + -0.0003620886137684871 + ], + [ + 0.00012697925008982292, + -0.000830569813392801, + -0.000361547288596307 + ], + [ + 0.00012719900296208152, + -0.00083024653057162, + -0.0003610059702630991 + ], + [ + 0.00012741875861068034, + -0.00082992324366611, + -0.00036046464509091895 + ], + [ + 0.00012763851425927914, + -0.0008295999567606001, + -0.0003599233199187389 + ], + [ + 0.00012785826713153776, + -0.0008292766739394192, + -0.0003593820015855311 + ], + [ + 0.0001280780227801366, + -0.0008289533870339092, + -0.000358840676413351 + ], + [ + 0.00012829777565239532, + -0.0008286301042127285, + -0.0003582993580801431 + ], + [ + 0.00012851753130099403, + -0.0008283068173072185, + -0.00035775803290796304 + ], + [ + 0.00012873728694959294, + -0.0008279835304017089, + -0.00035721670773578316 + ], + [ + 0.00012895703982185165, + -0.0008276602475805276, + -0.00035667538940257527 + ], + [ + 0.00012917679547045033, + -0.0008273369606750176, + -0.00035613406423039507 + ], + [ + 0.00012939654834270912, + -0.0008270136778538369, + -0.0003555927458971872 + ], + [ + 0.00012961630399130786, + -0.0008266903909483268, + -0.0003550514207250072 + ], + [ + 0.00012983605963990676, + -0.0008263671040428171, + -0.00035451009555282725 + ], + [ + 0.00013005581251216545, + -0.0008260438212216364, + -0.0003539687772196193 + ], + [ + 0.00013025589598102865, + -0.0008257537234403547, + -0.00035346813033413797 + ], + [ + 0.00013000987189533766, + -0.0008262162574187314, + -0.00035388994922760117 + ], + [ + 0.0001297638447013982, + -0.0008266787972407253, + -0.00035431177345029074 + ], + [ + 0.00012951781750745862, + -0.0008271413370627192, + -0.0003547335976729802 + ], + [ + 0.00012927179342176758, + -0.0008276038710410957, + -0.0003551554165664436 + ], + [ + 0.00012902576622782805, + -0.0008280664108630897, + -0.0003555772407891328 + ], + [ + 0.00012877974214213706, + -0.0008285289448414664, + -0.00035599905968259634 + ], + [ + 0.00012853371494819755, + -0.0008289914846634601, + -0.00035642088390528575 + ], + [ + 0.00012828768775425818, + -0.0008294540244854542, + -0.0003568427081279753 + ], + [ + 0.000128041663668567, + -0.0008299165584638304, + -0.0003572645270214385 + ], + [ + 0.00012779563647462763, + -0.0008303790982858245, + -0.00035768635124412804 + ], + [ + 0.00012754961238893662, + -0.0008308416322642011, + -0.0003581081701375914 + ], + [ + 0.00012730358519499695, + -0.0008313041720861948, + -0.00035852999436028086 + ], + [ + 0.00012705755800105755, + -0.0008317667119081886, + -0.00035895181858297033 + ], + [ + 0.00012681153391536654, + -0.0008322292458865654, + -0.0003593736374764338 + ], + [ + 0.000126565506721427, + -0.0008326917857085592, + -0.00035979546169912305 + ], + [ + 0.00012631948263573594, + -0.0008331543196869357, + -0.00036021728059258646 + ], + [ + 0.00012607345544179643, + -0.0008336168595089294, + -0.000360639104815276 + ], + [ + 0.0001258274282478569, + -0.0008340793993309231, + -0.0003610609290379654 + ], + [ + 0.0001255814041621659, + -0.0008345419333092999, + -0.0003614827479314287 + ], + [ + 0.00012533537696822643, + -0.0008350044731312942, + -0.0003619045721541183 + ], + [ + 0.0001250893528825354, + -0.0008354670071096707, + -0.00036232639104758147 + ], + [ + 0.00012484332568859585, + -0.0008359295469316641, + -0.00036274821527027077 + ], + [ + 0.00012459729849465637, + -0.000836392086753658, + -0.0003631700394929604 + ], + [ + 0.00012435127440896536, + -0.0008368546207320349, + -0.0003635918583864238 + ], + [ + 0.00012410524721502593, + -0.0008373171605540285, + -0.0003640136826091131 + ], + [ + 0.00012385922312933481, + -0.0008377796945324052, + -0.00036443550150257664 + ], + [ + 0.00012361319593539541, + -0.0008382422343543996, + -0.00036485732572526616 + ], + [ + 0.00012336716874145596, + -0.0008387047741763934, + -0.0003652791499479556 + ], + [ + 0.00012312114465576487, + -0.0008391673081547698, + -0.00036570096884141904 + ], + [ + 0.00012287511746182528, + -0.0008396298479767635, + -0.0003661227930641083 + ], + [ + 0.00012262909337613427, + -0.0008400923819551399, + -0.0003665446119575717 + ], + [ + 0.00012238306618219484, + -0.000840554921777134, + -0.0003669664361802611 + ], + [ + 0.00012213703898825528, + -0.0008410174615991278, + -0.0003673882604029505 + ], + [ + 0.0001218910149025642, + -0.0008414799955775043, + -0.00036781007929641393 + ], + [ + 0.00012164498770862477, + -0.000841942535399498, + -0.00036823190351910334 + ], + [ + 0.00012139896362293364, + -0.0008424050693778747, + -0.00036865372241256676 + ], + [ + 0.00012115293642899414, + -0.0008428676091998686, + -0.00036907554663525617 + ], + [ + 0.00012090690923505473, + -0.0008433301490218628, + -0.0003694973708579457 + ], + [ + 0.0001206608851493637, + -0.0008437926830002393, + -0.00036991918975140916 + ], + [ + 0.0001204148579554241, + -0.0008442552228222329, + -0.0003703410139740983 + ], + [ + 0.00012016883386973324, + -0.00084471775680061, + -0.0003707628328675619 + ], + [ + 0.0001199228066757936, + -0.0008451802966226037, + -0.0003711846570902513 + ], + [ + 0.00011986933389293292, + -0.0008451609523109955, + -0.00037122613354560166 + ], + [ + 0.00011991917816563116, + -0.000844883050031674, + -0.00037106353129332686 + ], + [ + 0.00011996902306805811, + -0.0008446051442413574, + -0.00037090092698674877 + ], + [ + 0.0001200188673407564, + -0.0008443272419620354, + -0.00037073832473447386 + ], + [ + 0.00012006871224318327, + -0.0008440493361717188, + -0.0003705757204278956 + ], + [ + 0.0001201185571456102, + -0.0008437714303814024, + -0.00037041311612131736 + ], + [ + 0.00012016840141830851, + -0.00084349352810208, + -0.00037025051386904267 + ], + [ + 0.00012021824632073545, + -0.0008432156223117638, + -0.00037008790956246436 + ], + [ + 0.00012026809059343375, + -0.0008429377200324415, + -0.0003699253073101896 + ], + [ + 0.00012031793549586058, + -0.0008426598142421251, + -0.00036976270300361126 + ], + [ + 0.00012036778039828745, + -0.0008423819084518081, + -0.0003696000986970327 + ], + [ + 0.00012041762467098582, + -0.0008421040061724864, + -0.00036943749644475815 + ], + [ + 0.00012046746957341273, + -0.0008418261003821695, + -0.0003692748921381797 + ], + [ + 0.00012051731384611102, + -0.0008415481981028479, + -0.0003691122898859051 + ], + [ + 0.00012056715874853778, + -0.000841270292312531, + -0.0003689496855793265 + ], + [ + 0.0001206170036509647, + -0.0008409923865222146, + -0.00036878708127274833 + ], + [ + 0.00012066684792366303, + -0.0008407144842428929, + -0.00036862447902047364 + ], + [ + 0.00012071669282608996, + -0.0008404365784525762, + -0.0003684618747138953 + ], + [ + 0.00012076653709878831, + -0.0008401586761732542, + -0.0003682992724616207 + ], + [ + 0.00012081638200121521, + -0.0008398807703829377, + -0.0003681366681550424 + ], + [ + 0.00012086622690364204, + -0.0008396028645926204, + -0.00036797406384846387 + ], + [ + 0.0001209160711763404, + -0.000839324962313299, + -0.00036781146159618934 + ], + [ + 0.00012096591607876721, + -0.000839047056522982, + -0.0003676488572896108 + ], + [ + 0.00012101576035146555, + -0.0008387691542436602, + -0.0003674862550373361 + ], + [ + 0.00012106560525389244, + -0.0008384912484533435, + -0.0003673236507307577 + ], + [ + 0.0001211154501563193, + -0.0008382133426630266, + -0.0003671610464241792 + ], + [ + 0.00012116529442901757, + -0.000837935440383705, + -0.0003669984441719047 + ], + [ + 0.0001212151393314444, + -0.000837657534593388, + -0.00036683583986532614 + ], + [ + 0.00012126498360414275, + -0.0008373796323140666, + -0.00036667323761305166 + ], + [ + 0.00012131482850656972, + -0.0008371017265237498, + -0.0003665106333064733 + ], [ - -0.9759213981885161, - 0.19770025365504246, - 0.0308763849206466, - -0.08682559021818281 + 0.00012136467340899644, + -0.0008368238207334328, + -0.00036634802899989483 ], [ - -0.9759217797223875, - 0.19770038943103885, - 0.030875517533035926, - -0.08682130095414695 - ] - ], - "angular_velocities": [ + 0.00012141451768169493, + -0.0008365459184541115, + -0.0003661854267476204 + ], [ - 6.916139485063021e-08, - -1.0404590249278905e-06, - 2.448709649864057e-06 + 0.00012146436258412168, + -0.0008362680126637945, + -0.000366022822441042 ], [ - 6.916139395176352e-08, - -1.0404590297499138e-06, - 2.448709648125881e-06 + 0.00012151420748654875, + -0.0008359901068734777, + -0.00036586021813446364 + ], + [ + 0.00012156405175924697, + -0.0008357122045941561, + -0.00036569761588218873 + ], + [ + 0.0001216138966616738, + -0.0008354342988038396, + -0.0003655350115756104 + ], + [ + 0.00012166374093437206, + -0.0008351563965245176, + -0.0003653724093233358 + ], + [ + 0.00012171358583679896, + -0.0008348784907342009, + -0.0003652098050167574 + ], + [ + 0.00012176343073922584, + -0.0008346005849438844, + -0.0003650472007101791 + ], + [ + 0.00012181327501192417, + -0.0008343226826645629, + -0.00036488459845790454 + ], + [ + 0.00012186311991435116, + -0.0008340447768742454, + -0.00036472199415132597 + ], + [ + 0.0001219129641870494, + -0.000833766874594924, + -0.0003645593918990514 + ], + [ + 0.0001220139041181562, + -0.0008335314992661531, + -0.0003644278129885036 + ], + [ + 0.0001222607448708073, + -0.0008334175688106039, + -0.00036438482646916485 + ], + [ + 0.0001225075825049315, + -0.0008333036397944241, + -0.00036434184049290717 + ], + [ + 0.0001227544232575825, + -0.0008331897093388746, + -0.0003642988539735681 + ], + [ + 0.0001230012608917069, + -0.0008330757803226961, + -0.00036425586799731087 + ], + [ + 0.0001232481016443579, + -0.0008329618498671461, + -0.00036421288147797193 + ], + [ + 0.00012349494239700896, + -0.0008328479194115966, + -0.0003641698949586331 + ], + [ + 0.0001237417800311332, + -0.0008327339903954172, + -0.0003641269089823752 + ], + [ + 0.0001239886207837843, + -0.0008326200599398675, + -0.00036408392246303626 + ], + [ + 0.00012423545841790855, + -0.0008325061309236882, + -0.0003640409364867788 + ], + [ + 0.0001244822991705596, + -0.0008323922004681383, + -0.0003639979499674397 + ], + [ + 0.0001247291399232106, + -0.0008322782700125889, + -0.0003639549634481009 + ], + [ + 0.00012497597755733487, + -0.0008321643409964099, + -0.00036391197747184334 + ], + [ + 0.0001252228183099859, + -0.0008320504105408603, + -0.0003638689909525044 + ], + [ + 0.00012546965594411016, + -0.0008319364815246804, + -0.0003638260049762468 + ], + [ + 0.00012571649669676114, + -0.0008318225510691313, + -0.00036378301845690783 + ], + [ + 0.00012596333744941229, + -0.0008317086206135815, + -0.00036374003193756884 + ], + [ + 0.0001262101750835365, + -0.0008315946915974025, + -0.00036369704596131127 + ], + [ + 0.00012645701583618752, + -0.0008314807611418529, + -0.0003636540594419724 + ], + [ + 0.00012670385347031177, + -0.0008313668321256732, + -0.0003636110734657151 + ], + [ + 0.00012695069422296278, + -0.000831252901670124, + -0.0003635680869463759 + ], + [ + 0.00012719753497561378, + -0.0008311389712145741, + -0.00036352510042703687 + ], + [ + 0.00012744437260973812, + -0.0008310250421983947, + -0.0003634821144507794 + ], + [ + 0.00012769121336238915, + -0.000830911111742845, + -0.00036343912793144036 + ], + [ + 0.00012793805099651338, + -0.0008307971827266655, + -0.0003633961419551828 + ], + [ + 0.00012818489174916452, + -0.0008306832522711168, + -0.000363353155435844 + ], + [ + 0.00012843173250181545, + -0.0008305693218155669, + -0.000363310168916505 + ], + [ + 0.00012867857013593983, + -0.0008304553927993875, + -0.0003632671829402474 + ], + [ + 0.00012892541088859081, + -0.0008303414623438378, + -0.0003632241964209084 + ], + [ + 0.00012917224852271498, + -0.0008302275333276582, + -0.0003631812104446509 + ], + [ + 0.00012941908927536613, + -0.0008301136028721087, + -0.00036313822392531193 + ], + [ + 0.00012966593002801722, + -0.0008299996724165595, + -0.00036309523740597305 + ], + [ + 0.00012991276766214133, + -0.0008298857434003798, + -0.0003630522514297154 + ], + [ + 0.0001301596084147924, + -0.0008297718129448302, + -0.00036300926491037637 + ], + [ + 0.00013040644604891675, + -0.0008296578839286511, + -0.0003629662789341189 + ], + [ + 0.00013065328680156776, + -0.0008295439534731014, + -0.00036292329241478 + ], + [ + 0.00013090012755421888, + -0.0008294300230175517, + -0.00036288030589544097 + ], + [ + 0.000131146965188343, + -0.0008293160940013724, + -0.00036283731991918345 + ], + [ + 0.00013139380594099403, + -0.0008292021635458232, + -0.00036279433339984446 + ], + [ + 0.00013164064357511836, + -0.0008290882345296435, + -0.00036275134742358716 + ], + [ + 0.00013188748432776942, + -0.0008289743040740941, + -0.00036270836090424816 + ], + [ + 0.00013213432508042046, + -0.0008288603736185448, + -0.0003626653743849093 + ], + [ + 0.00013233948681467403, + -0.0008287652256605093, + -0.00036263381741605103 + ], + [ + 0.00013205314953233725, + -0.0008288915695051514, + -0.00036273704719260537 + ], + [ + 0.00013176681586751673, + -0.0008290179117535949, + -0.0003628402756649793 + ], + [ + 0.00013148047858517982, + -0.0008291442555982367, + -0.0003629435054415335 + ], + [ + 0.00013119414130284297, + -0.000829270599442878, + -0.0003630467352180876 + ], + [ + 0.00013090780763802247, + -0.000829396941691322, + -0.00036314996369046163 + ], + [ + 0.00013062147035568578, + -0.0008295232855359637, + -0.00036325319346701597 + ], + [ + 0.00013033513669086534, + -0.0008296496277844075, + -0.00036335642193938996 + ], + [ + 0.00013004879940852832, + -0.000829775971629049, + -0.00036345965171594413 + ], + [ + 0.0001297624621261915, + -0.0008299023154736907, + -0.0003635628814924982 + ], + [ + 0.00012947612846137116, + -0.0008300286577221346, + -0.0003636661099648723 + ], + [ + 0.00012918979117903408, + -0.000830155001566776, + -0.00036376933974142635 + ], + [ + 0.00012890345751421383, + -0.0008302813438152197, + -0.0003638725682138004 + ], + [ + 0.00012861712023187709, + -0.0008304076876598618, + -0.00036397579799035473 + ], + [ + 0.00012833078294954018, + -0.0008305340315045035, + -0.00036407902776690895 + ], + [ + 0.00012804444928471968, + -0.0008306603737529472, + -0.00036418225623928294 + ], + [ + 0.00012775811200238282, + -0.0008307867175975885, + -0.0003642854860158371 + ], + [ + 0.0001274717783375625, + -0.0008309130598460329, + -0.00036438871448821105 + ], + [ + 0.00012718544105522553, + -0.0008310394036906743, + -0.0003644919442647654 ] ], "reference_frame": 1, "constant_frames": [ - 31001, - 31007, - 31006 + -85700, + -85000 ], "constant_rotation": [ - 0.9999998732547144, - -0.00032928542237557133, - 0.00038086961867138755, - 0.00032928600021094723, - 0.9999999457843062, - -1.4544409378362713e-06, - -0.00038086911909607826, - 1.5798557868269087e-06, - 0.9999999274681067 + 1.0, + 0.0, + -0.0, + 0.0, + 0.6743023875837233, + 0.7384553406258838, + 0.0, + -0.7384553406258838, + 0.6743023875837233 ] }, "naif_keywords": { - "BODY301_RADII": [ - 1737.4, - 1737.4, - 1737.4 - ], "BODY_FRAME_CODE": 31001, "BODY_CODE": 301, - "TKFRAME_-85700_UNITS": "DEGREES", - "TKFRAME_-85700_ANGLES": [ - -47.6, + "FRAME_-85700_CENTER": -85.0, + "FRAME_-85700_CLASS": 4.0, + "FRAME_-85700_CLASS_ID": -85700.0, + "FRAME_-85700_NAME": "LRO_MINIRF", + "INS-85700_CK_FRAME_ID": -85700.0, + "INS-85700_CK_REFERENCE_ID": 1.0, + "INS-85700_ITRANSL": [ + 0.0, 0.0, 0.0 ], - "FRAME_-85700_CENTER": -85.0, + "INS-85700_ITRANSS": [ + 1.0, + 0.13333333333333333, + 0.0 + ], "INS-85700_TRANSX": [ -7.5, 7.5, @@ -303,9 +8694,8 @@ 0.0, 0.0 ], - "FRAME_-85700_NAME": "LRO_MINIRF", - "INS-85700_ITRANSL": [ - 0.0, + "TKFRAME_-85700_ANGLES": [ + -47.6, 0.0, 0.0 ], @@ -314,21 +8704,24 @@ 2.0, 3.0 ], - "TKFRAME_-85700_SPEC": "ANGLES", - "INS-85700_ITRANSS": [ - 1.0, - 0.13333333333333333, - 0.0 - ], - "FRAME_-85700_CLASS_ID": -85700.0, - "FRAME_-85700_CLASS": 4.0, - "INS-85700_CK_FRAME_ID": -85700.0, "TKFRAME_-85700_RELATIVE": "LRO_SC_BUS", - "INS-85700_CK_REFERENCE_ID": 1.0, - "BODY301_POLE_RA": [ - 269.9949, - 0.0031, - 0.0 + "TKFRAME_-85700_SPEC": "ANGLES", + "TKFRAME_-85700_UNITS": "DEGREES", + "BODY301_LONG_AXIS": 0.0, + "BODY301_NUT_PREC_DEC": [ + 1.5419, + 0.0239, + -0.0278, + 0.0068, + 0.0, + -0.0029, + 0.0009, + 0.0, + 0.0, + 0.0008, + 0.0, + 0.0, + -0.0009 ], "BODY301_NUT_PREC_PM": [ 3.561, @@ -340,7 +8733,10 @@ -0.0047, -0.0046, 0.0028, - 0.0052 + 0.0052, + 0.004, + 0.0019, + -0.0044 ], "BODY301_NUT_PREC_RA": [ -3.8787000000000003, @@ -352,30 +8748,30 @@ 0.0, 0.0, 0.0, - -0.0052 - ], - "BODY301_LONG_AXIS": 0.0, - "BODY301_NUT_PREC_DEC": [ - 1.5419, - 0.0239, - -0.0278, - 0.0068, - 0.0, - -0.0029, - 0.0009, + -0.0052, 0.0, 0.0, - 0.0008 + 0.0043 + ], + "BODY301_PM": [ + 38.3213, + 13.17635815, + -1.3999999999999999e-12 ], "BODY301_POLE_DEC": [ 66.5392, 0.013, 0.0 ], - "BODY301_PM": [ - 38.3213, - 13.17635815, - -1.3999999999999999e-12 + "BODY301_POLE_RA": [ + 269.9949, + 0.0031, + 0.0 + ], + "BODY301_RADII": [ + 1737.4, + 1737.4, + 1737.4 ] }, "instrument_position": { @@ -1198,8 +9594,8 @@ ], [ -1602.1121150290217, - -516.301788761373, - 626.4244931973836 + -516.3017887613729, + 626.4244931973835 ], [ -1602.1154855546197, @@ -1318,8 +9714,8 @@ ], [ -1602.1929986144542, - -516.2444806539185, - 626.2663045073477 + -516.2444806539186, + 626.2663045073476 ], [ -1602.1963683800868, @@ -1477,8 +9873,8 @@ 626.0619674731489 ], [ - -1602.300816303273, - -516.168061130063, + -1602.3008163032732, + -516.1680611300632, 626.0553757447151 ], [ @@ -1493,8 +9889,8 @@ ], [ -1602.3109226496017, - -516.1608962870015, - 626.0356005291155 + -516.1608962870017, + 626.0356005291156 ], [ -1602.314291342393, @@ -1503,8 +9899,8 @@ ], [ -1602.3176600350425, - -516.156119699815, - 626.0224170273361 + -516.1561196998149, + 626.0224170273358 ], [ -1602.3210286979945, @@ -1579,7 +9975,7 @@ [ -1602.3681866706556, -516.120293872044, - 625.9235391025444 + 625.9235391025445 ], [ -1602.371554901344, @@ -1652,9 +10048,9 @@ 625.8312506703506 ], [ - -1602.4187065257443, + -1602.4187065257445, -516.0844658840293, - 625.8246585246152 + 625.8246585246153 ], [ -1602.4220742945745, @@ -1747,8 +10143,8 @@ 625.705998297551 ], [ - -1602.482688559513, - -516.0390806382487, + -1602.4826885595128, + -516.039080638249, 625.6994060025792 ], [ @@ -1847,8 +10243,8 @@ 625.5741491288869 ], [ - -1602.5500263212855, - -515.9913028587855, + -1602.5500263212857, + -515.9913028587854, 625.5675565954582 ], [ @@ -1877,9 +10273,9 @@ 625.5345935116088 ], [ - -1602.5702253042953, - -515.9769687898511, - 625.5280008218916 + -1602.5702253042955, + -515.9769687898512, + 625.5280008218917 ], [ -1602.5735917170423, @@ -1892,14 +10288,14 @@ 625.5148155018709 ], [ - -1602.5803243934477, - -515.9698016063571, + -1602.5803243934474, + -515.9698016063572, 625.5082227748951 ], [ - -1602.5836906571074, - -515.9674125305821, - 625.5016301222374 + -1602.5836906571071, + -515.9674125305822, + 625.5016301222372 ], [ -1602.5870569655387, @@ -1943,7 +10339,7 @@ ], [ -1602.6139860319001, - -515.9459103995628, + -515.9459103995626, 625.4422952432253 ], [ @@ -2037,9 +10433,9 @@ 625.3236226759637 ], [ - -1602.6779347745658, - -515.9005144236959, - 625.3170297103277 + -1602.6779347745655, + -515.900514423696, + 625.3170297103276 ], [ -1602.6813002037804, @@ -2117,7 +10513,7 @@ 625.2181328206772 ], [ - -1602.7317779457687, + -1602.7317779457685, -515.8622834997715, 625.2115395717829 ], @@ -2158,7 +10554,7 @@ ], [ -1602.758696625529, - -515.8431671060383, + -515.8431671060384, 625.1587933662552 ], [ @@ -2233,8 +10629,8 @@ ], [ -1602.8091639212043, - -515.8073222032317, - 625.0598922287816 + -515.8073222032318, + 625.0598922287815 ], [ -1602.8125281582925, @@ -2288,8 +10684,8 @@ ], [ -1602.8461689488222, - -515.7810345728552, - 624.9873630876683 + -515.7810345728551, + 624.9873630876682 ], [ -1602.8495328729325, @@ -2308,12 +10704,12 @@ ], [ -1602.8596244364624, - -515.7714751097016, + -515.7714751097014, 624.9609884459136 ], [ - -1602.862988211585, - -515.7690852582964, + -1602.8629882115852, + -515.7690852582963, 624.9543948099067 ], [ @@ -2347,9 +10743,9 @@ 624.9148331416109 ], [ - -1602.886534860589, - -515.752354394333, - 624.9082393490257 + -1602.8865348605889, + -515.7523543943329, + 624.9082393490256 ], [ -1602.8898983971776, @@ -2418,8 +10814,8 @@ ], [ -1602.9336217804312, - -515.7188940663852, - 624.8159254542871 + -515.7188940663855, + 624.815925454287 ], [ -1602.9369849444333, @@ -2438,8 +10834,8 @@ ], [ -1602.947074108878, - -515.7093336194029, - 624.7895496650439 + -515.709333619403, + 624.7895496650438 ], [ -1602.9504371387613, @@ -2633,7 +11029,7 @@ ], [ -1603.078209015053, - -515.6161110871191, + -515.6161110871192, 624.5323753638079 ], [ @@ -2818,8 +11214,8 @@ ], [ -1603.2025765530657, - -515.5276555585394, - 624.2883729697146 + -515.5276555585395, + 624.2883729697145 ], [ -1603.2059372880396, @@ -2883,8 +11279,8 @@ ], [ -1603.2462634411736, - -515.4965734130284, - 624.2026385450888 + -515.4965734130285, + 624.2026385450887 ], [ -1603.2496237887965, @@ -3413,8 +11809,8 @@ ], [ -1603.602289061893, - -515.2430732975441, - 623.5034990332765 + -515.243073297544, + 623.5034990332766 ], [ -1603.6056461608107, @@ -3503,8 +11899,8 @@ ], [ -1603.6627124915908, - -515.2000152809477, - 623.3847641537677 + -515.2000152809476, + 623.3847641537676 ], [ -1603.6660690839062, @@ -3557,9 +11953,9 @@ 623.3187985808006 ], [ - -1603.699633143942, - -515.1737005126274, - 623.3122019935872 + -1603.6996331439418, + -515.1737005126275, + 623.3122019935871 ], [ -1603.7029894084146, @@ -3633,8 +12029,8 @@ ], [ -1603.7499735490362, - -515.1378148199067, - 623.2132513614723 + -515.1378148199068, + 623.2132513614722 ], [ -1603.7533293812426, @@ -3668,7 +12064,7 @@ ], [ -1603.773463421193, - -515.1210674139597, + -515.1210674139598, 623.1670735152043 ], [ @@ -3747,7 +12143,7 @@ 623.0681189857937 ], [ - -1603.8271489886508, + -1603.8271489886506, -515.082785835078, 623.0615218843136 ], @@ -3843,7 +12239,7 @@ ], [ -1603.8908905337544, - -515.0373232574751, + -515.037323257475, 622.9361754921024 ], [ @@ -3853,7 +12249,7 @@ ], [ -1603.8975995904216, - -515.0325375201485, + -515.0325375201486, 622.9229808199667 ], [ @@ -3913,8 +12309,8 @@ ], [ -1603.937851039734, - -515.0038222746568, - 622.8438122066639 + -515.0038222746566, + 622.843812206664 ], [ -1603.9412051284444, @@ -3938,7 +12334,7 @@ ], [ -1603.9546212002417, - -514.9918571786053, + -514.9918571786054, 622.8108247774564 ], [ @@ -3947,7 +12343,7 @@ 622.8042272963177 ], [ - -1603.9613290499883, + -1603.9613290499888, -514.9870710677901, 622.7976297405655 ], @@ -3977,9 +12373,9 @@ 622.7646418940577 ], [ - -1603.981451913384, + -1603.9814519133843, -514.9727125140718, - 622.758044248886 + 622.7580442488861 ], [ -1603.9848055848393, @@ -4177,9 +12573,9 @@ 622.5007285719688 ], [ - -1604.1155763602842, - -514.8769798490833, - 622.4941304722367 + -1604.115576360284, + -514.8769798490832, + 622.4941304722369 ], [ -1604.1189288246705, @@ -4208,7 +12604,7 @@ ], [ -1604.1356908338778, - -514.8626186573117, + -514.8626186573114, 622.4545418210789 ], [ @@ -4352,9 +12748,9 @@ 622.26978899756 ], [ - -1604.232895582112, - -514.7932010887415, - 622.2631904653329 + -1604.2328955821117, + -514.7932010887416, + 622.2631904653327 ], [ -1604.2362469736563, @@ -4377,14 +12773,14 @@ 622.2367964489576 ], [ - -1604.2496524352193, + -1604.2496524352196, -514.7812317297813, 622.2301978723095 ], [ -1604.2530037074453, - -514.7788378552725, - 622.2235993550757 + -514.7788378552724, + 622.2235993550759 ], [ -1604.2563549499391, @@ -4393,7 +12789,7 @@ ], [ -1604.259706222232, - -514.7740500010567, + -514.7740500010566, 622.2104021496156 ], [ @@ -4413,8 +12809,8 @@ ], [ -1604.2731107748061, - -514.7644742189874, - 622.184007738298 + -514.7644742189873, + 622.1840077382979 ], [ -1604.276461868276, @@ -4498,8 +12894,8 @@ ], [ -1604.3300748479248, - -514.7237754127518, - 622.0718293179942 + -514.7237754127517, + 622.0718293179943 ], [ -1604.3334254347278, @@ -4605,8 +13001,8 @@ ], [ -0.7145430120277709, - 0.5060613773206715, - -1.3969914896560214 + 0.5060613773206716, + -1.3969914896560218 ], [ -0.7145366132627426, @@ -4705,8 +13101,8 @@ ], [ -0.7144150348252406, - 0.506102609230812, - -1.3970416442014892 + 0.5061026092308117, + -1.3970416442014888 ], [ -0.714408635791877, @@ -4945,8 +13341,8 @@ ], [ -0.7141078676273016, - 0.5062015501971325, - -1.3971619721472723 + 0.5062015501971324, + -1.3971619721472721 ], [ -0.7141014679500478, @@ -4984,8 +13380,8 @@ -1.397179514896719 ], [ - -0.7140566700761565, - 0.5062180382181356, + -0.7140566700761566, + 0.5062180382181355, -1.3971820209119952 ], [ @@ -5000,8 +13396,8 @@ ], [ -0.7140374707630376, - 0.5062242210710185, - -1.3971895387683555 + 0.5062242210710186, + -1.3971895387683557 ], [ -0.7140310710191113, @@ -5085,7 +13481,7 @@ ], [ -0.7139286724835036, - 0.5062592555762916, + 0.5062592555762918, -1.3972321354350998 ], [ @@ -5159,8 +13555,8 @@ -1.3972672093214238 ], [ - -0.7138326707689391, - 0.5062901660812817, + -0.7138326707689393, + 0.5062901660812819, -1.3972697144150454 ], [ @@ -5255,8 +13651,8 @@ ], [ -0.7137110642987564, - 0.5063293162841109, - -1.3973173059377737 + 0.506329316284111, + -1.3973173059377735 ], [ -0.7137046637901234, @@ -5354,7 +13750,7 @@ -1.397364887985151 ], [ - -0.7135830522256328, + -0.713583052225633, 0.5063705233000533, -1.3973673920201337 ], @@ -5385,7 +13781,7 @@ ], [ -0.7135446475258178, - 0.5063828846683718, + 0.5063828846683719, -1.3973824158032422 ], [ @@ -5400,12 +13796,12 @@ ], [ -0.7135254449949587, - 0.506389065223224, + 0.5063890652232241, -1.3973899273392487 ], [ - -0.7135190441784348, - 0.5063911253715543, + -0.7135190441784347, + 0.5063911253715541, -1.3973924311108794 ], [ @@ -5450,8 +13846,8 @@ ], [ -0.7134614357414476, - 0.5064096664324326, - -1.3974149640598232 + 0.5064096664324325, + -1.397414964059823 ], [ -0.7134550347908941, @@ -5545,7 +13941,7 @@ ], [ -0.7133398144999498, - 0.5064488060808598, + 0.50644880608086, -1.397462526560281 ], [ @@ -5579,9 +13975,9 @@ -1.3974775443384972 ], [ - -0.7132950054589595, - 0.5064632250783929, - -1.397480047188316 + -0.7132950054589596, + 0.5064632250783928, + -1.3974800471883162 ], [ -0.7132886040791413, @@ -5624,7 +14020,7 @@ -1.3975000691964239 ], [ - -0.7132373928007398, + -0.7132373928007397, 0.5064817631219695, -1.3975025718408591 ], @@ -5645,8 +14041,8 @@ ], [ -0.7132117868804194, - 0.5064900019860434, - -1.3975125820916485 + 0.5064900019860437, + -1.397512582091649 ], [ -0.7132053853264073, @@ -5684,9 +14080,9 @@ -1.3975300990637822 ], [ - -0.7131605743158193, - 0.5065064792805564, - -1.3975326013604867 + -0.7131605743158194, + 0.5065064792805565, + -1.3975326013604865 ], [ -0.7131541726546421, @@ -5735,13 +14131,13 @@ ], [ -0.7130965574244973, - 0.5065270750296585, - -1.3975576230682014 + 0.5065270750296584, + -1.397557623068201 ], [ - -0.7130901556293454, + -0.7130901556293453, 0.5065291345623849, - -1.3975601251067078 + -1.397560125106708 ], [ -0.7130837539016984, @@ -5795,7 +14191,7 @@ ], [ -0.7130197354028535, - 0.5065517886590758, + 0.5065517886590757, -1.3975876456341036 ], [ @@ -5815,18 +14211,18 @@ ], [ -0.7129941275797074, - 0.5065600262461454, + 0.5065600262461453, -1.3975976523343008 ], [ - -0.7129877256511239, + -0.7129877256511238, 0.5065620855996589, -1.3976001539197085 ], [ -0.7129813237096271, - 0.5065641449431495, - -1.397602655479133 + 0.5065641449431497, + -1.3976026554791334 ], [ -0.7129749216733566, @@ -5854,8 +14250,8 @@ -1.3976151629745097 ], [ - -0.7129429114528322, - 0.5065765009086718, + -0.7129429114528321, + 0.5065765009086716, -1.3976176644071652 ], [ @@ -5925,7 +14321,7 @@ ], [ -0.7128532810863905, - 0.5066053301185685, + 0.5066053301185686, -1.3976526815093784 ], [ @@ -5935,8 +14331,8 @@ ], [ -0.7128404765455802, - 0.5066094484200776, - -1.3976576835265815 + 0.5066094484200774, + -1.3976576835265813 ], [ -0.7128340742146416, @@ -5945,8 +14341,8 @@ ], [ -0.7128276719512248, - 0.5066135666832562, - -1.3976626854384093 + 0.5066135666832564, + -1.3976626854384095 ], [ -0.7128212695934899, @@ -6030,7 +14426,7 @@ ], [ -0.7127188305342107, - 0.5066485704377058, + 0.5066485704377057, -1.3977051975136414 ], [ @@ -6075,7 +14471,7 @@ ], [ -0.7126612071075258, - 0.5066671006946866, + 0.5066671006946867, -1.3977277007981692 ], [ @@ -6140,7 +14536,7 @@ ], [ -0.7125779712913809, - 0.5066938652711586, + 0.5066938652711587, -1.3977602017999267 ], [ @@ -6159,9 +14555,9 @@ -1.3977677014036556 ], [ - -0.7125523598531811, - 0.5067021001876244, - -1.3977702011978714 + -0.7125523598531812, + 0.5067021001876246, + -1.3977702011978717 ], [ -0.7125459569197193, @@ -6184,7 +14580,7 @@ -1.3977802002057962 ], [ - -0.7125203452137487, + -0.7125203452137489, 0.5067123936306651, -1.397782699868295 ], @@ -6325,8 +14721,8 @@ ], [ -0.7123410570324604, - 0.5067700324888329, - -1.3978526802574531 + 0.506770032488833, + -1.397852680257453 ], [ -0.7123346536572351, @@ -6389,8 +14785,8 @@ -1.397882665520748 ], [ - -0.7122578125154819, - 0.5067967908356215, + -0.712257812515482, + 0.5067967908356216, -1.3978851641345438 ], [ @@ -6505,8 +14901,8 @@ ], [ -0.7121105282268583, - 0.5068441285538823, - -1.3979426246965845 + 0.5068441285538824, + -1.3979426246965843 ], [ -0.7121041244508095, @@ -6910,7 +15306,7 @@ ], [ -0.711591775140425, - 0.5070107992341893, + 0.5070107992341896, -1.3981448747804646 ], [ @@ -6920,8 +15316,8 @@ ], [ -0.7115789652462355, - 0.5070149137851645, - -1.398149866448121 + 0.5070149137851643, + -1.3981498664481207 ], [ -0.7115725603599758, @@ -6956,7 +15352,7 @@ [ -0.7115341304380236, 0.507029314332681, - -1.398167336360577 + -1.3981673363605769 ], [ -0.7115277254581996, @@ -6965,8 +15361,8 @@ ], [ -0.7115213203840453, - 0.5070334286848696, - -1.3981723275224258 + 0.5070334286848698, + -1.398172327522426 ], [ -0.7115149152965576, @@ -6974,9 +15370,9 @@ -1.398174823079543 ], [ - -0.7115085102765862, - 0.5070375429986894, - -1.3981773185788564 + -0.7115085102765861, + 0.5070375429986892, + -1.3981773185788562 ], [ -0.7115021051623546, @@ -7010,7 +15406,7 @@ ], [ -0.7114636744388559, - 0.5070519428080885, + 0.5070519428080884, -1.3981947864619542 ], [ @@ -7064,8 +15460,8 @@ -1.3982197383810944 ], [ - -0.7113932167409921, - 0.507074570148996, + -0.7113932167409919, + 0.5070745701489962, -1.3982222334060335 ], [ @@ -7176,7 +15572,7 @@ [ -0.7112522965734991, 0.5071198213235427, - -1.3982771176957725 + -1.3982771176957722 ], [ -0.7112458909245254, @@ -7361,7 +15757,7 @@ [ -0.7110152797927977, 0.507195915132206, - -1.398369394359988 + -1.3983693943599877 ], [ -0.7110088737302808, @@ -7419,9 +15815,9 @@ -1.3983968209780524 ], [ - -0.7109384055938709, - 0.5072205913733001, - -1.398399314163102 + -0.7109384055938708, + 0.5072205913733, + -1.3983993141631017 ], [ -0.7109319993709711, @@ -7444,9 +15840,9 @@ -1.3984092865768565 ], [ - -0.7109063741030017, - 0.5072308727346172, - -1.3984117796302238 + -0.710906374103002, + 0.5072308727346171, + -1.398411779630224 ], [ -0.7108999678133465, @@ -7454,9 +15850,9 @@ -1.3984142726255793 ], [ - -0.710893561429369, - 0.5072349852071485, - -1.3984167656261113 + -0.7108935614293691, + 0.5072349852071484, + -1.398416765626111 ], [ -0.7108871550319991, @@ -7484,7 +15880,7 @@ -1.3984292301706724 ], [ - -0.710855123006739, + -0.7108551230067391, 0.5072473224195534, -1.3984317230130514 ], @@ -7569,9 +15965,9 @@ -1.3984716046862324 ], [ - -0.710746211638779, - 0.5072822759447398, - -1.398474097080604 + -0.7107462116387792, + 0.50728227594474, + -1.3984740970806042 ], [ -0.7107398050151158, @@ -7615,7 +16011,7 @@ ], [ -0.7106885511401202, - 0.5073007796221353, + 0.5073007796221354, -1.3984965273170331 ], [ @@ -7630,7 +16026,7 @@ ], [ -0.7106693307065043, - 0.5073069473506213, + 0.5073069473506212, -1.3985040035984866 ], [ @@ -7685,7 +16081,7 @@ ], [ -0.7105988547816875, - 0.5073295616072562, + 0.5073295616072563, -1.3985314145903123 ], [ @@ -7715,8 +16111,8 @@ ], [ -0.7105604127532246, - 0.5073418961457383, - -1.3985463646701966 + 0.5073418961457382, + -1.3985463646701963 ], [ -0.7105540056612769, @@ -7859,8 +16255,8 @@ -1.3986161192554554 ], [ - -0.7103746025549443, - 0.5074015083029046, + -0.7103746025549444, + 0.5074015083029049, -1.398618610120827 ], [ @@ -7884,14 +16280,14 @@ -1.3986285732554105 ], [ - -0.7103425651872141, + -0.7103425651872143, 0.507411785442759, - -1.3986310639888397 + -1.3986310639888395 ], [ -0.7103361577221872, 0.5074138408262487, - -1.3986335546645203 + -1.3986335546645206 ], [ -0.710329750162869, @@ -7899,7 +16295,7 @@ -1.3986360453452271 ], [ - -0.7103233425901948, + -0.7103233425901947, 0.507417951616742, -1.3986385359995628 ], @@ -7920,8 +16316,8 @@ ], [ -0.7102977123278574, - 0.5074261730302629, - -1.3986484982904988 + 0.5074261730302627, + -1.3986484982904985 ], [ -0.7102913046884227, @@ -8005,7 +16401,7 @@ ], [ -0.7101887812083836, - 0.507461112363603, + 0.5074611123636029, -1.3986908333681065 ], [ @@ -8030,8 +16426,8 @@ ], [ -0.710156741904845, - 0.5074713881118774, - -1.3987032834132607 + 0.5074713881118775, + -1.398703283413261 ], [ -0.7101503339717288, diff --git a/tests/pytests/data/isds/msl_nadir_isd.json b/tests/pytests/data/isds/msl_nadir_isd.json index 519319850..49015b158 100644 --- a/tests/pytests/data/isds/msl_nadir_isd.json +++ b/tests/pytests/data/isds/msl_nadir_isd.json @@ -145,7 +145,21 @@ -0.17476887, 0.12719345, 0.9763594, - -0.17553059 + -0.17553059, + -5.566e-05, + 0.98447398, + -0.17480715, + -0.12735688, + 0.97633124, + 1.62e-05, + -0.12838394, + 0.99172454, + 0.1749107, + -0.12728511, + 0.97632205, + 0.17557293, + 3.78e-05, + 0.98446643 ], "INS-76210_PIXEL_LINES": 1200.0, "INS-76210_CAHVOR_MODEL": " CAHVOR", diff --git a/tests/pytests/test_lo_drivers.py b/tests/pytests/test_lo_drivers.py index a7c247acb..4d5c0c318 100644 --- a/tests/pytests/test_lo_drivers.py +++ b/tests/pytests/test_lo_drivers.py @@ -75,10 +75,10 @@ def test_naif_keywords(self): data_naif_keywords.return_value = {} naif_keywords = { - "INS-533001_TRANSX" : [115.50954565137394, -0.006953956655748381, -3.945326343250231e-06], - "INS-533001_TRANSY" : [-31.50245193387461, -2.8238081535064857e-06, 0.0069466064358475335], - "INS-533001_ITRANSS" : [16608.04530570599, -143.80299143001824, -0.08167293419694324], - "INS-533001_ITRANSL" : [4541.692430539061, -0.05845617762411283, 143.95514969883214] + "INS-533001_TRANSX" : [115.50954565137368, -0.0069539566557483634, -3.945326343273575e-06], + "INS-533001_TRANSY" : [-31.502451933874543, -2.8238081535057043e-06, 0.006946606435847521], + "INS-533001_ITRANSS" : [16608.04530570598, -143.8029914300184, -0.08167293419690833], + "INS-533001_ITRANSL" : [4541.6924305390585, -0.058456177624059004, 143.9551496988325] } assert self.driver.naif_keywords == naif_keywords diff --git a/tests/pytests/test_lro_drivers.py b/tests/pytests/test_lro_drivers.py index 602222edf..d32b1f56e 100644 --- a/tests/pytests/test_lro_drivers.py +++ b/tests/pytests/test_lro_drivers.py @@ -8,6 +8,7 @@ import ale from ale import util +from ale.drivers import AleJsonEncoder from ale.drivers.lro_drivers import LroLrocNacPds3LabelNaifSpiceDriver from ale.drivers.lro_drivers import LroLrocNacIsisLabelNaifSpiceDriver from ale.drivers.lro_drivers import LroLrocWacIsisLabelNaifSpiceDriver @@ -282,15 +283,15 @@ def test_range_conversion_coefficients(self): def test_ephmeris_start_time(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: - assert self.driver.ephemeris_start_time == 12345 + assert self.driver.ephemeris_start_time == 12344.995295578527 calls = [call('utcToEt', {'utc': '2010-04-25 04:22:31.244874', 'searchKernels': False}, False)] spiceql_call.assert_has_calls(calls) assert spiceql_call.call_count == 1 def test_ephmeris_stop_time(self): with patch('ale.spiceql_access.spiceql_call', side_effect=[12345]) as spiceql_call: - assert self.driver.ephemeris_stop_time == 12345 - calls = [call('utcToEt', {'utc': '2010-04-25 04:22:34.537874', 'searchKernels': False}, False)] + assert self.driver.ephemeris_stop_time == 12348.297799453276 + calls = [call('utcToEt', {'utc': '2010-04-25 04:22:31.244874', 'searchKernels': False}, False)] spiceql_call.assert_has_calls(calls) assert spiceql_call.call_count == 1 From cd46b88161f97a24ab38cbcce7472e38ca3a3488 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 11 Dec 2023 14:02:09 -0700 Subject: [PATCH 66/73] Added pyspiceql to env file --- environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.yml b/environment.yml index 062d3e934..9f3a71f13 100644 --- a/environment.yml +++ b/environment.yml @@ -11,6 +11,7 @@ dependencies: - jupyter - nlohmann_json - numpy + - pyspiceql - pvl - pytz - python From 6d740875ffcbc1af9752212e2c41a9719410169c Mon Sep 17 00:00:00 2001 From: acpaquette Date: Mon, 11 Dec 2023 14:24:46 -0700 Subject: [PATCH 67/73] Change env pyspiceql entry to spiceql entry --- environment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 9f3a71f13..975fa700d 100644 --- a/environment.yml +++ b/environment.yml @@ -11,7 +11,7 @@ dependencies: - jupyter - nlohmann_json - numpy - - pyspiceql + - spiceql - pvl - pytz - python From 79467362642f3445c320c13ddbe37494ef0a43c1 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Tue, 11 Jun 2024 21:32:31 -0700 Subject: [PATCH 68/73] Fixed missed merge conflict --- ale/formatters/formatter.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py index ed0b77226..2e0f1d2ac 100644 --- a/ale/formatters/formatter.py +++ b/ale/formatters/formatter.py @@ -1,12 +1,3 @@ -<<<<<<< HEAD -import json -import numpy as np -from scipy.interpolate import interp1d, BPoly - -import spiceypy as spice - -======= ->>>>>>> 6d740875ffcbc1af9752212e2c41a9719410169c from networkx.algorithms.shortest_paths.generic import shortest_path from ale.base.type_sensor import LineScanner, Framer, Radar, PushFrame From bf464ac287ae883a896f2b36d8e8b6936fb6aef7 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Tue, 11 Jun 2024 21:48:27 -0700 Subject: [PATCH 69/73] Removed util tests that are part of kernel access --- tests/pytests/test_util.py | 103 ------------------------------------- 1 file changed, 103 deletions(-) diff --git a/tests/pytests/test_util.py b/tests/pytests/test_util.py index d3a07c444..e4fa68100 100644 --- a/tests/pytests/test_util.py +++ b/tests/pytests/test_util.py @@ -73,109 +73,6 @@ def test_pvl_parser(pvl_three_group): assert obj["Settings"]["delsystem32"] == "yes" -def test_find_kernels(cube_kernels, tmpdir): - ck_db = """ - Object = Pointing - Group = Selection - Time = ( "2016 JAN 01 00:00:00.000000 TDB", "2016 DEC 31 00:00:00.000000 TDB" ) - Type = Reconstructed - File = $MRO/fake - End_Group - End_Object - """ - - ik_db = """ - Object = instrument - Group = Selection - Match = ("Instrument", "InstrumentId", "fake") - File = ("fake", "not/a/real/file") - End_Group - End_Object - """ - translation = """ - Group = MissionName - InputKey = SpacecraftName - InputGroup = "IsisCube,Instrument" - InputPosition = (IsisCube, Instrument) - Translation = (fake, "fake") - End_Group - """ - - tmpdir.mkdir("fake").mkdir("kernels").mkdir("ik") - tmpdir.mkdir("base").mkdir("kernels").mkdir("ck") - tmpdir.mkdir("base", "translations") - - ck_db_file = tmpdir.join("base", "kernels", "ck", "kernel.01.db") - ik_db_file = tmpdir.join("fake", "kernels", "ik", "kernel.01.db") - translation_file = tmpdir.join("base", "translations", "MissionName2DataDir.trn") - cube_file = tmpdir.join("test.cub") - - with open(translation_file, "w") as f: - f.write(translation) - - with open(ck_db_file, "w") as f: - f.write(ck_db) - - with open(ik_db_file, "w") as f: - f.write(ik_db) - - with open(cube_file, "w") as cube: - cube.write(cube_kernels) - - print(pvl.load(str(cube_file))) - kernels = util.find_kernels(str(cube_file), str(tmpdir)) - assert kernels == {'Pointing': {'kernels': [str(tmpdir / 'MRO/fake')], 'types': ['Reconstructed']}, 'instrument': {'kernels': [str(tmpdir / 'fake/not/a/real/file')]}} - - -def test_kernel_from_cube_list(cube_kernels): - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name) - assert kernels == ['$messenger/targetposition0', '$messenger/targetposition1','$messenger/instrumentposition', '$messenger/instrumentpointing0', '$messenger/instrumentpointing1', '$base/attitudeshape', '$messenger/instrument', '$base/clock'] - -def test_kernel_from_cube_list_expanded(monkeypatch, tmpdir, pvl_four_group, cube_kernels): - monkeypatch.setenv('ISISROOT', str(tmpdir)) - monkeypatch.setenv('ISISDATA', '/test/path') - - with open(tmpdir.join('IsisPreferences'), 'w+') as pvl_isisroot_file: - pvl_isisroot_file.write(pvl_four_group) - pvl_isisroot_file.flush() - - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name, expand=True) - assert kernels == ['/test/path/messenger/targetposition0', '/test/path/messenger/targetposition1', '/test/path/messenger/instrumentposition', '/test/path/messenger/instrumentpointing0', '/test/path/messenger/instrumentpointing1', '/test/path/base/attitudeshape', '/test/path/messenger/instrument', '/test/path/base/clock'] - -def test_kernel_from_cube_dict(cube_kernels): - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name, format_as='dict') - assert kernels == OrderedDict([('TargetPosition', ['$messenger/targetposition0', '$messenger/targetposition1']), ('InstrumentPosition', ['$messenger/instrumentposition']), ('InstrumentPointing', ['$messenger/instrumentpointing0', '$messenger/instrumentpointing1']), ('Frame', [None]), ('TargetAttitudeShape', ['$base/attitudeshape']), ('Instrument', ['$messenger/instrument']), ('InstrumentAddendum', [None]), ('LeapSecond', [None]), ('SpacecraftClock', ['$base/clock']), ('Extra', [None]), ('Clock', [None])]) - -def test_kernel_from_cube_dict_expanded(monkeypatch, tmpdir, pvl_four_group, cube_kernels): - monkeypatch.setenv('ISISROOT', str(tmpdir)) - monkeypatch.setenv('ISISDATA', '/test/path') - - with open(tmpdir.join('IsisPreferences'), 'w+') as pvl_isisroot_file: - pvl_isisroot_file.write(pvl_four_group) - pvl_isisroot_file.flush() - - with tempfile.NamedTemporaryFile('r+') as cube: - cube.write(cube_kernels) - cube.flush() - kernels = util.generate_kernels_from_cube(cube.name, expand=True, format_as='dict') - assert kernels == OrderedDict([('TargetPosition', ['/test/path/messenger/targetposition0', '/test/path/messenger/targetposition1']), ('InstrumentPosition', ['/test/path/messenger/instrumentposition']), ('InstrumentPointing', ['/test/path/messenger/instrumentpointing0', '/test/path/messenger/instrumentpointing1']), ('Frame', [None]), ('TargetAttitudeShape', ['/test/path/base/attitudeshape']), ('Instrument', ['/test/path/messenger/instrument']), ('InstrumentAddendum', [None]), ('LeapSecond', [None]), ('SpacecraftClock', ['/test/path/base/clock']), ('Extra', [None]), ('Clock', [None])]) - -def test_kernel_from_cube_no_kernel_group(): - with pytest.raises(KeyError): - with tempfile.NamedTemporaryFile('w+') as cube: - cube.write('') - cube.flush() - util.generate_kernels_from_cube(cube.name) - def test_get_preferences_arg(tmpdir, pvl_one_group): with open(tmpdir.join('IsisPrefrences'), 'w+') as pvl_file: pvl_file.write(pvl_one_group) From b5f9755e958d3b695a38dbd4f1e72c8b73761632 Mon Sep 17 00:00:00 2001 From: acpaquette Date: Tue, 11 Jun 2024 22:09:02 -0700 Subject: [PATCH 70/73] Fixed dawn tests --- ale/base/__init__.py | 1 + tests/pytests/test_dawn_drivers.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ale/base/__init__.py b/ale/base/__init__.py index 5c5e7f08e..5473e7817 100644 --- a/ale/base/__init__.py +++ b/ale/base/__init__.py @@ -87,4 +87,5 @@ "Near Infrared Camera": "nir", "High Resolution Camera": "clementine1", "Long Wave Infrared Camera": "clementine1", + "Visual and Infrared Spectrometer": "vir", } \ No newline at end of file diff --git a/tests/pytests/test_dawn_drivers.py b/tests/pytests/test_dawn_drivers.py index 6388359c1..5f949dba9 100644 --- a/tests/pytests/test_dawn_drivers.py +++ b/tests/pytests/test_dawn_drivers.py @@ -214,6 +214,7 @@ def test_ikid(self): def test_sensor_frame_id(self): ale.spice_root = "/foo/bar" assert self.driver.sensor_frame_id == -203223 + ale.spice_root = None def test_line_scan_rate(self): with patch('ale.drivers.dawn_drivers.read_table_data', return_value=12345) as read_table_data, \ @@ -273,4 +274,5 @@ def test_is_calibrated(self): def test_has_articulation_kernel(self): ale.spice_root = "/foo/bar" assert self.driver.has_articulation_kernel == False + ale.spice_root = None From 27201fcd078e75a30affef7e66d5f22283d60394 Mon Sep 17 00:00:00 2001 From: Christine Kim <125395064+chkim-usgs@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:19:52 -0400 Subject: [PATCH 71/73] Update ndarray value type --- ale/base/data_naif.py | 8 ++++---- ale/base/type_sensor.py | 4 ++-- ale/spiceql_access.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index a3ca6d31f..252f74e7a 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -408,7 +408,7 @@ def sun_position(self): if not hasattr(self, "_sun_position"): times = self.ephemeris_time if len(times) > 1: - times = [times[0], times[-1]] + times = np/array([times[0], times[-1]]) positions = [] velocities = [] @@ -449,8 +449,8 @@ def sensor_position(self): not hasattr(self, '_ephem'): ephem = self.ephemeris_time - if isinstance(ephem, np.ndarray): - ephem = ephem.tolist() + # if isinstance(ephem, np.ndarray): + # ephem = ephem.tolist() pos = [] vel = [] @@ -495,7 +495,7 @@ def sensor_position(self): ssb_obs_states = np.array(ssb_obs)[:,0:6] radius_lt = (self.target_body_radii[2] + self.target_body_radii[0]) / 2 / (scipy.constants.c/1000.0) - adjusted_time = np.array(ephem) - obs_tar_lts + radius_lt + adjusted_time = ephem - obs_tar_lts + radius_lt kwargs = {"target": target, "observer": "SSB", diff --git a/ale/base/type_sensor.py b/ale/base/type_sensor.py index 39574dbd4..19673e0c1 100644 --- a/ale/base/type_sensor.py +++ b/ale/base/type_sensor.py @@ -194,10 +194,10 @@ def ephemeris_time(self): Returns ------- - : double + : ndarray Center ephemeris time for the image """ - return [self.center_ephemeris_time] + return np.array([self.center_ephemeris_time]) @property def ephemeris_stop_time(self): diff --git a/ale/spiceql_access.py b/ale/spiceql_access.py index 46002bad3..b96ece380 100644 --- a/ale/spiceql_access.py +++ b/ale/spiceql_access.py @@ -24,7 +24,7 @@ def stringify_web_args(function_args): clean_function_args = function_args for key, value in function_args.items(): if isinstance(value, np.ndarray): - clean_function_args[key] = str(list(value)) + clean_function_args[key] = str(value.tolist()) if isinstance(value, list): clean_function_args[key] = str(value) if isinstance(value, bool): From 209d8ea341124c9c26ce07622ab05e743a4a8d86 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Thu, 24 Oct 2024 15:46:10 -0400 Subject: [PATCH 72/73] Fix typo --- ale/base/data_naif.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ale/base/data_naif.py b/ale/base/data_naif.py index 252f74e7a..5dd6eabbc 100644 --- a/ale/base/data_naif.py +++ b/ale/base/data_naif.py @@ -408,7 +408,7 @@ def sun_position(self): if not hasattr(self, "_sun_position"): times = self.ephemeris_time if len(times) > 1: - times = np/array([times[0], times[-1]]) + times = np.array([times[0], times[-1]]) positions = [] velocities = [] @@ -451,6 +451,8 @@ def sensor_position(self): # if isinstance(ephem, np.ndarray): # ephem = ephem.tolist() + # print("[data_naif.sensor_position] ephem is an ndarray") + # print("[data_naif.sensor_position] ephem type: " + str(type(ephem))) pos = [] vel = [] From a661097f20bde9c698cbb3fef81e9bacdfa67db6 Mon Sep 17 00:00:00 2001 From: Christine Kim Date: Thu, 24 Oct 2024 16:41:04 -0400 Subject: [PATCH 73/73] Another ndarray fix --- ale/transformation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ale/transformation.py b/ale/transformation.py index b04cfa6c7..7e0766652 100644 --- a/ale/transformation.py +++ b/ale/transformation.py @@ -379,6 +379,10 @@ def generate_rotations(self, frames, times, time_bias, rotation_type, mission="" times : list A list of times to compute the rotation at """ + # Convert list of np.floats to ndarray + if isinstance(times, list) and isinstance(times[0], np.floating): + times = np.array(times) + frame_tasks = [] for s, d in frames: function_args = {"toFrame": d, "refFrame": s, "mission": mission, "searchKernels": self.search_kernels}