Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d1c4d7f
disable polarimetric symmetrization by default
gshiroma Jul 3, 2025
0ef09a8
Merge branch 'isce-framework:develop' into develop
gshiroma Jul 9, 2025
2ac2694
revert changes to `symmetrize_cross_pol_channels`
gshiroma Jul 22, 2025
05d7fda
Update GCOV and GSLC specification XMLs
gshiroma Jul 22, 2025
749058d
Revert changes to the GCOV and GSLC specification XMLs
gshiroma Jul 23, 2025
fc8ac53
Merge branch 'isce-framework:develop' into develop
gshiroma Jul 24, 2025
064d073
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 7, 2025
22464ef
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 7, 2025
a75e7f1
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 11, 2025
ab21d36
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 12, 2025
d61d489
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 18, 2025
0af53dd
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 20, 2025
d454e6a
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 21, 2025
6e7e9d1
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 28, 2025
dd80c38
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 29, 2025
63853b2
Merge branch 'isce-framework:develop' into develop
gshiroma Aug 29, 2025
7c7272f
Merge branch 'isce-framework:develop' into develop
gshiroma Sep 2, 2025
dd18a84
Merge branch 'isce-framework:develop' into develop
gshiroma Sep 17, 2025
d43ca22
Merge branch 'isce-framework:develop' into develop
gshiroma Oct 6, 2025
c62d750
Merge branch 'isce-framework:develop' into develop
gshiroma Oct 29, 2025
5922bbf
Merge branch 'isce-framework:develop' into develop
gshiroma Nov 6, 2025
9cc7088
Merge branch 'isce-framework:develop' into develop
gshiroma Dec 15, 2025
c207327
Merge branch 'isce-framework:develop' into develop
gshiroma Jan 10, 2026
353c981
Update postings in STATIC layers granule ID to decimeters
gshiroma Feb 9, 2026
935378c
Update postings in STATIC layers granule ID to decimeters
gshiroma Feb 10, 2026
2194cfd
Update postings in STATIC layers granule ID to decimeters; fix unit t…
gshiroma Feb 10, 2026
69d47d1
Update postings in STATIC layers granule ID to decimeters; fix unit t…
gshiroma Feb 10, 2026
4d328cd
Update postings in STATIC layers granule ID to decimeters; fix unit t…
gshiroma Feb 10, 2026
1b36ef5
Update postings in STATIC layers granule ID to decimeters only for pr…
gshiroma Feb 10, 2026
9e130a4
Update postings in STATIC layers granule ID to decimeters only for pr…
gshiroma Feb 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 56 additions & 19 deletions python/packages/nisar/static/granule_id.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import string
from datetime import datetime
from osgeo import osr

import isce3


def int_to_3_digit_string(i: int) -> str:
def int_to_n_digit_string(i: int, n: int = 3) -> str:
"""
Format an integer as a 3-digit zero-padded string.
Format an integer as an n-digit zero-padded string.

Parameters
----------
i : int
The input integer. Must be >= 0 and <= 999.
The input integer. Must be >= 0 and <= 10^n - 1.

n : int
The number of digits in the output string.

Returns
-------
str
A 3-character string representation of the input integer, left-padded with
zeros.
An n-character string representation of the input integer, left-padded
with zeros.
"""
if (i < 0) or (i > 999):
raise ValueError(f"argument must be in the range [0, 999], got {i}")
return f"{i:03d}"
max_value = 10 ** n - 1
if (i < 0) or (i > max_value):
raise ValueError(f"argument must be in the range [0, {max_value}],"
f" got {i}")
return f"{i:0{n}d}"


def orbit_direction_to_char_code(direction: isce3.core.OrbitPassDirection) -> str:
Expand Down Expand Up @@ -99,6 +105,7 @@ def form_granule_id(
frame_number: int,
x_posting: float,
y_posting: float,
epsg_code: int,
validity_start_datetime: datetime,
composite_release_id: str,
processing_center: str,
Expand Down Expand Up @@ -129,6 +136,9 @@ def form_granule_id(
x_posting, y_posting : float
X and Y spacing of the raster coordinate grid, in the units of the grid's native
coordinate system. Must be > 0 and <= 999.
epsg_code : int
EPSG code of the spatial reference system in which the raster coordinate grid is
defined.
validity_start_datetime : datetime.datetime
UTC date and time of the start of the granule's validity date range. Must not
contain a fractional seconds component.
Expand All @@ -144,29 +154,56 @@ def form_granule_id(
Returns
-------
str
The granule ID.
The granule ID. If the spatial reference system specified by
epsg_code is projected, the X and Y postings are multiplied
by 10 and formatted as four-digit, zero-padded integers.
If the spatial reference system is geographic, the X and Y
postings are formatted directly (without multiplication) as
four-digit, zero-padded integers, with the decimal point
removed.

References
----------
.. [1] S. Niemoeller, "NASA SDS Product Specification Level-2 Static Layers", JPL
D-107727, 2025.
"""
template = string.Template(
"${MISSION}_${I}${L}_${PROD}_${REL}_${P}_${FRM}_${Xposting}_${Yposting}"
"_${ValidityStartDateTime}_${CRID}_${LOC}_${CTR}"
)
srs = osr.SpatialReference()
srs.ImportFromEPSG(epsg_code)

# The granule ID for projected coordinate systems encodes the X and Y
# postings in decimeters as 4-digit zero-padded integers,
# while the granule ID for geographic coordinate systems encodes the
# X and Y postings in degrees as 4-digit zero-padded integers with the
# decimal point removed.
if not srs.IsGeographic():
template = string.Template(
"${MISSION}_${I}${L}_${PROD}_${REL}_${P}_${FRM}"
"_${XpostingDecimeters}_${YpostingDecimeters}"
"_${ValidityStartDateTime}_${CRID}_${LOC}_${CTR}"
)
else:
template = string.Template(
"${MISSION}_${I}${L}_${PROD}_${REL}_${P}_${FRM}"
"_${Xposting}_${Yposting}"
"_${ValidityStartDateTime}_${CRID}_${LOC}_${CTR}"
)
return template.substitute(
MISSION=mission_id,
I=radar_band,
L=product_level,
PROD=product_type,
REL=int_to_3_digit_string(relative_orbit_number),
REL=int_to_n_digit_string(relative_orbit_number, n=3),
P=orbit_direction_to_char_code(orbit_pass_direction),
FRM=int_to_3_digit_string(frame_number),
Xposting=int_to_3_digit_string(int(round(x_posting))),
Yposting=int_to_3_digit_string(int(round(y_posting))),
ValidityStartDateTime=datetime_to_yyyymmddthhmmss(validity_start_datetime),
FRM=int_to_n_digit_string(frame_number, 3),
XpostingDecimeters=int_to_n_digit_string(int(10*round(x_posting)),
n=4),
YpostingDecimeters=int_to_n_digit_string(int(10*round(y_posting)),
n=4),
Xposting=int_to_n_digit_string(int(round(x_posting)), n=4),
Yposting=int_to_n_digit_string(int(round(y_posting)), n=4),
ValidityStartDateTime=datetime_to_yyyymmddthhmmss(
validity_start_datetime),
CRID=composite_release_id,
LOC=processing_center_to_char_code(processing_center),
CTR=int_to_3_digit_string(product_counter),
CTR=int_to_n_digit_string(product_counter, n=3),
)
1 change: 1 addition & 0 deletions python/packages/nisar/workflows/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ def run_static_layers_workflow(config_file: os.PathLike | str) -> None:
orbit_pass_direction=orbit_pass_direction,
x_posting=abs(geo_grid.spacing_x),
y_posting=abs(geo_grid.spacing_y),
epsg_code=geo_grid_params["epsg"],
validity_start_datetime=validity_start_datetime,
composite_release_id=primary_executable_params["composite_release_id"],
processing_center=primary_executable_params["processing_center"],
Expand Down
6 changes: 4 additions & 2 deletions tests/python/packages/nisar/static/granule_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ def test_form_granule_id():
frame_number=2,
x_posting=10.0,
y_posting=5.0,
epsg_code=32611,
validity_start_datetime=datetime.fromisoformat("1999-12-31T23:59:59"),
composite_release_id="T01023",
processing_center="JPL",
product_counter=1,
)
assert (
granule_id == "NISAR_L2_STATIC_001_A_002_010_005_19991231T235959_T01023_J_001"
granule_id == "NISAR_L2_STATIC_001_A_002_0100_0050_19991231T235959_T01023_J_001"
)

granule_id = form_granule_id(
Expand All @@ -33,11 +34,12 @@ def test_form_granule_id():
frame_number=124,
x_posting=80.0,
y_posting=80.0,
epsg_code=32611,
validity_start_datetime=datetime.fromisoformat("2000-01-01T00:00:00"),
composite_release_id="A11111",
processing_center="somewhere else",
product_counter=999,
)
assert (
granule_id == "NISAR_S2_STATIC_123_D_124_080_080_20000101T000000_A11111_X_999"
granule_id == "NISAR_S2_STATIC_123_D_124_0800_0800_20000101T000000_A11111_X_999"
)