From 98d3ae3933e295883c6553453f05bf7b1d499e03 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Wed, 26 Jul 2023 17:47:46 +0200 Subject: [PATCH 1/7] Adding facilities to parse MTL metadata from MTL text format --- src/stactools/landsat/mtl_metadata.py | 63 ++++++++++++++++++++++++++- src/stactools/landsat/stac.py | 12 ++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/stactools/landsat/mtl_metadata.py b/src/stactools/landsat/mtl_metadata.py index a72004c..eb31c00 100644 --- a/src/stactools/landsat/mtl_metadata.py +++ b/src/stactools/landsat/mtl_metadata.py @@ -1,10 +1,12 @@ from collections import defaultdict from datetime import datetime -from typing import Any, Dict, List, Optional +from typing import Any, Dict, List, Optional, Tuple, Iterator +from lxml import etree +from lxml.etree import _Element as lxmlElement from pyproj import Geod from pystac.utils import map_opt, str_to_datetime -from stactools.core.io import ReadHrefModifier +from stactools.core.io import ReadHrefModifier, read_text from stactools.core.io.xml import XmlElement from stactools.core.projection import transform_from_bbox @@ -321,3 +323,60 @@ def from_file( XmlElement.from_file(href, read_href_modifier), href=href, ) + + @classmethod + def from_text_file( + cls, + href: str, + read_href_modifier: Optional[ReadHrefModifier] = None, + ) -> "MtlMetadata": + text = read_text(href, read_href_modifier) + lines = text.split("\n") + mtl = _parse_mtl_group(lines) + return _mtl_group_to_element( + *next(iter(mtl.items())) + ) + + +def _parse_mtl_group(lines: Iterator[str]) -> dict: + group = {} + for line in lines: + key, value = _parse_mtl_line(line) + if not key or key == "END_GROUP": + break + elif key == "GROUP": + key = value + value = _parse_mtl_group(lines) + group[key] = value + return group + + +def _parse_mtl_line(line: str) -> Tuple[str, str]: + line = line.strip() + if not line or line == "END": + return (None, None) + + key, _, value = line.partition(" = ") + if value.startswith('"') and value.endswith('"'): + value = value[1:-1] + + return key, value + + +def _mtl_value_element(tag: str, value: str) -> lxmlElement: + element: lxmlElement = etree.Element(tag) + element.text = value + return element + + +def _mtl_group_to_element(name: str, group: dict) -> lxmlElement: + element: lxmlElement = etree.Element(name) + element.extend( + [ + _mtl_group_to_element(child_name, child) + if isinstance(child, dict) else + _mtl_value_element(child_name, child) + for child_name, child in group.items() + ] + ) + return element diff --git a/src/stactools/landsat/stac.py b/src/stactools/landsat/stac.py index 9bec294..d78a2e6 100644 --- a/src/stactools/landsat/stac.py +++ b/src/stactools/landsat/stac.py @@ -1,6 +1,7 @@ import logging from datetime import datetime, timezone from typing import Optional +from urllib.parse import urlparse import shapely from pystac import Collection, Item, Link, MediaType @@ -63,7 +64,16 @@ def create_item( """ base_href = "_".join(mtl_xml_href.split("_")[:-1]) - mtl_metadata = MtlMetadata.from_file(mtl_xml_href, read_href_modifier) + mtl_metadata = None + + if urlparse(mtl_xml_href).path.endswith(".txt"): + try: + mtl_metadata = MtlMetadata.from_text_file(mtl_xml_href, read_href_modifier) + except Exception as e: + pass + + if mtl_metadata is None: + mtl_metadata = MtlMetadata.from_file(mtl_xml_href, read_href_modifier) sensor = Sensor(mtl_metadata.item_id[1]) satellite = int(mtl_metadata.item_id[2:4]) From cf0767c9d17b598eaab6fb0bea2390ee16d4b856 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Wed, 26 Jul 2023 17:48:38 +0200 Subject: [PATCH 2/7] Logging parsing error --- src/stactools/landsat/stac.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stactools/landsat/stac.py b/src/stactools/landsat/stac.py index d78a2e6..63b26eb 100644 --- a/src/stactools/landsat/stac.py +++ b/src/stactools/landsat/stac.py @@ -70,7 +70,7 @@ def create_item( try: mtl_metadata = MtlMetadata.from_text_file(mtl_xml_href, read_href_modifier) except Exception as e: - pass + logger.warning(f"Failed to parse MTL from text: {e}") if mtl_metadata is None: mtl_metadata = MtlMetadata.from_file(mtl_xml_href, read_href_modifier) From 6b3ab2d8a68cdca95658cd313a6e913478669baa Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Wed, 26 Jul 2023 18:40:50 +0200 Subject: [PATCH 3/7] Adding tests and data files for MTL text parsing --- ...2SP_047027_20201204_20210313_02_T1_MTL.txt | 355 ++++++++++++++++++ ...2SR_084024_20160111_20201016_02_T1_MTL.txt | 322 ++++++++++++++++ ...2SP_010065_20220129_20220131_02_T1_MTL.txt | 351 +++++++++++++++++ tests/test_create_stac.py | 13 + 4 files changed, 1041 insertions(+) create mode 100644 tests/data-files/oli-tirs/LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt create mode 100644 tests/data-files/oli-tirs/LC08_L2SR_084024_20160111_20201016_02_T1_MTL.txt create mode 100644 tests/data-files/oli-tirs/LC09_L2SP_010065_20220129_20220131_02_T1_MTL.txt diff --git a/tests/data-files/oli-tirs/LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt b/tests/data-files/oli-tirs/LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt new file mode 100644 index 0000000..ef4d488 --- /dev/null +++ b/tests/data-files/oli-tirs/LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt @@ -0,0 +1,355 @@ +GROUP = LANDSAT_METADATA_FILE + GROUP = PRODUCT_CONTENTS + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P9OGBGM6" + LANDSAT_PRODUCT_ID = "LC08_L2SP_047027_20201204_20210313_02_T1" + PROCESSING_LEVEL = "L2SP" + COLLECTION_NUMBER = 02 + COLLECTION_CATEGORY = "T1" + OUTPUT_FORMAT = "GEOTIFF" + FILE_NAME_BAND_1 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B1.TIF" + FILE_NAME_BAND_2 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B2.TIF" + FILE_NAME_BAND_3 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B3.TIF" + FILE_NAME_BAND_4 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B4.TIF" + FILE_NAME_BAND_5 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B5.TIF" + FILE_NAME_BAND_6 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B6.TIF" + FILE_NAME_BAND_7 = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_B7.TIF" + FILE_NAME_BAND_ST_B10 = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_B10.TIF" + FILE_NAME_THERMAL_RADIANCE = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_TRAD.TIF" + FILE_NAME_UPWELL_RADIANCE = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_URAD.TIF" + FILE_NAME_DOWNWELL_RADIANCE = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_DRAD.TIF" + FILE_NAME_ATMOSPHERIC_TRANSMITTANCE = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_ATRAN.TIF" + FILE_NAME_EMISSIVITY = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_EMIS.TIF" + FILE_NAME_EMISSIVITY_STDEV = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_EMSD.TIF" + FILE_NAME_CLOUD_DISTANCE = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_CDIST.TIF" + FILE_NAME_QUALITY_L2_AEROSOL = "LC08_L2SP_047027_20201204_20210313_02_T1_SR_QA_AEROSOL.TIF" + FILE_NAME_QUALITY_L2_SURFACE_TEMPERATURE = "LC08_L2SP_047027_20201204_20210313_02_T1_ST_QA.TIF" + FILE_NAME_QUALITY_L1_PIXEL = "LC08_L2SP_047027_20201204_20210313_02_T1_QA_PIXEL.TIF" + FILE_NAME_QUALITY_L1_RADIOMETRIC_SATURATION = "LC08_L2SP_047027_20201204_20210313_02_T1_QA_RADSAT.TIF" + FILE_NAME_ANGLE_COEFFICIENT = "LC08_L2SP_047027_20201204_20210313_02_T1_ANG.txt" + FILE_NAME_METADATA_ODL = "LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt" + FILE_NAME_METADATA_XML = "LC08_L2SP_047027_20201204_20210313_02_T1_MTL.xml" + DATA_TYPE_BAND_1 = "UINT16" + DATA_TYPE_BAND_2 = "UINT16" + DATA_TYPE_BAND_3 = "UINT16" + DATA_TYPE_BAND_4 = "UINT16" + DATA_TYPE_BAND_5 = "UINT16" + DATA_TYPE_BAND_6 = "UINT16" + DATA_TYPE_BAND_7 = "UINT16" + DATA_TYPE_BAND_ST_B10 = "UINT16" + DATA_TYPE_THERMAL_RADIANCE = "INT16" + DATA_TYPE_UPWELL_RADIANCE = "INT16" + DATA_TYPE_DOWNWELL_RADIANCE = "INT16" + DATA_TYPE_ATMOSPHERIC_TRANSMITTANCE = "INT16" + DATA_TYPE_EMISSIVITY = "INT16" + DATA_TYPE_EMISSIVITY_STDEV = "INT16" + DATA_TYPE_CLOUD_DISTANCE = "INT16" + DATA_TYPE_QUALITY_L2_AEROSOL = "UINT8" + DATA_TYPE_QUALITY_L2_SURFACE_TEMPERATURE = "INT16" + DATA_TYPE_QUALITY_L1_PIXEL = "UINT16" + DATA_TYPE_QUALITY_L1_RADIOMETRIC_SATURATION = "UINT16" + END_GROUP = PRODUCT_CONTENTS + GROUP = IMAGE_ATTRIBUTES + SPACECRAFT_ID = "LANDSAT_8" + SENSOR_ID = "OLI_TIRS" + WRS_TYPE = 2 + WRS_PATH = 47 + WRS_ROW = 27 + NADIR_OFFNADIR = "NADIR" + TARGET_WRS_PATH = 47 + TARGET_WRS_ROW = 27 + DATE_ACQUIRED = 2020-12-04 + SCENE_CENTER_TIME = "19:02:11.1944860Z" + STATION_ID = "LGN" + CLOUD_COVER = 1.55 + CLOUD_COVER_LAND = 1.90 + IMAGE_QUALITY_OLI = 9 + IMAGE_QUALITY_TIRS = 9 + SATURATION_BAND_1 = "N" + SATURATION_BAND_2 = "N" + SATURATION_BAND_3 = "N" + SATURATION_BAND_4 = "N" + SATURATION_BAND_5 = "N" + SATURATION_BAND_6 = "Y" + SATURATION_BAND_7 = "Y" + SATURATION_BAND_8 = "N" + SATURATION_BAND_9 = "N" + ROLL_ANGLE = -0.001 + SUN_AZIMUTH = 164.91405951 + SUN_ELEVATION = 18.80722985 + EARTH_SUN_DISTANCE = 0.9854607 + TRUNCATION_OLI = "UPPER" + TIRS_SSM_MODEL = "FINAL" + TIRS_SSM_POSITION_STATUS = "ESTIMATED" + END_GROUP = IMAGE_ATTRIBUTES + GROUP = PROJECTION_ATTRIBUTES + MAP_PROJECTION = "UTM" + DATUM = "WGS84" + ELLIPSOID = "WGS84" + UTM_ZONE = 10 + GRID_CELL_SIZE_REFLECTIVE = 30.00 + GRID_CELL_SIZE_THERMAL = 30.00 + REFLECTIVE_LINES = 7971 + REFLECTIVE_SAMPLES = 7861 + THERMAL_LINES = 7971 + THERMAL_SAMPLES = 7861 + ORIENTATION = "NORTH_UP" + CORNER_UL_LAT_PRODUCT = 48.50387 + CORNER_UL_LON_PRODUCT = -124.98066 + CORNER_UR_LAT_PRODUCT = 48.51453 + CORNER_UR_LON_PRODUCT = -121.78809 + CORNER_LL_LAT_PRODUCT = 46.35366 + CORNER_LL_LON_PRODUCT = -124.90156 + CORNER_LR_LAT_PRODUCT = 46.36356 + CORNER_LR_LON_PRODUCT = -121.83650 + CORNER_UL_PROJECTION_X_PRODUCT = 353700.000 + CORNER_UL_PROJECTION_Y_PRODUCT = 5374200.000 + CORNER_UR_PROJECTION_X_PRODUCT = 589500.000 + CORNER_UR_PROJECTION_Y_PRODUCT = 5374200.000 + CORNER_LL_PROJECTION_X_PRODUCT = 353700.000 + CORNER_LL_PROJECTION_Y_PRODUCT = 5135100.000 + CORNER_LR_PROJECTION_X_PRODUCT = 589500.000 + CORNER_LR_PROJECTION_Y_PRODUCT = 5135100.000 + END_GROUP = PROJECTION_ATTRIBUTES + GROUP = LEVEL2_PROCESSING_RECORD + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P9OGBGM6" + REQUEST_ID = "P700p3y2un5a2_00004" + LANDSAT_PRODUCT_ID = "LC08_L2SP_047027_20201204_20210313_02_T1" + PROCESSING_LEVEL = "L2SP" + OUTPUT_FORMAT = "GEOTIFF" + DATE_PRODUCT_GENERATED = "2021-03-13T05:55:12Z" + PROCESSING_SOFTWARE_VERSION = "LPGS_15.4.0" + ALGORITHM_SOURCE_SURFACE_REFLECTANCE = "LaSRC_1.5.0" + DATA_SOURCE_OZONE = "MODIS" + DATA_SOURCE_PRESSURE = "Calculated" + DATA_SOURCE_WATER_VAPOR = "MODIS" + DATA_SOURCE_AIR_TEMPERATURE = "MODIS" + ALGORITHM_SOURCE_SURFACE_TEMPERATURE = "st_1.3.0" + DATA_SOURCE_REANALYSIS = "GEOS-5 FP-IT" + END_GROUP = LEVEL2_PROCESSING_RECORD + GROUP = LEVEL2_SURFACE_REFLECTANCE_PARAMETERS + REFLECTANCE_MAXIMUM_BAND_1 = 1.602213 + REFLECTANCE_MINIMUM_BAND_1 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_2 = 1.602213 + REFLECTANCE_MINIMUM_BAND_2 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_3 = 1.602213 + REFLECTANCE_MINIMUM_BAND_3 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_4 = 1.602213 + REFLECTANCE_MINIMUM_BAND_4 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_5 = 1.602213 + REFLECTANCE_MINIMUM_BAND_5 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_6 = 1.602213 + REFLECTANCE_MINIMUM_BAND_6 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_7 = 1.602213 + REFLECTANCE_MINIMUM_BAND_7 = -0.199972 + QUANTIZE_CAL_MAX_BAND_1 = 65535 + QUANTIZE_CAL_MIN_BAND_1 = 1 + QUANTIZE_CAL_MAX_BAND_2 = 65535 + QUANTIZE_CAL_MIN_BAND_2 = 1 + QUANTIZE_CAL_MAX_BAND_3 = 65535 + QUANTIZE_CAL_MIN_BAND_3 = 1 + QUANTIZE_CAL_MAX_BAND_4 = 65535 + QUANTIZE_CAL_MIN_BAND_4 = 1 + QUANTIZE_CAL_MAX_BAND_5 = 65535 + QUANTIZE_CAL_MIN_BAND_5 = 1 + QUANTIZE_CAL_MAX_BAND_6 = 65535 + QUANTIZE_CAL_MIN_BAND_6 = 1 + QUANTIZE_CAL_MAX_BAND_7 = 65535 + QUANTIZE_CAL_MIN_BAND_7 = 1 + REFLECTANCE_MULT_BAND_1 = 2.75e-05 + REFLECTANCE_MULT_BAND_2 = 2.75e-05 + REFLECTANCE_MULT_BAND_3 = 2.75e-05 + REFLECTANCE_MULT_BAND_4 = 2.75e-05 + REFLECTANCE_MULT_BAND_5 = 2.75e-05 + REFLECTANCE_MULT_BAND_6 = 2.75e-05 + REFLECTANCE_MULT_BAND_7 = 2.75e-05 + REFLECTANCE_ADD_BAND_1 = -0.2 + REFLECTANCE_ADD_BAND_2 = -0.2 + REFLECTANCE_ADD_BAND_3 = -0.2 + REFLECTANCE_ADD_BAND_4 = -0.2 + REFLECTANCE_ADD_BAND_5 = -0.2 + REFLECTANCE_ADD_BAND_6 = -0.2 + REFLECTANCE_ADD_BAND_7 = -0.2 + END_GROUP = LEVEL2_SURFACE_REFLECTANCE_PARAMETERS + GROUP = LEVEL2_SURFACE_TEMPERATURE_PARAMETERS + TEMPERATURE_MAXIMUM_BAND_ST_B10 = 372.999941 + TEMPERATURE_MINIMUM_BAND_ST_B10 = 149.003418 + QUANTIZE_CAL_MAXIMUM_BAND_ST_B10 = 65535 + QUANTIZE_CAL_MINIMUM_BAND_ST_B10 = 1 + TEMPERATURE_MULT_BAND_ST_B10 = 0.00341802 + TEMPERATURE_ADD_BAND_ST_B10 = 149.0 + END_GROUP = LEVEL2_SURFACE_TEMPERATURE_PARAMETERS + GROUP = LEVEL1_PROCESSING_RECORD + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P975CC9B" + REQUEST_ID = "P700p3y2un5a2_00004" + LANDSAT_SCENE_ID = "LC80470272020339LGN00" + LANDSAT_PRODUCT_ID = "LC08_L1TP_047027_20201204_20210313_02_T1" + PROCESSING_LEVEL = "L1TP" + COLLECTION_CATEGORY = "T1" + OUTPUT_FORMAT = "GEOTIFF" + DATE_PRODUCT_GENERATED = "2021-03-13T05:35:53Z" + PROCESSING_SOFTWARE_VERSION = "LPGS_15.4.0" + FILE_NAME_BAND_1 = "LC08_L1TP_047027_20201204_20210313_02_T1_B1.TIF" + FILE_NAME_BAND_2 = "LC08_L1TP_047027_20201204_20210313_02_T1_B2.TIF" + FILE_NAME_BAND_3 = "LC08_L1TP_047027_20201204_20210313_02_T1_B3.TIF" + FILE_NAME_BAND_4 = "LC08_L1TP_047027_20201204_20210313_02_T1_B4.TIF" + FILE_NAME_BAND_5 = "LC08_L1TP_047027_20201204_20210313_02_T1_B5.TIF" + FILE_NAME_BAND_6 = "LC08_L1TP_047027_20201204_20210313_02_T1_B6.TIF" + FILE_NAME_BAND_7 = "LC08_L1TP_047027_20201204_20210313_02_T1_B7.TIF" + FILE_NAME_BAND_8 = "LC08_L1TP_047027_20201204_20210313_02_T1_B8.TIF" + FILE_NAME_BAND_9 = "LC08_L1TP_047027_20201204_20210313_02_T1_B9.TIF" + FILE_NAME_BAND_10 = "LC08_L1TP_047027_20201204_20210313_02_T1_B10.TIF" + FILE_NAME_BAND_11 = "LC08_L1TP_047027_20201204_20210313_02_T1_B11.TIF" + FILE_NAME_QUALITY_L1_PIXEL = "LC08_L1TP_047027_20201204_20210313_02_T1_QA_PIXEL.TIF" + FILE_NAME_QUALITY_L1_RADIOMETRIC_SATURATION = "LC08_L1TP_047027_20201204_20210313_02_T1_QA_RADSAT.TIF" + FILE_NAME_ANGLE_COEFFICIENT = "LC08_L1TP_047027_20201204_20210313_02_T1_ANG.txt" + FILE_NAME_ANGLE_SENSOR_AZIMUTH_BAND_4 = "LC08_L1TP_047027_20201204_20210313_02_T1_VAA.TIF" + FILE_NAME_ANGLE_SENSOR_ZENITH_BAND_4 = "LC08_L1TP_047027_20201204_20210313_02_T1_VZA.TIF" + FILE_NAME_ANGLE_SOLAR_AZIMUTH_BAND_4 = "LC08_L1TP_047027_20201204_20210313_02_T1_SAA.TIF" + FILE_NAME_ANGLE_SOLAR_ZENITH_BAND_4 = "LC08_L1TP_047027_20201204_20210313_02_T1_SZA.TIF" + FILE_NAME_METADATA_ODL = "LC08_L1TP_047027_20201204_20210313_02_T1_MTL.txt" + FILE_NAME_METADATA_XML = "LC08_L1TP_047027_20201204_20210313_02_T1_MTL.xml" + FILE_NAME_CPF = "LC08CPF_20201129_20201211_02.06" + FILE_NAME_BPF_OLI = "LO8BPF20201204185710_20201204203603.01" + FILE_NAME_BPF_TIRS = "LT8BPF20201130223616_20201216101155.02" + FILE_NAME_RLUT = "LC08RLUT_20150303_20431231_02_01.h5" + DATA_SOURCE_TIRS_STRAY_LIGHT_CORRECTION = "TIRS" + DATA_SOURCE_ELEVATION = "GLS2000" + GROUND_CONTROL_POINTS_VERSION = 5 + GROUND_CONTROL_POINTS_MODEL = 839 + GEOMETRIC_RMSE_MODEL = 9.026 + GEOMETRIC_RMSE_MODEL_Y = 7.842 + GEOMETRIC_RMSE_MODEL_X = 4.471 + GROUND_CONTROL_POINTS_VERIFY = 546 + GEOMETRIC_RMSE_VERIFY = 18.481 + END_GROUP = LEVEL1_PROCESSING_RECORD + GROUP = LEVEL1_MIN_MAX_RADIANCE + RADIANCE_MAXIMUM_BAND_1 = 782.65582 + RADIANCE_MINIMUM_BAND_1 = -64.63197 + RADIANCE_MAXIMUM_BAND_2 = 801.44910 + RADIANCE_MINIMUM_BAND_2 = -66.18393 + RADIANCE_MAXIMUM_BAND_3 = 738.52850 + RADIANCE_MINIMUM_BAND_3 = -60.98792 + RADIANCE_MAXIMUM_BAND_4 = 622.76880 + RADIANCE_MINIMUM_BAND_4 = -51.42845 + RADIANCE_MAXIMUM_BAND_5 = 381.10345 + RADIANCE_MINIMUM_BAND_5 = -31.47165 + RADIANCE_MAXIMUM_BAND_6 = 94.77696 + RADIANCE_MINIMUM_BAND_6 = -7.82671 + RADIANCE_MAXIMUM_BAND_7 = 31.94491 + RADIANCE_MINIMUM_BAND_7 = -2.63802 + RADIANCE_MAXIMUM_BAND_8 = 704.80292 + RADIANCE_MINIMUM_BAND_8 = -58.20285 + RADIANCE_MAXIMUM_BAND_9 = 148.94388 + RADIANCE_MINIMUM_BAND_9 = -12.29983 + RADIANCE_MAXIMUM_BAND_10 = 22.00180 + RADIANCE_MINIMUM_BAND_10 = 0.10033 + RADIANCE_MAXIMUM_BAND_11 = 22.00180 + RADIANCE_MINIMUM_BAND_11 = 0.10033 + END_GROUP = LEVEL1_MIN_MAX_RADIANCE + GROUP = LEVEL1_MIN_MAX_REFLECTANCE + REFLECTANCE_MAXIMUM_BAND_1 = 1.210700 + REFLECTANCE_MINIMUM_BAND_1 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_2 = 1.210700 + REFLECTANCE_MINIMUM_BAND_2 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_3 = 1.210700 + REFLECTANCE_MINIMUM_BAND_3 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_4 = 1.210700 + REFLECTANCE_MINIMUM_BAND_4 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_5 = 1.210700 + REFLECTANCE_MINIMUM_BAND_5 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_6 = 1.210700 + REFLECTANCE_MINIMUM_BAND_6 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_7 = 1.210700 + REFLECTANCE_MINIMUM_BAND_7 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_8 = 1.210700 + REFLECTANCE_MINIMUM_BAND_8 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_9 = 1.210700 + REFLECTANCE_MINIMUM_BAND_9 = -0.099980 + END_GROUP = LEVEL1_MIN_MAX_REFLECTANCE + GROUP = LEVEL1_MIN_MAX_PIXEL_VALUE + QUANTIZE_CAL_MAX_BAND_1 = 65535 + QUANTIZE_CAL_MIN_BAND_1 = 1 + QUANTIZE_CAL_MAX_BAND_2 = 65535 + QUANTIZE_CAL_MIN_BAND_2 = 1 + QUANTIZE_CAL_MAX_BAND_3 = 65535 + QUANTIZE_CAL_MIN_BAND_3 = 1 + QUANTIZE_CAL_MAX_BAND_4 = 65535 + QUANTIZE_CAL_MIN_BAND_4 = 1 + QUANTIZE_CAL_MAX_BAND_5 = 65535 + QUANTIZE_CAL_MIN_BAND_5 = 1 + QUANTIZE_CAL_MAX_BAND_6 = 65535 + QUANTIZE_CAL_MIN_BAND_6 = 1 + QUANTIZE_CAL_MAX_BAND_7 = 65535 + QUANTIZE_CAL_MIN_BAND_7 = 1 + QUANTIZE_CAL_MAX_BAND_8 = 65535 + QUANTIZE_CAL_MIN_BAND_8 = 1 + QUANTIZE_CAL_MAX_BAND_9 = 65535 + QUANTIZE_CAL_MIN_BAND_9 = 1 + QUANTIZE_CAL_MAX_BAND_10 = 65535 + QUANTIZE_CAL_MIN_BAND_10 = 1 + QUANTIZE_CAL_MAX_BAND_11 = 65535 + QUANTIZE_CAL_MIN_BAND_11 = 1 + END_GROUP = LEVEL1_MIN_MAX_PIXEL_VALUE + GROUP = LEVEL1_RADIOMETRIC_RESCALING + RADIANCE_MULT_BAND_1 = 1.2929E-02 + RADIANCE_MULT_BAND_2 = 1.3239E-02 + RADIANCE_MULT_BAND_3 = 1.2200E-02 + RADIANCE_MULT_BAND_4 = 1.0288E-02 + RADIANCE_MULT_BAND_5 = 6.2956E-03 + RADIANCE_MULT_BAND_6 = 1.5657E-03 + RADIANCE_MULT_BAND_7 = 5.2771E-04 + RADIANCE_MULT_BAND_8 = 1.1643E-02 + RADIANCE_MULT_BAND_9 = 2.4605E-03 + RADIANCE_MULT_BAND_10 = 3.3420E-04 + RADIANCE_MULT_BAND_11 = 3.3420E-04 + RADIANCE_ADD_BAND_1 = -64.64490 + RADIANCE_ADD_BAND_2 = -66.19717 + RADIANCE_ADD_BAND_3 = -61.00012 + RADIANCE_ADD_BAND_4 = -51.43874 + RADIANCE_ADD_BAND_5 = -31.47794 + RADIANCE_ADD_BAND_6 = -7.82828 + RADIANCE_ADD_BAND_7 = -2.63855 + RADIANCE_ADD_BAND_8 = -58.21450 + RADIANCE_ADD_BAND_9 = -12.30229 + RADIANCE_ADD_BAND_10 = 0.10000 + RADIANCE_ADD_BAND_11 = 0.10000 + REFLECTANCE_MULT_BAND_1 = 2.0000E-05 + REFLECTANCE_MULT_BAND_2 = 2.0000E-05 + REFLECTANCE_MULT_BAND_3 = 2.0000E-05 + REFLECTANCE_MULT_BAND_4 = 2.0000E-05 + REFLECTANCE_MULT_BAND_5 = 2.0000E-05 + REFLECTANCE_MULT_BAND_6 = 2.0000E-05 + REFLECTANCE_MULT_BAND_7 = 2.0000E-05 + REFLECTANCE_MULT_BAND_8 = 2.0000E-05 + REFLECTANCE_MULT_BAND_9 = 2.0000E-05 + REFLECTANCE_ADD_BAND_1 = -0.100000 + REFLECTANCE_ADD_BAND_2 = -0.100000 + REFLECTANCE_ADD_BAND_3 = -0.100000 + REFLECTANCE_ADD_BAND_4 = -0.100000 + REFLECTANCE_ADD_BAND_5 = -0.100000 + REFLECTANCE_ADD_BAND_6 = -0.100000 + REFLECTANCE_ADD_BAND_7 = -0.100000 + REFLECTANCE_ADD_BAND_8 = -0.100000 + REFLECTANCE_ADD_BAND_9 = -0.100000 + END_GROUP = LEVEL1_RADIOMETRIC_RESCALING + GROUP = LEVEL1_THERMAL_CONSTANTS + K1_CONSTANT_BAND_10 = 774.8853 + K2_CONSTANT_BAND_10 = 1321.0789 + K1_CONSTANT_BAND_11 = 480.8883 + K2_CONSTANT_BAND_11 = 1201.1442 + END_GROUP = LEVEL1_THERMAL_CONSTANTS + GROUP = LEVEL1_PROJECTION_PARAMETERS + MAP_PROJECTION = "UTM" + DATUM = "WGS84" + ELLIPSOID = "WGS84" + UTM_ZONE = 10 + GRID_CELL_SIZE_PANCHROMATIC = 15.00 + GRID_CELL_SIZE_REFLECTIVE = 30.00 + GRID_CELL_SIZE_THERMAL = 30.00 + ORIENTATION = "NORTH_UP" + RESAMPLING_OPTION = "CUBIC_CONVOLUTION" + END_GROUP = LEVEL1_PROJECTION_PARAMETERS +END_GROUP = LANDSAT_METADATA_FILE diff --git a/tests/data-files/oli-tirs/LC08_L2SR_084024_20160111_20201016_02_T1_MTL.txt b/tests/data-files/oli-tirs/LC08_L2SR_084024_20160111_20201016_02_T1_MTL.txt new file mode 100644 index 0000000..93bdda0 --- /dev/null +++ b/tests/data-files/oli-tirs/LC08_L2SR_084024_20160111_20201016_02_T1_MTL.txt @@ -0,0 +1,322 @@ +GROUP = LANDSAT_METADATA_FILE + GROUP = PRODUCT_CONTENTS + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P9OGBGM6" + LANDSAT_PRODUCT_ID = "LC08_L2SR_084024_20160111_20201016_02_T1" + PROCESSING_LEVEL = "L2SR" + COLLECTION_NUMBER = 02 + COLLECTION_CATEGORY = "T1" + OUTPUT_FORMAT = "GEOTIFF" + FILE_NAME_BAND_1 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B1.TIF" + FILE_NAME_BAND_2 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B2.TIF" + FILE_NAME_BAND_3 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B3.TIF" + FILE_NAME_BAND_4 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B4.TIF" + FILE_NAME_BAND_5 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B5.TIF" + FILE_NAME_BAND_6 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B6.TIF" + FILE_NAME_BAND_7 = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_B7.TIF" + FILE_NAME_QUALITY_L2_AEROSOL = "LC08_L2SR_084024_20160111_20201016_02_T1_SR_QA_AEROSOL.TIF" + FILE_NAME_QUALITY_L1_PIXEL = "LC08_L2SR_084024_20160111_20201016_02_T1_QA_PIXEL.TIF" + FILE_NAME_QUALITY_L1_RADIOMETRIC_SATURATION = "LC08_L2SR_084024_20160111_20201016_02_T1_QA_RADSAT.TIF" + FILE_NAME_ANGLE_COEFFICIENT = "LC08_L2SR_084024_20160111_20201016_02_T1_ANG.txt" + FILE_NAME_METADATA_ODL = "LC08_L2SR_084024_20160111_20201016_02_T1_MTL.txt" + FILE_NAME_METADATA_XML = "LC08_L2SR_084024_20160111_20201016_02_T1_MTL.xml" + DATA_TYPE_BAND_1 = "UINT16" + DATA_TYPE_BAND_2 = "UINT16" + DATA_TYPE_BAND_3 = "UINT16" + DATA_TYPE_BAND_4 = "UINT16" + DATA_TYPE_BAND_5 = "UINT16" + DATA_TYPE_BAND_6 = "UINT16" + DATA_TYPE_BAND_7 = "UINT16" + DATA_TYPE_QUALITY_L2_AEROSOL = "UINT8" + DATA_TYPE_QUALITY_L1_PIXEL = "UINT16" + DATA_TYPE_QUALITY_L1_RADIOMETRIC_SATURATION = "UINT16" + END_GROUP = PRODUCT_CONTENTS + GROUP = IMAGE_ATTRIBUTES + SPACECRAFT_ID = "LANDSAT_8" + SENSOR_ID = "OLI_TIRS" + WRS_TYPE = 2 + WRS_PATH = 84 + WRS_ROW = 24 + NADIR_OFFNADIR = "NADIR" + TARGET_WRS_PATH = 84 + TARGET_WRS_ROW = 24 + DATE_ACQUIRED = 2016-01-11 + SCENE_CENTER_TIME = "22:49:22.9309350Z" + STATION_ID = "LGN" + CLOUD_COVER = 30.41 + CLOUD_COVER_LAND = -1 + IMAGE_QUALITY_OLI = 9 + IMAGE_QUALITY_TIRS = 9 + SATURATION_BAND_1 = "N" + SATURATION_BAND_2 = "N" + SATURATION_BAND_3 = "N" + SATURATION_BAND_4 = "N" + SATURATION_BAND_5 = "N" + SATURATION_BAND_6 = "N" + SATURATION_BAND_7 = "N" + SATURATION_BAND_8 = "N" + SATURATION_BAND_9 = "N" + ROLL_ANGLE = -0.001 + SUN_AZIMUTH = 162.36050444 + SUN_ELEVATION = 14.78250544 + EARTH_SUN_DISTANCE = 0.9834788 + TRUNCATION_OLI = "UPPER" + TIRS_SSM_MODEL = "FINAL" + TIRS_SSM_POSITION_STATUS = "ESTIMATED" + END_GROUP = IMAGE_ATTRIBUTES + GROUP = PROJECTION_ATTRIBUTES + MAP_PROJECTION = "UTM" + DATUM = "WGS84" + ELLIPSOID = "WGS84" + UTM_ZONE = 1 + GRID_CELL_SIZE_REFLECTIVE = 30.00 + REFLECTIVE_LINES = 8121 + REFLECTIVE_SAMPLES = 8031 + ORIENTATION = "NORTH_UP" + CORNER_UL_LAT_PRODUCT = 52.74262 + CORNER_UL_LON_PRODUCT = 179.40576 + CORNER_UR_LAT_PRODUCT = 52.79710 + CORNER_UR_LON_PRODUCT = -177.02521 + CORNER_LL_LAT_PRODUCT = 50.55640 + CORNER_LL_LON_PRODUCT = 179.57482 + CORNER_LR_LAT_PRODUCT = 50.60679 + CORNER_LR_LON_PRODUCT = -177.02402 + CORNER_UL_PROJECTION_X_PRODUCT = 257400.000 + CORNER_UL_PROJECTION_Y_PRODUCT = 5849700.000 + CORNER_UR_PROJECTION_X_PRODUCT = 498300.000 + CORNER_UR_PROJECTION_Y_PRODUCT = 5849700.000 + CORNER_LL_PROJECTION_X_PRODUCT = 257400.000 + CORNER_LL_PROJECTION_Y_PRODUCT = 5606100.000 + CORNER_LR_PROJECTION_X_PRODUCT = 498300.000 + CORNER_LR_PROJECTION_Y_PRODUCT = 5606100.000 + END_GROUP = PROJECTION_ATTRIBUTES + GROUP = LEVEL2_PROCESSING_RECORD + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P9OGBGM6" + REQUEST_ID = "L2" + LANDSAT_PRODUCT_ID = "LC08_L2SR_084024_20160111_20201016_02_T1" + PROCESSING_LEVEL = "L2SR" + OUTPUT_FORMAT = "GEOTIFF" + DATE_PRODUCT_GENERATED = "2020-10-16T10:24:19Z" + PROCESSING_SOFTWARE_VERSION = "LPGS_15.3.1c" + ALGORITHM_SOURCE_SURFACE_REFLECTANCE = "LaSRC_1.5.0" + DATA_SOURCE_OZONE = "MODIS" + DATA_SOURCE_PRESSURE = "Calculated" + DATA_SOURCE_WATER_VAPOR = "MODIS" + DATA_SOURCE_AIR_TEMPERATURE = "MODIS" + END_GROUP = LEVEL2_PROCESSING_RECORD + GROUP = LEVEL2_SURFACE_REFLECTANCE_PARAMETERS + REFLECTANCE_MAXIMUM_BAND_1 = 1.602213 + REFLECTANCE_MINIMUM_BAND_1 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_2 = 1.602213 + REFLECTANCE_MINIMUM_BAND_2 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_3 = 1.602213 + REFLECTANCE_MINIMUM_BAND_3 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_4 = 1.602213 + REFLECTANCE_MINIMUM_BAND_4 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_5 = 1.602213 + REFLECTANCE_MINIMUM_BAND_5 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_6 = 1.602213 + REFLECTANCE_MINIMUM_BAND_6 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_7 = 1.602213 + REFLECTANCE_MINIMUM_BAND_7 = -0.199972 + QUANTIZE_CAL_MAX_BAND_1 = 65535 + QUANTIZE_CAL_MIN_BAND_1 = 1 + QUANTIZE_CAL_MAX_BAND_2 = 65535 + QUANTIZE_CAL_MIN_BAND_2 = 1 + QUANTIZE_CAL_MAX_BAND_3 = 65535 + QUANTIZE_CAL_MIN_BAND_3 = 1 + QUANTIZE_CAL_MAX_BAND_4 = 65535 + QUANTIZE_CAL_MIN_BAND_4 = 1 + QUANTIZE_CAL_MAX_BAND_5 = 65535 + QUANTIZE_CAL_MIN_BAND_5 = 1 + QUANTIZE_CAL_MAX_BAND_6 = 65535 + QUANTIZE_CAL_MIN_BAND_6 = 1 + QUANTIZE_CAL_MAX_BAND_7 = 65535 + QUANTIZE_CAL_MIN_BAND_7 = 1 + REFLECTANCE_MULT_BAND_1 = 2.75e-05 + REFLECTANCE_MULT_BAND_2 = 2.75e-05 + REFLECTANCE_MULT_BAND_3 = 2.75e-05 + REFLECTANCE_MULT_BAND_4 = 2.75e-05 + REFLECTANCE_MULT_BAND_5 = 2.75e-05 + REFLECTANCE_MULT_BAND_6 = 2.75e-05 + REFLECTANCE_MULT_BAND_7 = 2.75e-05 + REFLECTANCE_ADD_BAND_1 = -0.2 + REFLECTANCE_ADD_BAND_2 = -0.2 + REFLECTANCE_ADD_BAND_3 = -0.2 + REFLECTANCE_ADD_BAND_4 = -0.2 + REFLECTANCE_ADD_BAND_5 = -0.2 + REFLECTANCE_ADD_BAND_6 = -0.2 + REFLECTANCE_ADD_BAND_7 = -0.2 + END_GROUP = LEVEL2_SURFACE_REFLECTANCE_PARAMETERS + GROUP = LEVEL1_PROCESSING_RECORD + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P975CC9B" + REQUEST_ID = "L2" + LANDSAT_SCENE_ID = "LC80840242016011LGN01" + LANDSAT_PRODUCT_ID = "LC08_L1TP_084024_20160111_20201016_02_T1" + PROCESSING_LEVEL = "L1TP" + COLLECTION_CATEGORY = "T1" + OUTPUT_FORMAT = "GEOTIFF" + DATE_PRODUCT_GENERATED = "2020-10-16T10:19:16Z" + PROCESSING_SOFTWARE_VERSION = "LPGS_15.3.1c" + FILE_NAME_BAND_1 = "LC08_L1TP_084024_20160111_20201016_02_T1_B1.TIF" + FILE_NAME_BAND_2 = "LC08_L1TP_084024_20160111_20201016_02_T1_B2.TIF" + FILE_NAME_BAND_3 = "LC08_L1TP_084024_20160111_20201016_02_T1_B3.TIF" + FILE_NAME_BAND_4 = "LC08_L1TP_084024_20160111_20201016_02_T1_B4.TIF" + FILE_NAME_BAND_5 = "LC08_L1TP_084024_20160111_20201016_02_T1_B5.TIF" + FILE_NAME_BAND_6 = "LC08_L1TP_084024_20160111_20201016_02_T1_B6.TIF" + FILE_NAME_BAND_7 = "LC08_L1TP_084024_20160111_20201016_02_T1_B7.TIF" + FILE_NAME_BAND_8 = "LC08_L1TP_084024_20160111_20201016_02_T1_B8.TIF" + FILE_NAME_BAND_9 = "LC08_L1TP_084024_20160111_20201016_02_T1_B9.TIF" + FILE_NAME_BAND_10 = "LC08_L1TP_084024_20160111_20201016_02_T1_B10.TIF" + FILE_NAME_BAND_11 = "LC08_L1TP_084024_20160111_20201016_02_T1_B11.TIF" + FILE_NAME_QUALITY_L1_PIXEL = "LC08_L1TP_084024_20160111_20201016_02_T1_QA_PIXEL.TIF" + FILE_NAME_QUALITY_L1_RADIOMETRIC_SATURATION = "LC08_L1TP_084024_20160111_20201016_02_T1_QA_RADSAT.TIF" + FILE_NAME_ANGLE_COEFFICIENT = "LC08_L1TP_084024_20160111_20201016_02_T1_ANG.txt" + FILE_NAME_ANGLE_SENSOR_AZIMUTH_BAND_4 = "LC08_L1TP_084024_20160111_20201016_02_T1_VAA.TIF" + FILE_NAME_ANGLE_SENSOR_ZENITH_BAND_4 = "LC08_L1TP_084024_20160111_20201016_02_T1_VZA.TIF" + FILE_NAME_ANGLE_SOLAR_AZIMUTH_BAND_4 = "LC08_L1TP_084024_20160111_20201016_02_T1_SAA.TIF" + FILE_NAME_ANGLE_SOLAR_ZENITH_BAND_4 = "LC08_L1TP_084024_20160111_20201016_02_T1_SZA.TIF" + FILE_NAME_METADATA_ODL = "LC08_L1TP_084024_20160111_20201016_02_T1_MTL.txt" + FILE_NAME_METADATA_XML = "LC08_L1TP_084024_20160111_20201016_02_T1_MTL.xml" + FILE_NAME_CPF = "LC08CPF_20160101_20160331_02.01" + FILE_NAME_BPF_OLI = "LO8BPF20160111224533_20160111232900.03" + FILE_NAME_BPF_TIRS = "LT8BPF20160110081635_20160124145303.02" + FILE_NAME_RLUT = "LC08RLUT_20150303_20431231_02_01.h5" + DATA_SOURCE_TIRS_STRAY_LIGHT_CORRECTION = "TIRS" + DATA_SOURCE_ELEVATION = "GLS2000" + GROUND_CONTROL_POINTS_VERSION = 5 + GROUND_CONTROL_POINTS_MODEL = 37 + GEOMETRIC_RMSE_MODEL = 11.360 + GEOMETRIC_RMSE_MODEL_Y = 7.645 + GEOMETRIC_RMSE_MODEL_X = 8.403 + END_GROUP = LEVEL1_PROCESSING_RECORD + GROUP = LEVEL1_MIN_MAX_RADIANCE + RADIANCE_MAXIMUM_BAND_1 = 785.81323 + RADIANCE_MINIMUM_BAND_1 = -64.89272 + RADIANCE_MAXIMUM_BAND_2 = 804.68237 + RADIANCE_MINIMUM_BAND_2 = -66.45093 + RADIANCE_MAXIMUM_BAND_3 = 741.50793 + RADIANCE_MINIMUM_BAND_3 = -61.23396 + RADIANCE_MAXIMUM_BAND_4 = 625.28125 + RADIANCE_MINIMUM_BAND_4 = -51.63593 + RADIANCE_MAXIMUM_BAND_5 = 382.64093 + RADIANCE_MINIMUM_BAND_5 = -31.59861 + RADIANCE_MAXIMUM_BAND_6 = 95.15932 + RADIANCE_MINIMUM_BAND_6 = -7.85829 + RADIANCE_MAXIMUM_BAND_7 = 32.07378 + RADIANCE_MINIMUM_BAND_7 = -2.64866 + RADIANCE_MAXIMUM_BAND_8 = 707.64630 + RADIANCE_MINIMUM_BAND_8 = -58.43766 + RADIANCE_MAXIMUM_BAND_9 = 149.54475 + RADIANCE_MINIMUM_BAND_9 = -12.34945 + RADIANCE_MAXIMUM_BAND_10 = 22.00180 + RADIANCE_MINIMUM_BAND_10 = 0.10033 + RADIANCE_MAXIMUM_BAND_11 = 22.00180 + RADIANCE_MINIMUM_BAND_11 = 0.10033 + END_GROUP = LEVEL1_MIN_MAX_RADIANCE + GROUP = LEVEL1_MIN_MAX_REFLECTANCE + REFLECTANCE_MAXIMUM_BAND_1 = 1.210700 + REFLECTANCE_MINIMUM_BAND_1 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_2 = 1.210700 + REFLECTANCE_MINIMUM_BAND_2 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_3 = 1.210700 + REFLECTANCE_MINIMUM_BAND_3 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_4 = 1.210700 + REFLECTANCE_MINIMUM_BAND_4 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_5 = 1.210700 + REFLECTANCE_MINIMUM_BAND_5 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_6 = 1.210700 + REFLECTANCE_MINIMUM_BAND_6 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_7 = 1.210700 + REFLECTANCE_MINIMUM_BAND_7 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_8 = 1.210700 + REFLECTANCE_MINIMUM_BAND_8 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_9 = 1.210700 + REFLECTANCE_MINIMUM_BAND_9 = -0.099980 + END_GROUP = LEVEL1_MIN_MAX_REFLECTANCE + GROUP = LEVEL1_MIN_MAX_PIXEL_VALUE + QUANTIZE_CAL_MAX_BAND_1 = 65535 + QUANTIZE_CAL_MIN_BAND_1 = 1 + QUANTIZE_CAL_MAX_BAND_2 = 65535 + QUANTIZE_CAL_MIN_BAND_2 = 1 + QUANTIZE_CAL_MAX_BAND_3 = 65535 + QUANTIZE_CAL_MIN_BAND_3 = 1 + QUANTIZE_CAL_MAX_BAND_4 = 65535 + QUANTIZE_CAL_MIN_BAND_4 = 1 + QUANTIZE_CAL_MAX_BAND_5 = 65535 + QUANTIZE_CAL_MIN_BAND_5 = 1 + QUANTIZE_CAL_MAX_BAND_6 = 65535 + QUANTIZE_CAL_MIN_BAND_6 = 1 + QUANTIZE_CAL_MAX_BAND_7 = 65535 + QUANTIZE_CAL_MIN_BAND_7 = 1 + QUANTIZE_CAL_MAX_BAND_8 = 65535 + QUANTIZE_CAL_MIN_BAND_8 = 1 + QUANTIZE_CAL_MAX_BAND_9 = 65535 + QUANTIZE_CAL_MIN_BAND_9 = 1 + QUANTIZE_CAL_MAX_BAND_10 = 65535 + QUANTIZE_CAL_MIN_BAND_10 = 1 + QUANTIZE_CAL_MAX_BAND_11 = 65535 + QUANTIZE_CAL_MIN_BAND_11 = 1 + END_GROUP = LEVEL1_MIN_MAX_PIXEL_VALUE + GROUP = LEVEL1_RADIOMETRIC_RESCALING + RADIANCE_MULT_BAND_1 = 1.2981E-02 + RADIANCE_MULT_BAND_2 = 1.3293E-02 + RADIANCE_MULT_BAND_3 = 1.2249E-02 + RADIANCE_MULT_BAND_4 = 1.0329E-02 + RADIANCE_MULT_BAND_5 = 6.3210E-03 + RADIANCE_MULT_BAND_6 = 1.5720E-03 + RADIANCE_MULT_BAND_7 = 5.2984E-04 + RADIANCE_MULT_BAND_8 = 1.1690E-02 + RADIANCE_MULT_BAND_9 = 2.4704E-03 + RADIANCE_MULT_BAND_10 = 3.3420E-04 + RADIANCE_MULT_BAND_11 = 3.3420E-04 + RADIANCE_ADD_BAND_1 = -64.90569 + RADIANCE_ADD_BAND_2 = -66.46422 + RADIANCE_ADD_BAND_3 = -61.24621 + RADIANCE_ADD_BAND_4 = -51.64626 + RADIANCE_ADD_BAND_5 = -31.60493 + RADIANCE_ADD_BAND_6 = -7.85986 + RADIANCE_ADD_BAND_7 = -2.64919 + RADIANCE_ADD_BAND_8 = -58.44935 + RADIANCE_ADD_BAND_9 = -12.35192 + RADIANCE_ADD_BAND_10 = 0.10000 + RADIANCE_ADD_BAND_11 = 0.10000 + REFLECTANCE_MULT_BAND_1 = 2.0000E-05 + REFLECTANCE_MULT_BAND_2 = 2.0000E-05 + REFLECTANCE_MULT_BAND_3 = 2.0000E-05 + REFLECTANCE_MULT_BAND_4 = 2.0000E-05 + REFLECTANCE_MULT_BAND_5 = 2.0000E-05 + REFLECTANCE_MULT_BAND_6 = 2.0000E-05 + REFLECTANCE_MULT_BAND_7 = 2.0000E-05 + REFLECTANCE_MULT_BAND_8 = 2.0000E-05 + REFLECTANCE_MULT_BAND_9 = 2.0000E-05 + REFLECTANCE_ADD_BAND_1 = -0.100000 + REFLECTANCE_ADD_BAND_2 = -0.100000 + REFLECTANCE_ADD_BAND_3 = -0.100000 + REFLECTANCE_ADD_BAND_4 = -0.100000 + REFLECTANCE_ADD_BAND_5 = -0.100000 + REFLECTANCE_ADD_BAND_6 = -0.100000 + REFLECTANCE_ADD_BAND_7 = -0.100000 + REFLECTANCE_ADD_BAND_8 = -0.100000 + REFLECTANCE_ADD_BAND_9 = -0.100000 + END_GROUP = LEVEL1_RADIOMETRIC_RESCALING + GROUP = LEVEL1_THERMAL_CONSTANTS + K1_CONSTANT_BAND_10 = 774.8853 + K2_CONSTANT_BAND_10 = 1321.0789 + K1_CONSTANT_BAND_11 = 480.8883 + K2_CONSTANT_BAND_11 = 1201.1442 + END_GROUP = LEVEL1_THERMAL_CONSTANTS + GROUP = LEVEL1_PROJECTION_PARAMETERS + MAP_PROJECTION = "UTM" + DATUM = "WGS84" + ELLIPSOID = "WGS84" + UTM_ZONE = 1 + GRID_CELL_SIZE_PANCHROMATIC = 15.00 + GRID_CELL_SIZE_REFLECTIVE = 30.00 + GRID_CELL_SIZE_THERMAL = 30.00 + ORIENTATION = "NORTH_UP" + RESAMPLING_OPTION = "CUBIC_CONVOLUTION" + END_GROUP = LEVEL1_PROJECTION_PARAMETERS +END_GROUP = LANDSAT_METADATA_FILE diff --git a/tests/data-files/oli-tirs/LC09_L2SP_010065_20220129_20220131_02_T1_MTL.txt b/tests/data-files/oli-tirs/LC09_L2SP_010065_20220129_20220131_02_T1_MTL.txt new file mode 100644 index 0000000..0dc802d --- /dev/null +++ b/tests/data-files/oli-tirs/LC09_L2SP_010065_20220129_20220131_02_T1_MTL.txt @@ -0,0 +1,351 @@ +GROUP = LANDSAT_METADATA_FILE + GROUP = PRODUCT_CONTENTS + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P9OGBGM6" + LANDSAT_PRODUCT_ID = "LC09_L2SP_010065_20220129_20220131_02_T1" + PROCESSING_LEVEL = "L2SP" + COLLECTION_NUMBER = 02 + COLLECTION_CATEGORY = "T1" + OUTPUT_FORMAT = "GEOTIFF" + FILE_NAME_BAND_1 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B1.TIF" + FILE_NAME_BAND_2 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B2.TIF" + FILE_NAME_BAND_3 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B3.TIF" + FILE_NAME_BAND_4 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B4.TIF" + FILE_NAME_BAND_5 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B5.TIF" + FILE_NAME_BAND_6 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B6.TIF" + FILE_NAME_BAND_7 = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_B7.TIF" + FILE_NAME_BAND_ST_B10 = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_B10.TIF" + FILE_NAME_THERMAL_RADIANCE = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_TRAD.TIF" + FILE_NAME_UPWELL_RADIANCE = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_URAD.TIF" + FILE_NAME_DOWNWELL_RADIANCE = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_DRAD.TIF" + FILE_NAME_ATMOSPHERIC_TRANSMITTANCE = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_ATRAN.TIF" + FILE_NAME_EMISSIVITY = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_EMIS.TIF" + FILE_NAME_EMISSIVITY_STDEV = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_EMSD.TIF" + FILE_NAME_CLOUD_DISTANCE = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_CDIST.TIF" + FILE_NAME_QUALITY_L2_AEROSOL = "LC09_L2SP_010065_20220129_20220131_02_T1_SR_QA_AEROSOL.TIF" + FILE_NAME_QUALITY_L2_SURFACE_TEMPERATURE = "LC09_L2SP_010065_20220129_20220131_02_T1_ST_QA.TIF" + FILE_NAME_QUALITY_L1_PIXEL = "LC09_L2SP_010065_20220129_20220131_02_T1_QA_PIXEL.TIF" + FILE_NAME_QUALITY_L1_RADIOMETRIC_SATURATION = "LC09_L2SP_010065_20220129_20220131_02_T1_QA_RADSAT.TIF" + FILE_NAME_ANGLE_COEFFICIENT = "LC09_L2SP_010065_20220129_20220131_02_T1_ANG.txt" + FILE_NAME_METADATA_ODL = "LC09_L2SP_010065_20220129_20220131_02_T1_MTL.txt" + FILE_NAME_METADATA_XML = "LC09_L2SP_010065_20220129_20220131_02_T1_MTL.xml" + DATA_TYPE_BAND_1 = "UINT16" + DATA_TYPE_BAND_2 = "UINT16" + DATA_TYPE_BAND_3 = "UINT16" + DATA_TYPE_BAND_4 = "UINT16" + DATA_TYPE_BAND_5 = "UINT16" + DATA_TYPE_BAND_6 = "UINT16" + DATA_TYPE_BAND_7 = "UINT16" + DATA_TYPE_BAND_ST_B10 = "UINT16" + DATA_TYPE_THERMAL_RADIANCE = "INT16" + DATA_TYPE_UPWELL_RADIANCE = "INT16" + DATA_TYPE_DOWNWELL_RADIANCE = "INT16" + DATA_TYPE_ATMOSPHERIC_TRANSMITTANCE = "INT16" + DATA_TYPE_EMISSIVITY = "INT16" + DATA_TYPE_EMISSIVITY_STDEV = "INT16" + DATA_TYPE_CLOUD_DISTANCE = "INT16" + DATA_TYPE_QUALITY_L2_AEROSOL = "UINT8" + DATA_TYPE_QUALITY_L2_SURFACE_TEMPERATURE = "INT16" + DATA_TYPE_QUALITY_L1_PIXEL = "UINT16" + DATA_TYPE_QUALITY_L1_RADIOMETRIC_SATURATION = "UINT16" + END_GROUP = PRODUCT_CONTENTS + GROUP = IMAGE_ATTRIBUTES + SPACECRAFT_ID = "LANDSAT_9" + SENSOR_ID = "OLI_TIRS" + WRS_TYPE = 2 + WRS_PATH = 10 + WRS_ROW = 65 + NADIR_OFFNADIR = "NADIR" + TARGET_WRS_PATH = 10 + TARGET_WRS_ROW = 65 + DATE_ACQUIRED = 2022-01-29 + SCENE_CENTER_TIME = "15:28:34.3964289Z" + STATION_ID = "LGN" + CLOUD_COVER = 21.12 + CLOUD_COVER_LAND = 23.54 + IMAGE_QUALITY_OLI = 9 + IMAGE_QUALITY_TIRS = 9 + SATURATION_BAND_1 = "N" + SATURATION_BAND_2 = "N" + SATURATION_BAND_3 = "N" + SATURATION_BAND_4 = "N" + SATURATION_BAND_5 = "N" + SATURATION_BAND_6 = "Y" + SATURATION_BAND_7 = "Y" + SATURATION_BAND_8 = "N" + SATURATION_BAND_9 = "N" + ROLL_ANGLE = -0.001 + SUN_AZIMUTH = 112.20059080 + SUN_ELEVATION = 57.84396063 + EARTH_SUN_DISTANCE = 0.9849984 + END_GROUP = IMAGE_ATTRIBUTES + GROUP = PROJECTION_ATTRIBUTES + MAP_PROJECTION = "UTM" + DATUM = "WGS84" + ELLIPSOID = "WGS84" + UTM_ZONE = 17 + GRID_CELL_SIZE_REFLECTIVE = 30.00 + GRID_CELL_SIZE_THERMAL = 30.00 + REFLECTIVE_LINES = 7741 + REFLECTIVE_SAMPLES = 7611 + THERMAL_LINES = 7741 + THERMAL_SAMPLES = 7611 + ORIENTATION = "NORTH_UP" + CORNER_UL_LAT_PRODUCT = -6.18540 + CORNER_UL_LON_PRODUCT = -81.07231 + CORNER_UR_LAT_PRODUCT = -6.18168 + CORNER_UR_LON_PRODUCT = -79.00911 + CORNER_LL_LAT_PRODUCT = -8.28585 + CORNER_LL_LON_PRODUCT = -81.07265 + CORNER_LR_LAT_PRODUCT = -8.28085 + CORNER_LR_LON_PRODUCT = -78.99989 + CORNER_UL_PROJECTION_X_PRODUCT = 492000.000 + CORNER_UL_PROJECTION_Y_PRODUCT = -683700.000 + CORNER_UR_PROJECTION_X_PRODUCT = 720300.000 + CORNER_UR_PROJECTION_Y_PRODUCT = -683700.000 + CORNER_LL_PROJECTION_X_PRODUCT = 492000.000 + CORNER_LL_PROJECTION_Y_PRODUCT = -915900.000 + CORNER_LR_PROJECTION_X_PRODUCT = 720300.000 + CORNER_LR_PROJECTION_Y_PRODUCT = -915900.000 + END_GROUP = PROJECTION_ATTRIBUTES + GROUP = LEVEL2_PROCESSING_RECORD + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P9OGBGM6" + REQUEST_ID = "P7018sain93wo_00013" + LANDSAT_PRODUCT_ID = "LC09_L2SP_010065_20220129_20220131_02_T1" + PROCESSING_LEVEL = "L2SP" + OUTPUT_FORMAT = "GEOTIFF" + DATE_PRODUCT_GENERATED = "2022-01-31T05:45:26Z" + PROCESSING_SOFTWARE_VERSION = "LPGS_15.6.0" + ALGORITHM_SOURCE_SURFACE_REFLECTANCE = "LaSRC_1.5.0" + DATA_SOURCE_OZONE = "MODIS" + DATA_SOURCE_PRESSURE = "Calculated" + DATA_SOURCE_WATER_VAPOR = "MODIS" + DATA_SOURCE_AIR_TEMPERATURE = "MODIS" + ALGORITHM_SOURCE_SURFACE_TEMPERATURE = "st_1.3.0" + DATA_SOURCE_REANALYSIS = "GEOS-5 FP-IT" + END_GROUP = LEVEL2_PROCESSING_RECORD + GROUP = LEVEL2_SURFACE_REFLECTANCE_PARAMETERS + REFLECTANCE_MAXIMUM_BAND_1 = 1.602213 + REFLECTANCE_MINIMUM_BAND_1 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_2 = 1.602213 + REFLECTANCE_MINIMUM_BAND_2 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_3 = 1.602213 + REFLECTANCE_MINIMUM_BAND_3 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_4 = 1.602213 + REFLECTANCE_MINIMUM_BAND_4 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_5 = 1.602213 + REFLECTANCE_MINIMUM_BAND_5 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_6 = 1.602213 + REFLECTANCE_MINIMUM_BAND_6 = -0.199972 + REFLECTANCE_MAXIMUM_BAND_7 = 1.602213 + REFLECTANCE_MINIMUM_BAND_7 = -0.199972 + QUANTIZE_CAL_MAX_BAND_1 = 65535 + QUANTIZE_CAL_MIN_BAND_1 = 1 + QUANTIZE_CAL_MAX_BAND_2 = 65535 + QUANTIZE_CAL_MIN_BAND_2 = 1 + QUANTIZE_CAL_MAX_BAND_3 = 65535 + QUANTIZE_CAL_MIN_BAND_3 = 1 + QUANTIZE_CAL_MAX_BAND_4 = 65535 + QUANTIZE_CAL_MIN_BAND_4 = 1 + QUANTIZE_CAL_MAX_BAND_5 = 65535 + QUANTIZE_CAL_MIN_BAND_5 = 1 + QUANTIZE_CAL_MAX_BAND_6 = 65535 + QUANTIZE_CAL_MIN_BAND_6 = 1 + QUANTIZE_CAL_MAX_BAND_7 = 65535 + QUANTIZE_CAL_MIN_BAND_7 = 1 + REFLECTANCE_MULT_BAND_1 = 2.75e-05 + REFLECTANCE_MULT_BAND_2 = 2.75e-05 + REFLECTANCE_MULT_BAND_3 = 2.75e-05 + REFLECTANCE_MULT_BAND_4 = 2.75e-05 + REFLECTANCE_MULT_BAND_5 = 2.75e-05 + REFLECTANCE_MULT_BAND_6 = 2.75e-05 + REFLECTANCE_MULT_BAND_7 = 2.75e-05 + REFLECTANCE_ADD_BAND_1 = -0.2 + REFLECTANCE_ADD_BAND_2 = -0.2 + REFLECTANCE_ADD_BAND_3 = -0.2 + REFLECTANCE_ADD_BAND_4 = -0.2 + REFLECTANCE_ADD_BAND_5 = -0.2 + REFLECTANCE_ADD_BAND_6 = -0.2 + REFLECTANCE_ADD_BAND_7 = -0.2 + END_GROUP = LEVEL2_SURFACE_REFLECTANCE_PARAMETERS + GROUP = LEVEL2_SURFACE_TEMPERATURE_PARAMETERS + TEMPERATURE_MAXIMUM_BAND_ST_B10 = 372.999941 + TEMPERATURE_MINIMUM_BAND_ST_B10 = 149.003418 + QUANTIZE_CAL_MAXIMUM_BAND_ST_B10 = 65535 + QUANTIZE_CAL_MINIMUM_BAND_ST_B10 = 1 + TEMPERATURE_MULT_BAND_ST_B10 = 0.00341802 + TEMPERATURE_ADD_BAND_ST_B10 = 149.0 + END_GROUP = LEVEL2_SURFACE_TEMPERATURE_PARAMETERS + GROUP = LEVEL1_PROCESSING_RECORD + ORIGIN = "Image courtesy of the U.S. Geological Survey" + DIGITAL_OBJECT_IDENTIFIER = "https://doi.org/10.5066/P975CC9B" + REQUEST_ID = "P7018pe9oq2qk_00013" + LANDSAT_SCENE_ID = "LC90100652022029LGN00" + LANDSAT_PRODUCT_ID = "LC09_L1TP_010065_20220129_20220129_02_T1" + PROCESSING_LEVEL = "L1TP" + COLLECTION_CATEGORY = "T1" + OUTPUT_FORMAT = "GEOTIFF" + DATE_PRODUCT_GENERATED = "2022-01-29T19:00:10Z" + PROCESSING_SOFTWARE_VERSION = "LPGS_15.6.0" + FILE_NAME_BAND_1 = "LC09_L1TP_010065_20220129_20220129_02_T1_B1.TIF" + FILE_NAME_BAND_2 = "LC09_L1TP_010065_20220129_20220129_02_T1_B2.TIF" + FILE_NAME_BAND_3 = "LC09_L1TP_010065_20220129_20220129_02_T1_B3.TIF" + FILE_NAME_BAND_4 = "LC09_L1TP_010065_20220129_20220129_02_T1_B4.TIF" + FILE_NAME_BAND_5 = "LC09_L1TP_010065_20220129_20220129_02_T1_B5.TIF" + FILE_NAME_BAND_6 = "LC09_L1TP_010065_20220129_20220129_02_T1_B6.TIF" + FILE_NAME_BAND_7 = "LC09_L1TP_010065_20220129_20220129_02_T1_B7.TIF" + FILE_NAME_BAND_8 = "LC09_L1TP_010065_20220129_20220129_02_T1_B8.TIF" + FILE_NAME_BAND_9 = "LC09_L1TP_010065_20220129_20220129_02_T1_B9.TIF" + FILE_NAME_BAND_10 = "LC09_L1TP_010065_20220129_20220129_02_T1_B10.TIF" + FILE_NAME_BAND_11 = "LC09_L1TP_010065_20220129_20220129_02_T1_B11.TIF" + FILE_NAME_QUALITY_L1_PIXEL = "LC09_L1TP_010065_20220129_20220129_02_T1_QA_PIXEL.TIF" + FILE_NAME_QUALITY_L1_RADIOMETRIC_SATURATION = "LC09_L1TP_010065_20220129_20220129_02_T1_QA_RADSAT.TIF" + FILE_NAME_ANGLE_COEFFICIENT = "LC09_L1TP_010065_20220129_20220129_02_T1_ANG.txt" + FILE_NAME_ANGLE_SENSOR_AZIMUTH_BAND_4 = "LC09_L1TP_010065_20220129_20220129_02_T1_VAA.TIF" + FILE_NAME_ANGLE_SENSOR_ZENITH_BAND_4 = "LC09_L1TP_010065_20220129_20220129_02_T1_VZA.TIF" + FILE_NAME_ANGLE_SOLAR_AZIMUTH_BAND_4 = "LC09_L1TP_010065_20220129_20220129_02_T1_SAA.TIF" + FILE_NAME_ANGLE_SOLAR_ZENITH_BAND_4 = "LC09_L1TP_010065_20220129_20220129_02_T1_SZA.TIF" + FILE_NAME_METADATA_ODL = "LC09_L1TP_010065_20220129_20220129_02_T1_MTL.txt" + FILE_NAME_METADATA_XML = "LC09_L1TP_010065_20220129_20220129_02_T1_MTL.xml" + FILE_NAME_CPF = "LC09CPF_20220101_20220331_02.03" + FILE_NAME_BPF_OLI = "LO9BPF20220129150937_20220129164631.01" + FILE_NAME_BPF_TIRS = "LT9BPF20220129150446_20220129164139.01" + FILE_NAME_RLUT = "LC09RLUT_20210927_20531231_02_07.h5" + DATA_SOURCE_ELEVATION = "GLS2000" + GROUND_CONTROL_POINTS_VERSION = 5 + GROUND_CONTROL_POINTS_MODEL = 147 + GEOMETRIC_RMSE_MODEL = 7.646 + GEOMETRIC_RMSE_MODEL_Y = 6.224 + GEOMETRIC_RMSE_MODEL_X = 4.441 + GROUND_CONTROL_POINTS_VERIFY = 42 + GEOMETRIC_RMSE_VERIFY = 7.091 + END_GROUP = LEVEL1_PROCESSING_RECORD + GROUP = LEVEL1_MIN_MAX_RADIANCE + RADIANCE_MAXIMUM_BAND_1 = 782.40094 + RADIANCE_MINIMUM_BAND_1 = -64.61092 + RADIANCE_MAXIMUM_BAND_2 = 803.58759 + RADIANCE_MINIMUM_BAND_2 = -66.36053 + RADIANCE_MAXIMUM_BAND_3 = 738.39124 + RADIANCE_MINIMUM_BAND_3 = -60.97659 + RADIANCE_MAXIMUM_BAND_4 = 625.84460 + RADIANCE_MINIMUM_BAND_4 = -51.68245 + RADIANCE_MAXIMUM_BAND_5 = 383.96490 + RADIANCE_MINIMUM_BAND_5 = -31.70795 + RADIANCE_MAXIMUM_BAND_6 = 95.92091 + RADIANCE_MINIMUM_BAND_6 = -7.92118 + RADIANCE_MAXIMUM_BAND_7 = 32.38846 + RADIANCE_MINIMUM_BAND_7 = -2.67465 + RADIANCE_MAXIMUM_BAND_8 = 708.43524 + RADIANCE_MINIMUM_BAND_8 = -58.50281 + RADIANCE_MAXIMUM_BAND_9 = 159.28333 + RADIANCE_MINIMUM_BAND_9 = -13.15367 + RADIANCE_MAXIMUM_BAND_10 = 25.00330 + RADIANCE_MINIMUM_BAND_10 = 0.10038 + RADIANCE_MAXIMUM_BAND_11 = 22.97172 + RADIANCE_MINIMUM_BAND_11 = 0.10035 + END_GROUP = LEVEL1_MIN_MAX_RADIANCE + GROUP = LEVEL1_MIN_MAX_REFLECTANCE + REFLECTANCE_MAXIMUM_BAND_1 = 1.210700 + REFLECTANCE_MINIMUM_BAND_1 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_2 = 1.210700 + REFLECTANCE_MINIMUM_BAND_2 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_3 = 1.210700 + REFLECTANCE_MINIMUM_BAND_3 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_4 = 1.210700 + REFLECTANCE_MINIMUM_BAND_4 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_5 = 1.210700 + REFLECTANCE_MINIMUM_BAND_5 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_6 = 1.210700 + REFLECTANCE_MINIMUM_BAND_6 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_7 = 1.210700 + REFLECTANCE_MINIMUM_BAND_7 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_8 = 1.210700 + REFLECTANCE_MINIMUM_BAND_8 = -0.099980 + REFLECTANCE_MAXIMUM_BAND_9 = 1.210700 + REFLECTANCE_MINIMUM_BAND_9 = -0.099980 + END_GROUP = LEVEL1_MIN_MAX_REFLECTANCE + GROUP = LEVEL1_MIN_MAX_PIXEL_VALUE + QUANTIZE_CAL_MAX_BAND_1 = 65535 + QUANTIZE_CAL_MIN_BAND_1 = 1 + QUANTIZE_CAL_MAX_BAND_2 = 65535 + QUANTIZE_CAL_MIN_BAND_2 = 1 + QUANTIZE_CAL_MAX_BAND_3 = 65535 + QUANTIZE_CAL_MIN_BAND_3 = 1 + QUANTIZE_CAL_MAX_BAND_4 = 65535 + QUANTIZE_CAL_MIN_BAND_4 = 1 + QUANTIZE_CAL_MAX_BAND_5 = 65535 + QUANTIZE_CAL_MIN_BAND_5 = 1 + QUANTIZE_CAL_MAX_BAND_6 = 65535 + QUANTIZE_CAL_MIN_BAND_6 = 1 + QUANTIZE_CAL_MAX_BAND_7 = 65535 + QUANTIZE_CAL_MIN_BAND_7 = 1 + QUANTIZE_CAL_MAX_BAND_8 = 65535 + QUANTIZE_CAL_MIN_BAND_8 = 1 + QUANTIZE_CAL_MAX_BAND_9 = 65535 + QUANTIZE_CAL_MIN_BAND_9 = 1 + QUANTIZE_CAL_MAX_BAND_10 = 65535 + QUANTIZE_CAL_MIN_BAND_10 = 1 + QUANTIZE_CAL_MAX_BAND_11 = 65535 + QUANTIZE_CAL_MIN_BAND_11 = 1 + END_GROUP = LEVEL1_MIN_MAX_PIXEL_VALUE + GROUP = LEVEL1_RADIOMETRIC_RESCALING + RADIANCE_MULT_BAND_1 = 1.2925E-02 + RADIANCE_MULT_BAND_2 = 1.3275E-02 + RADIANCE_MULT_BAND_3 = 1.2198E-02 + RADIANCE_MULT_BAND_4 = 1.0339E-02 + RADIANCE_MULT_BAND_5 = 6.3429E-03 + RADIANCE_MULT_BAND_6 = 1.5846E-03 + RADIANCE_MULT_BAND_7 = 5.3504E-04 + RADIANCE_MULT_BAND_8 = 1.1703E-02 + RADIANCE_MULT_BAND_9 = 2.6313E-03 + RADIANCE_MULT_BAND_10 = 3.8000E-04 + RADIANCE_MULT_BAND_11 = 3.4900E-04 + RADIANCE_ADD_BAND_1 = -64.62385 + RADIANCE_ADD_BAND_2 = -66.37380 + RADIANCE_ADD_BAND_3 = -60.98879 + RADIANCE_ADD_BAND_4 = -51.69279 + RADIANCE_ADD_BAND_5 = -31.71429 + RADIANCE_ADD_BAND_6 = -7.92276 + RADIANCE_ADD_BAND_7 = -2.67518 + RADIANCE_ADD_BAND_8 = -58.51451 + RADIANCE_ADD_BAND_9 = -13.15630 + RADIANCE_ADD_BAND_10 = 0.10000 + RADIANCE_ADD_BAND_11 = 0.10000 + REFLECTANCE_MULT_BAND_1 = 2.0000E-05 + REFLECTANCE_MULT_BAND_2 = 2.0000E-05 + REFLECTANCE_MULT_BAND_3 = 2.0000E-05 + REFLECTANCE_MULT_BAND_4 = 2.0000E-05 + REFLECTANCE_MULT_BAND_5 = 2.0000E-05 + REFLECTANCE_MULT_BAND_6 = 2.0000E-05 + REFLECTANCE_MULT_BAND_7 = 2.0000E-05 + REFLECTANCE_MULT_BAND_8 = 2.0000E-05 + REFLECTANCE_MULT_BAND_9 = 2.0000E-05 + REFLECTANCE_ADD_BAND_1 = -0.100000 + REFLECTANCE_ADD_BAND_2 = -0.100000 + REFLECTANCE_ADD_BAND_3 = -0.100000 + REFLECTANCE_ADD_BAND_4 = -0.100000 + REFLECTANCE_ADD_BAND_5 = -0.100000 + REFLECTANCE_ADD_BAND_6 = -0.100000 + REFLECTANCE_ADD_BAND_7 = -0.100000 + REFLECTANCE_ADD_BAND_8 = -0.100000 + REFLECTANCE_ADD_BAND_9 = -0.100000 + END_GROUP = LEVEL1_RADIOMETRIC_RESCALING + GROUP = LEVEL1_THERMAL_CONSTANTS + K1_CONSTANT_BAND_10 = 799.0284 + K2_CONSTANT_BAND_10 = 1329.2405 + K1_CONSTANT_BAND_11 = 475.6581 + K2_CONSTANT_BAND_11 = 1198.3494 + END_GROUP = LEVEL1_THERMAL_CONSTANTS + GROUP = LEVEL1_PROJECTION_PARAMETERS + MAP_PROJECTION = "UTM" + DATUM = "WGS84" + ELLIPSOID = "WGS84" + UTM_ZONE = 17 + GRID_CELL_SIZE_PANCHROMATIC = 15.00 + GRID_CELL_SIZE_REFLECTIVE = 30.00 + GRID_CELL_SIZE_THERMAL = 30.00 + ORIENTATION = "NORTH_UP" + RESAMPLING_OPTION = "CUBIC_CONVOLUTION" + END_GROUP = LEVEL1_PROJECTION_PARAMETERS +END_GROUP = LANDSAT_METADATA_FILE diff --git a/tests/test_create_stac.py b/tests/test_create_stac.py index 54bafcb..38c55a6 100644 --- a/tests/test_create_stac.py +++ b/tests/test_create_stac.py @@ -150,3 +150,16 @@ def test_no_emis_coefficient() -> None: assert "emissivity" in item_dict["assets"]["emsd"]["roles"] assert item_dict["assets"]["emis"]["raster:bands"][0].pop("unit", None) is None assert item_dict["assets"]["emsd"]["raster:bands"][0].pop("unit", None) is None + + +def test_mtl_text() -> None: + mtl_path = test_data.get_path( + "data-files/oli-tirs/LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt" + ) + item = create_item(mtl_path, use_usgs_geometry=True) + item_dict = item.to_dict() + + asset_keys = ["qa_pixel", "qa_radsat", "qa_aerosol"] + for key in asset_keys: + bitfield_band = item_dict["assets"][key] + assert "classification:bitfields" in bitfield_band \ No newline at end of file From a35d2635a62f0e44d19a902fb579834a7eaad593 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Wed, 26 Jul 2023 18:41:02 +0200 Subject: [PATCH 4/7] Fixing MTL text parsing --- src/stactools/landsat/mtl_metadata.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/stactools/landsat/mtl_metadata.py b/src/stactools/landsat/mtl_metadata.py index eb31c00..918fb33 100644 --- a/src/stactools/landsat/mtl_metadata.py +++ b/src/stactools/landsat/mtl_metadata.py @@ -331,10 +331,15 @@ def from_text_file( read_href_modifier: Optional[ReadHrefModifier] = None, ) -> "MtlMetadata": text = read_text(href, read_href_modifier) - lines = text.split("\n") + lines = iter(text.split("\n")) mtl = _parse_mtl_group(lines) - return _mtl_group_to_element( - *next(iter(mtl.items())) + return cls( + XmlElement( + _mtl_group_to_element( + *next(iter(mtl.items())) + ) + ), + href=href ) From ac79b28e4f4a7f8683e243267fed33b0331097d9 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Mon, 21 Aug 2023 12:19:27 +0200 Subject: [PATCH 5/7] Splitting off MTL text based creation from the `create_item` function --- src/stactools/landsat/stac.py | 89 ++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 13 deletions(-) diff --git a/src/stactools/landsat/stac.py b/src/stactools/landsat/stac.py index 63b26eb..e0dd3f1 100644 --- a/src/stactools/landsat/stac.py +++ b/src/stactools/landsat/stac.py @@ -1,7 +1,6 @@ import logging from datetime import datetime, timezone from typing import Optional -from urllib.parse import urlparse import shapely from pystac import Collection, Item, Link, MediaType @@ -63,18 +62,73 @@ def create_item( Item: A STAC Item representing the Landsat scene. """ base_href = "_".join(mtl_xml_href.split("_")[:-1]) + return create_item_from_mtl_metadata( + base_href, + MtlMetadata.from_file(mtl_xml_href, read_href_modifier), + use_usgs_geometry, + antimeridian_strategy, + read_href_modifier, + ) + + +def create_item_from_mtl_text( + mtl_text_href: str, + use_usgs_geometry: bool = True, + antimeridian_strategy: Strategy = Strategy.SPLIT, + read_href_modifier: Optional[ReadHrefModifier] = None, +) -> Item: + """Creates a STAC Item for Landsat 1-5 Collection 2 Level-1 or Landsat + 4-5, 7-9 Collection 2 Level-2 scene data. + + Args: + mtl_text_href (str): An href to an MTL text metadata file. + use_usgs_geometry (bool): Use the geometry from a USGS STAC file that is + stored alongside the text metadata file or pulled from the USGS STAC + API. + antimeridian_strategy (Antimeridian): Either split on -180 or + normalize geometries so all longitudes are either positive or + negative. + read_href_modifier (Callable[[str], str]): An optional function to + modify the MTL and USGS STAC hrefs (e.g., to add a token to a url). + + Returns: + Item: A STAC Item representing the Landsat scene. + """ + base_href = "_".join(mtl_text_href.split("_")[:-1]) + return create_item_from_mtl_metadata( + base_href, + MtlMetadata.from_text_file(mtl_text_href, read_href_modifier), + use_usgs_geometry, + antimeridian_strategy, + read_href_modifier, + ) - mtl_metadata = None - if urlparse(mtl_xml_href).path.endswith(".txt"): - try: - mtl_metadata = MtlMetadata.from_text_file(mtl_xml_href, read_href_modifier) - except Exception as e: - logger.warning(f"Failed to parse MTL from text: {e}") +def create_item_from_mtl_metadata( + base_href: str, + mtl_metadata: MtlMetadata, + use_usgs_geometry: bool = True, + antimeridian_strategy: Strategy = Strategy.SPLIT, + read_href_modifier: Optional[ReadHrefModifier] = None, +) -> Item: + """Creates a STAC Item for Landsat 1-5 Collection 2 Level-1 or Landsat + 4-5, 7-9 Collection 2 Level-2 scene data. - if mtl_metadata is None: - mtl_metadata = MtlMetadata.from_file(mtl_xml_href, read_href_modifier) + Args: + base_href (str): + mtl_metadata (MtlMetadata): The parsed MTL metadata. + use_usgs_geometry (bool): Use the geometry from a USGS STAC file that is + stored alongside the XML metadata file or pulled from the USGS STAC + API. + antimeridian_strategy (Antimeridian): Either split on -180 or + normalize geometries so all longitudes are either positive or + negative. + read_href_modifier (Callable[[str], str]): An optional function to + modify the MTL and USGS STAC hrefs (e.g., to add a token to a url). + Returns: + Item: A STAC Item representing the Landsat scene. + """ sensor = Sensor(mtl_metadata.item_id[1]) satellite = int(mtl_metadata.item_id[2:4]) level = int(mtl_metadata.item_id[6]) @@ -94,7 +148,9 @@ def create_item( geometry = shapely.geometry.mapping( shapely.geometry.box(*mtl_metadata.bbox) ) - logger.warning(f"Using bbox for geometry for {mtl_metadata.product_id}.") + logger.warning( + f"Using bbox for geometry for {mtl_metadata.product_id}." + ) item = Item( id=mtl_metadata.item_id, @@ -113,7 +169,9 @@ def create_item( item.common_metadata.gsd = SENSORS[sensor.name]["reflective_gsd"] item.common_metadata.description = f"Landsat Collection 2 Level-{level}" - fragments = Fragments(sensor, satellite, base_href, mtl_metadata.level1_radiance) + fragments = Fragments( + sensor, satellite, base_href, mtl_metadata.level1_radiance + ) # Common assets assets = fragments.common_assets() @@ -123,7 +181,9 @@ def create_item( continue # MTL files are specific to the processing level if key.startswith("mtl"): - asset.description = asset.description.replace("Level-X", f"Level-{level}") + asset.description = asset.description.replace( + "Level-X", f"Level-{level}" + ) item.add_asset(key, asset) # Optical assets @@ -173,7 +233,10 @@ def create_item( projection.shape = mtl_metadata.sr_shape projection.transform = mtl_metadata.sr_transform centroid = shapely.geometry.shape(item.geometry).centroid - projection.centroid = {"lat": round(centroid.y, 5), "lon": round(centroid.x, 5)} + projection.centroid = { + "lat": round(centroid.y, 5), + "lon": round(centroid.x, 5), + } item.stac_extensions.append(LANDSAT_EXTENSION_SCHEMA) item.properties.update(**mtl_metadata.landsat_metadata) From c9673f07019f8bf182749009b37cfde891d30ec6 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Mon, 21 Aug 2023 12:52:20 +0200 Subject: [PATCH 6/7] Fixing typing issues in MTL text parsing Fixed formatting --- src/stactools/landsat/mtl_metadata.py | 32 ++++++++++++++------------- src/stactools/landsat/stac.py | 12 +++------- tests/test_create_stac.py | 2 +- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/stactools/landsat/mtl_metadata.py b/src/stactools/landsat/mtl_metadata.py index 918fb33..d305ac6 100644 --- a/src/stactools/landsat/mtl_metadata.py +++ b/src/stactools/landsat/mtl_metadata.py @@ -1,6 +1,6 @@ from collections import defaultdict from datetime import datetime -from typing import Any, Dict, List, Optional, Tuple, Iterator +from typing import Any, Dict, Iterator, List, Optional, Tuple, Union, cast from lxml import etree from lxml.etree import _Element as lxmlElement @@ -15,6 +15,9 @@ class MTLError(Exception): pass +MTLGroup = Dict[str, Union[str, "MTLGroup"]] + + class MtlMetadata: """Parses a Collection 2 MTL XML file. @@ -204,7 +207,8 @@ def sr_transform(self) -> List[float]: @property def thermal_transform(self) -> Optional[List[float]]: return map_opt( - lambda shape: transform_from_bbox(self.proj_bbox, shape), self.thermal_shape + lambda shape: transform_from_bbox(self.proj_bbox, shape), + self.thermal_shape, ) @property @@ -333,21 +337,19 @@ def from_text_file( text = read_text(href, read_href_modifier) lines = iter(text.split("\n")) mtl = _parse_mtl_group(lines) + root_name, root_group = next(iter(mtl.items())) return cls( - XmlElement( - _mtl_group_to_element( - *next(iter(mtl.items())) - ) - ), - href=href + XmlElement(_mtl_group_to_element(root_name, cast(MTLGroup, root_group))), + href=href, ) -def _parse_mtl_group(lines: Iterator[str]) -> dict: - group = {} +def _parse_mtl_group(lines: Iterator[str]) -> MTLGroup: + group: MTLGroup = {} for line in lines: + value: Union[str, MTLGroup] key, value = _parse_mtl_line(line) - if not key or key == "END_GROUP": + if not key or key in ("END", "END_GROUP"): break elif key == "GROUP": key = value @@ -359,7 +361,7 @@ def _parse_mtl_group(lines: Iterator[str]) -> dict: def _parse_mtl_line(line: str) -> Tuple[str, str]: line = line.strip() if not line or line == "END": - return (None, None) + return ("END", "") key, _, value = line.partition(" = ") if value.startswith('"') and value.endswith('"'): @@ -374,13 +376,13 @@ def _mtl_value_element(tag: str, value: str) -> lxmlElement: return element -def _mtl_group_to_element(name: str, group: dict) -> lxmlElement: +def _mtl_group_to_element(name: str, group: MTLGroup) -> lxmlElement: element: lxmlElement = etree.Element(name) element.extend( [ _mtl_group_to_element(child_name, child) - if isinstance(child, dict) else - _mtl_value_element(child_name, child) + if isinstance(child, dict) + else _mtl_value_element(child_name, child) for child_name, child in group.items() ] ) diff --git a/src/stactools/landsat/stac.py b/src/stactools/landsat/stac.py index e0dd3f1..3f666b9 100644 --- a/src/stactools/landsat/stac.py +++ b/src/stactools/landsat/stac.py @@ -148,9 +148,7 @@ def create_item_from_mtl_metadata( geometry = shapely.geometry.mapping( shapely.geometry.box(*mtl_metadata.bbox) ) - logger.warning( - f"Using bbox for geometry for {mtl_metadata.product_id}." - ) + logger.warning(f"Using bbox for geometry for {mtl_metadata.product_id}.") item = Item( id=mtl_metadata.item_id, @@ -169,9 +167,7 @@ def create_item_from_mtl_metadata( item.common_metadata.gsd = SENSORS[sensor.name]["reflective_gsd"] item.common_metadata.description = f"Landsat Collection 2 Level-{level}" - fragments = Fragments( - sensor, satellite, base_href, mtl_metadata.level1_radiance - ) + fragments = Fragments(sensor, satellite, base_href, mtl_metadata.level1_radiance) # Common assets assets = fragments.common_assets() @@ -181,9 +177,7 @@ def create_item_from_mtl_metadata( continue # MTL files are specific to the processing level if key.startswith("mtl"): - asset.description = asset.description.replace( - "Level-X", f"Level-{level}" - ) + asset.description = asset.description.replace("Level-X", f"Level-{level}") item.add_asset(key, asset) # Optical assets diff --git a/tests/test_create_stac.py b/tests/test_create_stac.py index 38c55a6..47f0b0d 100644 --- a/tests/test_create_stac.py +++ b/tests/test_create_stac.py @@ -162,4 +162,4 @@ def test_mtl_text() -> None: asset_keys = ["qa_pixel", "qa_radsat", "qa_aerosol"] for key in asset_keys: bitfield_band = item_dict["assets"][key] - assert "classification:bitfields" in bitfield_band \ No newline at end of file + assert "classification:bitfields" in bitfield_band From 0e512f036ca0e1892e6fff2bfdf7e319a85825d7 Mon Sep 17 00:00:00 2001 From: Fabian Schindler Date: Mon, 21 Aug 2023 18:33:44 +0200 Subject: [PATCH 7/7] Fixing test to parse from MTL text --- tests/test_create_stac.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_create_stac.py b/tests/test_create_stac.py index b943a91..179f730 100644 --- a/tests/test_create_stac.py +++ b/tests/test_create_stac.py @@ -2,7 +2,7 @@ from antimeridian import FixWindingWarning from pystac.extensions.grid import GridExtension -from stactools.landsat.stac import create_item +from stactools.landsat.stac import create_item, create_item_from_mtl_text from tests import test_data @@ -162,7 +162,7 @@ def test_mtl_text() -> None: mtl_path = test_data.get_path( "data-files/oli-tirs/LC08_L2SP_047027_20201204_20210313_02_T1_MTL.txt" ) - item = create_item(mtl_path, use_usgs_geometry=True) + item = create_item_from_mtl_text(mtl_path, use_usgs_geometry=True) item_dict = item.to_dict() asset_keys = ["qa_pixel", "qa_radsat", "qa_aerosol"]