Skip to content

Bug: latency_graph.py detecting the wrong inputs as "latest input granules" #135

@sjlewis-jpl

Description

@sjlewis-jpl

In the latency_graph.py module, the function get_latest_input_granule looks like it's using times parsed from the granule IDs. This will give either the sensor time (called "temporal time" by CMR), or the Production Time (for OPERA products). However, our requirements are tied to the latest revision time for the input granules. For RTC and CSLC inputs, this will be close to the revision time, but if there are any delays uploading to the DAAC, we may be penalizing ourselves unnecessarily. And for the HLS inputs, we can only get the latest sensor time. When the actual latency is calculated, the code seems to fetch the revision time of the "latest input granule", which is not guaranteed to be the latest revision time among the inputs. Not a huge deal for DSWx-HLS, since it only has 1 input, but we should at least make some comments to keep aware of how the code is working.

Also, this function will silently pass on errors - this might bury errors that we'd want to detect. I believe the code is passing a list of all input files (which include ancillaries) to this function, so this is likely intended to filter out the ancillary files, so another method of filtering those might be prudent.
e.g.

if len(gran.split("_")) < 6:
continue

Full function:

def get_latest_input_granule(input_gran_list, prod_type):
'''
hls inputs:
"HLS.L30.T41WPU.2025121T071630.v2.0.B02.tif",
"HLS.L30.T41WPU.2025121T071630.v2.0.B03.tif",
"HLS.L30.T41WPU.2025121T071630.v2.0.B04.tif",
cslc inputs:
S1A_IW_SLC__1SDV_20250408T191358_20250408T191425_058669_0743B7_0ADC
rtc inputs:
S1A_IW_SLC__1SDV_20250506T143226_20250506T143253_059075_075429_E267
dswx-s1 inputs:
"OPERA_L2_RTC-S1_T018-038556-IW3_20250505T233312Z_20250506T114007Z_S1A_30_v1.0.h5",
"OPERA_L2_RTC-S1_T018-038556-IW3_20250505T233312Z_20250506T114007Z_S1A_30_v1.0_VH.tif",
"OPERA_L2_RTC-S1_T018-038556-IW3_20250505T233312Z_20250506T114007Z_S1A_30_v1.0_VV.tif",
"OPERA_L2_RTC-S1_T018-038556-IW3_20250505T233312Z_20250506T114007Z_S1A_30_v1.0_mask.tif"
"OPERA_L2_RTC-S1_T018-038572-IW1_20250505T233354Z_20250506T204752Z_S1A_30_v1.0.h5",
"OPERA_L2_RTC-S1_T018-038572-IW1_20250505T233354Z_20250506T204752Z_S1A_30_v1.0_VH.tif",
"OPERA_L2_RTC-S1_T018-038572-IW1_20250505T233354Z_20250506T204752Z_S1A_30_v1.0_VV.tif",
"OPERA_L2_RTC-S1_T018-038572-IW1_20250505T233354Z_20250506T204752Z_S1A_30_v1.0_mask.tif
'''
latest_end_time = ""
latest_gran_id = ""
latest_begin_time = ""
slc_add = ""
for gran in input_gran_list:
# S1A_IW_SLC__1SDV_20250501T175323_20250501T175344_059004_075162_1906
if prod_type == "CSLC-S1" or prod_type == "RTC-S1":
if len(gran.split("_")) < 6:
continue
end_time = gran.split("_")[6]
begin_time = gran.split("_")[5]
slc_add = "-SLC"
elif prod_type == "DSWx-HLS":
# HLS.S30.T55HFC.2025111T001109.v2.0.Fmask.tif
if len(gran.split(".")) < 6:
continue
if "HLS" not in gran:
continue
end_time = gran.split(".")[3]
begin_time = end_time
elif prod_type == "DSWx-S1":
if len(gran.split("_")) < 5:
continue
end_time = gran.split("_")[5]
begin_time = gran.split("_")[4]
if end_time > latest_end_time:
latest_end_time = end_time
latest_begin_time = begin_time
latest_gran_id = gran
if "." in latest_gran_id:
latest_gran_id = os.path.splitext(latest_gran_id)[0]
if "HLS" in latest_gran_id:
latest_gran_id = os.path.splitext(latest_gran_id)[0]
if "SLC" in latest_gran_id:
latest_gran_id += slc_add
# latest_end_time = string_to_datetime(latest_end_time, gran_input=prod_type)
# latest_begin_time = string_to_datetime(latest_begin_time, gran_input=prod_type)
return latest_gran_id, latest_end_time, latest_begin_time

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions