Repository: nasa/opera-sds-pge
Pull request #671: TROPO ISO XML Generation
Author: login: kevinmarlis
Created: 2025-05-15T23:31:59Z | Merged: 2025-05-20T23:09:51Z

## Description
- Adds support for ISO XML and Measured Parameters Config for TROPO PGE
- Ensures that framework for populating ISO XML with TROPO output product metadata works as intended.
- There are a few outstanding values that are using placeholders until we get confirmation otherwise:
    - latitude / longitude spacing: Product spec says ~0.07 degree resolution which is equivalent to roughly 8000 meters
    - spatial extent: Product is global on a regular 2d grid, so we're using the min/max lat/lon values to define the spatial extent
    - zone identifier: No reference in product spec, but the product is global
    - start_time / end_time: Single time value per product along with a temporal_resolution metadata field of "6h". Currently using time value from product for start_time and start_time + timedelta(hours=6) for end_time

## Affected Issues
- Closes #654 

## Testing
- Added ISO XML test which ensures all placeholders have been filled and that the appropriate error is raised when unable to generate ISO XML
- Will update after running Build/Test Jenkins pipeline



Diff:
diff --git a/.ci/scripts/tropo/opera_pge_tropo_0.2_calval_runconfig.yaml b/.ci/scripts/tropo/opera_pge_tropo_0.2_calval_runconfig.yaml
index 0e90d6c0..a638bad7 100644
--- a/.ci/scripts/tropo/opera_pge_tropo_0.2_calval_runconfig.yaml
+++ b/.ci/scripts/tropo/opera_pge_tropo_0.2_calval_runconfig.yaml
@@ -21,9 +21,9 @@ RunConfig:
         ErrorCodeBase: 800000
         SchemaPath: /home/ops/opera/pge/tropo/schema/tropo_sas_schema.yaml
         AlgorithmParametersSchemaPath: 
-        IsoMeasuredParameterDescriptions:
+        IsoMeasuredParameterDescriptions: /home/ops/opera/pge/tropo/templates/tropo_measured_parameters.yaml
         DataValidityStartDate:
-        IsoTemplatePath: ""
+        IsoTemplatePath: /home/ops/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
       QAExecutable:
         Enabled: true
         ProgramPath: /home/ops/opera/.ci/scripts/tropo/compare_tropo_products.sh
diff --git a/.secrets.baseline b/.secrets.baseline
index 29eb2dd2..6f2ac3d0 100644
--- a/.secrets.baseline
+++ b/.secrets.baseline
@@ -133,8 +133,7 @@
         "venv",
         "dist",
         "build",
-        ".*\\.egg-info",
-        ".idea"
+        ".*\\.egg-info"
       ]
     }
   ],
@@ -317,6 +316,26 @@
         "is_secret": false
       }
     ],
+    "src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2": [
+      {
+        "type": "Email Address",
+        "filename": "src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2",
+        "hashed_secret": "f3fd1cde8687b42e8848fceca28fc38e70034e95",
+        "is_verified": false,
+        "line_number": 52,
+        "is_secret": false
+      }
+    ],
+    "src/opera/pge/tropo/templates/tropo_measured_parameters.yaml": [
+      {
+        "type": "Email Address",
+        "filename": "src/opera/pge/tropo/templates/tropo_measured_parameters.yaml",
+        "hashed_secret": "bc2a672d48cb7c8d30fd1ee6aab21208c51d4301",
+        "is_verified": false,
+        "line_number": 19,
+        "is_secret": false
+      }
+    ],
     "src/opera/test/data/sample_iso_template.xml.jinja2": [
       {
         "type": "Email Address",
@@ -338,5 +357,5 @@
       }
     ]
   },
-  "generated_at": "2025-04-24T15:02:43Z"
+  "generated_at": "2025-05-20T15:55:58Z"
 }
diff --git a/examples/tropo_sample_runconfig-v3.0.0-er.2.0.yaml b/examples/tropo_sample_runconfig-v3.0.0-er.2.0.yaml
index 2402bd11..af3982a3 100644
--- a/examples/tropo_sample_runconfig-v3.0.0-er.2.0.yaml
+++ b/examples/tropo_sample_runconfig-v3.0.0-er.2.0.yaml
@@ -83,8 +83,7 @@ RunConfig:
         # container, and typically should reference a template file bundled
         # with the opera_pge installation directory within the container
         # Consult the Docker image build scripts for more info
-        # TBD for TROPO
-        IsoMeasuredParameterDescriptions: ""
+        IsoMeasuredParameterDescriptions: /home/ops/opera/pge/tropo/templates/tropo_measured_parameters.yaml
 
         # Path to the Jinja2 template used to generate the ISO xml
         # metadata file
@@ -92,8 +91,7 @@ RunConfig:
         # container, and typically should reference a template file bundled
         # with the opera_pge installation directory within the container
         # Consult the Docker image build scripts for more info
-        # TBD for TROPO
-        IsoTemplatePath: ""
+        IsoTemplatePath: /home/ops/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
 
       QAExecutable:
         # Set to True to enable execution of an additional "Quality Assurance"
diff --git a/src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2 b/src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
new file mode 100644
index 00000000..91a1339c
--- /dev/null
+++ b/src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
@@ -0,0 +1,704 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>World Geodetic System 1984 (WGS84)</gco:CharacterString>
+                            </gmd:title>
+                        </gmd:CI_Citation>
+                    </gmd:authority>
+                </gmd:MD_Identifier>
+            </gmd:referenceSystemIdentifier>
+        </gmd:MD_ReferenceSystem>
+    </gmd:referenceSystemInfo>
+    <!-- This section documents granule data in this metadata record. -->
+    <gmd:identificationInfo>
+        <gmd:MD_DataIdentification>
+            <!-- This section holds the granule MetadataProviderDates, and the granule identifiers -->
+            <gmd:citation>
+                <gmd:CI_Citation>
+                    <gmd:title>
+                        <gmx:FileName>{{ custom_data.ISO_OPERA_ProducerGranuleId }}{# ISO_OPERA_ProducerGranuleId #}</gmx:FileName>
+                    </gmd:title>
+                    <gmd:alternateTitle>
+                        <gco:CharacterString>Troposphere Zenith Radar Delays Product</gco:CharacterString>
+                    </gmd:alternateTitle>
+                    <!-- The date/time that data provider created or updated the granule info on data provider's database.-->
+                    <gmd:date>
+                        <gmd:CI_Date>
+                            <gmd:date>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_MetadataProvider_Action_DateTime #}</gco:DateTime>
+                            </gmd:date>
+                            <gmd:dateType>
+                                <gmd:CI_DateTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}">{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}</gmd:CI_DateTypeCode>
+                            </gmd:dateType>
+                        </gmd:CI_Date>
+                    </gmd:date>
+                    <gmd:edition>
+                        <gco:CharacterString>{{ run_config.Groups.PGE.PrimaryExecutable.ProductVersion }}{# ISO_OPERA_ProductVersion #}</gco:CharacterString>
+                    </gmd:edition>
+                    <!-- This is the producer granule id -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.producergranuleid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>ProducerGranuleId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- PGE Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: PGEVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- SAS Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: SASVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <gmd:citedResponsibleParty>
+                        <gmd:CI_ResponsibleParty>
+                            <gmd:organisationName>
+                                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+                            </gmd:organisationName>
+                            <gmd:contactInfo>
+                                <gmd:CI_Contact xlink:href="#JPLcontactInfo"/>
+                            </gmd:contactInfo>
+                            <gmd:role>
+                                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="originator">originator</gmd:CI_RoleCode>
+                            </gmd:role>
+                        </gmd:CI_ResponsibleParty>
+                    </gmd:citedResponsibleParty>
+                    <gmd:presentationForm>
+                        <gmd:CI_PresentationFormCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_PresentationFormCode" codeListValue="documentDigital">documentDigital</gmd:CI_PresentationFormCode>
+                    </gmd:presentationForm>
+                </gmd:CI_Citation>
+            </gmd:citation>
+            <gmd:abstract>
+                <gco:CharacterString>The L4 Troposphere Zenith Radar Delays (TROPO) product consists of radar sensor-agnostic, one-way troposphere zenith-integrated delays, including both wet and hydrostatic components, at various height levels. TROPO products are distributed over projected map coordinates aligned with the WGS84 reference system.</gco:CharacterString>
+            </gmd:abstract>
+            <gmd:status>
+                <gmd:MD_ProgressCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ProgressCode" codeListValue="completed">completed</gmd:MD_ProgressCode>
+            </gmd:status>
+            <!-- This section holds the ReprocessingPlanned value -->
+            <gmd:resourceMaintenance>
+                <gmd:MD_MaintenanceInformation>
+                    <gmd:maintenanceAndUpdateFrequency>
+                        <gmd:MD_MaintenanceFrequencyCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode" codeListValue="asNeeded">asNeeded</gmd:MD_MaintenanceFrequencyCode>
+                    </gmd:maintenanceAndUpdateFrequency>
+                </gmd:MD_MaintenanceInformation>
+            </gmd:resourceMaintenance>
+            <!-- This section describes projects as keywords. The CMR does not read this section.-->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for project_kw in custom_data.ISO_OPERA_ProjectKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ project_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="project">project</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Project Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes platform keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for platform_kw in custom_data.ISO_OPERA_PlatformKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ platform_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="platform">platform</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Platform Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes instrument keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for instr_kw in custom_data.ISO_OPERA_InstrumentKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ instr_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type><gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="instrument">instrument</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Instrument Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This is the granule collection short name. If this is used then the Collection Version must also exist.  Only this and Collection Version or or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Name }}{# ISO_OPERA_CollectionShortName #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionshortname</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionShortName</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is the granule collection version. If this is used then the Collection Short Name must also exist. Only this and Collection Short Name or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_CollectionVersion #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionversion</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionVersion</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is where View Related Information or Project Home Page RelatedUrls go.-->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://www.jpl.nasa.gov/go/opera</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:aggregateDataSetName>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <gmd:spatialRepresentationType>
+                <gmd:MD_SpatialRepresentationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode" codeListValue="grid">grid</gmd:MD_SpatialRepresentationTypeCode>
+            </gmd:spatialRepresentationType>
+            <!-- This is the language used in the granule -->
+            <gmd:language>
+                <gco:CharacterString>eng</gco:CharacterString>
+            </gmd:language>
+            <!-- this is the character set used in the granule -->
+            <gmd:characterSet>
+                <gmd:MD_CharacterSetCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+            </gmd:characterSet>
+            <gmd:topicCategory>
+                <gmd:MD_TopicCategoryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_TopicCategoryCode" codeListValue="geoscientificInformation">geoscientificInformation</gmd:MD_TopicCategoryCode>
+            </gmd:topicCategory>
+            <gmd:environmentDescription>
+                <gco:CharacterString>Data product generated in Network Common Data From version 4 format with ISO 19115 conformant metadata.</gco:CharacterString>
+            </gmd:environmentDescription>
+            <!-- This section documents the granules spatial and temporal extent as well as the grid mapping names and the projection names - NOT the TilingIdentificationSystem. -->
+            <gmd:extent>
+                <!-- the EX_Extent id must exist with boundingExtent -->
+                <gmd:EX_Extent id="boundingExtent">
+                    <!--Bounding Rectangle-->
+                    <gmd:geographicElement>
+                        <gmd:EX_GeographicBoundingBox>
+                            <gmd:westBoundLongitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lon_min }}{# doc ID ISO_OPERA_westBoundLongitude #}</gco:Decimal>
+                            </gmd:westBoundLongitude>
+                            <gmd:eastBoundLongitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lon_max }}{# doc ID ISO_OPERA_eastBoundLongitude #}</gco:Decimal>
+                            </gmd:eastBoundLongitude>
+                            <gmd:southBoundLatitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lat_min }}{# doc ID ISO_OPERA_southBoundLatitude #}</gco:Decimal>
+                            </gmd:southBoundLatitude>
+                            <gmd:northBoundLatitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lat_max }}{# doc ID ISO_OPERA_northBoundLatitude #}</gco:Decimal>
+                            </gmd:northBoundLatitude>
+                        </gmd:EX_GeographicBoundingBox>
+                    </gmd:geographicElement>
+                    <!-- This section documents the ZoneIdentifier -->
+                    <gmd:geographicElement>
+                        <gmd:EX_GeographicDescription id="ZoneIdentifier">
+                            <gmd:geographicIdentifier>
+                                <gmd:MD_Identifier>
+                                    <gmd:code>
+                                        <gco:CharacterString>{{ product_output.zone_identifier }}{# ISO_OPERA_zoneIdentifier #}</gco:CharacterString>
+                                    </gmd:code>
+                                    <gmd:codeSpace>
+                                        <gco:CharacterString>gov.nasa.esdis.umm.zoneidentifier</gco:CharacterString>
+                                    </gmd:codeSpace>
+                                    <gmd:description>
+                                        <gco:CharacterString>ZoneIdentifier</gco:CharacterString>
+                                    </gmd:description>
+                                </gmd:MD_Identifier>
+                            </gmd:geographicIdentifier>
+                        </gmd:EX_GeographicDescription>
+                    </gmd:geographicElement>
+                    <!-- This is the granules temporal extent -->
+                    <gmd:temporalElement>
+                        <!--RangeDateTime-->
+                        <gmd:EX_TemporalExtent id="boundingTemporalExtent">
+                            <gmd:extent>
+                                <gml:TimePeriod gml:id="TROPO_Time_Range">
+                                    <gml:beginPosition>{{ product_output.temporal_extent.start_time }}{# ISO_OPERA_refDateTime #}</gml:beginPosition>
+                                    <gml:endPosition>{{ product_output.temporal_extent.end_time }}{# ISO_OPERA_secDateTime #}</gml:endPosition>
+                                </gml:TimePeriod>
+                            </gmd:extent>
+                        </gmd:EX_TemporalExtent>
+                    </gmd:temporalElement>
+                </gmd:EX_Extent>
+            </gmd:extent>
+            <gmd:supplementalInformation/>
+        </gmd:MD_DataIdentification>
+    </gmd:identificationInfo>
+    <!-- This is the Measured Parameters section - it needs to be in its own contentInfo section - not within Additional Attributes, DayNightFlag, or CloudCover -->
+    <gmd:contentInfo>
+        <gmd:MD_CoverageDescription>
+            <gmd:attributeDescription>
+                <gco:RecordType>MeasuredParameters</gco:RecordType>
+            </gmd:attributeDescription>
+            <gmd:contentType>
+                <gmd:MD_CoverageContentTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CoverageContentTypeCode" codeListValue="physicalMeasurement">physicalMeasurement</gmd:MD_CoverageContentTypeCode>
+            </gmd:contentType>
+            <gmd:dimension>
+                <gmd:MD_Band>
+                    <gmd:otherProperty>
+                        <gco:Record>
+                            <eos:AdditionalAttributes>
+                                {%- for attribute in product_output.MeasuredParameters.values() %}
+                                <eos:AdditionalAttribute>
+                                    <eos:reference>
+                                        <eos:EOS_AdditionalAttributeDescription>
+                                            <eos:type>
+                                                <eos:EOS_AdditionalAttributeTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/eosCodelists.xml#EOS_AdditionalAttributeTypeCode" codeListValue="{{ attribute.attr_type }}">{{ attribute.attr_type }}</eos:EOS_AdditionalAttributeTypeCode>
+                                            </eos:type>
+                                            <eos:name>
+                                                <gco:CharacterString>{{ attribute.name }}</gco:CharacterString>
+                                            </eos:name>
+                                            <eos:description>
+                                                <gco:CharacterString>{{ attribute.attr_description }}</gco:CharacterString>
+                                            </eos:description>
+                                            <eos:dataType>
+                                                <eos:EOS_AdditionalAttributeDataTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/eosCodelists.xml#EOS_AdditionalAttributeDataTypeCode" codeListValue="{{ attribute.data_type }}">{{ attribute.data_type }}</eos:EOS_AdditionalAttributeDataTypeCode>
+                                            </eos:dataType>
+                                        </eos:EOS_AdditionalAttributeDescription>
+                                    </eos:reference>
+                                    <eos:value>
+                                        <gco:CharacterString>{{ attribute.value }}</gco:CharacterString>
+                                    </eos:value>
+                                </eos:AdditionalAttribute>
+                                {%- endfor %}
+                            </eos:AdditionalAttributes>
+                        </gco:Record>
+                    </gmd:otherProperty>
+                </gmd:MD_Band>
+            </gmd:dimension>
+        </gmd:MD_CoverageDescription>
+    </gmd:contentInfo>
+    <!-- This section holds the Related URLs that pertain to distributions - where UMM-G RelatedUrl/Type = GET SERVICE, GET DATA, OPENDAP DATA ACCESS -->
+    <gmd:distributionInfo>
+        <gmd:MD_Distribution>
+            <gmd:distributor>
+                <gmd:MD_Distributor>
+                    <gmd:distributionFormat>
+                        <gmd:MD_Format>
+                            <gmd:name>
+                                <gco:CharacterString>NetCDF</gco:CharacterString>
+                            </gmd:name>
+                        </gmd:MD_Format>
+                    </gmd:distributionFormat>
+                    <gmd:distributorContact gco:nilReason="missing"/>
+                    <gmd:distributorTransferOptions gco:nilReason="missing"/>
+                    <gmd:distributionOrderProcess>
+                        <gmd:MD_StandardOrderProcess>
+                            <gmd:fees>
+                                <gco:CharacterString>free</gco:CharacterString>
+                            </gmd:fees>
+                        </gmd:MD_StandardOrderProcess>
+                    </gmd:distributionOrderProcess>
+                </gmd:MD_Distributor>
+            </gmd:distributor>
+        </gmd:MD_Distribution>
+    </gmd:distributionInfo>
+    <!-- This is the data quality section. It holds ReprocessingActual, ProductionDateTime, PGEVersionClass, Some AdditionalAttributes, and InputGranules.
+         The MeasuredParameters go into its own dataQualityInfo Section. -->
+    <gmd:dataQualityInfo>
+        <gmd:DQ_DataQuality>
+            <!-- this lists that the scope for the data quality section pertains to the data set - the granule. -->
+            <gmd:scope>
+                <gmd:DQ_Scope>
+                    <gmd:level>
+                        <gmd:MD_ScopeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+                    </gmd:level>
+                </gmd:DQ_Scope>
+            </gmd:scope>
+            <gmd:lineage>
+                <gmd:LI_Lineage>
+                    <gmd:statement>
+                        <gco:CharacterString>OPERA L4 TROPO product generated by JPL using ECMWF HRES weather model data and SAS version {{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                    </gmd:statement>
+                    <!-- This section contains the PGEVersionClass -->
+                    <gmd:processStep>
+                        <gmi:LE_ProcessStep>
+                            <gmd:description>
+                                <gco:CharacterString>PGEVersionClass</gco:CharacterString>
+                            </gmd:description>
+                            <gmi:processingInformation>
+                                <eos:EOS_Processing>
+                                    <gmi:identifier>
+                                        <gmd:MD_Identifier>
+                                            <gmd:code>
+                                                <gco:CharacterString>PGEName: {{ catalog_metadata.PGE_Name }}{# ISO_OPERA_pgeName #} PGEVersion: {{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                                            </gmd:code>
+                                            <gmd:codeSpace>
+                                                <gco:CharacterString>gov.nasa.esdis.umm.pgeversionclass</gco:CharacterString>
+                                            </gmd:codeSpace>
+                                            <gmd:description>
+                                                <gco:CharacterString>PGEVersionClass</gco:CharacterString>
+                                            </gmd:description>
+                                        </gmd:MD_Identifier>
+                                    </gmi:identifier>
+                                </eos:EOS_Processing>
+                            </gmi:processingInformation>
+                            <gmi:output>
+                                <gmd:LI_Source>
+                                    <gmd:description>
+                                        <gco:CharacterString>Troposphere Zenith Radar Delays (TROPO) Product - {{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                                    </gmd:description>
+                                </gmd:LI_Source>
+                            </gmi:output>
+                        </gmi:LE_ProcessStep>
+                    </gmd:processStep>
+                    <!-- This is the production date time -->
+                    <gmd:processStep>
+                        <gmi:LE_ProcessStep>
+                            <gmd:description>
+                                <gco:CharacterString>ProductionDateTime</gco:CharacterString>
+                            </gmd:description>
+                            <gmd:dateTime>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+                            </gmd:dateTime>
+                        </gmi:LE_ProcessStep>
+                    </gmd:processStep>
+                    <!-- This section holds the GranuleInputs -->
+                    {%- for input_list_item in catalog_metadata.Input_Files %}
+                    <gmd:source>
+                        <gmi:LE_Source>
+                            <gmd:description>
+                                <gco:CharacterString>GranuleInput</gco:CharacterString>
+                            </gmd:description>
+                            <gmd:sourceCitation>
+                                <gmd:CI_Citation>
+                                    <gmd:title>
+                                        <gmx:FileName src="{{ input_list_item }}{# ISO_OPERA_InputGranuleN #}">
+                                            {{ input_list_item }}{# ISO_OPERA_InputGranuleN #}
+                                        </gmx:FileName>
+                                    </gmd:title>
+                                    <gmd:date gco:nilReason="unknown"/>
+                                </gmd:CI_Citation>
+                            </gmd:sourceCitation>
+                        </gmi:LE_Source>
+                    </gmd:source>
+                    {%- endfor %}
+                </gmd:LI_Lineage>
+            </gmd:lineage>
+        </gmd:DQ_DataQuality>
+    </gmd:dataQualityInfo>
+    <gmd:metadataMaintenance>
+        <gmd:MD_MaintenanceInformation>
+            <gmd:maintenanceAndUpdateFrequency>
+                <gmd:MD_MaintenanceFrequencyCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode" codeListValue="asNeeded">asNeeded</gmd:MD_MaintenanceFrequencyCode>
+            </gmd:maintenanceAndUpdateFrequency>
+        </gmd:MD_MaintenanceInformation>
+    </gmd:metadataMaintenance>
+</gmi:MI_Metadata>
diff --git a/src/opera/pge/tropo/templates/tropo_measured_parameters.yaml b/src/opera/pge/tropo/templates/tropo_measured_parameters.yaml
new file mode 100644
index 00000000..f59f45da
--- /dev/null
+++ b/src/opera/pge/tropo/templates/tropo_measured_parameters.yaml
@@ -0,0 +1,86 @@
+Conventions:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: NetCDF-4 conventions adopted in this product
+  display_name: Conventions
+title:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: "OPERA_L4_TROPO-ZENITH"
+  display_name: Title
+institution:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: Name of producing agency (e.g. “NASA JPL”).
+  display_name: Institution
+contact:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: Contact information for the producer of the product. (e.g., "opera-sds-ops@jpl.nasa.gov").
+  display_name: Contact
+source:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Source provider (e.g. ECMWF)
+  display_name: Source
+platform:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Numerical Weather Model input. (e.g. Model High Resolution 15-day Forecast (HRES))
+  display_name: Platform
+spatial_resolution:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Spatial resolution of source and product (e.g. 0.07deg)
+  display_name: SpatialResolution
+temporal_resolution:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Temporal resolution of source and product (e.g. 6 hours)
+  display_name: TemporalResolution
+source_url:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Source url documentation, (e.g. https://www.ecmwf.int/en/forecasts/datasets/set-i for HRES)
+  display_name: SourceUrl
+  escape_html: true
+references:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Url documentation for software (e.g. "https://raider.readthedocs.io/en/latest/" for RAiDER)
+  display_name: Reference
+mission_name:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: "OEPRA"
+  display_name: MissionName
+description:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: OPERA One-way Tropospheric Zenith-integrated Delay for Synthetic Aperture Radar
+  display_name: Description
+comment:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Intersect/interpolate with DEM, project to slant-range and multiply with -4pi/wavelength (2way) to get SAR correction
+  display_name: Comment
+software:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: RAiDER
+  display_name: Software
+software_version:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: "0.5.3"
+  display_name: SoftwareVersion
+reference_document:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Name and version of Product Description Document to use as reference for product. (TBD)
+  display_name: ReferenceDocument
+history:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Created on processing datetime, e.g. 2025-02-06 01:14:14.265581+00:00 (UTC)
+  display_name: History
\ No newline at end of file
diff --git a/src/opera/pge/tropo/tropo_pge.py b/src/opera/pge/tropo/tropo_pge.py
index 715515e3..9541494a 100644
--- a/src/opera/pge/tropo/tropo_pge.py
+++ b/src/opera/pge/tropo/tropo_pge.py
@@ -7,6 +7,7 @@
 Module defining the implementation for the TROPO PGE.
 """
 
+from datetime import datetime, timedelta
 from os.path import abspath, basename, exists, getsize, join, splitext
 from os import listdir
 import re
@@ -16,7 +17,9 @@
 from opera.pge.base.base_pge import PreProcessorMixin
 from opera.util.error_codes import ErrorCode
 from opera.util.input_validation import check_input
+from opera.util.render_jinja2 import augment_hdf5_measured_parameters, render_jinja2
 from opera.util.run_utils import get_checksum
+from opera.util.h5_utils import get_extent_from_coordinates, get_tropo_product_metadata
 
 
 class TROPOPreProcessorMixin(PreProcessorMixin):
@@ -117,7 +120,6 @@ def _validate_outputs(self):
                 error_msg = f'Invalid product filename {output_filename}'
                 self.logger.critical(self.name, ErrorCode.INVALID_OUTPUT, error_msg)
                 
-
     def _checksum_output_products(self):
         """
         Generates a dictionary mapping output product file names to the
@@ -150,7 +152,277 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+            
+        Raises
+        ------
+        ValueError
+            If time_res is not a valid time format string.
+        ValueError
+            If time unit extracted from time_res is not one of the
+            supported units: s, m, h, d, w.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        """
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        """
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
+
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'TROPO', 'Troposphere', 'Zenith', 'Radar', 'Delays'],
+            'ISO_OPERA_PlatformKeywords': ['TROPO'],
+            'ISO_OPERA_InstrumentKeywords': ['TROPO']
+        }
+
+        return custom_metadata
+    
+    def _create_iso_metadata(self, tropo_metadata, product_filename):
+        """
+        Creates a rendered version of the ISO metadata template for TROPO
+        output products using metadata from the following locations:
+
+            * RunConfig (in dictionary form)
+            * Output product (dictionary extracted from NetCDF product attributes)
+            * Catalog metadata
+            * "Custom" metadata (all metadata not found anywhere else)
+
+        Parameters
+        ----------
+        tropo_metadata : dict
+            The product metadata corresponding to a NetCDF product to
+            be included as the "product_output" metadata in the rendered ISO xml.
+
+        Returns
+        -------
+        rendered_template : str
+            The ISO metadata template for TROPO filled in with values from the
+            sourced metadata dictionaries.
 
+        """
+        # Use the base PGE implemenation to validate existence of the template
+        super()._create_iso_metadata()
+        
+        runconfig_dict = self.runconfig.asdict()
+
+        product_output_dict = tropo_metadata
+
+        catalog_metadata_dict = self._create_catalog_metadata().asdict()
+
+        custom_data_dict = self._create_custom_metadata(product_filename)
+
+        iso_metadata = {
+            'run_config': runconfig_dict,
+            'product_output': product_output_dict,
+            'catalog_metadata': catalog_metadata_dict,
+            'custom_data': custom_data_dict
+        }
+
+        iso_template_path = abspath(self.runconfig.iso_template_path)
+
+        rendered_template = render_jinja2(iso_template_path, iso_metadata, self.logger)
+
+        return rendered_template    
+    
+    def _stage_output_files(self):
+        """
+        Ensures that all output products produced by both the SAS and this PGE
+        are staged to the output location defined by the RunConfig. This includes
+        reassignment of file names to meet the file-naming conventions required
+        by the PGE.
+
+        In addition to staging of the output products created by the SAS, this
+        function is also responsible for ensuring the catalog metadata, ISO
+        metadata, and combined PGE/SAS log are also written to the expected
+        output product location with the appropriate file names.
+        """
+        # Gather the list of output files produced by the SAS
+        output_products = self.runconfig.get_output_product_filenames()
+
+        #Extracts netCDF output product.
+        nc_product = None
+        for output_product in output_products:
+            if output_product.endswith('.nc'):
+                nc_product = output_product
+                break
+        
+        # For each output file name, assign the final file name matching the
+        # expected conventions.   
+        for output_product in output_products:
+            self._assign_filename(output_product, self.runconfig.output_product_path)
+
+        # Write the catalog metadata to disk with the appropriate filename
+        catalog_metadata = self._create_catalog_metadata()
+
+        if not catalog_metadata.validate(catalog_metadata.get_schema_file_path()):
+            msg = f"Failed to create valid catalog metadata, reason(s):\n {catalog_metadata.get_error_msg()}"
+            self.logger.critical(self.name, ErrorCode.INVALID_CATALOG_METADATA, msg)
+
+        cat_meta_filename = self._catalog_metadata_filename()
+        cat_meta_filepath = join(self.runconfig.output_product_path, cat_meta_filename)
+
+        self.logger.info(self.name, ErrorCode.CREATING_CATALOG_METADATA,
+                         f"Writing Catalog Metadata to {cat_meta_filepath}")
+
+        try:
+            catalog_metadata.write(cat_meta_filepath)
+        except OSError as err:
+            msg = f"Failed to write catalog metadata file {cat_meta_filepath}, reason: {str(err)}"
+            self.logger.critical(self.name, ErrorCode.CATALOG_METADATA_CREATION_FAILED, msg)
+
+        tropo_metadata = self._collect_tropo_product_metadata(nc_product)
+
+        # Generate the ISO metadata for use with product submission to DAAC(s)
+        iso_metadata = self._create_iso_metadata(tropo_metadata, nc_product)
+
+        iso_meta_filename = self._iso_metadata_filename()
+        iso_meta_filepath = join(self.runconfig.output_product_path, iso_meta_filename)
+
+        if iso_metadata:
+            self.logger.info(self.name, ErrorCode.RENDERING_ISO_METADATA,
+                             f"Writing ISO Metadata to {iso_meta_filepath}")
+            with open(iso_meta_filepath, 'w', encoding='utf-8') as outfile:
+                outfile.write(iso_metadata)
+
+        # Write the QA application log to disk with the appropriate filename,
+        # if necessary
+        if self.runconfig.qa_enabled:
+            qa_log_filename = self._qa_log_filename()
+            qa_log_filepath = join(self.runconfig.output_product_path, qa_log_filename)
+            self.qa_logger.move(qa_log_filepath)
+
+            try:
+                self._finalize_log(self.qa_logger)
+            except OSError as err:
+                msg = f"Failed to write QA log file to {qa_log_filepath}, reason: {str(err)}"
+                self.logger.critical(self.name, ErrorCode.LOG_FILE_CREATION_FAILED, msg)
+
+        # Lastly, write the combined PGE/SAS log to disk with the appropriate filename
+        log_filename = self._log_filename()
+        log_filepath = join(self.runconfig.output_product_path, log_filename)
+        self.logger.move(log_filepath)
+
+        try:
+            self._finalize_log(self.logger)
+        except OSError as err:
+            msg = f"Failed to write log file to {log_filepath}, reason: {str(err)}"
+
+            # Log stream might be closed by this point so raise an Exception instead
+            raise RuntimeError(msg)
+    
     def run_postprocessor(self, **kwargs):
         """
         Executes the post-processing steps for the TROPO PGE.
diff --git a/src/opera/test/data/test_tropo_config.yaml b/src/opera/test/data/test_tropo_config.yaml
index 3bd20dbd..2ec2076d 100644
--- a/src/opera/test/data/test_tropo_config.yaml
+++ b/src/opera/test/data/test_tropo_config.yaml
@@ -21,9 +21,9 @@ RunConfig:
         ErrorCodeBase: 800000
         SchemaPath: pge/tropo/schema/tropo_sas_schema.yaml
         AlgorithmParametersSchemaPath: 
-        IsoMeasuredParameterDescriptions:
+        IsoMeasuredParameterDescriptions: pge/tropo/templates/tropo_measured_parameters.yaml
         DataValidityStartDate:
-        IsoTemplatePath: ""
+        IsoTemplatePath: pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
       QAExecutable:
         Enabled: false
         ProgramPath: null
diff --git a/src/opera/test/pge/tropo/test_tropo_pge.py b/src/opera/test/pge/tropo/test_tropo_pge.py
index 3415a391..0f6ce8b6 100644
--- a/src/opera/test/pge/tropo/test_tropo_pge.py
+++ b/src/opera/test/pge/tropo/test_tropo_pge.py
@@ -14,7 +14,7 @@
 import unittest
 from io import StringIO
 import os
-from os.path import abspath, join
+from os.path import abspath, exists, join
 from os import listdir
 
 from pkg_resources import resource_filename
@@ -23,6 +23,8 @@
 from opera.pge import RunConfig
 from opera.pge.tropo.tropo_pge import TROPOExecutor
 from opera.util import PgeLogger
+from opera.util.h5_utils import create_test_tropo_metadata_product
+from opera.util.render_jinja2 import UNDEFINED_ERROR
 
 
 class TROPOPgeTestCase(unittest.TestCase):
@@ -65,7 +67,7 @@ def setUp(self) -> None:
             Path(dummy_file_path).parent.mkdir(parents=True, exist_ok=True)
             with open(dummy_file_path, "wb") as f:
                 f.write(random.randbytes(1024))
-                
+                                
         # Create the output directories expected by the test Runconfig file and add
         # dummy output files
         self.test_output_dir = abspath(join(self.working_dir.name, "tropo_pge_test/output_dir"))
@@ -74,9 +76,12 @@ def setUp(self) -> None:
         sas_version = rc.sas_config["product_path_group"]["product_version"]
         self.base_filename = f"OPERA_L4_TROPO-ZENITH_20250101T010101Z_20250101T010101Z_HRES_v{sas_version}"
         
-        for extension in (".nc", ".png"):
-            self._write_valid_output(extension)
+        self._write_valid_output(".png")
+        
+        self.tropo_metadata_path = abspath(join(self.test_output_dir, f'{self.base_filename}.nc'))
 
+        create_test_tropo_metadata_product(self.tropo_metadata_path)
+            
         os.chdir(self.working_dir.name)
 
     def tearDown(self) -> None:
@@ -121,6 +126,21 @@ def test_tropo_pge_execution(self):
         # Check that a RunConfig for the SAS was isolated within the scratch directory
         expected_sas_config_file = join(pge.runconfig.scratch_path, 'test_tropo_config_sas.yaml')
         self.assertTrue(os.path.exists(expected_sas_config_file))
+        
+        # Check that the catalog metadata file was created in the output directory
+        expected_catalog_metadata_file = join(
+            pge.runconfig.output_product_path, pge._catalog_metadata_filename())
+        self.assertTrue(os.path.exists(expected_catalog_metadata_file))
+
+        # # Check that the ISO metadata file was created and filled in as expected
+        expected_iso_metadata_file = join(
+            pge.runconfig.output_product_path, pge._iso_metadata_filename())
+        self.assertTrue(os.path.exists(expected_iso_metadata_file))
+        
+        with open(expected_iso_metadata_file, 'r', encoding='utf-8') as infile:
+            iso_contents = infile.read()
+
+        self.assertNotIn(UNDEFINED_ERROR, iso_contents)
 
         # Check that the log file was created and moved into the output directory
         expected_log_file = pge.logger.get_file_name()
@@ -183,6 +203,41 @@ def _write_valid_output(self, extension: str):
         with open(file_path, "wb") as f:
             f.write(random.randbytes(1024))
     
+    def test_iso_metadata_creation(self):
+        """
+        Test that the ISO metadata template is fully filled out when realistic
+        TROPO product metadata is available.
+        """
+        runconfig_path = join(self.data_dir, 'test_tropo_config.yaml')
+
+        pge = TROPOExecutor(pge_name="TROPOPgeTest", runconfig_path=runconfig_path)
+
+        # Run only the pre-processor steps to ingest the runconfig and set
+        # up directories
+        pge.run_preprocessor()
+
+        # Create a sample metadata file within the output directory of the PGE
+        tropo_metadata = pge._collect_tropo_product_metadata(self.tropo_metadata_path)
+
+        iso_metadata = pge._create_iso_metadata(tropo_metadata, self.tropo_metadata_path)
+
+        self.assertNotIn(UNDEFINED_ERROR, iso_metadata)
+
+        os.unlink(self.tropo_metadata_path)
+
+        # Test no file from which to extract data
+        tropo_metadata_path = join(self.test_output_dir, 'No_file.nc')
+
+        with self.assertRaises(RuntimeError):
+            pge._collect_tropo_product_metadata(tropo_metadata_path)
+
+        # Verify the proper Runtime error message
+        log_file = pge.logger.get_file_name()
+        self.assertTrue(exists(log_file))
+        with open(log_file, 'r', encoding='utf-8') as l_file:
+            log = l_file.read()
+        self.assertIn(f'Failed to extract metadata from {tropo_metadata_path}', log)
+    
     def test_tropo_pge_input_validation(self):
         """
         Test the input validation checks made by TropoPreProcessorMixin:
diff --git a/src/opera/util/h5_utils.py b/src/opera/util/h5_utils.py
index 80654790..3c29c539 100644
--- a/src/opera/util/h5_utils.py
+++ b/src/opera/util/h5_utils.py
@@ -56,7 +56,11 @@ def get_hdf5_group_as_dict(file_name, group_path, ignore_keys=None):
     -------
     group_dict : dict
         Python dict containing variable data from the group path location.
-
+        
+    Raises
+    -------
+    RuntimeError
+        If group_path is not able to be retrieved from the opened h5file
     """
     with h5py.File(file_name, 'r') as h5file:
         group_object = h5file.get(group_path)
@@ -141,6 +145,108 @@ def convert_h5py_dataset(dataset_object):
     return result
 
 
+def get_hdf5_attrs_as_dict(file_name, group_path, ignore_keys=None):
+    """
+    Returns HDF5 group attributes as a python dict for a given file and group
+    path.
+
+    Variable data are not included.
+
+    Parameters
+    ----------
+    file_name : str
+        File system path and filename for the HDF5 file to use.
+    group_path : str
+        Group path within the HDF5 file.
+    ignore_keys : iterable, optional
+        Keys within the group to not include in the returned dict.
+
+    Returns
+    -------
+    group_dict : dict
+        Python dict containing variable data from the group path location.
+
+    Raises
+    -------
+    RuntimeError
+        If group_path is not able to be retrieved from the opened h5file
+    """
+    
+    if ignore_keys is None:
+        ignore_keys = []
+    
+    with h5py.File(file_name, "r") as h5file:
+        group_object = h5file.get(group_path)
+
+        if group_object is None:
+            raise RuntimeError(f"An error occurred retrieving object '{group_path}' "
+                               f"from file '{file_name}'.")
+
+        group_dict = dict()
+        for k, v in group_object.attrs.items():
+            if k in ignore_keys:
+                continue
+            if isinstance(v, str):
+                group_dict[k] = v
+            elif isinstance(v, np.bytes_):
+                group_dict[k] = v.decode("UTF-8")
+
+    return group_dict
+                               
+        
+def get_extent_from_coordinates(file_name, group_path, longitude='longitude', latitude='latitude'):
+    """
+    Returns spatial extent as (min_lon, max_lon, min_lat, max_lat).
+
+    Variable data are not included.
+
+    Parameters
+    ----------
+    file_name : str
+        File system path and filename for the HDF5 file to use.
+    group_path : str
+        Group path within the HDF5 file.
+    longitude : str
+        Name of longitude coordinate found in group_path.
+    latitude : str
+        Name of latitude coordinate found in group_path.
+
+    Returns
+    -------
+    extent : (float, float, float, float)
+        Tuple containing (min_lon, max_lon, min_lat, max_lat).
+        
+    Raises
+    -------
+    RuntimeError
+        If group_path is not able to be retrieved from the opened h5file
+    RuntimeError
+        If longitude variable is not contained within the group object.
+    RuntimeError
+        If latitude variable is not contained within the group object.
+    """
+    with h5py.File(file_name, 'r') as h5file:
+        group_object = h5file.get(group_path)
+
+        if group_object is None:
+            raise RuntimeError(f"An error occurred retrieving object '{group_path}' "
+                            f"from file '{file_name}'.")
+        if longitude not in group_object:
+            raise RuntimeError(f"An error occured retrieving variable '{longitude}'"
+                            f"from group path '{group_path}' in file '{file_name}'.")
+        if latitude not in group_object:
+            raise RuntimeError(f"An error occured retrieving variable '{latitude}'"
+                            f"from group path '{group_path}' in file '{file_name}'.")
+        
+        extent = (
+            min(group_object[longitude]), 
+            max(group_object[longitude]),
+            min(group_object[latitude]), 
+            max(group_object[latitude])
+        )
+            
+        return extent
+        
 def get_rtc_s1_product_metadata(file_name):
     """
     Returns a python dict containing the RTC-S1 product_output metadata
@@ -830,3 +936,68 @@ def create_test_disp_metadata_product(
                                                                                   data=np.bytes_("0.15.1"))
             source_data_software_s1_reader_version_dset = metadata_grp.create_dataset(
                 "source_data_software_s1_reader_version", data=np.bytes_("0.2.4"))
+
+
+def get_tropo_product_metadata(file_name):
+    """
+    Returns a python dict containing the TROPO metadata
+    which will be used with the ISO metadata template.
+
+    Parameters
+    ----------
+    file_name : str
+        the TROPO metadata file.
+
+    Returns
+    -------
+    tropo_metadata : dict
+        python dict containing the HDF5 file metadata which is used in the
+        ISO template.
+    """
+    tropo_metadata = get_hdf5_attrs_as_dict(file_name, "/")
+    return tropo_metadata
+    
+def create_test_tropo_metadata_product(file_path):
+    """
+    Creates a dummy TROPO netCDF metadata file with expected global attributes
+    and latitude and longitude arrays. This function is intended for use with 
+    unit tests, but is included in this module, so it will be importable from 
+    within a built container. 
+    
+    Global attribute values are currently written in TROPO products as Numpy 
+    byte strings, which has been reflected here.
+
+    Parameters
+    ----------
+    file_path : str
+        Full path to write the dummy TROPO netCDF metadata file to.
+    """
+    tropo_attrs = {
+        "Conventions": np.bytes_("CF-1.8"),
+        "title": np.bytes_("OPERA_L4_TROPO-ZENITH"),
+        "institution": np.bytes_("NASA Jet Propulsion Laboratory (JPL)"),
+        "contact": np.bytes_("opera-sds-ops@jpl.nasa.gov"),
+        "source": np.bytes_("ECMWF"),
+        "platform": np.bytes_("Model High Resolution 15-day Forecast (HRES)"),
+        "spatial_resolution": np.bytes_("~0.07deg"),
+        "temporal_resolution": np.bytes_("6h"),
+        "source_url": np.bytes_("https://www.ecmwf.int/en/forecasts/datasets/set-i"),
+        "references": np.bytes_("https://raider.readthedocs.io/en/latest/"),
+        "mission_name": np.bytes_("OPERA"),
+        "description": np.bytes_("OPERA One-way Tropospheric Zenith-integrated Delay for Synthetic Aperture Radar"),
+        "comment": np.bytes_("Intersect/interpolate with DEM, project to slant range and multiple with -4pi/radar wavelength (2 way) to get SAR correction"),
+        "software": np.bytes_("RAiDER"),
+        "software_version": np.bytes_("0.5.3"),
+        "reference_document": np.bytes_("TBD"),
+        "history": np.bytes_("Created on: 2025-03-24 21:28:42.426525+00:00"),
+        "reference_time": np.bytes_("2024-02-15 12:00:00")
+    }
+    
+    with h5py.File(file_path, 'w') as outfile:
+        for k,v in tropo_attrs.items():
+            outfile.attrs[k] = v
+        lon_data = np.random.uniform(low=-180, high=180, size=(5120,))
+        lat_data = np.random.uniform(low=-90, high=90, size=(2560,))
+        
+        longitude_dset = outfile.create_dataset("longitude", data=lon_data, dtype='float64')
+        latitude_dset = outfile.create_dataset("latitude", data=lat_data, dtype='float64')
\ No newline at end of file


Reviews:
user: login: sdcolli1
body: Branch is looking good, just a few minor things to address
state: CHANGES_REQUESTED
author_association: COLLABORATOR
submitted_at: 2025-05-20T16:06:19Z
user: login: RKuttruff
body: I went over the ISO template and raised some questions, but also found some things to change/add
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T16:12:54Z
user: login: kevinmarlis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T16:34:12Z
user: login: kevinmarlis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T16:39:31Z
user: login: RKuttruff
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T16:58:57Z
user: login: kevinmarlis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:06:16Z
user: login: kevinmarlis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:19:36Z
user: login: kevinmarlis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:21:25Z
user: login: RKuttruff
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:22:49Z
user: login: kevinmarlis
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:27:11Z
user: login: RKuttruff
body: All my main requested changes have been resolved. So I think this is good to go pending discussion on the outstanding points/questions Kevin mentioned.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-20T17:59:28Z
user: login: sdcolli1
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-20T21:23:04Z

Review comments:
diff_hunk: @@ -84,16 +84,15 @@ RunConfig:
         # with the opera_pge installation directory within the container
         # Consult the Docker image build scripts for more info
         # TBD for TROPO
path: examples/tropo_sample_runconfig-v3.0.0-er.2.0.yaml
user: login: sdcolli1
body: Can remove this TBD now
created_at: 2025-05-20T15:19:52Z
author_association: COLLABORATOR
diff_hunk: @@ -84,16 +84,15 @@ RunConfig:
         # with the opera_pge installation directory within the container
         # Consult the Docker image build scripts for more info
         # TBD for TROPO
-        IsoMeasuredParameterDescriptions: ""
-
+        IsoMeasuredParameterDescriptions: /home/ops/opera/pge/tropo/templates/tropo_measured_parameters.yaml
         # Path to the Jinja2 template used to generate the ISO xml
         # metadata file
         # Path should correspond to the file system within the Docker
         # container, and typically should reference a template file bundled
         # with the opera_pge installation directory within the container
         # Consult the Docker image build scripts for more info
         # TBD for TROPO
path: examples/tropo_sample_runconfig-v3.0.0-er.2.0.yaml
user: login: sdcolli1
body: This one too
created_at: 2025-05-20T15:19:59Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>Universal Transverse Mercator (UTM)</gco:CharacterString>
+                            </gmd:title>
+                        </gmd:CI_Citation>
+                    </gmd:authority>
+                </gmd:MD_Identifier>
+            </gmd:referenceSystemIdentifier>
+        </gmd:MD_ReferenceSystem>
+    </gmd:referenceSystemInfo>
+    <!-- This section documents granule data in this metadata record. -->
+    <gmd:identificationInfo>
+        <gmd:MD_DataIdentification>
+            <!-- This section holds the granule MetadataProviderDates, and the granule identifiers -->
+            <gmd:citation>
+                <gmd:CI_Citation>
+                    <gmd:title>
+                        <gmx:FileName>{{ custom_data.ISO_OPERA_ProducerGranuleId }}{# ISO_OPERA_ProducerGranuleId #}</gmx:FileName>
+                    </gmd:title>
+                    <gmd:alternateTitle>
+                        <gco:CharacterString>Troposphere Zenith Radar Delays Product</gco:CharacterString>
+                    </gmd:alternateTitle>
+                    <!-- The date/time that data provider created or updated the granule info on data provider's database.-->
+                    <gmd:date>
+                        <gmd:CI_Date>
+                            <gmd:date>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_MetadataProvider_Action_DateTime #}</gco:DateTime>
+                            </gmd:date>
+                            <gmd:dateType>
+                                <gmd:CI_DateTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}">{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}</gmd:CI_DateTypeCode>
+                            </gmd:dateType>
+                        </gmd:CI_Date>
+                    </gmd:date>
+                    <gmd:edition>
+                        <gco:CharacterString>{{ run_config.Groups.PGE.PrimaryExecutable.ProductVersion }}{# ISO_OPERA_ProductVersion #}</gco:CharacterString>
+                    </gmd:edition>
+                    <!-- This is the producer granule id -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.producergranuleid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>ProducerGranuleId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- PGE Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: PGEVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- SAS Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: SASVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <gmd:citedResponsibleParty>
+                        <gmd:CI_ResponsibleParty>
+                            <gmd:organisationName>
+                                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+                            </gmd:organisationName>
+                            <gmd:contactInfo>
+                                <gmd:CI_Contact xlink:href="#JPLcontactInfo"/>
+                            </gmd:contactInfo>
+                            <gmd:role>
+                                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="originator">originator</gmd:CI_RoleCode>
+                            </gmd:role>
+                        </gmd:CI_ResponsibleParty>
+                    </gmd:citedResponsibleParty>
+                    <gmd:presentationForm>
+                        <gmd:CI_PresentationFormCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_PresentationFormCode" codeListValue="documentDigital">documentDigital</gmd:CI_PresentationFormCode>
+                    </gmd:presentationForm>
+                </gmd:CI_Citation>
+            </gmd:citation>
+            <gmd:abstract>
+                <gco:CharacterString>The L4 Troposphere Zenith Radar Delays (TROPO) product consists of radar sensor-agnostic, one-way troposphere zenith-integrated delays, including both wet and hydrostatic components, at various height levels. TROPO products are distributed over projected map coordinates aligned with the WGS84 reference system.</gco:CharacterString>
+            </gmd:abstract>
+            <gmd:status>
+                <gmd:MD_ProgressCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ProgressCode" codeListValue="completed">completed</gmd:MD_ProgressCode>
+            </gmd:status>
+            <!-- This section holds the ReprocessingPlanned value -->
+            <gmd:resourceMaintenance>
+                <gmd:MD_MaintenanceInformation>
+                    <gmd:maintenanceAndUpdateFrequency>
+                        <gmd:MD_MaintenanceFrequencyCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode" codeListValue="asNeeded">asNeeded</gmd:MD_MaintenanceFrequencyCode>
+                    </gmd:maintenanceAndUpdateFrequency>
+                </gmd:MD_MaintenanceInformation>
+            </gmd:resourceMaintenance>
+            <!-- This section describes projects as keywords. The CMR does not read this section.-->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for project_kw in custom_data.ISO_OPERA_ProjectKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ project_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="project">project</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Project Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes platform keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for platform_kw in custom_data.ISO_OPERA_PlatformKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ platform_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="platform">platform</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Platform Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes instrument keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for instr_kw in custom_data.ISO_OPERA_InstrumentKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ instr_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type><gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="instrument">instrument</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Instrument Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This is the granule collection short name. If this is used then the Collection Version must also exist.  Only this and Collection Version or or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Name }}{# ISO_OPERA_CollectionShortName #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionshortname</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionShortName</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is the granule collection version. If this is used then the Collection Short Name must also exist. Only this and Collection Short Name or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_CollectionVersion #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionversion</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionVersion</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is where View Related Information or Project Home Page RelatedUrls go.-->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://www.jpl.nasa.gov/go/opera</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:aggregateDataSetName>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <gmd:spatialRepresentationType>
+                <gmd:MD_SpatialRepresentationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode" codeListValue="grid">grid</gmd:MD_SpatialRepresentationTypeCode>
+            </gmd:spatialRepresentationType>
+            <!-- This is the language used in the granule -->
+            <gmd:language>
+                <gco:CharacterString>eng</gco:CharacterString>
+            </gmd:language>
+            <!-- this is the character set used in the granule -->
+            <gmd:characterSet>
+                <gmd:MD_CharacterSetCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+            </gmd:characterSet>
+            <gmd:topicCategory>
+                <gmd:MD_TopicCategoryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_TopicCategoryCode" codeListValue="geoscientificInformation">geoscientificInformation</gmd:MD_TopicCategoryCode>
+            </gmd:topicCategory>
+            <gmd:environmentDescription>
+                <gco:CharacterString>Data product generated in Network Common Data From version 4 format with ISO 19115 conformant metadata.</gco:CharacterString>
+            </gmd:environmentDescription>
+            <!-- This section documents the granules spatial and temporal extent as well as the grid mapping names and the projection names - NOT the TilingIdentificationSystem. -->
+            <gmd:extent>
+                <!-- the EX_Extent id must exist with boundingExtent -->
+                <gmd:EX_Extent id="boundingExtent">
+                    <!--Bounding Rectangle-->
+                    <gmd:geographicElement>
+                        <gmd:EX_GeographicBoundingBox>
+                            <gmd:westBoundLongitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lon_min }}{# doc ID ISO_OPERA_westBoundLongitude #}</gco:Decimal>
+                            </gmd:westBoundLongitude>
+                            <gmd:eastBoundLongitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lon_max }}{# doc ID ISO_OPERA_eastBoundLongitude #}</gco:Decimal>
+                            </gmd:eastBoundLongitude>
+                            <gmd:southBoundLatitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lat_min }}{# doc ID ISO_OPERA_southBoundLatitude #}</gco:Decimal>
+                            </gmd:southBoundLatitude>
+                            <gmd:northBoundLatitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lat_max }}{# doc ID ISO_OPERA_northBoundLatitude #}</gco:Decimal>
+                            </gmd:northBoundLatitude>
+                        </gmd:EX_GeographicBoundingBox>
+                    </gmd:geographicElement>
+                    <!-- This section documents the ZoneIdentifier -->
+                    <gmd:geographicElement>
+                        <gmd:EX_GeographicDescription id="ZoneIdentifier">
+                            <gmd:geographicIdentifier>
+                                <gmd:MD_Identifier>
+                                    <gmd:code>
+                                        <gco:CharacterString>{{ product_output.zone_identifier }}{# ISO_OPERA_zoneIdentifier #}</gco:CharacterString>
+                                    </gmd:code>
+                                    <gmd:codeSpace>
+                                        <gco:CharacterString>gov.nasa.esdis.umm.zoneidentifier</gco:CharacterString>
+                                    </gmd:codeSpace>
+                                    <gmd:description>
+                                        <gco:CharacterString>ZoneIdentifier</gco:CharacterString>
+                                    </gmd:description>
+                                </gmd:MD_Identifier>
+                            </gmd:geographicIdentifier>
+                        </gmd:EX_GeographicDescription>
+                    </gmd:geographicElement>
+                    <!-- This is the granules temporal extent -->
+                    <gmd:temporalElement>
+                        <!--RangeDateTime-->
+                        <gmd:EX_TemporalExtent id="boundingTemporalExtent">
+                            <gmd:extent>
+                                <gml:TimePeriod gml:id="TROPO_Time_Range">
+                                    <gml:beginPosition>{{ product_output.temporal_extent.start_time }}{# ISO_OPERA_refDateTime #}</gml:beginPosition>
+                                    <gml:endPosition>{{ product_output.temporal_extent.end_time }}{# ISO_OPERA_secDateTime #}</gml:endPosition>
+                                </gml:TimePeriod>
+                            </gmd:extent>
+                        </gmd:EX_TemporalExtent>
+                    </gmd:temporalElement>
+                </gmd:EX_Extent>
+            </gmd:extent>
+            <gmd:supplementalInformation/>
+        </gmd:MD_DataIdentification>
+    </gmd:identificationInfo>
+    <!-- This is the Measured Parameters section - it needs to be in its own contentInfo section - not within Additional Attributes, DayNightFlag, or CloudCover -->
+    <gmd:contentInfo>
+        <gmd:MD_CoverageDescription>
+            <gmd:attributeDescription>
+                <gco:RecordType>MeasuredParameters</gco:RecordType>
+            </gmd:attributeDescription>
+            <gmd:contentType>
+                <gmd:MD_CoverageContentTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CoverageContentTypeCode" codeListValue="physicalMeasurement">physicalMeasurement</gmd:MD_CoverageContentTypeCode>
+            </gmd:contentType>
+            <gmd:dimension>
+                <gmd:MD_Band>
+                    <gmd:otherProperty>
+                        <gco:Record>
+                            <eos:AdditionalAttributes>
+                                {%- for attribute in product_output.MeasuredParameters.values() %}
+                                <eos:AdditionalAttribute>
+                                    <eos:reference>
+                                        <eos:EOS_AdditionalAttributeDescription>
+                                            <eos:type>
+                                                <eos:EOS_AdditionalAttributeTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/eosCodelists.xml#EOS_AdditionalAttributeTypeCode" codeListValue="{{ attribute.attr_type }}">{{ attribute.attr_type }}</eos:EOS_AdditionalAttributeTypeCode>
+                                            </eos:type>
+                                            <eos:name>
+                                                <gco:CharacterString>{{ attribute.name }}</gco:CharacterString>
+                                            </eos:name>
+                                            <eos:description>
+                                                <gco:CharacterString>{{ attribute.attr_description }}</gco:CharacterString>
+                                            </eos:description>
+                                            <eos:dataType>
+                                                <eos:EOS_AdditionalAttributeDataTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/eosCodelists.xml#EOS_AdditionalAttributeDataTypeCode" codeListValue="{{ attribute.data_type }}">{{ attribute.data_type }}</eos:EOS_AdditionalAttributeDataTypeCode>
+                                            </eos:dataType>
+                                        </eos:EOS_AdditionalAttributeDescription>
+                                    </eos:reference>
+                                    <eos:value>
+                                        <gco:CharacterString>{{ attribute.value }}</gco:CharacterString>
+                                    </eos:value>
+                                </eos:AdditionalAttribute>
+                                {%- endfor %}
+                            </eos:AdditionalAttributes>
+                        </gco:Record>
+                    </gmd:otherProperty>
+                </gmd:MD_Band>
+            </gmd:dimension>
+        </gmd:MD_CoverageDescription>
+    </gmd:contentInfo>
+    <!-- This section holds the Related URLs that pertain to distributions - where UMM-G RelatedUrl/Type = GET SERVICE, GET DATA, OPENDAP DATA ACCESS -->
+    <gmd:distributionInfo>
+        <gmd:MD_Distribution>
+            <gmd:distributor>
+                <gmd:MD_Distributor>
+                    <gmd:distributionFormat>
+                        <gmd:MD_Format>
+                            <gmd:name>
+                                <gco:CharacterString>GeoTIFF</gco:CharacterString>
+                            </gmd:name>
+                        </gmd:MD_Format>
+                    </gmd:distributionFormat>
+                    <gmd:distributorContact gco:nilReason="missing"/>
+                    <gmd:distributorTransferOptions gco:nilReason="missing"/>
+                    <gmd:distributionOrderProcess>
+                        <gmd:MD_StandardOrderProcess>
+                            <gmd:fees>
+                                <gco:CharacterString>free</gco:CharacterString>
+                            </gmd:fees>
+                        </gmd:MD_StandardOrderProcess>
+                    </gmd:distributionOrderProcess>
+                </gmd:MD_Distributor>
+            </gmd:distributor>
+        </gmd:MD_Distribution>
+    </gmd:distributionInfo>
+    <!-- This is the data quality section. It holds ReprocessingActual, ProductionDateTime, PGEVersionClass, Some AdditionalAttributes, and InputGranules.
+         The MeasuredParameters go into its own dataQualityInfo Section. -->
+    <gmd:dataQualityInfo>
+        <gmd:DQ_DataQuality>
+            <!-- this lists that the scope for the data quality section pertains to the data set - the granule. -->
+            <gmd:scope>
+                <gmd:DQ_Scope>
+                    <gmd:level>
+                        <gmd:MD_ScopeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+                    </gmd:level>
+                </gmd:DQ_Scope>
+            </gmd:scope>
+            <gmd:lineage>
+                <gmd:LI_Lineage>
+                    <gmd:statement>
+                        <gco:CharacterString>OPERA L4 TROPO product generated by JPL using ECMWF HRES weather model data and SAS version {{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                    </gmd:statement>
+                    <!-- This section contains the PGEVersionClass -->
+                    <gmd:processStep>
+                        <gmi:LE_ProcessStep>
+                            <gmd:description>
+                                <gco:CharacterString>PGEVersionClass</gco:CharacterString>
+                            </gmd:description>
+                            <gmi:processingInformation>
+                                <eos:EOS_Processing>
+                                    <gmi:identifier>
+                                        <gmd:MD_Identifier>
+                                            <gmd:code>
+                                                <gco:CharacterString>PGEName: {{ catalog_metadata.PGE_Name }}{# ISO_OPERA_pgeName #} PGEVersion: {{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                                            </gmd:code>
+                                            <gmd:codeSpace>
+                                                <gco:CharacterString>gov.nasa.esdis.umm.pgeversionclass</gco:CharacterString>
+                                            </gmd:codeSpace>
+                                            <gmd:description>
+                                                <gco:CharacterString>PGEVersionClass</gco:CharacterString>
+                                            </gmd:description>
+                                        </gmd:MD_Identifier>
+                                    </gmi:identifier>
+                                </eos:EOS_Processing>
+                            </gmi:processingInformation>
+                            <gmi:output>
+                                <gmd:LI_Source>
+                                    <gmd:description>
+                                        <gco:CharacterString>Troposphere Zenith Radar Delays (TROPO) Product - {{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                                    </gmd:description>
+                                </gmd:LI_Source>
+                            </gmi:output>
+                        </gmi:LE_ProcessStep>
+                    </gmd:processStep>
+                    <!-- This is the production date time -->
+                    <gmd:processStep>
+                        <gmi:LE_ProcessStep>
+                            <gmd:description>
+                                <gco:CharacterString>ProductionDateTime</gco:CharacterString>
+                            </gmd:description>
+                            <gmd:dateTime>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+                            </gmd:dateTime>
+                        </gmi:LE_ProcessStep>
+                    </gmd:processStep>
+                    <!-- This section holds the GranuleInputs -->
+                    {%- for input_list_item in catalog_metadata.Input_Files %}
+                    <gmd:source>
+                        <gmi:LE_Source>
+                            <gmd:description>
+                                <gco:CharacterString>GranuleInput</gco:CharacterString>
+                            </gmd:description>
+                            <gmd:sourceCitation>
+                                <gmd:CI_Citation>
+                                    <gmd:title>
+                                        <gmx:FileName src="{{ input_list_item }}{# ISO_OPERA_InputGranuleN #}">
+                                            {{ input_list_item }}{# ISO_OPERA_InputGranuleN #}
+                                        </gmx:FileName>
+                                    </gmd:title>
+                                    <gmd:date gco:nilReason="unknown"/>
+                                </gmd:CI_Citation>
+                            </gmd:sourceCitation>
+                        </gmi:LE_Source>
+                    </gmd:source>
+                    {%- endfor %}
+                    <!--
+                    <gmd:source>
+                        <gmd:LI_Source>
+                            <gmd:description>
+{#                                <gco:CharacterString>Reference DEM - {{ run_config.Groups.PGE.DynamicAncillaryFilesGroup.AncillaryFileMap.dem_file }}{# ISO_OPERA_digitalElevationModelFile #}</gco:CharacterString>#}
+                            </gmd:description>
+                        </gmd:LI_Source>
+                    </gmd:source>
+                    <gmd:source>
+                        <gmd:LI_Source>
+                            <gmd:description>
+{#                                <gco:CharacterString>Reference Water File - {{ run_config.Groups.PGE.DynamicAncillaryFilesGroup.AncillaryFileMap.mask_file }}{# ISO_OPERA_waterMaskFile #}</gco:CharacterString>#}
+                            </gmd:description>
+                        </gmd:LI_Source>
+                    </gmd:source>
+                    -->
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: sdcolli1
body: Let's just remove this altogether since it won't be needed for TROPO
created_at: 2025-05-20T15:27:17Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,85 @@
+Conventions:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: NetCDF-4 conventions adopted in this product
+  display_name: Conventions
+title:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: "OPERA_L4_TROPO-ZENITH"
+  display_name: Title
+institution:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: Name of producing agency (e.g. “NASA JPL”).
+  display_name: Institution
+contact:
+  attribute_data_type: string
+  attribute_type: contentInformation
+  description: Contact information for the producer of the product. (e.g., "opera-sds-ops@jpl.nasa.gov").
+  display_name: Contact
+source:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Source provider (e.g. ECMWF)
+  display_name: Source
+platform:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Numerical Weather Model input. (e.g. Model High Resolution 15-day Forecast (HRES))
+  display_name: Platform
+spatial_resolution:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Spatial resolution of source and product (e.g. 0.07deg)
+  display_name: SpatialResolution
+temporal_resolution:
+  attribute_data_type: string
+  attribute_type: processingInformation
+  description: Temporal resolution of source and product (e.g. 6 hours)
+  display_name: TemporalResolution
+source_url:
path: src/opera/pge/tropo/templates/tropo_measured_parameters.yaml
user: login: sdcolli1
body: Since this is a URL, we need to include `escape_html: true` for this entry to ensure we don't insert any characters that would interfere with XML parsing
created_at: 2025-05-20T15:29:40Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: Nitpick, but let's stick with double quotes for block comments
created_at: 2025-05-20T15:31:12Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: Since this function can raise its own `ValueError`, the causes should be documented in the docstring under a `Raises` section
created_at: 2025-05-20T15:32:31Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: Nice approach here 👍 
created_at: 2025-05-20T15:33:40Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: Need to replace the DSWx-relatd keywords with ones applicable to this PGE (i.e. TROPO, Troposphere, etc.)
created_at: 2025-05-20T15:37:05Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
+            'ISO_OPERA_PlatformKeywords': ['TROPO'],
+            'ISO_OPERA_InstrumentKeywords': ['TROPO']
+        }
+
+        return custom_metadata
+    
+    def _create_iso_metadata(self, tropo_metadata, product_filename):
+        """
+        Creates a rendered version of the ISO metadata template for TROPO
+        output products using metadata from the following locations:
+
+            * RunConfig (in dictionary form)
+            * Output product (dictionary extracted from NetCDF product attributes)
+            * Catalog metadata
+            * "Custom" metadata (all metadata not found anywhere else)
+
+        Parameters
+        ----------
+        tropo_metadata : dict
+            The product metadata corresponding to a NetCDF product to
+            be included as the "product_output" metadata in the rendered ISO xml.
+
+        Returns
+        -------
+        rendered_template : str
+            The ISO metadata template for TROPO filled in with values from the
+            sourced metadata dictionaries.
+
+        """
+        # Use the base PGE implemenation to validate existence of the template
+        super()._create_iso_metadata()
+        
+        runconfig_dict = self.runconfig.asdict()
+
+        product_output_dict = tropo_metadata
+
+        catalog_metadata_dict = self._create_catalog_metadata().asdict()
+
+        custom_data_dict = self._create_custom_metadata(product_filename)
+
+        iso_metadata = {
+            'run_config': runconfig_dict,
+            'product_output': product_output_dict,
+            'catalog_metadata': catalog_metadata_dict,
+            'custom_data': custom_data_dict
+        }
+
+        iso_template_path = abspath(self.runconfig.iso_template_path)
+
+        rendered_template = render_jinja2(iso_template_path, iso_metadata, self.logger)
+
+        return rendered_template    
+    
+    def _stage_output_files(self):
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: Missing docstring here. At a minimum it should detail what makes this implementation different from the one in `base_pge.py`
created_at: 2025-05-20T15:38:03Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
+            'ISO_OPERA_PlatformKeywords': ['TROPO'],
+            'ISO_OPERA_InstrumentKeywords': ['TROPO']
+        }
+
+        return custom_metadata
+    
+    def _create_iso_metadata(self, tropo_metadata, product_filename):
+        """
+        Creates a rendered version of the ISO metadata template for TROPO
+        output products using metadata from the following locations:
+
+            * RunConfig (in dictionary form)
+            * Output product (dictionary extracted from NetCDF product attributes)
+            * Catalog metadata
+            * "Custom" metadata (all metadata not found anywhere else)
+
+        Parameters
+        ----------
+        tropo_metadata : dict
+            The product metadata corresponding to a NetCDF product to
+            be included as the "product_output" metadata in the rendered ISO xml.
+
+        Returns
+        -------
+        rendered_template : str
+            The ISO metadata template for TROPO filled in with values from the
+            sourced metadata dictionaries.
+
+        """
+        # Use the base PGE implemenation to validate existence of the template
+        super()._create_iso_metadata()
+        
+        runconfig_dict = self.runconfig.asdict()
+
+        product_output_dict = tropo_metadata
+
+        catalog_metadata_dict = self._create_catalog_metadata().asdict()
+
+        custom_data_dict = self._create_custom_metadata(product_filename)
+
+        iso_metadata = {
+            'run_config': runconfig_dict,
+            'product_output': product_output_dict,
+            'catalog_metadata': catalog_metadata_dict,
+            'custom_data': custom_data_dict
+        }
+
+        iso_template_path = abspath(self.runconfig.iso_template_path)
+
+        rendered_template = render_jinja2(iso_template_path, iso_metadata, self.logger)
+
+        return rendered_template    
+    
+    def _stage_output_files(self):
+        # Gather the list of output files produced by the SAS
+        output_products = self.runconfig.get_output_product_filenames()
+
+        # For each output file name, assign the final file name matching the
+        # expected conventions. Also extracts netCDF output product.
+        nc_product = None
+        for output_product in output_products:
+            if output_product.endswith('nc'):
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: For consistency's sake, lets check for `'.nc'`
created_at: 2025-05-20T15:40:30Z
author_association: COLLABORATOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
+            'ISO_OPERA_PlatformKeywords': ['TROPO'],
+            'ISO_OPERA_InstrumentKeywords': ['TROPO']
+        }
+
+        return custom_metadata
+    
+    def _create_iso_metadata(self, tropo_metadata, product_filename):
+        """
+        Creates a rendered version of the ISO metadata template for TROPO
+        output products using metadata from the following locations:
+
+            * RunConfig (in dictionary form)
+            * Output product (dictionary extracted from NetCDF product attributes)
+            * Catalog metadata
+            * "Custom" metadata (all metadata not found anywhere else)
+
+        Parameters
+        ----------
+        tropo_metadata : dict
+            The product metadata corresponding to a NetCDF product to
+            be included as the "product_output" metadata in the rendered ISO xml.
+
+        Returns
+        -------
+        rendered_template : str
+            The ISO metadata template for TROPO filled in with values from the
+            sourced metadata dictionaries.
+
+        """
+        # Use the base PGE implemenation to validate existence of the template
+        super()._create_iso_metadata()
+        
+        runconfig_dict = self.runconfig.asdict()
+
+        product_output_dict = tropo_metadata
+
+        catalog_metadata_dict = self._create_catalog_metadata().asdict()
+
+        custom_data_dict = self._create_custom_metadata(product_filename)
+
+        iso_metadata = {
+            'run_config': runconfig_dict,
+            'product_output': product_output_dict,
+            'catalog_metadata': catalog_metadata_dict,
+            'custom_data': custom_data_dict
+        }
+
+        iso_template_path = abspath(self.runconfig.iso_template_path)
+
+        rendered_template = render_jinja2(iso_template_path, iso_metadata, self.logger)
+
+        return rendered_template    
+    
+    def _stage_output_files(self):
+        # Gather the list of output files produced by the SAS
+        output_products = self.runconfig.get_output_product_filenames()
+
+        # For each output file name, assign the final file name matching the
+        # expected conventions. Also extracts netCDF output product.
+        nc_product = None
+        for output_product in output_products:
+            if output_product.endswith('nc'):
+                nc_product = output_product
path: src/opera/pge/tropo/tropo_pge.py
user: login: sdcolli1
body: For completeness, I think we should add a `break` after we've found the `.nc` file
created_at: 2025-05-20T15:41:23Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>Universal Transverse Mercator (UTM)</gco:CharacterString>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: RKuttruff
body: The product spec says this is in WGS84 reference system. I don't know if that requires changing this or how to properly cite for WGS84
created_at: 2025-05-20T16:00:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -141,6 +141,92 @@ def convert_h5py_dataset(dataset_object):
     return result
 
 
+def get_hdf5_attrs_as_dict(file_name, group_path, ignore_keys=[]):
path: src/opera/util/h5_utils.py
user: login: sdcolli1
body: Usually want to avoid assigning a mutable object as a default argument value. `ignore_keys` should default to `None` and this function should initialize it to an empty list if `None` is provided.
created_at: 2025-05-20T16:03:13Z
author_association: COLLABORATOR
diff_hunk: @@ -141,6 +141,92 @@ def convert_h5py_dataset(dataset_object):
     return result
 
 
+def get_hdf5_attrs_as_dict(file_name, group_path, ignore_keys=[]):
+    """
+    Returns HDF5 group attributes as a python dict for a given file and group
+    path.
+
+    Variable data are not included.
+
+    Parameters
+    ----------
+    file_name : str
+        File system path and filename for the HDF5 file to use.
+    group_path : str
+        Group path within the HDF5 file.
+    ignore_keys : iterable, optional
+        Keys within the group to not include in the returned dict.
+
+    Returns
+    -------
+    group_dict : dict
+        Python dict containing variable data from the group path location.
+
+    """
+    with h5py.File(file_name, "r") as h5file:
+        group_object = h5file.get(group_path)
+
+        if group_object is None:
+            raise RuntimeError(f"An error occurred retrieving object '{group_path}' "
+                               f"from file '{file_name}'.")
+
+        group_dict = dict()
+        for k, v in group_object.attrs.items():
+            if k in ignore_keys:
+                continue
+            if isinstance(v, str):
+                group_dict[k] = v
+            elif isinstance(v, np.bytes_):
+                group_dict[k] = v.decode("UTF-8")
+
+    return group_dict
+                               
+        
+def get_extent_from_coordinates(file_name, group_path, longitude='longitude', latitude='latitude'):
+    """
+    Returns spatial extent as (min_lon, max_lon, min_lat, max_lat).
+
+    Variable data are not included.
+
+    Parameters
+    ----------
+    file_name : str
+        File system path and filename for the HDF5 file to use.
+    group_path : str
+        Group path within the HDF5 file.
+    longitude : str
+        Name of longitude coordinate found in group_path.
+    latitude : str
+        Name of latitude coordinate found in group_path.
+
+    Returns
+    -------
+    extent : (float, float, float, float)
+        Tuple containing (min_lon, max_lon, min_lat, max_lat).
+
+    """
+    with h5py.File(file_name, 'r') as h5file:
+        group_object = h5file.get(group_path)
+
+        if group_object is None:
+            raise RuntimeError(f"An error occurred retrieving object '{group_path}' "
path: src/opera/util/h5_utils.py
user: login: sdcolli1
body: See above comment about including a `Raises` section in the docstring
created_at: 2025-05-20T16:04:06Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: RKuttruff
body: I couldn't find it in the schema on a quick search, but I wonder if this can be given in degrees instead of meters
created_at: 2025-05-20T16:05:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>Universal Transverse Mercator (UTM)</gco:CharacterString>
+                            </gmd:title>
+                        </gmd:CI_Citation>
+                    </gmd:authority>
+                </gmd:MD_Identifier>
+            </gmd:referenceSystemIdentifier>
+        </gmd:MD_ReferenceSystem>
+    </gmd:referenceSystemInfo>
+    <!-- This section documents granule data in this metadata record. -->
+    <gmd:identificationInfo>
+        <gmd:MD_DataIdentification>
+            <!-- This section holds the granule MetadataProviderDates, and the granule identifiers -->
+            <gmd:citation>
+                <gmd:CI_Citation>
+                    <gmd:title>
+                        <gmx:FileName>{{ custom_data.ISO_OPERA_ProducerGranuleId }}{# ISO_OPERA_ProducerGranuleId #}</gmx:FileName>
+                    </gmd:title>
+                    <gmd:alternateTitle>
+                        <gco:CharacterString>Troposphere Zenith Radar Delays Product</gco:CharacterString>
+                    </gmd:alternateTitle>
+                    <!-- The date/time that data provider created or updated the granule info on data provider's database.-->
+                    <gmd:date>
+                        <gmd:CI_Date>
+                            <gmd:date>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_MetadataProvider_Action_DateTime #}</gco:DateTime>
+                            </gmd:date>
+                            <gmd:dateType>
+                                <gmd:CI_DateTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}">{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}</gmd:CI_DateTypeCode>
+                            </gmd:dateType>
+                        </gmd:CI_Date>
+                    </gmd:date>
+                    <gmd:edition>
+                        <gco:CharacterString>{{ run_config.Groups.PGE.PrimaryExecutable.ProductVersion }}{# ISO_OPERA_ProductVersion #}</gco:CharacterString>
+                    </gmd:edition>
+                    <!-- This is the producer granule id -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.producergranuleid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>ProducerGranuleId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- PGE Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: PGEVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- SAS Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: SASVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <gmd:citedResponsibleParty>
+                        <gmd:CI_ResponsibleParty>
+                            <gmd:organisationName>
+                                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+                            </gmd:organisationName>
+                            <gmd:contactInfo>
+                                <gmd:CI_Contact xlink:href="#JPLcontactInfo"/>
+                            </gmd:contactInfo>
+                            <gmd:role>
+                                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="originator">originator</gmd:CI_RoleCode>
+                            </gmd:role>
+                        </gmd:CI_ResponsibleParty>
+                    </gmd:citedResponsibleParty>
+                    <gmd:presentationForm>
+                        <gmd:CI_PresentationFormCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_PresentationFormCode" codeListValue="documentDigital">documentDigital</gmd:CI_PresentationFormCode>
+                    </gmd:presentationForm>
+                </gmd:CI_Citation>
+            </gmd:citation>
+            <gmd:abstract>
+                <gco:CharacterString>The L4 Troposphere Zenith Radar Delays (TROPO) product consists of radar sensor-agnostic, one-way troposphere zenith-integrated delays, including both wet and hydrostatic components, at various height levels. TROPO products are distributed over projected map coordinates aligned with the WGS84 reference system.</gco:CharacterString>
+            </gmd:abstract>
+            <gmd:status>
+                <gmd:MD_ProgressCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ProgressCode" codeListValue="completed">completed</gmd:MD_ProgressCode>
+            </gmd:status>
+            <!-- This section holds the ReprocessingPlanned value -->
+            <gmd:resourceMaintenance>
+                <gmd:MD_MaintenanceInformation>
+                    <gmd:maintenanceAndUpdateFrequency>
+                        <gmd:MD_MaintenanceFrequencyCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode" codeListValue="asNeeded">asNeeded</gmd:MD_MaintenanceFrequencyCode>
+                    </gmd:maintenanceAndUpdateFrequency>
+                </gmd:MD_MaintenanceInformation>
+            </gmd:resourceMaintenance>
+            <!-- This section describes projects as keywords. The CMR does not read this section.-->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for project_kw in custom_data.ISO_OPERA_ProjectKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ project_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="project">project</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Project Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes platform keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for platform_kw in custom_data.ISO_OPERA_PlatformKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ platform_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="platform">platform</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Platform Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes instrument keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for instr_kw in custom_data.ISO_OPERA_InstrumentKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ instr_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type><gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="instrument">instrument</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Instrument Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This is the granule collection short name. If this is used then the Collection Version must also exist.  Only this and Collection Version or or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Name }}{# ISO_OPERA_CollectionShortName #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionshortname</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionShortName</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is the granule collection version. If this is used then the Collection Short Name must also exist. Only this and Collection Short Name or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_CollectionVersion #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionversion</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionVersion</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is where View Related Information or Project Home Page RelatedUrls go.-->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://www.jpl.nasa.gov/go/opera</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:aggregateDataSetName>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <gmd:spatialRepresentationType>
+                <gmd:MD_SpatialRepresentationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode" codeListValue="grid">grid</gmd:MD_SpatialRepresentationTypeCode>
+            </gmd:spatialRepresentationType>
+            <!-- This is the language used in the granule -->
+            <gmd:language>
+                <gco:CharacterString>eng</gco:CharacterString>
+            </gmd:language>
+            <!-- this is the character set used in the granule -->
+            <gmd:characterSet>
+                <gmd:MD_CharacterSetCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+            </gmd:characterSet>
+            <gmd:topicCategory>
+                <gmd:MD_TopicCategoryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_TopicCategoryCode" codeListValue="geoscientificInformation">geoscientificInformation</gmd:MD_TopicCategoryCode>
+            </gmd:topicCategory>
+            <gmd:environmentDescription>
+                <gco:CharacterString>Data product generated in Network Common Data From version 4 format with ISO 19115 conformant metadata.</gco:CharacterString>
+            </gmd:environmentDescription>
+            <!-- This section documents the granules spatial and temporal extent as well as the grid mapping names and the projection names - NOT the TilingIdentificationSystem. -->
+            <gmd:extent>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: RKuttruff
body: Should we include vertical extent here since this product exists at multiple elevation layers?
created_at: 2025-05-20T16:08:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>Universal Transverse Mercator (UTM)</gco:CharacterString>
+                            </gmd:title>
+                        </gmd:CI_Citation>
+                    </gmd:authority>
+                </gmd:MD_Identifier>
+            </gmd:referenceSystemIdentifier>
+        </gmd:MD_ReferenceSystem>
+    </gmd:referenceSystemInfo>
+    <!-- This section documents granule data in this metadata record. -->
+    <gmd:identificationInfo>
+        <gmd:MD_DataIdentification>
+            <!-- This section holds the granule MetadataProviderDates, and the granule identifiers -->
+            <gmd:citation>
+                <gmd:CI_Citation>
+                    <gmd:title>
+                        <gmx:FileName>{{ custom_data.ISO_OPERA_ProducerGranuleId }}{# ISO_OPERA_ProducerGranuleId #}</gmx:FileName>
+                    </gmd:title>
+                    <gmd:alternateTitle>
+                        <gco:CharacterString>Troposphere Zenith Radar Delays Product</gco:CharacterString>
+                    </gmd:alternateTitle>
+                    <!-- The date/time that data provider created or updated the granule info on data provider's database.-->
+                    <gmd:date>
+                        <gmd:CI_Date>
+                            <gmd:date>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_MetadataProvider_Action_DateTime #}</gco:DateTime>
+                            </gmd:date>
+                            <gmd:dateType>
+                                <gmd:CI_DateTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}">{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}</gmd:CI_DateTypeCode>
+                            </gmd:dateType>
+                        </gmd:CI_Date>
+                    </gmd:date>
+                    <gmd:edition>
+                        <gco:CharacterString>{{ run_config.Groups.PGE.PrimaryExecutable.ProductVersion }}{# ISO_OPERA_ProductVersion #}</gco:CharacterString>
+                    </gmd:edition>
+                    <!-- This is the producer granule id -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.producergranuleid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>ProducerGranuleId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- PGE Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: PGEVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- SAS Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: SASVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <gmd:citedResponsibleParty>
+                        <gmd:CI_ResponsibleParty>
+                            <gmd:organisationName>
+                                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+                            </gmd:organisationName>
+                            <gmd:contactInfo>
+                                <gmd:CI_Contact xlink:href="#JPLcontactInfo"/>
+                            </gmd:contactInfo>
+                            <gmd:role>
+                                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="originator">originator</gmd:CI_RoleCode>
+                            </gmd:role>
+                        </gmd:CI_ResponsibleParty>
+                    </gmd:citedResponsibleParty>
+                    <gmd:presentationForm>
+                        <gmd:CI_PresentationFormCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_PresentationFormCode" codeListValue="documentDigital">documentDigital</gmd:CI_PresentationFormCode>
+                    </gmd:presentationForm>
+                </gmd:CI_Citation>
+            </gmd:citation>
+            <gmd:abstract>
+                <gco:CharacterString>The L4 Troposphere Zenith Radar Delays (TROPO) product consists of radar sensor-agnostic, one-way troposphere zenith-integrated delays, including both wet and hydrostatic components, at various height levels. TROPO products are distributed over projected map coordinates aligned with the WGS84 reference system.</gco:CharacterString>
+            </gmd:abstract>
+            <gmd:status>
+                <gmd:MD_ProgressCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ProgressCode" codeListValue="completed">completed</gmd:MD_ProgressCode>
+            </gmd:status>
+            <!-- This section holds the ReprocessingPlanned value -->
+            <gmd:resourceMaintenance>
+                <gmd:MD_MaintenanceInformation>
+                    <gmd:maintenanceAndUpdateFrequency>
+                        <gmd:MD_MaintenanceFrequencyCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode" codeListValue="asNeeded">asNeeded</gmd:MD_MaintenanceFrequencyCode>
+                    </gmd:maintenanceAndUpdateFrequency>
+                </gmd:MD_MaintenanceInformation>
+            </gmd:resourceMaintenance>
+            <!-- This section describes projects as keywords. The CMR does not read this section.-->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for project_kw in custom_data.ISO_OPERA_ProjectKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ project_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="project">project</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Project Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes platform keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for platform_kw in custom_data.ISO_OPERA_PlatformKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ platform_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="platform">platform</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Platform Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes instrument keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for instr_kw in custom_data.ISO_OPERA_InstrumentKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ instr_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type><gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="instrument">instrument</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Instrument Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This is the granule collection short name. If this is used then the Collection Version must also exist.  Only this and Collection Version or or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Name }}{# ISO_OPERA_CollectionShortName #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionshortname</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionShortName</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is the granule collection version. If this is used then the Collection Short Name must also exist. Only this and Collection Short Name or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_CollectionVersion #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionversion</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionVersion</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is where View Related Information or Project Home Page RelatedUrls go.-->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://www.jpl.nasa.gov/go/opera</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:aggregateDataSetName>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <gmd:spatialRepresentationType>
+                <gmd:MD_SpatialRepresentationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode" codeListValue="grid">grid</gmd:MD_SpatialRepresentationTypeCode>
+            </gmd:spatialRepresentationType>
+            <!-- This is the language used in the granule -->
+            <gmd:language>
+                <gco:CharacterString>eng</gco:CharacterString>
+            </gmd:language>
+            <!-- this is the character set used in the granule -->
+            <gmd:characterSet>
+                <gmd:MD_CharacterSetCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+            </gmd:characterSet>
+            <gmd:topicCategory>
+                <gmd:MD_TopicCategoryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_TopicCategoryCode" codeListValue="geoscientificInformation">geoscientificInformation</gmd:MD_TopicCategoryCode>
+            </gmd:topicCategory>
+            <gmd:environmentDescription>
+                <gco:CharacterString>Data product generated in Network Common Data From version 4 format with ISO 19115 conformant metadata.</gco:CharacterString>
+            </gmd:environmentDescription>
+            <!-- This section documents the granules spatial and temporal extent as well as the grid mapping names and the projection names - NOT the TilingIdentificationSystem. -->
+            <gmd:extent>
+                <!-- the EX_Extent id must exist with boundingExtent -->
+                <gmd:EX_Extent id="boundingExtent">
+                    <!--Bounding Rectangle-->
+                    <gmd:geographicElement>
+                        <gmd:EX_GeographicBoundingBox>
+                            <gmd:westBoundLongitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lon_min }}{# doc ID ISO_OPERA_westBoundLongitude #}</gco:Decimal>
+                            </gmd:westBoundLongitude>
+                            <gmd:eastBoundLongitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lon_max }}{# doc ID ISO_OPERA_eastBoundLongitude #}</gco:Decimal>
+                            </gmd:eastBoundLongitude>
+                            <gmd:southBoundLatitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lat_min }}{# doc ID ISO_OPERA_southBoundLatitude #}</gco:Decimal>
+                            </gmd:southBoundLatitude>
+                            <gmd:northBoundLatitude>
+                                <gco:Decimal>{{ product_output.spatial_extent.lat_max }}{# doc ID ISO_OPERA_northBoundLatitude #}</gco:Decimal>
+                            </gmd:northBoundLatitude>
+                        </gmd:EX_GeographicBoundingBox>
+                    </gmd:geographicElement>
+                    <!-- This section documents the ZoneIdentifier -->
+                    <gmd:geographicElement>
+                        <gmd:EX_GeographicDescription id="ZoneIdentifier">
+                            <gmd:geographicIdentifier>
+                                <gmd:MD_Identifier>
+                                    <gmd:code>
+                                        <gco:CharacterString>{{ product_output.zone_identifier }}{# ISO_OPERA_zoneIdentifier #}</gco:CharacterString>
+                                    </gmd:code>
+                                    <gmd:codeSpace>
+                                        <gco:CharacterString>gov.nasa.esdis.umm.zoneidentifier</gco:CharacterString>
+                                    </gmd:codeSpace>
+                                    <gmd:description>
+                                        <gco:CharacterString>ZoneIdentifier</gco:CharacterString>
+                                    </gmd:description>
+                                </gmd:MD_Identifier>
+                            </gmd:geographicIdentifier>
+                        </gmd:EX_GeographicDescription>
+                    </gmd:geographicElement>
+                    <!-- This is the granules temporal extent -->
+                    <gmd:temporalElement>
+                        <!--RangeDateTime-->
+                        <gmd:EX_TemporalExtent id="boundingTemporalExtent">
+                            <gmd:extent>
+                                <gml:TimePeriod gml:id="TROPO_Time_Range">
+                                    <gml:beginPosition>{{ product_output.temporal_extent.start_time }}{# ISO_OPERA_refDateTime #}</gml:beginPosition>
+                                    <gml:endPosition>{{ product_output.temporal_extent.end_time }}{# ISO_OPERA_secDateTime #}</gml:endPosition>
+                                </gml:TimePeriod>
+                            </gmd:extent>
+                        </gmd:EX_TemporalExtent>
+                    </gmd:temporalElement>
+                </gmd:EX_Extent>
+            </gmd:extent>
+            <gmd:supplementalInformation/>
+        </gmd:MD_DataIdentification>
+    </gmd:identificationInfo>
+    <!-- This is the Measured Parameters section - it needs to be in its own contentInfo section - not within Additional Attributes, DayNightFlag, or CloudCover -->
+    <gmd:contentInfo>
+        <gmd:MD_CoverageDescription>
+            <gmd:attributeDescription>
+                <gco:RecordType>MeasuredParameters</gco:RecordType>
+            </gmd:attributeDescription>
+            <gmd:contentType>
+                <gmd:MD_CoverageContentTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CoverageContentTypeCode" codeListValue="physicalMeasurement">physicalMeasurement</gmd:MD_CoverageContentTypeCode>
+            </gmd:contentType>
+            <gmd:dimension>
+                <gmd:MD_Band>
+                    <gmd:otherProperty>
+                        <gco:Record>
+                            <eos:AdditionalAttributes>
+                                {%- for attribute in product_output.MeasuredParameters.values() %}
+                                <eos:AdditionalAttribute>
+                                    <eos:reference>
+                                        <eos:EOS_AdditionalAttributeDescription>
+                                            <eos:type>
+                                                <eos:EOS_AdditionalAttributeTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/eosCodelists.xml#EOS_AdditionalAttributeTypeCode" codeListValue="{{ attribute.attr_type }}">{{ attribute.attr_type }}</eos:EOS_AdditionalAttributeTypeCode>
+                                            </eos:type>
+                                            <eos:name>
+                                                <gco:CharacterString>{{ attribute.name }}</gco:CharacterString>
+                                            </eos:name>
+                                            <eos:description>
+                                                <gco:CharacterString>{{ attribute.attr_description }}</gco:CharacterString>
+                                            </eos:description>
+                                            <eos:dataType>
+                                                <eos:EOS_AdditionalAttributeDataTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/eosCodelists.xml#EOS_AdditionalAttributeDataTypeCode" codeListValue="{{ attribute.data_type }}">{{ attribute.data_type }}</eos:EOS_AdditionalAttributeDataTypeCode>
+                                            </eos:dataType>
+                                        </eos:EOS_AdditionalAttributeDescription>
+                                    </eos:reference>
+                                    <eos:value>
+                                        <gco:CharacterString>{{ attribute.value }}</gco:CharacterString>
+                                    </eos:value>
+                                </eos:AdditionalAttribute>
+                                {%- endfor %}
+                            </eos:AdditionalAttributes>
+                        </gco:Record>
+                    </gmd:otherProperty>
+                </gmd:MD_Band>
+            </gmd:dimension>
+        </gmd:MD_CoverageDescription>
+    </gmd:contentInfo>
+    <!-- This section holds the Related URLs that pertain to distributions - where UMM-G RelatedUrl/Type = GET SERVICE, GET DATA, OPENDAP DATA ACCESS -->
+    <gmd:distributionInfo>
+        <gmd:MD_Distribution>
+            <gmd:distributor>
+                <gmd:MD_Distributor>
+                    <gmd:distributionFormat>
+                        <gmd:MD_Format>
+                            <gmd:name>
+                                <gco:CharacterString>GeoTIFF</gco:CharacterString>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: RKuttruff
body: This should be NetCDF
created_at: 2025-05-20T16:08:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
path: src/opera/pge/tropo/tropo_pge.py
user: login: RKuttruff
body: Should update these to apply to TROPO
created_at: 2025-05-20T16:10:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -121,6 +126,16 @@ def test_tropo_pge_execution(self):
         # Check that a RunConfig for the SAS was isolated within the scratch directory
         expected_sas_config_file = join(pge.runconfig.scratch_path, 'test_tropo_config_sas.yaml')
         self.assertTrue(os.path.exists(expected_sas_config_file))
+        
+        # Check that the catalog metadata file was created in the output directory
+        expected_catalog_metadata_file = join(
+            pge.runconfig.output_product_path, pge._catalog_metadata_filename())
+        self.assertTrue(os.path.exists(expected_catalog_metadata_file))
+
+        # # Check that the ISO metadata file was created and filled in as expected
+        expected_iso_metadata_file = join(
+            pge.runconfig.output_product_path, pge._iso_metadata_filename())
+        self.assertTrue(os.path.exists(expected_iso_metadata_file))
path: src/opera/test/pge/tropo/test_tropo_pge.py
user: login: RKuttruff
body: You should add a check here that the ISO file is fully populated and does not contain the template undefined error string
Reference: https://github.com/nasa/opera-sds-pge/blob/f13869f9c67a1b3451c3ca75fe10bcfcb09d96dc/src/opera/test/pge/dist_s1/test_dist_s1_pge.py#L179-L182
created_at: 2025-05-20T16:11:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
+            'ISO_OPERA_PlatformKeywords': ['TROPO'],
+            'ISO_OPERA_InstrumentKeywords': ['TROPO']
+        }
+
+        return custom_metadata
+    
+    def _create_iso_metadata(self, tropo_metadata, product_filename):
+        """
+        Creates a rendered version of the ISO metadata template for TROPO
+        output products using metadata from the following locations:
+
+            * RunConfig (in dictionary form)
+            * Output product (dictionary extracted from NetCDF product attributes)
+            * Catalog metadata
+            * "Custom" metadata (all metadata not found anywhere else)
+
+        Parameters
+        ----------
+        tropo_metadata : dict
+            The product metadata corresponding to a NetCDF product to
+            be included as the "product_output" metadata in the rendered ISO xml.
+
+        Returns
+        -------
+        rendered_template : str
+            The ISO metadata template for TROPO filled in with values from the
+            sourced metadata dictionaries.
+
+        """
+        # Use the base PGE implemenation to validate existence of the template
+        super()._create_iso_metadata()
+        
+        runconfig_dict = self.runconfig.asdict()
+
+        product_output_dict = tropo_metadata
+
+        catalog_metadata_dict = self._create_catalog_metadata().asdict()
+
+        custom_data_dict = self._create_custom_metadata(product_filename)
+
+        iso_metadata = {
+            'run_config': runconfig_dict,
+            'product_output': product_output_dict,
+            'catalog_metadata': catalog_metadata_dict,
+            'custom_data': custom_data_dict
+        }
+
+        iso_template_path = abspath(self.runconfig.iso_template_path)
+
+        rendered_template = render_jinja2(iso_template_path, iso_metadata, self.logger)
+
+        return rendered_template    
+    
+    def _stage_output_files(self):
+        # Gather the list of output files produced by the SAS
+        output_products = self.runconfig.get_output_product_filenames()
+
+        # For each output file name, assign the final file name matching the
+        # expected conventions. Also extracts netCDF output product.
+        nc_product = None
+        for output_product in output_products:
+            if output_product.endswith('nc'):
+                nc_product = output_product
path: src/opera/pge/tropo/tropo_pge.py
user: login: kevinmarlis
body: Even though we're not currently doing any file renaming for TROPO, this for loop does include that step. I could break out the '.nc' search into it's own for loop and add the break. 
created_at: 2025-05-20T16:34:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -141,6 +141,92 @@ def convert_h5py_dataset(dataset_object):
     return result
 
 
+def get_hdf5_attrs_as_dict(file_name, group_path, ignore_keys=[]):
+    """
+    Returns HDF5 group attributes as a python dict for a given file and group
+    path.
+
+    Variable data are not included.
+
+    Parameters
+    ----------
+    file_name : str
+        File system path and filename for the HDF5 file to use.
+    group_path : str
+        Group path within the HDF5 file.
+    ignore_keys : iterable, optional
+        Keys within the group to not include in the returned dict.
+
+    Returns
+    -------
+    group_dict : dict
+        Python dict containing variable data from the group path location.
+
+    """
+    with h5py.File(file_name, "r") as h5file:
+        group_object = h5file.get(group_path)
+
+        if group_object is None:
+            raise RuntimeError(f"An error occurred retrieving object '{group_path}' "
+                               f"from file '{file_name}'.")
+
+        group_dict = dict()
+        for k, v in group_object.attrs.items():
+            if k in ignore_keys:
+                continue
+            if isinstance(v, str):
+                group_dict[k] = v
+            elif isinstance(v, np.bytes_):
+                group_dict[k] = v.decode("UTF-8")
+
+    return group_dict
+                               
+        
+def get_extent_from_coordinates(file_name, group_path, longitude='longitude', latitude='latitude'):
+    """
+    Returns spatial extent as (min_lon, max_lon, min_lat, max_lat).
+
+    Variable data are not included.
+
+    Parameters
+    ----------
+    file_name : str
+        File system path and filename for the HDF5 file to use.
+    group_path : str
+        Group path within the HDF5 file.
+    longitude : str
+        Name of longitude coordinate found in group_path.
+    latitude : str
+        Name of latitude coordinate found in group_path.
+
+    Returns
+    -------
+    extent : (float, float, float, float)
+        Tuple containing (min_lon, max_lon, min_lat, max_lat).
+
+    """
+    with h5py.File(file_name, 'r') as h5file:
+        group_object = h5file.get(group_path)
+
+        if group_object is None:
+            raise RuntimeError(f"An error occurred retrieving object '{group_path}' "
path: src/opera/util/h5_utils.py
user: login: kevinmarlis
body: I'll go ahead and add it to `get_hdf5_group_as_dict` as well since I'm in here already
created_at: 2025-05-20T16:39:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -150,7 +152,254 @@ def _checksum_output_products(self):
         }
 
         return checksums
+    
+    def _parse_temporal_resolution(self, time_res: str):
+        """
+        Converts a time resolution string of the format "{value}{unit}"
+        to a datetime timedelta object. TROPO products define a 
+        temporal_resolution metadata attribute, ex: "6h".
+        
+        Parameters
+        ----------
+        time_res : str
+            Contents of the temporal_resolution attribute from a TROPO
+            output NetCDF product.
+            
+        Returns
+        ----------
+        time_delta : timedelta
+            Datetime timedelta object used to compute the end time of
+            a TROPO output product.
+        """
+        match = re.fullmatch(r'(\d+)([smhdw])', time_res.strip().lower())
+        if not match:
+            raise ValueError(f"Invalid temporal resolution format: {time_res}")
+        
+        value, unit = match.groups()
+        value = int(value)
+
+        unit_map = {
+            's': 'seconds',
+            'm': 'minutes',
+            'h': 'hours',
+            'd': 'days',
+            'w': 'weeks',
+        }
+
+        if unit not in unit_map:
+            raise ValueError(f"Unsupported time unit: {unit}")
+
+        time_delta = timedelta(**{unit_map[unit]: value})
+        return time_delta
+
+
+    def _collect_tropo_product_metadata(self, tropo_product):
+        '''
+        Gathers the available metadata from a sample output TROPO product for
+        use in filling out the ISO metadata template fro the TROPO pge.
+        
+        Parameters
+        ----------
+        tropo_product : str
+            Path to the TROPO NetCDF product to collect metadata from.
+
+        Returns
+        -------
+        output_product_metadata : dict
+            Dictionary containing TROPO output product metadata, formatted
+            for use with the ISO metadata Jinja2 template.
+        '''
+        output_product_metadata = dict()
+        
+        try:
+            measured_parameters = get_tropo_product_metadata(tropo_product)
+            output_product_metadata['MeasuredParameters'] = augment_hdf5_measured_parameters(
+                measured_parameters,
+                self.runconfig.iso_measured_parameter_descriptions,
+                self.logger
+            )
+        except Exception as err:
+            msg = f'Failed to extract metadata from {tropo_product}, reason: {err}'
+            self.logger.critical(self.name, ErrorCode.ISO_METADATA_COULD_NOT_EXTRACT_METADATA, msg)
 
+        # Determine time bounds
+        ref_time = datetime.fromisoformat(measured_parameters["reference_time"])
+        time_res_delta = self._parse_temporal_resolution(measured_parameters["temporal_resolution"])
+        
+        # TODO: end_time needs confirmation
+        output_product_metadata['temporal_extent'] = {
+            'start_time': ref_time,
+            'end_time': ref_time + time_res_delta
+        }
+        
+        spatial_extent = get_extent_from_coordinates(tropo_product, "/")
+        output_product_metadata['spatial_extent'] = {
+            'lon_min': spatial_extent[0],
+            'lon_max': spatial_extent[1],
+            'lat_min': spatial_extent[2],
+            'lat_max': spatial_extent[3]
+        }
+        
+        # TODO: this is a placeholder
+        output_product_metadata["zone_identifier"] = "global"
+        
+        # TODO: spacing value needs confirmation
+        output_product_metadata['xCoordinates'] = {
+            'size': 5120,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        output_product_metadata['yCoordinates'] = {
+            'size': 2560,
+            'spacing': 8000 # 0.07 degrees is ~8km
+        }
+        
+        return output_product_metadata
+    
+    def _create_custom_metadata(self, granule_filename):
+        """
+        Creates the "custom data" dictionary used with the ISO metadata rendering.
+
+        Custom data contains all metadata information needed for the ISO template
+        that is not found within any of the other metadata sources (such as the
+        RunConfig, output product(s), or catalog metadata).
+
+        Returns
+        -------
+        custom_metadata : dict
+            Dictionary containing the custom metadata as expected by the ISO
+            metadata Jinja2 template.
+
+        """
+        custom_metadata = {
+            'ISO_OPERA_FilePackageName': granule_filename,
+            'ISO_OPERA_ProducerGranuleId': granule_filename,
+            'MetadataProviderAction': "creation",
+            'GranuleFilename': granule_filename,
+            'ISO_OPERA_ProjectKeywords': ['OPERA', 'JPL', 'DSWx', 'Dynamic', 'Surface', 'Water', 'Extent'],
path: src/opera/pge/tropo/tropo_pge.py
user: login: RKuttruff
body: Resolving as duplicate
created_at: 2025-05-20T16:58:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>Universal Transverse Mercator (UTM)</gco:CharacterString>
+                            </gmd:title>
+                        </gmd:CI_Citation>
+                    </gmd:authority>
+                </gmd:MD_Identifier>
+            </gmd:referenceSystemIdentifier>
+        </gmd:MD_ReferenceSystem>
+    </gmd:referenceSystemInfo>
+    <!-- This section documents granule data in this metadata record. -->
+    <gmd:identificationInfo>
+        <gmd:MD_DataIdentification>
+            <!-- This section holds the granule MetadataProviderDates, and the granule identifiers -->
+            <gmd:citation>
+                <gmd:CI_Citation>
+                    <gmd:title>
+                        <gmx:FileName>{{ custom_data.ISO_OPERA_ProducerGranuleId }}{# ISO_OPERA_ProducerGranuleId #}</gmx:FileName>
+                    </gmd:title>
+                    <gmd:alternateTitle>
+                        <gco:CharacterString>Troposphere Zenith Radar Delays Product</gco:CharacterString>
+                    </gmd:alternateTitle>
+                    <!-- The date/time that data provider created or updated the granule info on data provider's database.-->
+                    <gmd:date>
+                        <gmd:CI_Date>
+                            <gmd:date>
+                                <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_MetadataProvider_Action_DateTime #}</gco:DateTime>
+                            </gmd:date>
+                            <gmd:dateType>
+                                <gmd:CI_DateTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_DateTypeCode" codeListValue="{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}">{{ custom_data.MetadataProviderAction }}{# ISO_OPERA_MetadataProvider_Action #}</gmd:CI_DateTypeCode>
+                            </gmd:dateType>
+                        </gmd:CI_Date>
+                    </gmd:date>
+                    <gmd:edition>
+                        <gco:CharacterString>{{ run_config.Groups.PGE.PrimaryExecutable.ProductVersion }}{# ISO_OPERA_ProductVersion #}</gco:CharacterString>
+                    </gmd:edition>
+                    <!-- This is the producer granule id -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ custom_data.GranuleFilename }}{# ISO_OPERA_ProducerGranuleId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.producergranuleid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>ProducerGranuleId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- PGE Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_PGEVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: PGEVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <!-- SAS Version -->
+                    <gmd:identifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.SAS_Version }}{# ISO_OPERA_SASVersionId #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.otherid</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>OtherId: SASVersionId</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:identifier>
+                    <gmd:citedResponsibleParty>
+                        <gmd:CI_ResponsibleParty>
+                            <gmd:organisationName>
+                                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+                            </gmd:organisationName>
+                            <gmd:contactInfo>
+                                <gmd:CI_Contact xlink:href="#JPLcontactInfo"/>
+                            </gmd:contactInfo>
+                            <gmd:role>
+                                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="originator">originator</gmd:CI_RoleCode>
+                            </gmd:role>
+                        </gmd:CI_ResponsibleParty>
+                    </gmd:citedResponsibleParty>
+                    <gmd:presentationForm>
+                        <gmd:CI_PresentationFormCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_PresentationFormCode" codeListValue="documentDigital">documentDigital</gmd:CI_PresentationFormCode>
+                    </gmd:presentationForm>
+                </gmd:CI_Citation>
+            </gmd:citation>
+            <gmd:abstract>
+                <gco:CharacterString>The L4 Troposphere Zenith Radar Delays (TROPO) product consists of radar sensor-agnostic, one-way troposphere zenith-integrated delays, including both wet and hydrostatic components, at various height levels. TROPO products are distributed over projected map coordinates aligned with the WGS84 reference system.</gco:CharacterString>
+            </gmd:abstract>
+            <gmd:status>
+                <gmd:MD_ProgressCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_ProgressCode" codeListValue="completed">completed</gmd:MD_ProgressCode>
+            </gmd:status>
+            <!-- This section holds the ReprocessingPlanned value -->
+            <gmd:resourceMaintenance>
+                <gmd:MD_MaintenanceInformation>
+                    <gmd:maintenanceAndUpdateFrequency>
+                        <gmd:MD_MaintenanceFrequencyCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_MaintenanceFrequencyCode" codeListValue="asNeeded">asNeeded</gmd:MD_MaintenanceFrequencyCode>
+                    </gmd:maintenanceAndUpdateFrequency>
+                </gmd:MD_MaintenanceInformation>
+            </gmd:resourceMaintenance>
+            <!-- This section describes projects as keywords. The CMR does not read this section.-->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for project_kw in custom_data.ISO_OPERA_ProjectKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ project_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="project">project</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Project Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes platform keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for platform_kw in custom_data.ISO_OPERA_PlatformKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ platform_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type>
+                        <gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="platform">platform</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Platform Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This section describes instrument keywords -->
+            <gmd:descriptiveKeywords>
+                <gmd:MD_Keywords>
+                    {%- for instr_kw in custom_data.ISO_OPERA_InstrumentKeywords %}
+                    <gmd:keyword>
+                        <gco:CharacterString>{{ instr_kw }}</gco:CharacterString>
+                    </gmd:keyword>
+                    {%- endfor %}
+                    <gmd:type><gmd:MD_KeywordTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_KeywordTypeCode" codeListValue="instrument">instrument</gmd:MD_KeywordTypeCode>
+                    </gmd:type>
+                    <gmd:thesaurusName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>NASA Instrument Keywords</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:organisationName>
+                                        <gco:CharacterString>NASA</gco:CharacterString>
+                                    </gmd:organisationName>
+                                    <gmd:positionName>
+                                        <gco:CharacterString>User Support Office</gco:CharacterString>
+                                    </gmd:positionName>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://support.earthdata.nasa.gov/</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:name>
+                                                        <gco:CharacterString>Earthdata Support</gco:CharacterString>
+                                                    </gmd:name>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>File an issue or provide feedback</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:thesaurusName>
+                </gmd:MD_Keywords>
+            </gmd:descriptiveKeywords>
+            <!-- This is the granule collection short name. If this is used then the Collection Version must also exist.  Only this and Collection Version or or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Name }}{# ISO_OPERA_CollectionShortName #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionshortname</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionShortName</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is the granule collection version. If this is used then the Collection Short Name must also exist. Only this and Collection Short Name or Collection Entry Id are required. -->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetIdentifier>
+                        <gmd:MD_Identifier>
+                            <gmd:code>
+                                <gco:CharacterString>{{ catalog_metadata.PGE_Version|truncate(10, True, '', 0) }}{# ISO_OPERA_CollectionVersion #}</gco:CharacterString>
+                            </gmd:code>
+                            <gmd:codeSpace>
+                                <gco:CharacterString>gov.nasa.esdis.umm.collectionversion</gco:CharacterString>
+                            </gmd:codeSpace>
+                            <gmd:description>
+                                <gco:CharacterString>CollectionVersion</gco:CharacterString>
+                            </gmd:description>
+                        </gmd:MD_Identifier>
+                    </gmd:aggregateDataSetIdentifier>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <!-- This is where View Related Information or Project Home Page RelatedUrls go.-->
+            <gmd:aggregationInfo>
+                <gmd:MD_AggregateInformation>
+                    <gmd:aggregateDataSetName>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                            </gmd:title>
+                            <gmd:date gco:nilReason="unknown"/>
+                            <gmd:citedResponsibleParty>
+                                <gmd:CI_ResponsibleParty>
+                                    <gmd:contactInfo>
+                                        <gmd:CI_Contact>
+                                            <gmd:onlineResource>
+                                                <gmd:CI_OnlineResource>
+                                                    <gmd:linkage>
+                                                        <gmd:URL>https://www.jpl.nasa.gov/go/opera</gmd:URL>
+                                                    </gmd:linkage>
+                                                    <gmd:description>
+                                                        <gco:CharacterString>OPERA Project Homepage</gco:CharacterString>
+                                                    </gmd:description>
+                                                    <gmd:function>
+                                                        <gmd:CI_OnLineFunctionCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_OnLineFunctionCode" codeListValue="information">information</gmd:CI_OnLineFunctionCode>
+                                                    </gmd:function>
+                                                </gmd:CI_OnlineResource>
+                                            </gmd:onlineResource>
+                                        </gmd:CI_Contact>
+                                    </gmd:contactInfo>
+                                    <gmd:role>
+                                        <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="custodian">custodian</gmd:CI_RoleCode>
+                                    </gmd:role>
+                                </gmd:CI_ResponsibleParty>
+                            </gmd:citedResponsibleParty>
+                        </gmd:CI_Citation>
+                    </gmd:aggregateDataSetName>
+                    <gmd:associationType>
+                        <gmd:DS_AssociationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#DS_AssociationTypeCode" codeListValue="LargerWorkCitation">LargerWorkCitation</gmd:DS_AssociationTypeCode>
+                    </gmd:associationType>
+                </gmd:MD_AggregateInformation>
+            </gmd:aggregationInfo>
+            <gmd:spatialRepresentationType>
+                <gmd:MD_SpatialRepresentationTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_SpatialRepresentationTypeCode" codeListValue="grid">grid</gmd:MD_SpatialRepresentationTypeCode>
+            </gmd:spatialRepresentationType>
+            <!-- This is the language used in the granule -->
+            <gmd:language>
+                <gco:CharacterString>eng</gco:CharacterString>
+            </gmd:language>
+            <!-- this is the character set used in the granule -->
+            <gmd:characterSet>
+                <gmd:MD_CharacterSetCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+            </gmd:characterSet>
+            <gmd:topicCategory>
+                <gmd:MD_TopicCategoryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_TopicCategoryCode" codeListValue="geoscientificInformation">geoscientificInformation</gmd:MD_TopicCategoryCode>
+            </gmd:topicCategory>
+            <gmd:environmentDescription>
+                <gco:CharacterString>Data product generated in Network Common Data From version 4 format with ISO 19115 conformant metadata.</gco:CharacterString>
+            </gmd:environmentDescription>
+            <!-- This section documents the granules spatial and temporal extent as well as the grid mapping names and the projection names - NOT the TilingIdentificationSystem. -->
+            <gmd:extent>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: kevinmarlis
body: We can, but the extent is variable as the vertical layers produced are configurable via the runconfig.
created_at: 2025-05-20T17:06:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: kevinmarlis
body: I think we can use degree but would need to change Length to Angle as well. I can try and track down some more resources on this. I'll leave as meter for now though.
created_at: 2025-05-20T17:19:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="column">column</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.yCoordinates.size }}{# ISO_OPERA_azimuthCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.yCoordinates.spacing }}{# ISO_OPERA_azimuthPixelSize #}</gco:Length>
+                    </gmd:resolution>
+                </gmd:MD_Dimension>
+            </gmd:axisDimensionProperties>
+            <gmd:cellGeometry>
+                <gmd:MD_CellGeometryCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CellGeometryCode" codeListValue="area">area</gmd:MD_CellGeometryCode>
+            </gmd:cellGeometry>
+            <gmd:transformationParameterAvailability>
+                <gco:Boolean>false</gco:Boolean>
+            </gmd:transformationParameterAvailability>
+        </gmd:MD_GridSpatialRepresentation>
+    </gmd:spatialRepresentationInfo>
+    <gmd:referenceSystemInfo>
+        <gmd:MD_ReferenceSystem>
+            <gmd:referenceSystemIdentifier>
+                <gmd:MD_Identifier>
+                    <gmd:authority>
+                        <gmd:CI_Citation>
+                            <gmd:title>
+                                <gco:CharacterString>Universal Transverse Mercator (UTM)</gco:CharacterString>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: kevinmarlis
body: Ah, good catch! I believe it should be 
```<gco:CharacterString>World Geodetic System 1984 (WGS84)</gco:CharacterString>```
created_at: 2025-05-20T17:21:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,720 @@
+<?xml version='1.0' encoding='utf-8'?>
+<gmi:MI_Metadata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xmlns:gmd="http://www.isotc211.org/2005/gmd"
+                 xmlns:gco="http://www.isotc211.org/2005/gco"
+                 xmlns:eos="http://earthdata.nasa.gov/schema/eos"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+                 xmlns:gml="http://www.opengis.net/gml/3.2"
+                 xmlns:gmi="http://www.isotc211.org/2005/gmi"
+                 xmlns:gmx="http://www.isotc211.org/2005/gmx">
+    <!-- The granule file name. Should map to core filename used with the PGE -->
+    <gmd:fileIdentifier>
+        <gco:CharacterString>{{ custom_data.ISO_OPERA_FilePackageName }}{# ISO_OPERA_FilePackageName #}</gco:CharacterString>
+    </gmd:fileIdentifier>
+    <!-- The language used as the content of this metadata record. -->
+    <gmd:language>
+        <gco:CharacterString>eng</gco:CharacterString>
+    </gmd:language>
+    <!-- The character set used in this metadata record.-->
+    <gmd:characterSet>
+        <gmd:MD_CharacterSetCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_CharacterSetCode" codeListValue="utf8">utf8</gmd:MD_CharacterSetCode>
+    </gmd:characterSet>
+    <!-- What is represented by this metadata record - currently series means collection and dataset means granule.-->
+    <gmd:hierarchyLevel>
+        <gmd:MD_ScopeCode codeList="http://www.ngdc.noaa.gov/metadata/published/xsd/schema/resources/Codelist/gmxCodelists.xml#MD_ScopeCode" codeListValue="dataset">dataset</gmd:MD_ScopeCode>
+    </gmd:hierarchyLevel>
+    <!-- Contact information for JPL -->
+    <gmd:contact>
+        <gmd:CI_ResponsibleParty>
+            <gmd:organisationName>
+                <gco:CharacterString>Jet Propulsion Laboratory</gco:CharacterString>
+            </gmd:organisationName>
+            <gmd:contactInfo>
+                <gmd:CI_Contact gml:id="JPLcontactInfo">
+                    <gmd:address>
+                        <gmd:CI_Address>
+                            <gmd:deliveryPoint>
+                                <gco:CharacterString>4800 Oak Grove Drive</gco:CharacterString>
+                            </gmd:deliveryPoint>
+                            <gmd:city>
+                                <gco:CharacterString>Pasadena</gco:CharacterString>
+                            </gmd:city>
+                            <gmd:administrativeArea>
+                                <gco:CharacterString>CA</gco:CharacterString>
+                            </gmd:administrativeArea>
+                            <gmd:postalCode>
+                                <gco:CharacterString>91109</gco:CharacterString>
+                            </gmd:postalCode>
+                            <gmd:country>
+                                <gco:CharacterString>USA</gco:CharacterString>
+                            </gmd:country>
+                            <gmd:electronicMailAddress>
+                                <gco:CharacterString>ops@jpl.nasa.gov</gco:CharacterString>
+                            </gmd:electronicMailAddress>
+                        </gmd:CI_Address>
+                    </gmd:address>
+                </gmd:CI_Contact>
+            </gmd:contactInfo>
+            <gmd:role>
+                <gmd:CI_RoleCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#CI_RoleCode" codeListValue="pointOfContact">pointOfContact</gmd:CI_RoleCode>
+            </gmd:role>
+        </gmd:CI_ResponsibleParty>
+    </gmd:contact>
+    <!-- The catalog metadata creation date for the granule -->
+    <gmd:dateStamp>
+        <gco:DateTime>{{ catalog_metadata.Production_DateTime }}{# ISO_OPERA_CreationDateTime_Product #}</gco:DateTime>
+    </gmd:dateStamp>
+    <!-- This section just documents the ISO schema and version used for this record. -->
+    <gmd:metadataStandardName>
+        <gco:CharacterString>ISO 19115-2 Geographic Information - Metadata Part 2 Extensions for imagery and gridded data</gco:CharacterString>
+    </gmd:metadataStandardName>
+    <gmd:metadataStandardVersion>
+        <gco:CharacterString>ISO 19115-2:2019(E)</gco:CharacterString>
+    </gmd:metadataStandardVersion>
+    <gmd:spatialRepresentationInfo>
+        <gmd:MD_GridSpatialRepresentation>
+            <gmd:numberOfDimensions>
+                <gco:Integer>2</gco:Integer>
+            </gmd:numberOfDimensions>
+            <gmd:axisDimensionProperties>
+                <gmd:MD_Dimension>
+                    <gmd:dimensionName>
+                        <gmd:MD_DimensionNameTypeCode codeList="https://cdn.earthdata.nasa.gov/iso/resources/Codelist/gmxCodelists.xml#MD_DimensionNameTypeCode" codeListValue="row">row</gmd:MD_DimensionNameTypeCode>
+                    </gmd:dimensionName>
+                    <gmd:dimensionSize>
+                        <gco:Integer>{{ product_output.xCoordinates.size }}{# ISO_OPERA_rangeCount #}</gco:Integer>
+                    </gmd:dimensionSize>
+                    <gmd:resolution>
+                        <gco:Length uom="meter">{{ product_output.xCoordinates.spacing }}{# ISO_OPERA_rangePixelSize #}</gco:Length>
path: src/opera/pge/tropo/templates/OPERA_ISO_metadata_L4_TROPO_template.xml.jinja2
user: login: RKuttruff
body: FWIW I tried pulling the ISO files for global WGS84 collections like MUR, and they didn't even have some of these sections like spacing and zone identifier
created_at: 2025-05-20T17:22:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -141,6 +141,92 @@ def convert_h5py_dataset(dataset_object):
     return result
 
 
+def get_hdf5_attrs_as_dict(file_name, group_path, ignore_keys=[]):
path: src/opera/util/h5_utils.py
user: login: kevinmarlis
body: Great catch, thank you!
created_at: 2025-05-20T17:27:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: RKuttruff
created_at: 2025-05-20T15:34:19Z
body: @kevinmarlis Secrets detection is flagging this PR, which is normal for ISO XML additions because they contain contact info. I'll message you with the details
author_association: CONTRIBUTOR
user: login: kevinmarlis
created_at: 2025-05-20T17:47:11Z
body: Addressed concerns and closed conversations where changes were implemented. Test is passing on opera-dev-pge. Outstanding items are:

- ISO XML WGS84 usage of spacing and zone identifier
- ISO XML addition of vertical extent
author_association: CONTRIBUTOR