Source code for gedih3.egi.config

# Copyright (C) 2026, University of Maryland. All Rights Reserved.
# Authors: Tiago de Conto, Amelia Grace Holcomb
# For commercial licensing inquiries, contact UM Ventures at umdtechtransfer@umd.edu

"""
EGI (EASE Grid Index) Configuration Module

This module defines constants and configuration for the EASE-Grid 2.0 (EPSG:6933)
spatial indexing system used for GEDI L4B-compatible square pixel outputs.

The EGI system provides:
- 12 resolution levels (1m to 160km)
- Perfect alignment with GEDI L4B products at level 6 (~1km)
- Native raster output without resampling artifacts
- Hash-based coordinate encoding for efficient spatial indexing

Reference:
- EASE-Grid 2.0: https://nsidc.org/ease/ease-grid-projection-gt
- EPSG:6933: WGS 84 / NSIDC EASE-Grid 2.0 Global
"""
from typing import Dict

# Integer limits for hash validation
UINT_MAX: int = 18_446_744_073_709_551_615  # 2^64 - 1
INT_MAX: int = 9_223_372_036_854_775_807     # 2^63 - 1

# EPSG:6933 projected coordinate bounds (meters)
# These define the valid extent of the EASE-Grid 2.0 projection
LIMITS: Dict[str, float] = {
    'lat_s': -7_314_540.830638599582016,   # Southern bound (meters)
    'lat_n':  7_314_540.830638599582016,   # Northern bound (meters)
    'lon_w': -17_367_530.445161499083042,  # Western bound (meters)
    'lon_e':  17_367_530.445161499083042,  # Eastern bound (meters)
}

# Base resolution at level 6 (GEDI baseline ~1km)
EGI_RES6: float = 1000.89502334956

# Resolution lookup table: level -> pixel size in meters
# Levels 1-5 are finer than GEDI baseline (higher resolution)
# Levels 7-12 are coarser than GEDI baseline (lower resolution)
RESOLUTIONS: Dict[int, float] = {
    1:  round(EGI_RES6 / 1000, 6),   # ~1m (finest)
    2:  round(EGI_RES6 / 200, 6),    # ~5m
    3:  round(EGI_RES6 / 40, 6),     # ~25m
    4:  round(EGI_RES6 / 10, 6),     # ~100m (NISAR compatible)
    5:  round(EGI_RES6 / 5, 6),      # ~200m (BIOMASS compatible)
    6:  round(EGI_RES6, 6),          # ~1km (GEDI baseline)
    7:  round(EGI_RES6 * 2, 6),      # ~2km (GEDI threshold)
    8:  round(EGI_RES6 * 10, 6),     # ~10km (GEDI wall-to-wall)
    9:  round(EGI_RES6 * 20, 6),     # ~20km
    10: round(EGI_RES6 * 40, 6),     # ~40km
    11: round(EGI_RES6 * 80, 6),     # ~80km
    12: round(EGI_RES6 * 160, 6),    # ~160km (coarsest, partition level)
}

# Outer tile resolution (coarsest level, used for partitioning)
OUTER_RES: float = max(RESOLUTIONS.values())
OUTER_LEVEL: int = max(RESOLUTIONS.keys())

# EPSG code for EASE-Grid 2.0
EGI_CRS: int = 6933

# Coordinate reference system string
EGI_CRS_STRING: str = "EPSG:6933"

# Column naming convention for EGI indices
[docs] def egi_col_name(level: int) -> str: """ Generate standard EGI column name for a given resolution level. Parameters ---------- level : int EGI resolution level (1-12) Returns ------- str Column name in format 'egi{level:02d}' (e.g., 'egi01', 'egi12') """ return f'egi{level:02d}'
[docs] def validate_level(level: int) -> None: """ Validate that a level is within the supported range. Parameters ---------- level : int EGI resolution level to validate Raises ------ ValueError If level is not between 1 and 12 """ if not 1 <= level <= 12: raise ValueError(f"EGI level must be between 1 and 12, got {level}")
[docs] def get_resolution(level: int) -> float: """ Get the pixel size in meters for a given EGI level. Parameters ---------- level : int EGI resolution level (1-12) Returns ------- float Pixel size in meters Raises ------ ValueError If level is not between 1 and 12 """ validate_level(level) return RESOLUTIONS[level]
[docs] def get_level_from_resolution(resolution: float, tolerance: float = 0.01) -> int: """ Find the EGI level closest to a given resolution. Parameters ---------- resolution : float Target resolution in meters tolerance : float Relative tolerance for matching (default 1%) Returns ------- int EGI level with closest matching resolution Raises ------ ValueError If no level matches within tolerance """ for level, res in RESOLUTIONS.items(): if abs(res - resolution) / res < tolerance: return level raise ValueError( f"No EGI level matches resolution {resolution}m within {tolerance*100}% tolerance. " f"Available resolutions: {list(RESOLUTIONS.values())}" )