diff --git a/hls_vi/generate_metadata.py b/hls_vi/generate_metadata.py
index 1bd6681..225e314 100644
--- a/hls_vi/generate_metadata.py
+++ b/hls_vi/generate_metadata.py
@@ -92,7 +92,13 @@ def generate_metadata(input_dir: Path, output_dir: Path) -> None:
processing_time = tags["HLS_VI_PROCESSING_TIME"]
granule_ur = tree.find("GranuleUR")
+ input_granule_ur = granule_ur.text
granule_ur.text = granule_ur.text.replace("HLS", "HLS-VI")
+ set_additional_attribute(
+ tree.find("AdditionalAttributes"),
+ "Input_HLS_GranuleUR",
+ input_granule_ur,
+ )
time_format = "%Y-%m-%dT%H:%M:%S.%fZ"
formatted_date = datetime.now(timezone.utc).strftime(time_format)
@@ -125,6 +131,14 @@ def generate_metadata(input_dir: Path, output_dir: Path) -> None:
tree.find("DataFormat").text = "COG"
+ append_fmask_online_access_urls(
+ tree.find("OnlineAccessURLs"),
+ input_granule_ur,
+ )
+
+ # ensure any added attributes are indented
+ ET.indent(tree)
+
with (
importlib_resources.files("hls_vi")
/ "schema"
@@ -142,7 +156,7 @@ def generate_metadata(input_dir: Path, output_dir: Path) -> None:
def normalize_additional_attributes(container: ElementBase) -> None:
"""Normalize additional attribute values.
- On rare occassions, granule data is split and recombined upstream. When this
+ On rare occasions, granule data is split and recombined upstream. When this
occurs, the associated metadata is also split and recombined, resulting in values
for additional attributes that are created by joining the separate parts with the
string `" + "`.
@@ -193,6 +207,39 @@ def set_additional_attribute(attrs: ElementBase, name: str, value: str) -> None:
attrs.append(attr)
+def append_fmask_online_access_urls(
+ access_urls: ElementBase, hls_granule_ur: str
+) -> None:
+ """Include links to Fmask layer from HLS granule in metadata
+
+ This is intended to help users find the relevant Fmask band without
+ having to duplicate it into the HLS-VI product. See,
+ https://github.com/NASA-IMPACT/hls-vi/issues/47
+ """
+ prefix = "HLSL30.020" if hls_granule_ur.startswith("HLS.L30") else "HLSS30.020"
+
+ http_attr = Element("OnlineAccessURL", None, None)
+ http_attr_url = Element("URL", None, None)
+ http_attr_url.text = f"https://data.lpdaac.earthdatacloud.nasa.gov/lp-prod-protected/{prefix}/{hls_granule_ur}/{hls_granule_ur}.Fmask.tif" # noqa: E501
+ http_attr_desc = Element("URLDescription", None, None)
+ http_attr_desc.text = f"Download Fmask quality layer {hls_granule_ur}.Fmask.tif"
+ http_attr.append(http_attr_url)
+ http_attr.append(http_attr_desc)
+
+ s3_attr = Element("OnlineAccessURL", None, None)
+ s3_attr_url = Element("URL", None, None)
+ s3_attr_url.text = (
+ f"s3://lp-prod-protected/{prefix}/{hls_granule_ur}/{hls_granule_ur}.Fmask.tif"
+ )
+ s3_attr_desc = Element("URLDescription", None, None)
+ s3_attr_desc.text = f"This link provides direct download access via S3 to the Fmask quality layer {hls_granule_ur}.Fmask.tif" # noqa: E501
+ s3_attr.append(s3_attr_url)
+ s3_attr.append(s3_attr_desc)
+
+ access_urls.append(http_attr)
+ access_urls.append(s3_attr)
+
+
def parse_args() -> Tuple[Path, Path]:
short_options = "i:o:"
long_options = ["instrument=", "inputdir=", "outputdir="]
diff --git a/hls_vi/schema/Granule.xsd b/hls_vi/schema/Granule.xsd
index ddb5b36..52e46e0 100644
--- a/hls_vi/schema/Granule.xsd
+++ b/hls_vi/schema/Granule.xsd
@@ -14,6 +14,7 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
@@ -1298,7 +1299,7 @@ xmlns:xs="http://www.w3.org/2001/XMLSchema">
type="ListOfAdditionalAttributeValues">
The ordered list of values of the
- additioanl attribute for this granule. The values will be
+ additional attribute for this granule. The values will be
kept in the order which they appear.
diff --git a/hls_vi/schema/MetadataCommon.xsd b/hls_vi/schema/MetadataCommon.xsd
index 4ef8338..12ac2b2 100644
--- a/hls_vi/schema/MetadataCommon.xsd
+++ b/hls_vi/schema/MetadataCommon.xsd
@@ -446,7 +446,7 @@
-
+
The element should contain no children. In
diff --git a/setup.py b/setup.py
index 713b4ed..c19d61e 100644
--- a/setup.py
+++ b/setup.py
@@ -9,8 +9,10 @@
"dataclasses",
"geojson",
"importlib_resources",
- "lxml==3.6.0",
- "numpy~=1.19.0",
+ "lxml==5.3.0",
+ # 1.19 is latest for our container, but ~1.19 allows
+ # a more recent 1.x version for our host
+ "numpy~=1.19",
"pystac[validation]==1.0.0rc2",
"rasterio",
"shapely",
diff --git a/tests/fixtures/HLS-VI.L30.T06WVS.2024120T211159.v2.0.cmr.xml b/tests/fixtures/HLS-VI.L30.T06WVS.2024120T211159.v2.0.cmr.xml
index 01ba39b..5831deb 100644
--- a/tests/fixtures/HLS-VI.L30.T06WVS.2024120T211159.v2.0.cmr.xml
+++ b/tests/fixtures/HLS-VI.L30.T06WVS.2024120T211159.v2.0.cmr.xml
@@ -9,7 +9,7 @@
HLS-VI.L30.T06WVS.2024120T211159
DAY
- UPDATE HLS Prodution DATETIME
+ UPDATE HLS Production DATETIME
2.0
@@ -240,8 +240,22 @@
https://doi.org
+
+ Input_HLS_GranuleUR
+
+ HLS.L30.T06WVS.2024120T211159.v2.0
+
+
+
+ https://data.lpdaac.earthdatacloud.nasa.gov/lp-prod-protected/HLSL30.020/HLS.L30.T06WVS.2024120T211159.v2.0/HLS.L30.T06WVS.2024120T211159.v2.0.Fmask.tif
+ Download Fmask quality layer HLS.L30.T06WVS.2024120T211159.v2.0.Fmask.tif
+
+
+ s3://lp-prod-protected/HLSL30.020/HLS.L30.T06WVS.2024120T211159.v2.0/HLS.L30.T06WVS.2024120T211159.v2.0.Fmask.tif
+ This link provides direct download access via S3 to the Fmask quality layer HLS.L30.T06WVS.2024120T211159.v2.0.Fmask.tif
+
diff --git a/tests/fixtures/HLS-VI.S30.T13RCN.2024128T173909.v2.0.cmr.xml b/tests/fixtures/HLS-VI.S30.T13RCN.2024128T173909.v2.0.cmr.xml
index 9211d51..0f0e6b9 100644
--- a/tests/fixtures/HLS-VI.S30.T13RCN.2024128T173909.v2.0.cmr.xml
+++ b/tests/fixtures/HLS-VI.S30.T13RCN.2024128T173909.v2.0.cmr.xml
@@ -9,7 +9,7 @@
HLS-VI.S30.T13RCN.2024128T173909
DAY
- UPDATE HLS Prodution DATETIME
+ UPDATE HLS Production DATETIME
2.0
@@ -302,8 +302,22 @@
https://doi.org
+
+ Input_HLS_GranuleUR
+
+ HLS.S30.T13RCN.2024128T173909.v2.0
+
+
+
+ https://data.lpdaac.earthdatacloud.nasa.gov/lp-prod-protected/HLSS30.020/HLS.S30.T13RCN.2024128T173909.v2.0/HLS.S30.T13RCN.2024128T173909.v2.0.Fmask.tif
+ Download Fmask quality layer HLS.S30.T13RCN.2024128T173909.v2.0.Fmask.tif
+
+
+ s3://lp-prod-protected/HLSS30.020/HLS.S30.T13RCN.2024128T173909.v2.0/HLS.S30.T13RCN.2024128T173909.v2.0.Fmask.tif
+ This link provides direct download access via S3 to the Fmask quality layer HLS.S30.T13RCN.2024128T173909.v2.0.Fmask.tif
+