From 549a9041186b1747d3212232aa9c7bd2c9f2bf9c Mon Sep 17 00:00:00 2001
From: Amy Stamile <74275278+amystamile-usgs@users.noreply.github.com>
Date: Tue, 29 Oct 2024 10:13:58 -0700
Subject: [PATCH] Adds Chandrayaan2 to isisimport (#5648)

* Adds chandrayaan2 to isisimport

* Addressed PR feedback
---
 CHANGELOG.md                                  |   1 +
 isis/appdata/import/PDS4/Chandrayaan2TMC2.tpl |  96 ++++++++++
 isis/appdata/import/fileTemplate.tpl          |   5 +
 isis/src/base/apps/isisimport/isisimport.cpp  |  12 ++
 .../FunctionalTestsIsisImportChandrayaan2.cpp | 175 ++++++++++++++++++
 ..._tmc_nca_20191128T0035389755_b_brw_d18.xml |  91 +++++++++
 6 files changed, 380 insertions(+)
 create mode 100644 isis/appdata/import/PDS4/Chandrayaan2TMC2.tpl
 create mode 100644 isis/tests/FunctionalTestsIsisImportChandrayaan2.cpp
 create mode 100644 isis/tests/data/isisimport/chan2/ch2_tmc_nca_20191128T0035389755_b_brw_d18.xml

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6edf242875..afc29fcea2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ release.
 - Added TOVECT output parameter which generate a geospatial CSV file with a VRT metadata sidecar file [#5571](https://github.com/DOI-USGS/ISIS3/issues/5571)  
 - Added Vectorize to ProcessGroundPolygon library
 - Added gtest files for the app and unit test 
+- Added Chandrayaan2 template for isisimport
 
 ### Changed
 - Refactored the pixel2map app
diff --git a/isis/appdata/import/PDS4/Chandrayaan2TMC2.tpl b/isis/appdata/import/PDS4/Chandrayaan2TMC2.tpl
new file mode 100644
index 0000000000..dd05ce68a7
--- /dev/null
+++ b/isis/appdata/import/PDS4/Chandrayaan2TMC2.tpl
@@ -0,0 +1,96 @@
+{% set file_name = Product_Observational.File_Area_Observational.File.file_name %}
+{% set sensor = FindCH2Sensor(file_name) %}
+
+{% set ImageArray = Product_Observational.File_Area_Observational.Array_2D_Image %}
+
+Object = IsisCube
+  Object = Core
+    Group = Dimensions
+      Samples = {{ ImageArray.Axis_Array.0.elements }}
+      Lines   = {{ ImageArray.Axis_Array.1.elements }}
+      Bands   = 1
+    End_Group
+
+    Group = Pixels
+      {% set pixelType = ImageArray.Element_Array.data_type %}
+      {% if exists("Product_Observational.File_Area_Observational.Array_2D_Image.Element_Array.data_type") %}
+      Type       = {% if pixelType == "IEEE754LSBDouble" %} Double
+                   {% else if pixelType == "IEEE754LSBSingle" %} Real
+                   {% else if pixelType == "IEEE754MSBDouble" %} Double
+                   {% else if pixelType == "IEEE754MSBSingle" %} Real
+                   {% else if pixelType == "SignedByte" %} SignedByte
+                   {% else if pixelType == "SignedLSB2" %} SignedWord
+                   {% else if pixelType == "SignedLSB4" %} SignedInteger
+                   {% else if pixelType == "SignedMSB2" %} SignedWord
+                   {% else if pixelType == "SignedMSB4" %} SignedInteger
+                   {% else if pixelType == "UnsignedByte" %} UnsignedByte
+                   {% else if pixelType == "UnsignedLSB2" %} UnsignedWord
+                   {% else if pixelType == "UnsignedLSB4" %} UnsignedInteger
+                   {% else if pixelType == "UnsignedMSB2" %} UnsignedWord
+                   {% else if pixelType == "UnsignedMSB4" %} UnsignedInteger
+                   {% else %} Real
+                   {% endif %}
+      ByteOrder  = {% if pixelType == "IEEE754LSBDouble" %} LSB
+                   {% else if pixelType == "IEEE754LSBSingle" %} LSB
+                   {% else if pixelType == "IEEE754MSBDouble" %} MSB
+                   {% else if pixelType == "IEEE754MSBSingle" %} MSB
+                   {% else if pixelType == "SignedByte" %} LSB
+                   {% else if pixelType == "SignedLSB2" %} LSB
+                   {% else if pixelType == "SignedLSB4" %} LSB
+                   {% else if pixelType == "SignedMSB2" %} MSB
+                   {% else if pixelType == "SignedMSB4" %} MSB
+                   {% else if pixelType == "UnsignedByte" %} LSB
+                   {% else if pixelType == "UnsignedLSB2" %} LSB
+                   {% else if pixelType == "UnsignedLSB4" %} LSB
+                   {% else if pixelType == "UnsignedMSB2" %} MSB
+                   {% else if pixelType == "UnsignedMSB4" %} MSB
+                   {% else %} Lsb
+                   {% endif %}
+      {% else %}
+      Type       = Real
+      ByteOrder  = Lsb
+      {% endif %}
+
+      Base       = {% if exists("Product_Observational.File_Area_Observational.Array_2D_Image.Element_Array.value_offset") %}
+                   {{ ImageArray.Element_Array.value_offset }}
+                   {% else if exists("Product_Observational.File_Area_Observational.Array_2D_Image.offset._text") %}
+                   {{ ImageArray.offset._text }}
+                   {% else %}
+                   0
+                   {% endif %}
+      Multiplier = {% if exists("Product_Observational.File_Area_Observational.Array_2D_Image.Element_Array.scaling_factor") %}
+                   {{ ImageArray.Element_Array.scaling_factor._text }}
+                   {% else %}
+                   1
+                   {% endif %}
+    End_Group
+  End_Object
+
+  Group = Instrument
+    SpacecraftName            = {{ Product_Observational.Observation_Area.Investigation_Area.name }}
+    {% set inst_name = Product_Observational.Observation_Area.Observing_System.Observing_System_Component.1.name %}
+    {% if inst_name == "terrain mapping camera" %}
+    InstrumentId              = TMC-2
+    {% endif %}
+    TargetName                = {{ Product_Observational.Observation_Area.Target_Identification.name }}
+    StartTime                 = {{ RemoveStartTimeZ(Product_Observational.Observation_Area.Time_Coordinates.start_date_time) }}
+    StopTime                  = {{ RemoveStartTimeZ(Product_Observational.Observation_Area.Time_Coordinates.stop_date_time) }}
+  End_Group
+
+  Group = BandBin
+    Center = 675
+    Width = 175
+  End_Group
+
+  Group = Kernels
+    NaifFrameCode = {% if sensor == "a" %}-152212
+                    {% else if sensor == "f" %}-152211
+                    {% else if sensor == "n" %}-152210
+                    {% endif %}
+
+  End_Group
+End_Object
+
+Object = Translation
+End_Object
+End
diff --git a/isis/appdata/import/fileTemplate.tpl b/isis/appdata/import/fileTemplate.tpl
index 94535c6988..61db724210 100644
--- a/isis/appdata/import/fileTemplate.tpl
+++ b/isis/appdata/import/fileTemplate.tpl
@@ -93,6 +93,11 @@
   {%- if InstrumentId == "OSINAC" or InstrumentId == "OSIWAC"-%}
     {%- set InstrumentId="Osiris" -%}
   {%- endif -%}
+{%- else if SpacecraftName == "Chandrayaan-2"-%}
+  {%- set SpacecraftId="Chandrayaan2" -%}
+  {%- if InstrumentId == "terrain mapping camera"-%}
+    {%- set InstrumentId="TMC2" -%}
+  {%- endif -%}
 {%- endif -%}
 
 {#- Combine the pieces to output the file name to be used to import an image into a cube -#}
diff --git a/isis/src/base/apps/isisimport/isisimport.cpp b/isis/src/base/apps/isisimport/isisimport.cpp
index 2c6f2bfb60..71f20d1b05 100644
--- a/isis/src/base/apps/isisimport/isisimport.cpp
+++ b/isis/src/base/apps/isisimport/isisimport.cpp
@@ -341,6 +341,18 @@ namespace Isis {
 
       return inputString.substr(index, 1);
     });
+
+
+   /**
+    * Find sensor type from Chandrayaan2 label's file_name
+    */
+    env.add_callback("FindCH2Sensor", 1, [](Arguments& args) {
+      std::string fileName = args.at(0)->get<string>();
+
+      char sensor = fileName[10];
+
+      return std::string(1, sensor);
+    });
      // end of inja callbacks
 
 
diff --git a/isis/tests/FunctionalTestsIsisImportChandrayaan2.cpp b/isis/tests/FunctionalTestsIsisImportChandrayaan2.cpp
new file mode 100644
index 0000000000..b95d506d43
--- /dev/null
+++ b/isis/tests/FunctionalTestsIsisImportChandrayaan2.cpp
@@ -0,0 +1,175 @@
+#include <iostream>
+#include <time.h>
+
+#include <QRegExp>
+#include <QString>
+#include <QTemporaryDir>
+#include <QTemporaryFile>
+#include <QFileInfo>
+#include <QDataStream>
+#include <QTextStream>
+#include <QByteArray>
+#include <QDataStream>
+
+#include <nlohmann/json.hpp>
+#include "TempFixtures.h"
+#include "Histogram.h"
+#include "md5wrapper.h"
+#include "Pvl.h"
+#include "PvlGroup.h"
+#include "PvlKeyword.h"
+#include "TestUtilities.h"
+#include "isisimport.h"
+#include "gmock/gmock.h"
+
+using namespace Isis;
+using namespace testing;
+using json = nlohmann::json;
+
+static QString APP_XML = FileName("$ISISROOT/bin/xml/isisimport.xml").expanded();
+
+TEST_F(TempTestingFiles, FunctionalTestIsisImportChandrayaan2){
+  std::istringstream PvlInput(R"(
+    Object = IsisCube
+      Object = Core
+        StartByte   = 65537
+        Format      = Tile
+        TileSamples = 128
+        TileLines   = 400
+
+        Group = Dimensions
+          Samples = 17891
+          Lines   = 400
+          Bands   = 1
+        End_Group
+
+        Group = Pixels
+          Type       = UnsignedByte
+          ByteOrder  = Lsb
+          Base       = 0.0
+          Multiplier = 1.0
+        End_Group
+      End_Object
+
+      Group = Instrument
+        SpacecraftName = Chandrayaan-2
+        InstrumentId   = TMC-2
+        TargetName     = Moon
+        StartTime      = 2019-11-28T00:35:38.9755
+        StopTime       = 2019-11-28T00:45:17.9161
+      End_Group
+
+      Group = BandBin
+        Center = 675
+        Width  = 175
+      End_Group
+
+      Group = Kernels
+        NaifFrameCode = -152212
+      End_Group
+    End_Object
+
+    Object = Label
+      Bytes = 65536
+    End_Object
+
+    Object = History
+      Name      = IsisCube
+      StartByte = 7233537
+      Bytes     = 703
+    End_Object
+
+    Object = OriginalXmlLabel
+      Name      = IsisCube
+      StartByte = 7234240
+      Bytes     = 4223
+      ByteOrder = Lsb
+    End_Object
+    End
+  )");
+  QString dataFilePath= "data/isisimport/chan2/ch2_tmc_nca_20191128T0035389755_b_brw_d18.xml";
+  QString dataFileName = "ch2_tmc_nca_20191128T0035389755_b_brw_d18.xml";
+  QString imageFileName = "ch2_tmc_nca_20191128T0035389755_b_brw_d18.img";
+  QString cubeFileName = tempDir.path() + "/output.cub";
+
+  int samples = 400;
+  int lines = 17891;
+  int bytes = 2;
+
+  // create a temp img file and write data to it
+  QFile tempImgFile(tempDir.path() + "/" + imageFileName);
+
+  if(!tempImgFile.open(QFile::WriteOnly | QFile::Text)){
+      FAIL() << " Could not open file for writing";
+  }
+  QDataStream out(&tempImgFile);
+
+  // generate lines
+  QByteArray writeToFile = QByteArray();
+  short int fill = 0;
+  for(int i=-1; i<(samples * bytes); i++){
+    writeToFile.append(fill);
+  }
+
+  // write the lines to the temp file
+  for(int i=0; i<lines; i++){
+    QDataStream out(&tempImgFile);
+    out << writeToFile;
+  }
+  tempImgFile.flush();
+  tempImgFile.close();
+
+  // create a temp data file and copy the contents of the xml in to it
+  QFile tempDataFile(tempDir.path() + "/" + dataFileName);
+
+  if(!tempDataFile.open(QFile::ReadWrite | QFile::Text)){
+      FAIL() << " Could not open file for writing";
+  }
+
+  // open xml to get data
+  QFile realXmlFile(dataFilePath);
+  if (!realXmlFile.open(QIODevice::ReadOnly | QIODevice::Text))
+  {
+      FAIL() << "Failed to open file";
+  }
+
+  QTextStream xmlData(&tempDataFile);
+  xmlData << realXmlFile.readAll();
+
+  tempDataFile.close();
+  realXmlFile.close();
+
+  QFileInfo fileInfo(tempDataFile);
+
+  // testing with template
+  QVector<QString> args = {"from=" + fileInfo.absoluteFilePath(), "to=" + cubeFileName};
+  UserInterface options(APP_XML, args);
+  isisimport(options);
+
+  Pvl truthLabel;
+  PvlInput >> truthLabel;
+
+  Cube outCube(cubeFileName);
+  Pvl *outLabel = outCube.label();
+
+  PvlGroup truthGroup = truthLabel.findGroup("Dimensions", Pvl::Traverse);
+  PvlGroup &outGroup = outLabel->findGroup("Dimensions", Pvl::Traverse);
+  EXPECT_PRED_FORMAT2(AssertPvlGroupEqual, outGroup, truthGroup);
+
+  truthGroup = truthLabel.findGroup("Pixels", Pvl::Traverse);
+  outGroup = outLabel->findGroup("Pixels", Pvl::Traverse);
+  EXPECT_PRED_FORMAT2(AssertPvlGroupEqual, outGroup, truthGroup);
+
+  truthGroup = truthLabel.findGroup("Instrument", Pvl::Traverse);
+  outGroup = outLabel->findGroup("Instrument", Pvl::Traverse);
+  EXPECT_PRED_FORMAT2(AssertPvlGroupEqual, outGroup, truthGroup);
+
+  truthGroup = truthLabel.findGroup("BandBin", Pvl::Traverse);
+  outGroup = outLabel->findGroup("BandBin", Pvl::Traverse);
+  EXPECT_PRED_FORMAT2(AssertPvlGroupEqual, outGroup, truthGroup);
+
+  truthGroup = truthLabel.findGroup("Kernels", Pvl::Traverse);
+  outGroup = outLabel->findGroup("Kernels", Pvl::Traverse);
+  EXPECT_PRED_FORMAT2(AssertPvlGroupEqual, outGroup, truthGroup);
+
+}
\ No newline at end of file
diff --git a/isis/tests/data/isisimport/chan2/ch2_tmc_nca_20191128T0035389755_b_brw_d18.xml b/isis/tests/data/isisimport/chan2/ch2_tmc_nca_20191128T0035389755_b_brw_d18.xml
new file mode 100644
index 0000000000..f03cd63916
--- /dev/null
+++ b/isis/tests/data/isisimport/chan2/ch2_tmc_nca_20191128T0035389755_b_brw_d18.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><Product_Observational xmlns="http://pds.nasa.gov/pds4/pds/v1" xmlns:disp="http://pds.nasa.gov/pds4/disp/v1" xmlns:pds="http://pds.nasa.gov/pds4/pds/v1" xmlns:sp="http://pds.nasa.gov/pds4/sp/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pds.nasa.gov/pds4/pds/v1 http://pds.nasa.gov/pds4/pds/v1/PDS4_PDS_1B00.xsd       http://pds.nasa.gov/pds4/disp/v1 http://pds.nasa.gov/pds4/disp/v1/PDS4_DISP_1301.xsd      http://pds.nasa.gov/pds4/sp/v1 http://pds.nasa.gov/pds4/sp/v1/PDS4_SP_1100.xsd">
+    <Identification_Area>
+        <logical_identifier>urn:isro:isda:ch2_cho.tmc:data_calibrated:ch2_tmc_nca_20191128t0035389755_b_brw_d18</logical_identifier>
+        <version_id>1.0</version_id>
+        <title>Chandrayaan-2 Orbiter TMC 2 Experiment</title>
+        <information_model_version>1.11.0.0</information_model_version>
+        <product_class>Product_Observational</product_class>
+        <Modification_History>
+            <Modification_Detail>
+                <modification_date>2019-05-07</modification_date>
+                <version_id>1.0</version_id>
+                <description>PDS4 product label created by SAC Optical DP Team</description>
+            </Modification_Detail>
+        </Modification_History>
+    </Identification_Area>
+    <Observation_Area>
+        <Time_Coordinates>
+            <start_date_time>2019-11-28T00:35:38.9755Z</start_date_time>
+            <stop_date_time>2019-11-28T00:45:17.9161Z</stop_date_time>
+        </Time_Coordinates>
+        <Primary_Result_Summary>
+            <purpose>Science</purpose>
+	    <processing_level>Calibrated</processing_level>
+	</Primary_Result_Summary>
+        <Investigation_Area>
+            <name>Chandrayaan-2</name>
+            <type>Mission</type>
+            <Internal_Reference>
+                <lidvid_reference>urn:isro:isda:context:investigation:mission.chandrayaan2::1.0</lidvid_reference>
+                <reference_type>data_to_investigation</reference_type>
+            </Internal_Reference>
+        </Investigation_Area>
+        <Observing_System>
+            <Observing_System_Component>
+                <name>Chandrayaan 2 Orbiter</name>
+                <type>Spacecraft</type>
+                <description>
+                    Chandrayaan-2 Orbiter is an Orbiter craft under the Chandrayaan-2 Spacecraft 
+                    consists of various scientific instruments.
+                </description>
+            </Observing_System_Component>
+            <Observing_System_Component>
+                <name>terrain mapping camera</name>
+                <type>Instrument</type>
+                <description>
+                    TMC-2 (Terrain Mapping Camera) is one of the scientific instrument hosted 
+                    on the Chandrayaan-2 Orbiter. The instrument is passive electro-optical 
+                    imaging camera operating in visible-panchromatic band (500-800nm), 
+                    comprising three optical sensors Fore, Nadir and Aft placed with angles 
+                    of +25 deg, 0 deg and -25 deg to have three stereo views of the same target 
+                    as spacecraft moves along the track.
+                </description>
+            </Observing_System_Component>
+        </Observing_System>
+        <Target_Identification>
+            <name>Moon</name>
+            <type>Satellite</type>
+            <description>Moon is a natural satellite of Earth</description>
+        </Target_Identification>
+    </Observation_Area>
+    <File_Area_Observational>
+        <File>
+            <file_name>ch2_tmc_nca_20191128T0035389755_b_brw_d18.png</file_name>
+            <creation_date_time>2022-08-31T15:12:42</creation_date_time>
+            <file_size unit="byte">4068283</file_size>
+            <md5_checksum>43778d970f10bfcf651cc35ef2e11bbd</md5_checksum>
+            <comment>
+                This File contains the count calibrated sub sampled browse image
+                md5_checksum is provided for ensuring data integrity when users are downloading the data.
+            </comment>
+        </File>
+        <Array_2D_Image>
+            <offset unit="byte">0</offset>
+            <axes>2</axes>
+            <axis_index_order>Last Index Fastest</axis_index_order>
+            <Element_Array>
+                <data_type>UnsignedByte</data_type>
+            </Element_Array>
+            <Axis_Array>
+                <axis_name>Line</axis_name>
+                <elements>17891</elements>
+                <sequence_number>1</sequence_number>
+            </Axis_Array>
+            <Axis_Array>
+                <axis_name>Sample</axis_name>
+                <elements>400</elements>
+                <sequence_number>2</sequence_number>
+            </Axis_Array>
+        </Array_2D_Image>
+    </File_Area_Observational>
+</Product_Observational>
\ No newline at end of file
-- 
GitLab