Unverified Commit 454a3baa authored by AustinSanders's avatar AustinSanders Committed by GitHub
Browse files

Adds support for PSA compliant labels for TGO (#4631)



* Updated translation files to support PSA compliant labels

* Added logic to support PSA labels

* Test data for PSA labels

* Added a test for PSA labels

Co-authored-by: default avatarAustin Sanders <arsanders@ugs.gov>
parent b962201a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ End_Group

Group = ExposureDuration
  Auto
  Optional
  InputPosition        = (Observation_Area, Discipline_Area, img:Imaging, img:Imaging_Instrument_Parameters)
  InputKey             = img:exposure_duration
  OutputName           = ExposureDuration
+169 −0
Original line number Diff line number Diff line
# Translates CaSSIS xml labels into the Instrument PvlGroup values
# for the ingested ISIS cube labels.
#
# The Dependencies keyword specifies a tag or attribute at the same level as
# the InputKey that uniquely identifies the InputKey.
#
# Consider the following translation group and xml
#
# Group = Samples
#   Auto
#   InputPosition  = (Array_2D_Image, Axis_Array)
#   Dependencies   = "tag@axis_name|Sample"
#   InputKey       = elements
#   OutputName     = Samples
#   OutputPosition = (Group, Dimensions)
#   Translation    = (*, *)
# End_Group
#
# <Array_2D_Image>
#   <Axis_Array>
#     <axis_name>Line</axis_name>
#     <sequence_number>1</sequence_number>
#     <elements>2048</elements>
#   </Axis_Array>
#   <Axis_Array>
#     <axis_name>Sample</axis_name>
#     <sequence_number>2</sequence_number>
#     <elements>279</elements>
#   </Axis_Array>
# </Array_2D_Image>
#
# There are two Axis_Array tags below Array_2D_Image and both of them have an
# elements tag.  So, the Dependencies keyword specifies to take the value of
# the elements tag under the second Axis_Array array tag because it also has a
# axis_name tag with a value of Sample.
#
#
# This translation table is for translating CaSSIS xml labels into pvl cube
# labels.
#
# See $ISISROOT/appdata/translations/XmlExample.trn for an example xml translation table
# and documentation for the different options.
#
# history 2018-05-17 Kaitlyn Lee - Added ObservationId with a placeholder value for now.

Group = SpacecraftName
  Auto
  InputPosition        = (Observation_Area, Observing_System, Observing_System_Component)
  InputKeyDependencies = "tag@type|Host"
  InputKey             = name
  OutputName           = SpacecraftName
  OutputPosition       = (Object,IsisCube,Group,Instrument)
  Translation          = (*, *)
End_Group



Group = InstrumentId
  Auto
  InputPosition        = (Observation_Area, Observing_System, Observing_System_Component)
  InputKeyDependencies = "tag@type|Instrument"
  InputKey             = name
  OutputName           = InstrumentId
  OutputPosition       = (Object,IsisCube,Group,Instrument)
  Translation          = (*, *)
End_Group

Group = Expanded
  Auto
  InputDefault         = 1
  InputPosition        = (Observation_Area, Observing_System, Observing_System_Component)
  InputKeyDependencies = "tag@type|Host"
  InputKey             = name
  OutputName           = Expanded
  OutputPosition       = (Object,IsisCube,Group,Instrument)
  Translation          = (1, *)
End_Group

Group = ObservationId
  Auto
  InputPosition      = (Identification_Area, Alias_List, Alias)
  InputKey           = alternate_id
  OutputName         = ObservationId
  OutputPosition     = (Object, IsisCube, Group, Archive)
  Translation        = (*, *)
End_Group

Group = TargetName
  Auto
  InputPosition        = (Observation_Area, Target_Identification)
  InputKey             = name
  OutputName           = TargetName
  OutputPosition       = (Object,IsisCube,Group,Instrument)
  Translation          = (*, *)
End_Group

Group = StartTime
  Auto
  InputPosition        = (Observation_Area, Time_Coordinates)
  InputKey             = start_date_time
  OutputName           = StartTime
  OutputPosition       = (Object,IsisCube,Group,Instrument)
  Translation          = (*, *)
End_Group

Group = ExposureDuration
  Auto
  InputPosition        = (Observation_Area, Mission_Area, em16_tgo_cas:Cassis_Data, em16_tgo_cas:PEHK_Derived_Data)
  InputKey             = em16_tgo_cas:exposure_time
  OutputName           = ExposureDuration
  OutputPosition       = (Object, IsisCube, Group, Instrument)
  Translation          = (*, *)
End_Group

Group = Filter
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, img:Imaging, img:Optical_Filter)
  InputKey             = img:filter_name
  OutputName           = Filter
  OutputPosition       = (Object,IsisCube,Group,Instrument)
  Translation          = (*, *)
End_Group

Group = FilterName
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, img:Imaging, img:Optical_Filter)
  InputKey             = img:filter_name
  OutputName           = Filter
  OutputPosition       = (Object,IsisCube,Group,BandBin)
  Translation          = (*, *)
End_Group

Group = Center
  Auto
  InputPosition  = (Observation_Area, Discipline_Area, img:Imaging, img:Optical_Filter)
  InputKey       = img:filter_name
  OutputName     = Center
  OutputPosition = (Object, IsisCube, Group, BandBin)
  Translation    = (675, PAN)
  Translation    = (485, BLU)
  Translation    = (840, RED)
  Translation    = (985, NIR)

End_Group

Group = Width
  Auto
  InputPosition  = (Observation_Area, Discipline_Area, img:Imaging, img:Optical_Filter)
  InputKey       = img:filter_name
  OutputName     = Width
  OutputPosition = (Object, IsisCube, Group, BandBin)
  Translation    = (250, PAN)
  Translation    = (165, BLU)
  Translation    = (100, RED)
  Translation    = (220, NIR)

End_Group

Group = Expanded
  Auto
  Optional
  InputPosition        = (CaSSIS_Header, DERIVED_HEADER_DATA)
  InputKey             = Expanded
  OutputName           = Expanded
  OutputPosition       = (Object, IsisCube, Group, Instrument)
  Translation          = (*, *)
End_Group

End
+195 −0
Original line number Diff line number Diff line
# Translates CaSSIS xml labels into the Mapping PvlGroup values
# for the ingested ISIS cube labels.
#
# The Dependencies keyword specifies a tag or attribute at the same level as
# the InputKey that uniquely identifies the InputKey.
#
# Consider the following translation group and xml
#
# Group = Samples
#   Auto
#   InputPosition  = (Array_2D_Image, Axis_Array)
#   Dependencies   = "tag@axis_name|Sample"
#   InputKey       = elements
#   OutputName     = Samples
#   OutputPosition = (Group, Dimensions)
#   Translation    = (*, *)
# End_Group
#
# <Array_2D_Image>
#   <Axis_Array>
#     <axis_name>Line</axis_name>
#     <sequence_number>1</sequence_number>
#     <elements>2048</elements>
#   </Axis_Array>
#   <Axis_Array>
#     <axis_name>Sample</axis_name>
#     <sequence_number>2</sequence_number>
#     <elements>279</elements>
#   </Axis_Array>
# </Array_2D_Image>
#
#
# history 2018-08-09 Jeannie Backer - Changed group name from MapProjection
#                        to ProjectionName.

Group = ProjectionName
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Map_Projection)
  InputKey             = cart:map_projection_name
  OutputName           = ProjectionName
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = CenterLongitude
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Map_Projection, cart:Equirectangular)
  InputKey             = cart:longitude_of_central_meridian
  OutputName           = CenterLongitude
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = CenterLatitude
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Map_Projection, cart:Equirectangular)
  InputKey             = cart:latitude_of_projection_origin
  OutputName           = CenterLatitude
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

# input has different scales for x and y, but ISIS doesn't distinguish, so use x
Group = Scale
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Planar_Coordinate_Information, cart:Coordinate_Representation)
  InputKey             = cart:pixel_scale_x
  OutputName           = Scale
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

# input has different pixel resolutions for x and y, but ISIS doesn't distinguish, so use x
Group = PixelResolution
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Planar_Coordinate_Information, cart:Coordinate_Representation)
  InputKey             = cart:pixel_resolution_x
  OutputName           = PixelResolution
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = MaximumLatitude
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Domain, cart:Bounding_Coordinates)
  InputKey             = cart:north_bounding_coordinate
  OutputName           = MaximumLatitude
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = MinimumLatitude
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Domain, cart:Bounding_Coordinates)
  InputKey             = cart:south_bounding_coordinate
  OutputName           = MinimumLatitude
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = MaximumLongitude
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Domain, cart:Bounding_Coordinates)
  InputKey             = cart:west_bounding_coordinate
  OutputName           = MaximumLongitude
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = MinimumLongitude
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Domain, cart:Bounding_Coordinates)
  InputKey             = cart:east_bounding_coordinate
  OutputName           = MinimumLongitude
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = UpperLeftCornerX
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Geo_Transformation)
  InputKey             = cart:upperleft_corner_x
  OutputName           = UpperLeftCornerX
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = UpperLeftCornerY
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Planar, cart:Geo_Transformation)
  InputKey             = cart:upperleft_corner_y
  OutputName           = UpperLeftCornerY
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = EquatorialRadius
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Geodetic_Model)
  InputKey             = cart:a_axis_radius
  OutputName           = EquatorialRadius
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = PolarRadius
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Geodetic_Model)
  InputKey             = cart:c_axis_radius
  OutputName           = PolarRadius
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

Group = LatitudeType
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Geodetic_Model)
  InputKey             = cart:latitude_type
  OutputName           = LatitudeType
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (Planetocentric, planetocentric)
  Translation          = (*, *)
End_Group

Group = LongitudeDirection
  Auto
  InputPosition        = (Observation_Area, Discipline_Area, cart:Cartography, cart:Spatial_Reference_Information, cart:Horizontal_Coordinate_System_Definition, cart:Geodetic_Model)
  InputKey             = cart:longitude_direction
  OutputName           = LongitudeDirection
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (PositiveEast, "Positive East")
  Translation          = (PositiveWest, "Positive West")
End_Group

Group = TargetName
  Auto
  InputPosition        = (Observation_Area, Target_Identification)
  InputKey             = name
  OutputName           = TargetName
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

# Does not exist in xml label
Group = LongitudeDomain
  Auto
  InputDefault         = 360
  InputPosition        = (Nothing, Nothing)
  InputKey             = Nothing
  OutputName           = LongitudeDomain
  OutputPosition       = (Object,IsisCube,Group,Mapping)
  Translation          = (*, *)
End_Group

End
+28 −13
Original line number Diff line number Diff line
@@ -56,8 +56,16 @@ namespace Isis {
      Cube *outputCube = importer.SetOutputCube(ui.GetFileName("TO"), att);

      QString transRawFile = "TgoCassisInstrument.trn";
      QString transExportFile = "TgoCassisExportedInstrument.trn";

      QFile xmlFile(xmlFileName.expanded());
      QDomDocument xmlDoc;
      xmlDoc.setContent(&xmlFile, true);
      // If any instances of "Optical_Filter" exist, use PSA .trn file
      QString transExportFile;
      if (xmlDoc.elementsByTagName("Optical_Filter").size()){
        transExportFile = "TgoCassisExportedInstrument_PSA.trn";
      } else {
        transExportFile = "TgoCassisExportedInstrument.trn";
      }
      // first assume lev1b image
      Pvl *outputLabel = outputCube->label();
      QString target = "";
@@ -189,8 +197,16 @@ namespace Isis {
    //Translate the Mapping Group
    try {
      QString missionDir = "$ISISROOT/appdata/translations/";
      FileName mapTransFile(missionDir + "TgoCassisMapping.trn");

      QDomDocument xmlDoc;
      QFile xmlFile(xmlFileName.expanded());
      xmlDoc.setContent(&xmlFile, true);
      // If any instances of "Observing_System_Component" exist, use PSA .trn file
      FileName mapTransFile;
      if (xmlDoc.elementsByTagName("cart:a_axis_radius").size()){
        mapTransFile = FileName(missionDir + "TgoCassisMapping_PSA.trn");
      } else {
        mapTransFile = FileName(missionDir + "TgoCassisMapping.trn");
      }
      // Get the translation manager ready for translating the mapping label

      XmlToPvlTranslationManager labelXMappinglater(xmlFileName, mapTransFile.expanded());
@@ -309,8 +325,9 @@ namespace Isis {
    PvlGroup &inst = outputLabel->findGroup("Instrument", Pvl::Traverse);

    // Add units of measurement to keywords from translation table
    if (inst.hasKeyword("ExposureDuration")){
      inst.findKeyword("ExposureDuration").setUnits("seconds");

    }
    // Translate BandBin group
    FileName bandBinTransFile(missionDir + "TgoCassisBandBin.trn");
    XmlToPvlTranslationManager bandBinXlater(inputLabel, bandBinTransFile.expanded());
@@ -514,5 +531,3 @@ namespace Isis {

  }
}

+89 −31
Original line number Diff line number Diff line
@@ -506,3 +506,61 @@ TEST(TgoCassis2Isis, TgoCassis2IsisTestReingestedProj) {
  EXPECT_EQ(hist->ValidPixels(), 226);
  EXPECT_NEAR(hist->StandardDeviation(), 0.0031668801306310155, 0.0001);
}


TEST(TgoCassis2Isis, TgoCassis2IsisTestPSALabel) {
  QTemporaryDir prefix;
  QString cubeFileName = prefix.path() + "/psa.cub";
  QVector<QString> args = {"from=data/tgoCassis/tgocassis2isis/MY36_015782_024_0_PAN_cropped.xml",
                           "to=" + cubeFileName };
  UserInterface options(APP_XML, args);

  try {
    tgocassis2isis(options);
  }
  catch (IException &e) {
    FAIL() << "Unable to ingest image: " << e.toString().toStdString().c_str() << std::endl;
  }
  Cube cube(cubeFileName);
  Pvl *isisLabel = cube.label();

  // Dimensions Group
  EXPECT_EQ(cube.sampleCount(), 500);
  EXPECT_EQ(cube.lineCount(), 3);
  EXPECT_EQ(cube.bandCount(), 1);

  // Instrument Group
  PvlGroup &inst = isisLabel->findGroup("Instrument", Pvl::Traverse);
  EXPECT_EQ(inst["SpacecraftName"][0].toStdString(), "TRACE GAS ORBITER");
  EXPECT_EQ(inst["InstrumentId"][0].toStdString(), "CaSSIS");
  EXPECT_EQ(inst["TargetName"][0].toStdString(), "Mars" );
  EXPECT_EQ(inst["StartTime"][0].toStdString(), "2021-06-07T00:31:03.723");
  EXPECT_EQ(inst["ExposureDuration"][0].toStdString(), "1.018e-003");
  EXPECT_EQ(int(inst["SummingMode"]), 0);
  EXPECT_EQ(inst["Filter"][0].toStdString(), "PAN");

  // Archive Group
  PvlGroup &archive = isisLabel->findGroup("Archive", Pvl::Traverse);
  EXPECT_EQ(archive["ObservationId"][0].toStdString(), "MY36_015782_024_0");
  EXPECT_EQ(archive["ProductVersionId"][0].toStdString(), "1.0");
  EXPECT_EQ(archive["ScalingFactor"][0].toStdString(), "1.0");
  EXPECT_EQ(archive["YearDoy"][0].toStdString(), "2021158");

  // BandBin Group
  PvlGroup &bandbin = isisLabel->findGroup("BandBin", Pvl::Traverse);
  EXPECT_EQ(bandbin["FilterName"][0].toStdString(), "PAN");
  EXPECT_DOUBLE_EQ(double(bandbin["Center"]), 675);
  EXPECT_DOUBLE_EQ(double(bandbin["Width"]), 250);
  EXPECT_EQ(bandbin["NaifIkCode"][0].toStdString(), "-143421");

  // Kernels Group
  PvlGroup &kernels = isisLabel->findGroup("Kernels", Pvl::Traverse);
  EXPECT_EQ(int(kernels["NaifFrameCode"]), -143400);

  Histogram *hist = cube.histogram();

  EXPECT_NEAR(hist->Average(), 0.2833722, 0.0000001);
  EXPECT_DOUBLE_EQ(hist->Sum(), 326.72824501991272);
  EXPECT_EQ(hist->ValidPixels(), 1153);
  EXPECT_NEAR(hist->StandardDeviation(), 0.001798, 0.000001);
}
Loading