Unverified Commit e59d297b authored by Jesse Mapel's avatar Jesse Mapel Committed by GitHub
Browse files

Adds Cassini Vims driver for use within ISIS (#466)



* Added cassini vims vis/ir drivers

* Various cassini vims centric driver changes

* fixed rebase conflict

* Finalized cassini vims drivers

* Added cassini vims test data

* Added tests for cassini vims

* Updated cassini vims tests after pck loading order change

* Changed env var monkey patch from ISIS3DATA to ISISDATA

* Fixed typos in doc strings

---------

Co-authored-by: default avataracpaquette <acp263@nau.edu>
Co-authored-by: default avataracpaquette <acpaquette@usgs.gov>
parent bc50c79a
Loading
Loading
Loading
Loading
+220 −7
Original line number Diff line number Diff line
@@ -12,21 +12,36 @@ from ale.base.label_pds3 import Pds3Label
from ale.base.label_isis import IsisLabel
from ale.base.type_distortion import RadialDistortion, NoDistortion
from ale.base.type_sensor import Framer
from ale.base.type_sensor import LineScanner

from ale.rotation import ConstantRotation
from ale.transformation import FrameChain
from ale.util import query_kernel_pool
from scipy.spatial.transform import Rotation

id_lookup = {
vims_id_lookup = {
    "VIMS_VIS" : "CASSINI_VIMS_V",
    "VIMS_IR" : "CASSINI_VIMS_IR"
}

vims_name_lookup = {
    "VIMS" : "Visible and Infrared Mapping Spectrometer",
}

iss_id_lookup = {
    "ISSNA" : "CASSINI_ISS_NAC",
    "ISSWA" : "CASSINI_ISS_WAC"
}

name_lookup = {
iss_name_lookup = {
    "ISSNA" : "Imaging Science Subsystem Narrow Angle Camera",
    "ISSWA" : "Imaging Science Subsystem Wide Angle Camera"
}

spacecraft_name_lookup = {
    'Cassini-Huygens': 'Cassini'
}

nac_filter_to_focal_length = {
    ("P0","BL2"):2002.19,
    ("P0","CB1"):2002.30,
@@ -126,7 +141,7 @@ class CassiniIssIsisLabelNaifSpiceDriver(Framer, IsisLabel, NaifSpice, RadialDis
        : str
          instrument id
        """
        return id_lookup[super().instrument_id]
        return iss_id_lookup[super().instrument_id]

    @property
    def spacecraft_name(self):
@@ -151,7 +166,7 @@ class CassiniIssIsisLabelNaifSpiceDriver(Framer, IsisLabel, NaifSpice, RadialDis
        : str
          Name of the sensor
        """
        return name_lookup[super().instrument_id]
        return iss_name_lookup[super().instrument_id]

    @property
    def ephemeris_start_time(self):
@@ -293,6 +308,204 @@ class CassiniIssIsisLabelNaifSpiceDriver(Framer, IsisLabel, NaifSpice, RadialDis
    def sensor_model_version(self):
        return 1

class CassiniVimsIsisLabelNaifSpiceDriver(LineScanner, IsisLabel, NaifSpice, NoDistortion, Driver):

    @property
    def vims_channel(self):
        if not hasattr(self, '_vims_channel'):
            self._vims_channel = self.label['IsisCube']["Instrument"]["Channel"]
        return self._vims_channel

    @property
    def instrument_id(self):
        """
        Returns an instrument id for uniquely identifying the instrument, but often
        also used to be piped into Spice Kernels to acquire IKIDs. Therefore they
        the same ID the Spice expects in bods2c calls.
        Expects instrument_id to be defined in the IsisLabel mixin. This should be
        a string of the form 'CTX'

        Returns
        -------
        : str
          instrument id
        """
        return vims_id_lookup[super().instrument_id + "_" + self.vims_channel]

    @property
    def sensor_name(self):
        """
        ISIS doesn't propagate this to the ingested cube label, so hard-code it.
        """
        return vims_name_lookup[super().instrument_id]

    @property
    def spacecraft_name(self):
        """
        Returns the spacecraft name used in various Spice calls to acquire
        ephemeris data.
        Expects the platform_name to be defined. This should be a string of
        the form 'Mars_Reconnaissance_Orbiter'

        Returns
        -------
        : str
          spacecraft name
        """
        return spacecraft_name_lookup[super().platform_name]

    @property
    def exposure_duration(self):
        """
        The exposure duration of the image, in seconds

        Returns
        -------
        : float
          Exposure duration in seconds
        """
        if 'ExposureDuration' in self.label['IsisCube']['Instrument']:
            exposure_duration = self.label['IsisCube']['Instrument']['ExposureDuration']

            for i in exposure_duration:
                if i.units == "VIS":
                    exposure_duration = i

            exposure_duration = exposure_duration.value * 0.001
            return exposure_duration
        else:
            return self.line_exposure_duration

    @property
    def focal_length(self):
        """
        Hardcoded value taken from ISIS
        """
        if not hasattr(self, '_focal_length'):
            if self.vims_channel == "VIS":
                self._focal_length = 143.0
            else:
                self._focal_length = 426.0
        return self._focal_length

    @property
    def detector_center_line(self):
        return 0

    @property
    def detector_center_sample(self):
        return 0

    def compute_vims_time(self, line, sample, number_of_samples, mode="VIS"):
        instrument_group = self.label["IsisCube"]["Instrument"]
        time = str(instrument_group["NativeStartTime"])
        int_time, decimal_time = str(time).split(".")

        ephemeris_time = spice.scs2e(self.spacecraft_id, int_time)
        ephemeris_time += float(decimal_time) / 15959.0

        ir_exp = float(instrument_group["ExposureDuration"][0]) * 1.01725 / 1000.0;
        vis_exp = float(instrument_group["ExposureDuration"][1]) / 1000.0

        interline_delay = (float(instrument_group["InterlineDelayDuration"]) * 1.01725) / 1000.0

        swath_width = instrument_group["SwathWidth"];

        if mode == "VIS":
            ephemeris_time = (float(ephemeris_time) + (((ir_exp * swath_width) - vis_exp) / 2.0)) + ((line + 0.5) * vis_exp)
        elif mode == "IR":
            ephemeris_time = float(ephemeris_time) + (line * number_of_samples * ir_exp) + (line * interline_delay) + ((sample + 0.5) * ir_exp)

        return ephemeris_time

    @property
    def ephemeris_start_time(self):
        return self.compute_vims_time(0 - 0.5, 0 - 0.5, self.image_samples, mode=self.vims_channel)

    @property
    def ephemeris_stop_time(self):
        return self.compute_vims_time((self.image_lines - 1) + 0.5, (self.image_samples - 1) + 0.5, self.image_samples, mode=self.vims_channel)

    @property
    def sensor_model_version(self):
        """
        Returns instrument model version
        Returns
        -------
        : int
          ISIS sensor model version
        """
        try:
            return super().sensor_model_version
        except:
            return 1


class CassiniVimsIsisLabelIsisSpiceDriver(LineScanner, IsisLabel, IsisSpice, NoDistortion, Driver):

    @property
    def instrument_id(self):
        """
        Returns an instrument id for uniquely identifying the instrument, but often
        also used to be piped into Spice Kernels to acquire IKIDs. Therefore they
        the same ID the Spice expects in bods2c calls.
        Expects instrument_id to be defined in the IsisLabel mixin. This should be
        a string of the form 'CTX'

        Returns
        -------
        : str
          instrument id
        """

        image_type = self.label['IsisCube']["Instrument"]["Channel"]
        return vims_id_lookup[super().instrument_id + "_" + image_type]

    @property
    def sensor_name(self):
        """
        ISIS doesn't propagate this to the ingested cube label, so hard-code it.
        """
        return "Visible and Infrared Mapping Spectrometer"

    @property
    def spacecraft_name(self):
        """
        Returns the spacecraft name used in various Spice calls to acquire
        ephemeris data.
        Expects the platform_name to be defined. This should be a string of
        the form 'Mars_Reconnaissance_Orbiter'

        Returns
        -------
        : str
          spacecraft name
        """
        return spacecraft_name_lookup[super().platform_name]

    @property
    def exposure_duration(self):
        """
        The exposure duration of the image, in seconds

        Returns
        -------
        : float
          Exposure duration in seconds
        """
        if 'ExposureDuration' in self.label['IsisCube']['Instrument']:
            exposure_duration = self.label['IsisCube']['Instrument']['ExposureDuration']

            for i in exposure_duration:
                if i.units == "VIS":
                    exposure_duration = i

            exposure_duration = exposure_duration.value * 0.001
            return exposure_duration
        else:
            return self.line_exposure_duration


class CassiniIssPds3LabelNaifSpiceDriver(Framer, Pds3Label, NaifSpice, RadialDistortion, Driver):
    """
    Cassini mixin class for defining Spice calls.
@@ -313,7 +526,7 @@ class CassiniIssPds3LabelNaifSpiceDriver(Framer, Pds3Label, NaifSpice, RadialDis
        : str
          instrument id
        """
        return id_lookup[super().instrument_id]
        return iss_id_lookup[super().instrument_id]

    @property
    def focal_epsilon(self):
@@ -530,7 +743,7 @@ class CassiniIssIsisLabelIsisSpiceDriver(Framer, IsisLabel, IsisSpice, NoDistort
        : str
          ID of the sensor
        """
        return id_lookup[super().instrument_id]
        return iss_id_lookup[super().instrument_id]

    @property
    def sensor_name(self):
@@ -542,7 +755,7 @@ class CassiniIssIsisLabelIsisSpiceDriver(Framer, IsisLabel, IsisSpice, NoDistort
        : str
          Name of the sensor
        """
        return name_lookup[super().instrument_id]
        return iss_name_lookup[super().instrument_id]

    @property
    def center_ephemeris_time(self):
+1784 −0

File added.

Preview size limit exceeded, changes collapsed.

+1803 −0

File added.

Preview size limit exceeded, changes collapsed.

+1803 −0

File added.

Preview size limit exceeded, changes collapsed.

+279 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading