diff --git a/README.md b/README.md index f37ad0497073f8bc41797648d37aa4be4596c553..1c9addf563e48ac2a9874c18d56f85455d1b368b 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,14 @@ running the following command will retrieve the gtest submodule manually: git submodule update --init --recursive ``` +## Adding the ALESPICEROOT environment variable +If an ale driver is going to be used that leverages SPICE data, it is necessary to set the ALESPICEROOT. One can do this using normal shell syntax, e.g.: + +`export ALESPICEROOT=/path/to/ale/spice` + +or inside of a conda environment: + +`conda env config vars set ALESPICEROOT=/path/to/ale/spice`. ## Adding ALE as a dependency You can add ALE as a dependency of your CMake based C++ project by linking the exported CMake target, `ale::ale`. diff --git a/ale/base/type_distortion.py b/ale/base/type_distortion.py index e5f2eabdf4910f57e37d7b3ddbfc54f41171643e..f8421711a6a21923103ba4246817d0b44889f972 100644 --- a/ale/base/type_distortion.py +++ b/ale/base/type_distortion.py @@ -61,3 +61,48 @@ class NoDistortion(): Dictionary containing the usgscsm specification for no distortion. """ return {"radial": {"coefficients": [0.0, 0.0, 0.0]}} + +class KaguyaSeleneDistortion(): + """ + Mix-in for sensors on the Kaguya/Selene mission. + """ + + @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<INSTID>_DISTORTION_COEF_X = ( a0, a1, a2, a3) + INS<INSTID>_DISTORTION_COEF_Y = ( b0, b1, b2, b3), + + Distance r from the center: + r = - (n - INS<INSTID>_CENTER) * INS<INSTID>_PIXEL_SIZE. + + Line-of-sight vector v is calculated as + v[X] = INS<INSTID>BORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , + v[Y] = INS<INSTID>BORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , + v[Z] = INS<INSTID>BORESIGHT[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 + } + } diff --git a/ale/drivers/__init__.py b/ale/drivers/__init__.py index a4db5a50e98ba7ec322e1130771940697710ecaa..4c50d9b228525c512bb7d71f06007c11ac2d80ca 100644 --- a/ale/drivers/__init__.py +++ b/ale/drivers/__init__.py @@ -125,7 +125,6 @@ def load(label, props={}, formatter='ale', verbose=False): res = driver(label, props=props, parsed_label=parsed_label) # get instrument_id to force early failure res.instrument_id - with res as driver: isd = formatter(driver) if verbose: diff --git a/ale/drivers/selene_drivers.py b/ale/drivers/selene_drivers.py index 78fb6a9d6939bc48aa95952dedfe3c065e4d0a4f..13a5f8d0ec0d08a8c0aca7d6711b5dd9c70c2d21 100644 --- a/ale/drivers/selene_drivers.py +++ b/ale/drivers/selene_drivers.py @@ -1,16 +1,101 @@ -import os -from glob import glob -import numpy as np import spiceypy as spice from ale.base import Driver from ale.base.data_naif import NaifSpice +from ale.base.data_isis import IsisSpice from ale.base.label_pds3 import Pds3Label from ale.base.label_isis import IsisLabel +from ale.base.type_distortion import KaguyaSeleneDistortion from ale.base.type_sensor import LineScanner -class KaguyaTcPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, Driver): +class KaguyaTcIsisLabelIsisSpiceDriver(LineScanner, IsisLabel, IsisSpice, KaguyaSeleneDistortion, Driver): + """ + """ + + @property + def spacecraft_name(self): + return self.label['IsisCube']['Instrument']['SpacecraftName'] + + @property + def detector_start_line(self): + return 1 + + @property + def _swath_mode(self): + return self.label["IsisCube"]["Instrument"]["SwathModeId"] + + @property + def detector_start_sample(self): + if (self._swath_mode == "FULL"): + start_sample = 1 + elif (self._swath_mode == "NOMINAL"): + start_sample = 297 + elif (self._swath_mode == "HALF"): + start_sample = 1172; + return start_sample - 0.5 + + @property + def _odkx(self): + """ + Returns the x coefficients of the optical distortion model. + Expects tc_id to be defined. This should be a string of the form + LISM_TC1 or LISM_TC2. + + Returns + ------- + : list + Optical distortion x coefficients + """ + return self.label['NaifKeywords'][f'INS{self.ikid}_DISTORTION_COEF_X'] + + @property + def _odky(self): + """ + Returns the y coefficients of the optical distortion model. + Expects tc_id to be defined. This should be a string of the form + LISM_TC1 or LISM_TC2. + + Returns + ------- + : list + Optical distortion y coefficients + """ + return self.label['NaifKeywords'][f'INS{self.ikid}_DISTORTION_COEF_Y'] + + @property + def boresight_x(self): + """ + Returns the x focal plane coordinate of the boresight. + Expects ikid to be defined. This should be the NAIF integer ID for the + sensor. + + Returns + ------- + : float + Boresight focal plane x coordinate + """ + return self.label['NaifKeywords'][f'INS{self.ikid}_BORESIGHT'][0] + + @property + def boresight_y(self): + """ + Returns the y focal plane coordinate of the boresight. + Expects ikid to be defined. This should be the NAIF integer ID for the + sensor. + + Returns + ------- + : float + Boresight focal plane x coordinate + """ + return self.label['NaifKeywords'][f'INS{self.ikid}_BORESIGHT'][1] + + @property + def sensor_model_version(self): + return 2 + +class KaguyaTcPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, KaguyaSeleneDistortion, Driver): """ Driver for a PDS3 Kaguya Terrain Camera (TC) images. Specifically level2b0 mono and stereo images. @@ -350,46 +435,6 @@ class KaguyaTcPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, Driver): """ return float(spice.gdpool('INS{}_FOCAL_LENGTH'.format(self.ikid), 0, 1)[0]) - @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<INSTID>_DISTORTION_COEF_X = ( a0, a1, a2, a3) - INS<INSTID>_DISTORTION_COEF_Y = ( b0, b1, b2, b3), - - Distance r from the center: - r = - (n - INS<INSTID>_CENTER) * INS<INSTID>_PIXEL_SIZE. - - Line-of-sight vector v is calculated as - v[X] = INS<INSTID>BORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , - v[Y] = INS<INSTID>BORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , - v[Z] = INS<INSTID>BORESIGHT[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): """ @@ -497,8 +542,7 @@ class KaguyaTcPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, Driver): """ return 2 - -class KaguyaMiPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, Driver): +class KaguyaMiPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, KaguyaSeleneDistortion, Driver): """ Driver for a PDS3 Kaguya Multiband Imager (Mi) images. Specifically level2b2 Vis and Nir images. @@ -803,46 +847,6 @@ class KaguyaMiPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, Driver): """ return float(spice.gdpool('INS{}_FOCAL_LENGTH'.format(self.ikid), 0, 1)[0]) - @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<INSTID>_DISTORTION_COEF_X = ( a0, a1, a2, a3) - INS<INSTID>_DISTORTION_COEF_Y = ( b0, b1, b2, b3), - - Distance r from the center: - r = - (n - INS<INSTID>_CENTER) * INS<INSTID>_PIXEL_SIZE. - - Line-of-sight vector v is calculated as - v[X] = INS<INSTID>BORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , - v[Y] = INS<INSTID>BORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , - v[Z] = INS<INSTID>BORESIGHT[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): """ @@ -853,8 +857,7 @@ class KaguyaMiPds3NaifSpiceDriver(LineScanner, Pds3Label, NaifSpice, Driver): """ return 1 - -class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver): +class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, KaguyaSeleneDistortion, Driver): @property def base_band(self): """ @@ -920,8 +923,6 @@ class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver """ return self.label['IsisCube']['Instrument']['CorrectedScClockStartCount'].value - - @property def spacecraft_clock_stop_count(self): """ @@ -935,7 +936,6 @@ class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver """ return self.label['IsisCube']['Instrument']['CorrectedScClockStopCount'].value - @property def ephemeris_start_time(self): """ @@ -1071,49 +1071,6 @@ class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver """ return spice.gdpool('INS{}_BORESIGHT'.format(self.ikid), 1, 1)[0] - - - @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<INSTID>_DISTORTION_COEF_X = ( a0, a1, a2, a3) - INS<INSTID>_DISTORTION_COEF_Y = ( b0, b1, b2, b3), - - Distance r from the center: - r = - (n - INS<INSTID>_CENTER) * INS<INSTID>_PIXEL_SIZE. - - Line-of-sight vector v is calculated as - v[X] = INS<INSTID>BORESIGHT[X] + a0 + a1*r + a2*r^2 + a3*r^3 , - v[Y] = INS<INSTID>BORESIGHT[Y] + r+a0 + a1*r +a2*r^2 + a3*r^3 , - v[Z] = INS<INSTID>BORESIGHT[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): """ @@ -1137,8 +1094,6 @@ class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver except: return self.label['IsisCube']['Instrument']['CorrectedSamplingInterval'].value * 0.001 # Scale to seconds - - @property def focal2pixel_samples(self): """ @@ -1154,7 +1109,6 @@ class KaguyaMiIsisLabelNaifSpiceDriver(LineScanner, NaifSpice, IsisLabel, Driver pixel_size = spice.gdpool('INS{}_PIXEL_SIZE'.format(self.ikid), 0, 1)[0] return [0, 0, -1/pixel_size] - @property def focal2pixel_lines(self): """ diff --git a/tests/pytests/data/TC1S2B0_01_06691S820E0465/TC1S2B0_01_06691S820E0465_isis.lbl b/tests/pytests/data/TC1S2B0_01_06691S820E0465/TC1S2B0_01_06691S820E0465_isis.lbl new file mode 100644 index 0000000000000000000000000000000000000000..c82f507b5577406399b4e3e52e2dd1fdacaf4a13 --- /dev/null +++ b/tests/pytests/data/TC1S2B0_01_06691S820E0465/TC1S2B0_01_06691S820E0465_isis.lbl @@ -0,0 +1,439 @@ +Object = IsisCube + Object = Core + StartByte = 65537 + Format = Tile + TileSamples = 802 + TileLines = 776 + + Group = Dimensions + Samples = 3208 + Lines = 4656 + Bands = 1 + End_Group + + Group = Pixels + Type = SignedWord + ByteOrder = Lsb + Base = 0.0 + Multiplier = 0.013 + End_Group + End_Object + + Group = Instrument + MissionName = SELENE + SpacecraftName = KAGUYA + InstrumentName = "TERRAIN CAMERA 1" + InstrumentId = TC1 + TargetName = MOON + ObservationModeId = NORMAL + SensorDescription = "Imagery type:Pushbroom. + ImageryMode:Mono,Stereo. + ExposureTimeMode:Long,Middle,Short. + CompressionMode:NonComp,DCT. + Q-table:32 patterns. H-table:4 + patterns. + SwathMode:F(Full),N(Nominal),H(Half). + First pixel + number:1(F),297(N),1172(H)." + SensorDescription2 = "Pixel size:7x7[micron^2](TC1/TC2). + Wavelength range:430-850[nm](TC1/TC2). + A/D rate:10[bit](TC1/TC2). Slant + angle:+/-15[degree] (from nadir to +x + of S/C)(TC1/TC2). Focal + length:72.45/72.63[mm](TC1/TC2). F + number:3.97/3.98(TC1/TC2)." + StartTime = 2009-04-05T20:09:53.607478 + StopTime = 2009-04-05T20:10:23.864978 + OriginalStartTime = 2009-04-05T20:09:53.610804 + OriginalStopTime = 2009-04-05T20:10:23.868304 + ExposureModeId = LONG + ExposureDuration = 6.500000 <ms> + OriginalSpacecraftClockStartCount = "922997380.1775 <s>" + OriginalSpacecraftClockStopCount = "922997410.4350 <s>" + SpacecraftClockStartCount = 922997380.174174 <s> + SpacecraftClockStopCount = 922997410.431674 <s> + OriginalLineSamplingInterval = 6.500000 <ms> + LineSamplingInterval = 6.500000 <ms> + SwathModeId = FULL + IlluminationCondition = MORNING + End_Group + + Group = Archive + ProductId = TC1S2B0_01_06691S820E0465 + SoftwareName = RGC_TC_s_Level2B0 + SoftwareVersion = 1.0.0 + ProcessVersionId = L2B + ProductCreationTime = 2013-06-10T09:23:07 + ProgramStartTime = 2013-06-10T09:23:01 + ProducerId = LISM + ProductSetId = TC_s_Level2B0 + ProductVersionId = 01 + RegisteredProduct = Y + Level2AFileName = TC1S2A0_02TLF06691_001_0001.img + SpiceMetakernelFileName = RGC_INF_TCv401IK_MIv200IK_SPv105IK_RISE100h- + _02_LongCK_D_V02_de421_110706.mk + DataSetId = SLN-L-TC-3-S-LEVEL2B0-V1.0 + ImageValueType = RADIANCE + ImageUnit = W/m**2/micron/sr + MinForStatisticalEvaluation = 0 + MaxForStatisticalEvaluation = 32767 + SceneMaximumDn = 3612 + SceneMinimumDn = 0 + SceneAverageDn = 401.1 + SceneStdevDn = 420.5 + SceneModeDn = 0 + ShadowedAreaMinimum = 0 + ShadowedAreaMaximum = 0 + ShadowedAreaPercentage = 12 + InvalidType = (SATURATION, MINUS, DUMMY_DEFECT, OTHER) + InvalidValue = (-20000, -21000, -22000, -23000) + InvalidPixels = (3314, 0, 0, 0) + DarkFileName = TC1_DRK_04740_07536_L_N_b05.csv + FlatFileName = TC1_FLT_04740_07536_N_N_b05.csv + EfficFileName = TC1_EFF_PRFLT_N_N_v01.csv + NonlinFileName = TC1_NLT_PRFLT_N_N_v01.csv + RadCnvCoef = 3.790009 <W/m**2/micron/sr> + L2aDeadPixelThreshold = 30 + L2aSaturationThreshold = 1023 + DarkValidMinimum = -5 + RadianceSaturationThreshold = 425.971000 <W/m**2/micron/sr> + UpperLeftLatitude = -81.172073 <deg> + UpperLeftLongitude = 44.883039 <deg> + UpperRightLatitude = -81.200350 <deg> + UpperRightLongitude = 48.534829 <deg> + LowerLeftLatitude = -82.764677 <deg> + LowerLeftLongitude = 43.996992 <deg> + LowerRightLatitude = -82.797271 <deg> + LowerRightLongitude = 48.427901 <deg> + End_Group + + Group = BandBin + FilterName = BroadBand + Center = 640nm + Width = 420nm + End_Group + + Group = Kernels + NaifCkCode = -131350 + NaifFrameCode = -131351 + LeapSecond = $base/kernels/lsk/naif0012.tls + TargetAttitudeShape = ($base/kernels/pck/pck00009.tpc, + $kaguya/kernels/pck/moon_080317.tf, + $kaguya/kernels/pck/moon_assoc_me.tf) + TargetPosition = (Table, + $kaguya/kernels/tspk/moon_pa_de421_1900-2050.- + bpc, $kaguya/kernels/tspk/de421.bsp) + InstrumentPointing = (Table, $kaguya/kernels/ck/SEL_M_ALL_D_V02.BC, + $kaguya/kernels/fk/SEL_V01.TF) + Instrument = $kaguya/kernels/ik/SEL_TC_V01.TI + SpacecraftClock = $kaguya/kernels/sclk/SEL_M_V01.TSC + InstrumentPosition = (Table, + $kaguya/kernels/spk/SEL_M_071020_090610_SGMH_- + 02.BSP) + InstrumentAddendum = $kaguya/kernels/iak/kaguyaTcAddendum007.ti + ShapeModel = /caldera/projects/usgs/hazards/astro/dems/Lun- + ar_LRO_LOLAKaguya_DEMmerge_Global_512ppd_radi- + us.cub + InstrumentPositionQuality = Reconstructed + InstrumentPointingQuality = Reconstructed + CameraVersion = 2 + Source = isis + End_Group +End_Object + +Object = Label + Bytes = 65536 +End_Object + +Object = Table + Name = InstrumentPointing + StartByte = 29946357 + Bytes = 1088 + Records = 17 + ByteOrder = Lsb + TimeDependentFrames = (-131000, 1) + ConstantFrames = (-131350, -131320, -131000) + ConstantRotation = (0.96621809368586, -9.13008670889038e-04, + -0.25772419725208, 7.985363329953e-04, + 0.99999953055997, -5.4883472482896e-04, + 0.25772457735688, 3.24491906175013e-04, + 0.96621836917501) + CkTableStartTime = 292234259.82294 + CkTableEndTime = 292234290.08694 + CkTableOriginalSize = 4657 + FrameTypeCode = 3 + Description = "Created by spiceinit" + Kernels = ($kaguya/kernels/ck/SEL_M_ALL_D_V02.BC, + $kaguya/kernels/fk/SEL_V01.TF) + + Group = Field + Name = J2000Q0 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Q1 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Q2 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Q3 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = AV1 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = AV2 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = AV3 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = ET + Type = Double + Size = 1 + End_Group +End_Object + +Object = Table + Name = InstrumentPosition + StartByte = 29947445 + Bytes = 224 + Records = 4 + ByteOrder = Lsb + CacheType = HermiteSpline + SpkTableStartTime = 292234259.82294 + SpkTableEndTime = 292234290.08694 + SpkTableOriginalSize = 4657.0 + Description = "Created by spiceinit" + Kernels = $kaguya/kernels/spk/SEL_M_071020_090610_SGMH_02.BSP + + Group = Field + Name = J2000X + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Y + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Z + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000XV + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000YV + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000ZV + Type = Double + Size = 1 + End_Group + + Group = Field + Name = ET + Type = Double + Size = 1 + End_Group +End_Object + +Object = Table + Name = BodyRotation + StartByte = 29947669 + Bytes = 128 + Records = 2 + ByteOrder = Lsb + TimeDependentFrames = (31006, 1) + ConstantFrames = (31001, 31007, 31006) + ConstantRotation = (0.99999987325471, -3.29285422375571e-04, + 3.80869618671387e-04, 3.29286000210947e-04, + 0.99999994578431, -1.45444093783627e-06, + -3.80869119096078e-04, 1.57985578682691e-06, + 0.99999992746811) + CkTableStartTime = 292234259.82294 + CkTableEndTime = 292234290.08694 + CkTableOriginalSize = 2 + FrameTypeCode = 6 + Description = "Created by spiceinit" + Kernels = ($kaguya/kernels/tspk/moon_pa_de421_1900-2050.bpc, + $kaguya/kernels/tspk/de421.bsp, + $base/kernels/pck/pck00009.tpc, + $kaguya/kernels/pck/moon_080317.tf, + $kaguya/kernels/pck/moon_assoc_me.tf) + SolarLongitude = 65.391672102148 + + Group = Field + Name = J2000Q0 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Q1 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Q2 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Q3 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = AV1 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = AV2 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = AV3 + Type = Double + Size = 1 + End_Group + + Group = Field + Name = ET + Type = Double + Size = 1 + End_Group +End_Object + +Object = Table + Name = SunPosition + StartByte = 29947797 + Bytes = 112 + Records = 2 + ByteOrder = Lsb + CacheType = Linear + SpkTableStartTime = 292234259.82294 + SpkTableEndTime = 292234290.08694 + SpkTableOriginalSize = 2.0 + Description = "Created by spiceinit" + Kernels = ($kaguya/kernels/tspk/moon_pa_de421_1900-2050.bpc, + $kaguya/kernels/tspk/de421.bsp) + + Group = Field + Name = J2000X + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Y + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000Z + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000XV + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000YV + Type = Double + Size = 1 + End_Group + + Group = Field + Name = J2000ZV + Type = Double + Size = 1 + End_Group + + Group = Field + Name = ET + Type = Double + Size = 1 + End_Group +End_Object + +Object = History + Name = IsisCube + StartByte = 29947909 + Bytes = 1906 +End_Object + +Object = OriginalLabel + Name = IsisCube + StartByte = 29939209 + Bytes = 7148 +End_Object + +Object = NaifKeywords + BODY_CODE = 301 + BODY301_RADII = (1737.4, 1737.4, 1737.4) + BODY_FRAME_CODE = 31001 + INS-131351_SWAP_OBSERVER_TARGET = TRUE + INS-131351_LIGHTTIME_CORRECTION = NONE + INS-131351_LT_SURFACE_CORRECT = FALSE + INS-131351_FOCAL_LENGTH = 72.45 + INS-131351_PIXEL_PITCH = 0.007 + CLOCK_ET_-131_922997380.174174_COMPUTED = eeabd213246bb141 + INS-131351_TRANSX = (0.0, 0.0, -0.007) + INS-131351_TRANSY = (0.0, -0.007, 0.0) + INS-131351_ITRANSS = (0.0, 0.0, -142.857142857) + INS-131351_ITRANSL = (0.0, -142.857142857, 0.0) + INS-131351_BORESIGHT_SAMPLE = 2048.0 + INS-131351_BORESIGHT_LINE = 0.5 + INS-131351_DISTORTION_COEF_X = (-9.6499e-04, 9.8441e-04, + 8.5773e-06, -3.7438e-06) + INS-131351_DISTORTION_COEF_Y = (-0.0013796, 1.3502e-05, + 2.7251e-06, -6.1938e-06) + INS-131351_BORESIGHT = (-0.0725, 0.0214) +End_Object +End diff --git a/tests/pytests/test_distortion.py b/tests/pytests/test_distortion.py index 3f4b8767922af92611d82a9716df496f3ff80d06..3e8faeca09080f155e42015f942552f820104082 100644 --- a/tests/pytests/test_distortion.py +++ b/tests/pytests/test_distortion.py @@ -3,9 +3,21 @@ import pvl import ale from ale import base -from ale.base.type_distortion import RadialDistortion +from ale.base.type_distortion import RadialDistortion, KaguyaSeleneDistortion def test_radial_distortion(): radial_distortion = RadialDistortion() radial_distortion.odtk = [0.0, 0.1, 0.2] assert radial_distortion.usgscsm_distortion_model["radial"]["coefficients"] == [0.0, 0.1, 0.2] + +def test_kaguyaselene_distortion(): + kaguyaselene_distortion = KaguyaSeleneDistortion() + kaguyaselene_distortion._odkx = [1,2,3,4] + kaguyaselene_distortion._odky = [1,2,3,4] + kaguyaselene_distortion.boresight_x = 0.1 + kaguyaselene_distortion.boresight_y = -0.1 + + assert kaguyaselene_distortion.usgscsm_distortion_model['kaguyalism']['x'] == [1,2,3,4] + assert kaguyaselene_distortion.usgscsm_distortion_model['kaguyalism']['y'] == [1,2,3,4] + assert kaguyaselene_distortion.usgscsm_distortion_model['kaguyalism']['boresight_x'] == 0.1 + assert kaguyaselene_distortion.usgscsm_distortion_model['kaguyalism']['boresight_y'] == -0.1 diff --git a/tests/pytests/test_kaguya_drivers.py b/tests/pytests/test_kaguya_drivers.py index 50ebe3b766020e78952a565f635f0f94d76ad747..79cb734b512b2156a9cef386062b1af68f5912ed 100644 --- a/tests/pytests/test_kaguya_drivers.py +++ b/tests/pytests/test_kaguya_drivers.py @@ -2,7 +2,6 @@ import pytest import os import numpy as np from datetime import datetime, timezone -import spiceypy as spice from importlib import reload import json @@ -13,7 +12,7 @@ from conftest import get_isd, get_image_label, get_image_kernels, convert_kernel import ale -from ale.drivers.selene_drivers import KaguyaTcPds3NaifSpiceDriver, KaguyaMiIsisLabelNaifSpiceDriver +from ale.drivers.selene_drivers import KaguyaTcPds3NaifSpiceDriver, KaguyaMiIsisLabelNaifSpiceDriver, KaguyaTcIsisLabelIsisSpiceDriver image_dict = { 'TC1S2B0_01_06691S820E0465' : get_isd("kaguyatc"), @@ -191,3 +190,43 @@ class test_kaguyami_isis3_naif(unittest.TestCase): spacecraft_direction.return_value = -1 assert self.driver.focal2pixel_lines == [0, 1/2, 0] gdpool.assert_called_with('INS-12345_PIXEL_SIZE', 0, 1) + +# ========= Test kaguyatc isis3label and isisspice driver ========= + +class test_isis_isis(unittest.TestCase): + + def setUp(self): + label = get_image_label("TC1S2B0_01_06691S820E0465", "isis") + self.driver = KaguyaTcIsisLabelIsisSpiceDriver(label) + + def test_spacecraft_name(self): + assert self.driver.spacecraft_name == 'KAGUYA' + + def test_detector_start_line(self): + assert self.driver.detector_start_line == 1 + + def test_detector_start_sample(self): + # Check FULL; default in label + assert self.driver.detector_start_sample == 0.5 + + with patch('ale.drivers.selene_drivers.KaguyaTcIsisLabelIsisSpiceDriver._swath_mode', new_callable=PropertyMock) as swath_mode: + swath_mode.return_value = 'NOMINAL' + assert self.driver.detector_start_sample == 296.5 + + swath_mode.return_value = 'HALF' + assert self.driver.detector_start_sample == 1171.5 + + def test__odkx(self): + assert self.driver._odkx == [-9.6499e-04, 9.8441e-04, 8.5773e-06, -3.7438e-06] + + def test__odky(self): + assert self.driver._odky == [-0.0013796, 1.3502e-05, 2.7251e-06, -6.1938e-06] + + def test_boresight_x(self): + assert self.driver.boresight_x == -0.0725 + + def test_boresight_y(self): + assert self.driver.boresight_y == 0.0214 + + def test_sensor_model_version(self): + assert self.driver.sensor_model_version == 2 \ No newline at end of file