Commit 56431d4d authored by Kristin's avatar Kristin Committed by Jesse Mapel
Browse files

Add sensor model support for Calibrated VIRTIS_M_IR and VIRTIS_M_VIS images to ISIS (#647)

* Fixes the reading of SCETs into the ISIS3 table in the ingested image for level-3, calibrated VIRTIS-M images

* Added initial updates to the RosettaVirtisCamera model to support VIRTIS-M calibrated images

* Corrected StartTime and SpacecraftClockStartCount in calibrated VIRTIS-M ingested images and initial camera model cleanup

* Fix spacecraft clock start / stop count and start time and stop time in rosetta virtis labels

* Updated label fix for rosvirtis2isis.

* fixed StopTime and SpacecraftClockStopCount in virtis labels

* Cleanup of camera model

* Fix sclk calculation in rosvirtis2isis, update table attached to ingested cube to include the sclk string, update camera model to use updated table.

* Changes to the RosettaVirtisCamera and SpiceRotation to allow spiceinit with mirror kernels

* Clean up debug output

* Update SpiceRotation's minimize-cache-status setting function to not update if it has been previously set to fixed

* Update SpiceRotation to only set the time cache explicitly if one has not already been loaded from the InstrumentPosition table attached to the cube

* Clean up rosetta virtis changes

* Cleanup of merge of virtis changes
parent f81ecf74
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -714,7 +714,6 @@ namespace Isis {
      LineCache(tableName);

      //std::cout << "Full cache size is " << p_cache.size() << endl;

      p_minimizeCache = Yes;
      LoadTimeCache();

@@ -1931,6 +1930,12 @@ namespace Isis {
    return;
 }

  void SpiceRotation::SetCacheTime(std::vector<double> cacheTime) {
    // Do not reset the cache times if they are already loaded. 
    if (p_cacheTime.size() <= 0) {
      p_cacheTime = cacheTime; 
    }
  }

  /**
   * Evaluate the derivative of the fit polynomial defined by the
@@ -2398,7 +2403,7 @@ namespace Isis {

        // Don't read type 5 ck here
        if (ic[2] == 5) break;
//

        // Check times for type 3 ck segment if spacecraft matches
        if (ic[0] == spCode && ic[2] == 3) {
          sct2e_c((int) spCode / 1000, dc[0], &segStartEt);
@@ -2478,13 +2483,15 @@ namespace Isis {

    // Load times according to cache size (body rotations) -- handle first round of type 5 ck case
    //   and multiple ck case --Load a time for every line scan line and downsize later
    if (!timeLoaded) {
    if (! (timeLoaded || (p_cacheTime.size() > 1))) {
      double cacheSlope = 0.0;
      if (p_fullCacheSize > 1)
        cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double)(p_fullCacheSize - 1);
      for (int i = 0; i < p_fullCacheSize; i++)
        p_cacheTime.push_back(p_fullCacheStartTime + (double) i * cacheSlope); 
      if (p_source == Nadir) p_minimizeCache = No;
      if (p_source == Nadir) {
        p_minimizeCache = No;
      }
    }
    NaifStatus::CheckErrors();
  }
+1 −0
Original line number Diff line number Diff line
@@ -392,6 +392,7 @@ namespace Isis {
      double GetTimeScale();

      void SetOverrideBaseTime(double baseTime, double timeScale);
      void SetCacheTime(std::vector<double> cacheTime); 

      // Derivative methods
      double DPolynomial(const int coeffIndex);
+98 −11
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "UserInterface.h"
#include "PolynomialUnivariate.h"
#include "VirtisHK.h"
#include "iTime.h"

using namespace std;
using namespace Isis;
@@ -29,6 +30,7 @@ int word(const char byte1, const char byte2);
int swapb(const unsigned short int word);
double translateScet(int word1, int word2, int word3);
bool isValid(int word);
QString convertSCET(int word1, int word2, int word3); 

void IsisMain ()
{
@@ -59,6 +61,7 @@ void IsisMain ()

  p.SetPdsFile(pdsLabel, inFile.expanded());
  p.SetOrganization(Isis::ProcessImport::BIP);
  p.SaveDataSuffix(); 

  // NULL pixels are set to 65535 in the input QUB
  p.SetNull(65535, 65535);
@@ -90,6 +93,8 @@ void IsisMain ()
    throw IException(IException::Unknown, msg, _FILEINFO_);
  }

  // Processing level 2 = uncalibrated
  // Processing level 3 = calibrated
  int procLevel = (int) pdsLabel.findKeyword("PROCESSING_LEVEL_ID");

  // Override default DataTrailerBytes constructed from PDS header
@@ -102,6 +107,9 @@ void IsisMain ()
    p.SetDataSuffixBytes(4);
  }

  QString startScet;
  QString stopScet; 

  p.StartProcess();

  // Get the directory where the Rosetta translation tables are.
@@ -328,25 +336,44 @@ void IsisMain ()

    outcube->write(table);
  }
  // Level 3 = Calibrated VIRTIS-M data
  else if (procLevel == 3) {
    std::vector<char *> hkData = p.DataTrailer();

    // Create a table to hold SCET information
    TableRecord rec;
    TableField scETField("dataSCET", TableField::Double);
    TableField scETField("dataSCET", TableField::Text, 50);
    rec += scETField;
    Table table("VIRTISHouseKeeping", rec);
    for (unsigned int i=0; i < hkData.size() ; i++) {
      const char *hk = hkData.at(i);
      const unsigned short *uihk = reinterpret_cast<const unsigned short *> (hk);
      int word1 = swapb(uihk[0]);
      int word2 = swapb(uihk[1]);
      int word3 = swapb(uihk[2]);
      rec[0] = translateScet(word1, word2, word3);

    std::vector<std::vector<char *> > dataSuffix = p.DataSuffix();
    for (unsigned int i=0; i < dataSuffix.size(); i++) {
      std::vector<char*> dataSuffixRecord = dataSuffix[i];

      // The SCET for each line is stored as three 2-byte words. The three words are stored in the 
      // second byte of each of the first 3 lines of the suffix record. 
      std::vector<const unsigned short*> scetBytes; 
      std::vector<int> scetWords; 
      for (int j=0; j < 3; j++) {
        scetBytes.push_back(reinterpret_cast<const unsigned short *>(dataSuffixRecord.at(j)));
        scetWords.push_back(swapb(scetBytes[j][1]));    
      }
      
      // Calculate the SCET and add it to the table
      QString translatedScet = convertSCET(scetWords[0], scetWords[1], scetWords[2]); 
      rec[0] = translatedScet; 
      table += rec; 

      // Save off first and last scet values. 
      if (i==0) {
        startScet = translatedScet; 
      }
      else if (i == dataSuffix.size() - 1) {
        stopScet = translatedScet; 
      }
    }
    outcube->write(table);
  }


  // Create a PVL to store the translated labels in
  Pvl outLabel;

@@ -360,6 +387,51 @@ void IsisMain ()
  PvlToPvlTranslationManager instrumentXlater (pdsLabel, transFile.expanded());
  instrumentXlater.Auto(outLabel);

  if (procLevel == 3) {
    // Fix the StartTime and SpacecraftStartClockCount in the ISIS3 label
    PvlGroup &inst = outLabel.findGroup("Instrument", Pvl::Traverse);

    // Pass the Start/Stop SCET values to naif to get the utc time. 
    QString sclk = "$ISIS3DATA/rosetta/kernels/sclk/ROS_??????_STEP.TSC"; 
    QString lsk  = "$ISIS3DATA/base/kernels/lsk/naif????.tls"; 
    FileName sclkName(sclk);
    FileName lskName(lsk); 

    sclkName = sclkName.highestVersion(); 
    lskName = lskName.highestVersion(); 

    furnsh_c(lskName.expanded().toLatin1().data());
    furnsh_c(sclkName.expanded().toLatin1().data());
    
    SpiceDouble etStart;
    SpiceDouble etEnd;
    scs2e_c( (SpiceInt) -226, startScet.toLatin1().data(), &etStart);
    scs2e_c( (SpiceInt) -226, stopScet.toLatin1().data(), &etEnd);

    PvlKeyword &frameParam = inst["FrameParameter"];
    double exposureTime = toDouble(frameParam[0]);

    QString startTime = iTime(etStart-exposureTime).UTC(); 
    QString stopTime = iTime(etEnd-exposureTime).UTC(); 

    SpiceChar startSclkString[50]; 
    SpiceChar endSclkString[50]; 
    sce2s_c( (SpiceInt) -226, etStart-exposureTime, (SpiceInt) 50, startSclkString);
    sce2s_c( (SpiceInt) -226, etEnd-exposureTime, (SpiceInt) 50, endSclkString);
    
    inst.findKeyword("StartTime").setValue(startTime);
    inst.findKeyword("StopTime").setValue(stopTime); 

    inst.findKeyword("SpacecraftClockStartCount").setValue(startSclkString); 
    inst.findKeyword("SpacecraftClockStopCount").setValue(endSclkString); 

    outcube->putGroup(inst);

    // Unload the naif kernels
    unload_c(lsk.toLatin1().data());
    unload_c(sclk.toLatin1().data());
  }
  
  // Write the Archive and Instrument groups to the output cube label
  outcube->putGroup(outLabel.findGroup("Archive", Pvl::Traverse));
  outcube->putGroup(outLabel.findGroup("Instrument", Pvl::Traverse));
@@ -406,6 +478,20 @@ void IsisMain ()
  p.EndProcess ();
}

// Converts SCET format to SSSSSSSSSS:FFFFF format
QString convertSCET(int word1, int word2, int word3)
{
  double seconds = (double ((double) word1 * pow(2.0,16.0))) + (double) word2;
  double fractionalSeconds = (double) word3; 
  QString scetString = QString::number(seconds, 'f');
  QStringList scetStringList = scetString.split(".");
  // The integer portion
  scetString = scetStringList[0];
  scetString.append(":");
  scetString.append(QString::number(fractionalSeconds));
  return scetString; 
}


/**
 * Convert 2 bytes into a 2-byte word
@@ -427,6 +513,7 @@ int word(const char byte1, const char byte2)
  return swapper.w;
}

// swap bytes
int swapb(const unsigned short int word) {
  union {
    unsigned short int w;
+69 −11
Original line number Diff line number Diff line
@@ -93,43 +93,51 @@ namespace Isis {

    // Get other info from labels
    PvlKeyword &frameParam = inst["FrameParameter"];
    m_exposureTime = toDouble(frameParam[0]);

    // convert milliseconds to seconds

    m_exposureTime = toDouble(frameParam[0]) * 0.001;
    m_summing  = toDouble(frameParam[1]);
    m_scanRate = toDouble(frameParam[2]);

    // Setup detector map
    //  Get the line scan rates/times

    if (!m_is1BCalibrated) {
      readHouseKeeping(lab.fileName(), m_scanRate); 
    }
    else {
      readSCET(lab.fileName());
    }

    new VariableLineScanCameraDetectorMap(this, m_lineRates);
    DetectorMap()->SetDetectorSampleSumming(m_summing);

    // Setup focal plane map
    new CameraFocalPlaneMap(this, naifIkCode());

    //  Retrieve boresight location from instrument kernel (IK) (addendum?)
    QString ikernKey = "INS" + toString(naifIkCode()) + "_BORESIGHT_SAMPLE";
    double sampleBoreSight = getDouble(ikernKey);

    ikernKey = "INS" + toString(naifIkCode()) + "_BORESIGHT_LINE";
    double lineBoreSight = getDouble(ikernKey);

    FocalPlaneMap()->SetDetectorOrigin(sampleBoreSight, lineBoreSight);

    // Setup distortion map
    new CameraDistortionMap(this);

    // Setup the ground and sky map
    new LineScanCameraGroundMap(this);
    new LineScanCameraSkyMap(this);

    // Set initial start time always (label start time is inaccurate)

    if (!m_is1BCalibrated){
      setTime(iTime(startTime())); 
    }

    //  Now check to determine if we have a cache already.  If we have a cache
    //  table, we are beyond spiceinit and have already computed the proper
    //  point table from the housekeeping data or articulation kernel.
    if (!instrumentRotation()->IsCached() && !hasArtCK) {

    if (!instrumentRotation()->IsCached() && !hasArtCK && !m_is1BCalibrated) {
      // Create new table here prior to creating normal caches
      Table quats = getPointingTable(frameId, virFrame);

@@ -274,7 +282,57 @@ namespace Isis {


  /**
   * @brief Read the VIR houskeeping table from cube
   * @brief For calibrated VIRTIS-M images, read the SCET values from the cube
   *
   * 
   * @param filename The filename of the cube with the house keeping table.
   * @param linerate The linerate for the cube.
   *
   * @history 2011-07-22 Kris Becker
   */
  void RosettaVirtisCamera::readSCET(const QString &filename) {
   //  Open the ISIS table object
   std::vector<double> cacheTime; 
   Table hktable("VIRTISHouseKeeping", filename);
   m_lineRates.clear();
   int lineno(1);
   double lineEndTime = 0;
   for (int i = 0; i < hktable.Records(); i++) {
     TableRecord &trec = hktable[i];
     QString scetString = trec["dataSCET"];
     lineEndTime = getClockTime(scetString, naifSpkCode()).Et();
     m_lineRates.push_back(LineRateChange(lineno,
                                          lineEndTime-exposureTime(),
                                          exposureTime()));
     cacheTime.push_back(lineEndTime-exposureTime());
     lineno++;
   }
   cacheTime.push_back(lineEndTime);

   // Adjust the last time
   LineRateChange lastR = m_lineRates.back();

    // Normally the line rate changes would store the line scan rate instead of exposure time.
    // Storing the exposure time instead allows for better time calculations within a line.
    // In order for the VariableLineScanCameraDetectorMap to work correctly with this change,
    // every line in the cube must have a LineRateChange object.  This is because determining
    // the start time for one line based on another line requires the line scan rate.  Having
    // a LineRateChange for every line means never needing to calculate the start time for a line
    // because the start time is stored in that line's LineRateChange.  So, the detector map only
    // calculates times within a given line.
    // See VariableLineScanCameraDetectorMap::exposureDuration() for a description of the
    // difference between exposure time and line scan rate.

    m_lineRates.back() = LineRateChange(lastR.GetStartLine(),
                                        lastR.GetStartEt(),
                                        exposureTime());

    instrumentRotation()->SetCacheTime(cacheTime);
  }


  /**
   * @brief Read the VIRTIS houskeeping table from cube
   *
   * This method reads an ISIS Table object from the cube.  This table named,
   * "VIRHouseKeeping", contains four fields: ScetTimeClock, ShutterStatus,
+2 −0
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ namespace Isis {

    private:
      void readHouseKeeping(const QString &filename, double lineRate);
      void readSCET(const QString &filename);

      QString scrub(const QString &text) const;
      double exposureTime() const;
      double scanLineTime() const;