Skip to content

Commit ed1a2a7

Browse files
Enhance the FIMbench query modules (#15)
* added new version distribution files * updated the building footprint download with ArcGIS API * updated PWB module with Hosted ArcGIS Feature Layer * Release 0.1.58
1 parent 110d5f9 commit ed1a2a7

7 files changed

Lines changed: 1505 additions & 1238 deletions

File tree

65.9 KB
Binary file not shown.

dist/fimeval-0.1.58.tar.gz

79 KB
Binary file not shown.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "fimeval"
3-
version = "0.1.57"
3+
version = "0.1.58"
44
description = "A Framework for Automatic Evaluation of Flood Inundation Mapping Predictions Evaluation"
55
readme = "README.md"
66
requires-python = ">=3.10"

src/fimeval/BenchFIMQuery/access_benchfim.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
_record_day,
2626
_record_hour_or_none,
2727
_pretty_date_for_print,
28+
_ensure_local_gpkg,
2829
)
2930

3031
# Preferred area CRSs for area calculations
@@ -300,15 +301,28 @@ def _aoi_context_str(
300301
end_date=end_date,
301302
)
302303

304+
def _display_raster_name(rec: Dict[str, Any]) -> str:
305+
tif_url = rec.get("tif_url")
306+
if isinstance(tif_url, str) and tif_url.strip():
307+
# drop querystring if any
308+
tif_url = tif_url.split("?", 1)[0]
309+
return os.path.basename(tif_url)
310+
311+
# fallback: last path token of id
312+
rid = rec.get("id")
313+
if isinstance(rid, str) and rid.strip():
314+
return rid.strip().split("/")[-1] + ".tif"
315+
316+
return "NA"
303317

304318
# Build a single printable block, optionally with overlap appended
305319
def _format_block_with_overlap(
306320
rec: Dict[str, Any], pct: Optional[float], km2: Optional[float]
307321
) -> str:
308-
tier = rec.get("tier") or rec.get("quality") or "Unknown"
322+
tier = rec.get("tier") or rec.get("HWM") or rec.get("quality") or "Unknown"
309323
res = rec.get("resolution_m")
310324
res_txt = f"{res}m" if res is not None else "NA"
311-
fname = rec.get("file_name") or "NA"
325+
fname = _display_raster_name(rec)
312326

313327
lines = [f"Data Tier: {tier}"]
314328

@@ -404,20 +418,23 @@ def _gpkg_urls_from_record(rec: Dict[str, Any]) -> List[str]:
404418
out.append(u)
405419
return out
406420

407-
408421
def _read_benchmark_aoi_union_geom(rec: Dict[str, Any]) -> Optional[Polygon]:
409-
# Read and union AOI geometries referenced by the record (kept permissive)
422+
# Read and union AOI geometries referenced by the record
410423
urls = _gpkg_urls_from_record(rec)
411424
if not urls:
412425
return None
426+
413427
geoms: List[Polygon] = []
414428
for uri in urls:
415429
try:
416430
storage_opts = _storage_options_for_uri(uri)
431+
432+
uri_to_read = _ensure_local_gpkg(uri)
433+
417434
gdf = (
418-
gpd.read_file(uri, storage_options=storage_opts)
435+
gpd.read_file(uri_to_read, storage_options=storage_opts)
419436
if storage_opts
420-
else gpd.read_file(uri)
437+
else gpd.read_file(uri_to_read)
421438
)
422439
if gdf.empty:
423440
continue
@@ -429,8 +446,9 @@ def _read_benchmark_aoi_union_geom(rec: Dict[str, Any]) -> Optional[Polygon]:
429446
u = unary_union(gdf.geometry)
430447
if not u.is_empty:
431448
geoms.append(u)
432-
except Exception:
449+
except Exception as e:
433450
continue
451+
434452
if not geoms:
435453
return None
436454
uall = unary_union(geoms)

src/fimeval/BenchFIMQuery/utilis.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,72 @@ def s3_http_url(bucket: str, key: str) -> str:
3838
_YMDHMS_RE = re.compile(r"^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2})?$")
3939

4040

41+
#Support functions to ensute the geopackage file is local
42+
def _s3_bucket_key_from_http_url(url: str) -> Optional[tuple[str, str]]:
43+
try:
44+
u = urllib.parse.urlparse(url)
45+
host = (u.netloc or "").lower()
46+
path = (u.path or "").lstrip("/")
47+
if not host or not path:
48+
return None
49+
50+
if ".s3." in host or host.endswith(".s3.amazonaws.com"):
51+
bucket = host.split(".s3", 1)[0]
52+
key = path
53+
return bucket, key
54+
55+
return None
56+
except Exception:
57+
return None
58+
59+
60+
def _ensure_local_gpkg(uri: str) -> str:
61+
"""
62+
Ensure we can read a GPKG even when uri is an https S3 URL by caching locally.
63+
Returns a path usable by geopandas.read_file().
64+
"""
65+
if not isinstance(uri, str) or not uri.strip():
66+
return uri
67+
68+
u = uri.strip()
69+
if os.path.exists(u):
70+
return u
71+
72+
# Cache https S3 gpkg locally
73+
if u.lower().startswith("http") and ".amazonaws.com/" in u.lower() and u.lower().endswith(".gpkg"):
74+
parsed = _s3_bucket_key_from_http_url(u.split("?", 1)[0])
75+
if not parsed:
76+
return u
77+
78+
bucket, key = parsed
79+
cache_dir = os.path.join(os.path.expanduser("~"), ".fimeval_cache", "aoi_gpkg")
80+
os.makedirs(cache_dir, exist_ok=True)
81+
82+
local = os.path.join(cache_dir, os.path.basename(key))
83+
if not os.path.exists(local):
84+
_download(bucket, key, local)
85+
return local
86+
return u
87+
4188
def _normalize_user_dt(s: str) -> str:
4289
s = s.strip()
4390
s = s.replace("/", "-")
4491
s = re.sub(r"\s+", " ", s)
4592
return s
4693

94+
def _display_raster_name(rec: Dict[str, Any]) -> str:
95+
tif_url = rec.get("tif_url")
96+
if isinstance(tif_url, str) and tif_url.strip():
97+
# drop querystring if any
98+
tif_url = tif_url.split("?", 1)[0]
99+
return os.path.basename(tif_url)
100+
101+
# fallback: last path token of id
102+
rid = rec.get("id")
103+
if isinstance(rid, str) and rid.strip():
104+
return rid.strip().split("/")[-1] + ".tif"
105+
106+
return "NA"
47107

48108
def _to_date(s: str) -> dt.date:
49109
s = _normalize_user_dt(s)
@@ -186,7 +246,7 @@ def _return_period_text_local(r: Dict[str, Any]) -> str:
186246
tier = r.get("tier") or r.get("quality") or "Unknown"
187247
res = r.get("resolution_m")
188248
res_txt = f"{res}m" if res is not None else "NA"
189-
fname = r.get("file_name") or "NA"
249+
fname = _display_raster_name(r)
190250

191251
# Build lines with Tier-aware event text
192252
lines = [f"Data Tier: {tier}"]

tests/test_accessbenchmarkFIM.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import fimeval as fe
22

33
# For testing boundary/raster inputs
4-
raster_path = "/Users/supath/Downloads/MSResearch/FIMpef/CodeUsage/SM_prediction/HUC11110203_AR/hf_RS_HUC11110203_AR_binary_BM.tif" # ./paths/to/your/model_predicted_fim"
5-
boundary_path = "./paths/to/your/boundaryfile"
4+
# raster_path = "/Users/supath/Downloads/MSResearch/FIMpef/CodeUsage/SM_prediction/HUC11110203_AR/hf_RS_HUC11110203_AR_binary_BM.tif" # ./paths/to/your/model_predicted_fim"
5+
boundary_path = "/Users/Supath/Downloads/HWM_10_0m_20250704_991013W300036N_BM.gpkg"
66

77

88
# Benchmark FIM querying
@@ -39,15 +39,15 @@
3939

4040
def test_benchmark_fimquery():
4141
response = fe.benchFIMquery(
42-
raster_path=raster_path,
43-
boundary_path=None,
44-
huc8=None, # Example HUC8 ID: "03020202"
42+
# raster_path=raster_path,
43+
boundary_path=boundary_path,
44+
# huc8=None, # Example HUC8 ID: "03020202"
4545
# event_date = "2017-05-01",
4646
# start_date = "2017-04-01",
4747
# end_date = "2017-05-01",
4848
# file_name = None,
4949
area=True, # Default is false; if True, returns overlap stats
50-
# download = False,
50+
# download = True,
5151
# out_dir = None,
5252
)
5353
print(response)

0 commit comments

Comments
 (0)