Unverified Commit 92a8f3b9 authored by Amy Stamile's avatar Amy Stamile Committed by GitHub
Browse files

tgocassisrdrgen App Conversion (#4626)

* tgocassisrdrgen app conversion.

* added licensing to main.cpp and header.
parent 627313ac
Loading
Loading
Loading
Loading
+3 −220
Original line number Diff line number Diff line
@@ -8,229 +8,12 @@ find files of those names at the top level of this repository. **/

#include "Isis.h"

#include <QRegularExpression>
#include <QString>
#include <QDomDocument>

#include "Application.h"
#include "Cube.h"
#include "ExportDescription.h"
#include "FileName.h"
#include "iTime.h"
#include "Process.h"
#include "ProcessExportPds4.h"
#include "Pvl.h"
#include "PvlKeyword.h"
#include "PvlToXmlTranslationManager.h"
#include "tgocassisrdrgen.h"

using namespace Isis;
using namespace std;

void IsisMain() {
  UserInterface &ui = Application::GetUserInterface();

  // Check if input file is indeed, a cube
  if (ui.GetFileName("FROM").right(3) != "cub") {
    QString msg = "Input file [" + ui.GetFileName("FROM") +
                "] does not appear to be a cube";
    throw  IException(IException::User, msg, _FILEINFO_);
  }

  // Setup the process and set the input cube
  ProcessExportPds4 process;
  Cube *icube = process.SetInputCube("FROM");

  PvlObject *label= icube->label();

  PvlGroup targetGroup;
  QString logicalId = "urn:esa:psa:em16_tgo_cas:";

  if ( label->findObject("IsisCube").hasGroup("Instrument") ) {
    targetGroup = label->findObject("IsisCube").findGroup("Instrument");
    if (label->findObject("IsisCube").hasGroup("Mapping")) {
      logicalId += "data_projected:";
    }
    else {
      logicalId += "data_raw:";
    }
  }
  else if ( label->findObject("IsisCube").hasGroup("Mosaic") ) {
    targetGroup = label->findObject("IsisCube").findGroup("Mosaic");
    logicalId += "data_derived:";
  }

  // Check if the cube is able to be translated into a CaSSIS xml file
  // This could very well be unnecessary
  if (!targetGroup.findKeyword("InstrumentId").isEquivalent("CaSSIS")) {
    QString msg = "Input file [" + ui.GetFileName("FROM") +
                "] does not appear to be a CaSSIS RDR product. The image" +
                "instrument is not the CaSSIS instrument";
    throw  IException(IException::User, msg, _FILEINFO_);
  }

  // Add the ProductId keyword for translation. If a product id is not specified
  // by the user, set it to the Observation Id.
  // This is added before the translation instead of adding it to the exported xml
  // because of the ease of editing pvl vs xml.
  PvlKeyword productId("ProductId");
  if ( ui.WasEntered("PRODUCTID") ) {
    productId.setValue( ui.GetString("PRODUCTID") );
  }
  else {
    // Get the observationId from the Archive Group, or the Mosaic group, if the input is a mosaic
    QString observationId;

    if (label->findObject("IsisCube").hasGroup("Mosaic")) {
      PvlGroup mosaicGroup = label->findObject("IsisCube").findGroup("Mosaic");
      observationId = mosaicGroup.findKeyword("ObservationId")[0];
    }
    else if(label->findObject("IsisCube").hasGroup("Archive")){
      PvlGroup archiveGroup = label->findObject("IsisCube").findGroup("Archive");
      observationId = archiveGroup.findKeyword("ObservationId")[0];
    }
    productId.setValue(observationId);
  }

  targetGroup.addKeyword(productId);
  logicalId += productId[0];
  process.setLogicalId(logicalId);

  // For a mosaic, calculate stitched browse LID (lidvid)
  // This is as follows:
  // StartTime of the first framelet, rounded down to the nearest second
  if (label->findObject("IsisCube").hasGroup("Mosaic")) {
    QString startTime = label->findObject("IsisCube").findGroup("Mosaic").findKeyword("StartTime");
    startTime = iTime(startTime).UTC(0).toLower().remove("-").remove(":");

    // StopTime of the last framelet, rounded down to the nearest second + 4 seconds
    QString stopTime = label->findObject("IsisCube").findGroup("Mosaic").findKeyword("StopTime");
    stopTime = (iTime(iTime(stopTime).UTC(0)) + 4).UTC().toLower().remove("-").remove(":");

    // UID
    QString UID = label->findObject("IsisCube").findGroup("Archive").findKeyword("UID");
    // FilterName
    QString filterName = QString(label->findObject("IsisCube").findGroup("BandBin").
                                findKeyword("FilterName")).toLower();

    QString lid = QString("urn:esa:psa:em16_tgo_cas:data_calibrated:cas_cal_sc_%1-%2-%3-%4-sti").arg(startTime)
                          .arg(stopTime).arg(filterName).arg(UID);

    label->findObject("IsisCube").findGroup("Archive").addKeyword(PvlKeyword("LID", lid));
  }

  // Set Title
  if ( ui.WasEntered("TITLE") ) {
    process.setTitle( ui.GetString("TITLE") );
  }

  // Set Version ID
  if ( ui.WasEntered("VERSIONID") ) {
    process.setVersionId( ui.GetString("VERSIONID") );
  }

  process.setPixelDescription("Pixel values are in units of I/F (intensity/flux). I/F is defined as"
                              "the ratio of the observed radiance and the radiance of a 100% "
                              "lambertian reflector with the sun and camera orthogonal to the "
                              "observing surface.");

  // std PDS4 label
  process.StandardPds4Label();

  // Add PSA-specific schema
  process.addSchema("PDS4_PSA_1000.xsd",
                    "xmlns:psa",
                    "http://psa.esa.int/psa/v1");

  // Add CaSSIS-specific schema
  process.addSchema("PDS4_PSA_EM16_CAS_1000.xsd",
                    "xmlns:cas",
                    "http://psa.esa.int/psa/em16/cas/v1");

  // Add geometry schema for mosaics
  if (label->findObject("IsisCube").hasGroup("Mosaic")) {
    process.addSchema("PDS4_GEOM_1B00_1610.sch",
                      "PDS4_GEOM_1B00_1610.xsd",
                      "xmlns:geom",
                      "http://pds.nasa.gov/pds4/geom/v1");
  }

 /*
  * Add additional pds label data here
  */
  QDomDocument &pdsLabel = process.GetLabel();

  // The default translation for for non-mosaicked output
  QString exportTranslationFile = "$ISISROOT/appdata/translations/TgoCassisExport.trn";

  if (label->findObject("IsisCube").hasGroup("Mosaic")) {
    exportTranslationFile = "$ISISROOT/appdata/translations/TgoCassisExportMosaic.trn";
  }

  Pvl *labelPvl = icube->label();

  PvlToXmlTranslationManager cubeLab(*labelPvl, exportTranslationFile);
  cubeLab.Auto(pdsLabel);

  ProcessExportPds4::translateUnits(pdsLabel);
  process.reorder();

  // Units are automatically translated for the focal length, and there is no way at this time to
  // turn it off, but the cas:CASSIS_Data standard specifies that the focal-length output may not
  // have units, so remove the units from cas:focal length.
  QDomDocument &pdsLabelNext = process.GetLabel();
  QDomElement observationNode = pdsLabelNext.documentElement().firstChildElement("Observation_Area");
  QStringList xmlPath;
  xmlPath << "Observation_Area"
          << "Mission_Area"
          << "cas:CASSIS_Data"
          << "cas:telescope_information"
          << "cas:focal_length";
  QDomElement focalLengthNode = process.getElement(xmlPath, observationNode);

  if (focalLengthNode.hasAttribute("unit")) {
    focalLengthNode.removeAttribute("unit");
  }

  // Fix the footprint section's output structure
  QStringList xmlPath2;
  xmlPath2 << "Observation_Area"
          << "Discipline_Area"
          << "geom:Geometry"
          << "geom:Geometry_Orbiter"
          << "geom:Surface_Geometry"
          << "geom:Surface_Geometry_Specific"
          << "geom:Footprint_Vertices"
          << "geom:Pixel_Intercept";
  QDomElement pixelInterceptNode = process.getElement(xmlPath2, observationNode);

  if(pixelInterceptNode.hasChildNodes()) {
    QDomElement pixelInterceptNode2 = pixelInterceptNode.nextSiblingElement();
    QDomElement pixelInterceptNode3 = pixelInterceptNode2.nextSiblingElement();
    QDomElement pixelInterceptNode4 = pixelInterceptNode3.nextSiblingElement();

    pixelInterceptNode.insertAfter(pixelInterceptNode.firstChildElement("geom:pixel_latitude"), pixelInterceptNode.firstChildElement("geom:reference_pixel_location"));
    pixelInterceptNode2.insertAfter(pixelInterceptNode2.firstChildElement("geom:pixel_latitude"), pixelInterceptNode2.firstChildElement("geom:reference_pixel_location"));
    pixelInterceptNode3.insertAfter(pixelInterceptNode3.firstChildElement("geom:pixel_latitude"), pixelInterceptNode3.firstChildElement("geom:reference_pixel_location"));
    pixelInterceptNode4.insertAfter(pixelInterceptNode4.firstChildElement("geom:pixel_latitude"), pixelInterceptNode4.firstChildElement("geom:reference_pixel_location"));
    
    pixelInterceptNode2.setTagName("geom:Pixel_Intercept");
    pixelInterceptNode3.setTagName("geom:Pixel_Intercept");
    pixelInterceptNode4.setTagName("geom:Pixel_Intercept");
  }
  else {
  QStringList xmlPathFootprint;
  xmlPathFootprint << "Observation_Area"
                   << "Discipline_Area"
                   << "geom:Geometry"
                   << "geom:Geometry_Orbiter"
                   << "geom:Surface_Geometry"
                   << "geom:Surface_Geometry_Specific"
                   << "geom:Footprint_Vertices";
    QDomElement footprintNode = process.getElement(xmlPathFootprint, observationNode);
    footprintNode.parentNode().removeChild(footprintNode);
  }

  QString outFile = ui.GetFileName("TO");

  process.WritePds4(outFile);
  tgocassisrdrgen(ui);
}
 No newline at end of file
+249 −0
Original line number Diff line number Diff line
/** This is free and unencumbered software released into the public domain.

The authors of ISIS do not claim copyright on the contents of this file.
For more details about the LICENSE terms and the AUTHORS, you will
find files of those names at the top level of this repository. **/

/* SPDX-License-Identifier: CC0-1.0 */

#include "tgocassisrdrgen.h"

#include <QRegularExpression>
#include <QString>
#include <QDomDocument>

#include "Application.h"
#include "Cube.h"
#include "ExportDescription.h"
#include "FileName.h"
#include "iTime.h"
#include "Process.h"
#include "ProcessExportPds4.h"
#include "Pvl.h"
#include "PvlKeyword.h"
#include "PvlToXmlTranslationManager.h"


using namespace std;

namespace Isis {
  void tgocassisrdrgen(UserInterface &ui) {
    Cube icube;
    
    // Check if input file is indeed, a cube
    if (ui.GetFileName("FROM").right(3) != "cub") {
      QString msg = "Input file [" + ui.GetFileName("FROM") +
                  "] does not appear to be a cube";
      throw  IException(IException::User, msg, _FILEINFO_);
    }
    
    CubeAttributeInput inAtt = ui.GetInputAttribute("FROM");
    if (inAtt.bands().size() != 0) {
        icube.setVirtualBands(inAtt.bands());
    }

    icube.open(ui.GetFileName("FROM"), "r");
    tgocassisrdrgen(&icube, ui);
  }

  void tgocassisrdrgen(Cube *icube, UserInterface &ui) {
    // Setup the process and set the input cube
    ProcessExportPds4 process;
    process.SetInputCube(icube);

    PvlObject *label= icube->label();

    PvlGroup targetGroup;
    QString logicalId = "urn:esa:psa:em16_tgo_cas:";

    if ( label->findObject("IsisCube").hasGroup("Instrument") ) {
      targetGroup = label->findObject("IsisCube").findGroup("Instrument");
      if (label->findObject("IsisCube").hasGroup("Mapping")) {
        logicalId += "data_projected:";
      }
      else {
        logicalId += "data_raw:";
      }
    }
    else if ( label->findObject("IsisCube").hasGroup("Mosaic") ) {
      targetGroup = label->findObject("IsisCube").findGroup("Mosaic");
      logicalId += "data_derived:";
    }

    // Check if the cube is able to be translated into a CaSSIS xml file
    // This could very well be unnecessary
    if (!targetGroup.findKeyword("InstrumentId").isEquivalent("CaSSIS")) {
      QString msg = "Input file [" + ui.GetFileName("FROM") +
                  "] does not appear to be a CaSSIS RDR product. The image" +
                  "instrument is not the CaSSIS instrument";
      throw  IException(IException::User, msg, _FILEINFO_);
    }

    // Add the ProductId keyword for translation. If a product id is not specified
    // by the user, set it to the Observation Id.
    // This is added before the translation instead of adding it to the exported xml
    // because of the ease of editing pvl vs xml.
    PvlKeyword productId("ProductId");
    if ( ui.WasEntered("PRODUCTID") ) {
      productId.setValue( ui.GetString("PRODUCTID") );
    }
    else {
      // Get the observationId from the Archive Group, or the Mosaic group, if the input is a mosaic
      QString observationId;

      if (label->findObject("IsisCube").hasGroup("Mosaic")) {
        PvlGroup mosaicGroup = label->findObject("IsisCube").findGroup("Mosaic");
        observationId = mosaicGroup.findKeyword("ObservationId")[0];
      }
      else if(label->findObject("IsisCube").hasGroup("Archive")){
        PvlGroup archiveGroup = label->findObject("IsisCube").findGroup("Archive");
        observationId = archiveGroup.findKeyword("ObservationId")[0];
      }
      productId.setValue(observationId);
    }

    targetGroup.addKeyword(productId);
    logicalId += productId[0];
    process.setLogicalId(logicalId);

    // For a mosaic, calculate stitched browse LID (lidvid)
    // This is as follows:
    // StartTime of the first framelet, rounded down to the nearest second
    if (label->findObject("IsisCube").hasGroup("Mosaic")) {
      QString startTime = label->findObject("IsisCube").findGroup("Mosaic").findKeyword("StartTime");
      startTime = iTime(startTime).UTC(0).toLower().remove("-").remove(":");

      // StopTime of the last framelet, rounded down to the nearest second + 4 seconds
      QString stopTime = label->findObject("IsisCube").findGroup("Mosaic").findKeyword("StopTime");
      stopTime = (iTime(iTime(stopTime).UTC(0)) + 4).UTC().toLower().remove("-").remove(":");

      // UID
      QString UID = label->findObject("IsisCube").findGroup("Archive").findKeyword("UID");
      // FilterName
      QString filterName = QString(label->findObject("IsisCube").findGroup("BandBin").
                                  findKeyword("FilterName")).toLower();

      QString lid = QString("urn:esa:psa:em16_tgo_cas:data_calibrated:cas_cal_sc_%1-%2-%3-%4-sti").arg(startTime)
                            .arg(stopTime).arg(filterName).arg(UID);

      label->findObject("IsisCube").findGroup("Archive").addKeyword(PvlKeyword("LID", lid));
    }

    // Set Title
    if ( ui.WasEntered("TITLE") ) {
      process.setTitle( ui.GetString("TITLE") );
    }

    // Set Version ID
    if ( ui.WasEntered("VERSIONID") ) {
      process.setVersionId( ui.GetString("VERSIONID") );
    }

    process.setPixelDescription("Pixel values are in units of I/F (intensity/flux). I/F is defined as"
                                "the ratio of the observed radiance and the radiance of a 100% "
                                "lambertian reflector with the sun and camera orthogonal to the "
                                "observing surface.");

    // std PDS4 label
    process.StandardPds4Label();

    // Add PSA-specific schema
    process.addSchema("PDS4_PSA_1000.xsd",
                      "xmlns:psa",
                      "http://psa.esa.int/psa/v1");

    // Add CaSSIS-specific schema
    process.addSchema("PDS4_PSA_EM16_CAS_1000.xsd",
                      "xmlns:cas",
                      "http://psa.esa.int/psa/em16/cas/v1");

    // Add geometry schema for mosaics
    if (label->findObject("IsisCube").hasGroup("Mosaic")) {
      process.addSchema("PDS4_GEOM_1B00_1610.sch",
                        "PDS4_GEOM_1B00_1610.xsd",
                        "xmlns:geom",
                        "http://pds.nasa.gov/pds4/geom/v1");
    }

   /*
    * Add additional pds label data here
    */
    QDomDocument &pdsLabel = process.GetLabel();

    // The default translation for for non-mosaicked output
    QString exportTranslationFile = "$ISISROOT/appdata/translations/TgoCassisExport.trn";

    if (label->findObject("IsisCube").hasGroup("Mosaic")) {
      exportTranslationFile = "$ISISROOT/appdata/translations/TgoCassisExportMosaic.trn";
    }

    Pvl *labelPvl = icube->label();

    PvlToXmlTranslationManager cubeLab(*labelPvl, exportTranslationFile);
    cubeLab.Auto(pdsLabel);

    ProcessExportPds4::translateUnits(pdsLabel);
    process.reorder();

    // Units are automatically translated for the focal length, and there is no way at this time to
    // turn it off, but the cas:CASSIS_Data standard specifies that the focal-length output may not
    // have units, so remove the units from cas:focal length.
    QDomDocument &pdsLabelNext = process.GetLabel();
    QDomElement observationNode = pdsLabelNext.documentElement().firstChildElement("Observation_Area");
    QStringList xmlPath;
    xmlPath << "Observation_Area"
            << "Mission_Area"
            << "cas:CASSIS_Data"
            << "cas:telescope_information"
            << "cas:focal_length";
    QDomElement focalLengthNode = process.getElement(xmlPath, observationNode);

    if (focalLengthNode.hasAttribute("unit")) {
      focalLengthNode.removeAttribute("unit");
    }

    // Fix the footprint section's output structure
    QStringList xmlPath2;
    xmlPath2 << "Observation_Area"
            << "Discipline_Area"
            << "geom:Geometry"
            << "geom:Geometry_Orbiter"
            << "geom:Surface_Geometry"
            << "geom:Surface_Geometry_Specific"
            << "geom:Footprint_Vertices"
            << "geom:Pixel_Intercept";
    QDomElement pixelInterceptNode = process.getElement(xmlPath2, observationNode);

    if(pixelInterceptNode.hasChildNodes()) {
      QDomElement pixelInterceptNode2 = pixelInterceptNode.nextSiblingElement();
      QDomElement pixelInterceptNode3 = pixelInterceptNode2.nextSiblingElement();
      QDomElement pixelInterceptNode4 = pixelInterceptNode3.nextSiblingElement();

      pixelInterceptNode.insertAfter(pixelInterceptNode.firstChildElement("geom:pixel_latitude"), pixelInterceptNode.firstChildElement("geom:reference_pixel_location"));
      pixelInterceptNode2.insertAfter(pixelInterceptNode2.firstChildElement("geom:pixel_latitude"), pixelInterceptNode2.firstChildElement("geom:reference_pixel_location"));
      pixelInterceptNode3.insertAfter(pixelInterceptNode3.firstChildElement("geom:pixel_latitude"), pixelInterceptNode3.firstChildElement("geom:reference_pixel_location"));
      pixelInterceptNode4.insertAfter(pixelInterceptNode4.firstChildElement("geom:pixel_latitude"), pixelInterceptNode4.firstChildElement("geom:reference_pixel_location"));
      
      pixelInterceptNode2.setTagName("geom:Pixel_Intercept");
      pixelInterceptNode3.setTagName("geom:Pixel_Intercept");
      pixelInterceptNode4.setTagName("geom:Pixel_Intercept");
    }
    else {
    QStringList xmlPathFootprint;
    xmlPathFootprint << "Observation_Area"
                     << "Discipline_Area"
                     << "geom:Geometry"
                     << "geom:Geometry_Orbiter"
                     << "geom:Surface_Geometry"
                     << "geom:Surface_Geometry_Specific"
                     << "geom:Footprint_Vertices";
      QDomElement footprintNode = process.getElement(xmlPathFootprint, observationNode);
      footprintNode.parentNode().removeChild(footprintNode);
    }

    QString outFile = ui.GetFileName("TO");

    process.WritePds4(outFile);
  }
}
+20 −0
Original line number Diff line number Diff line
/** This is free and unencumbered software released into the public domain.

The authors of ISIS do not claim copyright on the contents of this file.
For more details about the LICENSE terms and the AUTHORS, you will
find files of those names at the top level of this repository. **/

/* SPDX-License-Identifier: CC0-1.0 */

#ifndef tgocassisrdrgen_h
#define tgocassisrdrgen_h

#include "Cube.h"
#include "UserInterface.h"

namespace Isis{
  extern void tgocassisrdrgen(Cube *icube, UserInterface &ui);
  extern void tgocassisrdrgen(UserInterface &ui);
}

#endif
 No newline at end of file