Skip to content

Commit e65e64d

Browse files
wrap the permission shell script within python module and fix building count issue
1 parent 1cf0886 commit e65e64d

File tree

12 files changed

+76
-366
lines changed

12 files changed

+76
-366
lines changed

docs/fimeval_usage.ipynb

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -255,18 +255,9 @@
255255
},
256256
{
257257
"cell_type": "code",
258-
"execution_count": null,
258+
"execution_count": 1,
259259
"metadata": {},
260-
"outputs": [
261-
{
262-
"name": "stderr",
263-
"output_type": "stream",
264-
"text": [
265-
"/Users/supath/Downloads/MSResearch/FIMpef/fimpef/.venv/lib/python3.11/site-packages/geemap/conversion.py:23: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.\n",
266-
" import pkg_resources\n"
267-
]
268-
}
269-
],
260+
"outputs": [],
270261
"source": [
271262
"#Import the package\n",
272263
"import fimeval as fp\n",
@@ -282,7 +273,7 @@
282273
},
283274
{
284275
"cell_type": "code",
285-
"execution_count": 6,
276+
"execution_count": 2,
286277
"metadata": {},
287278
"outputs": [],
288279
"source": [
@@ -337,7 +328,7 @@
337328
},
338329
{
339330
"cell_type": "code",
340-
"execution_count": 4,
331+
"execution_count": 3,
341332
"metadata": {},
342333
"outputs": [],
343334
"source": [
@@ -363,13 +354,13 @@
363354
},
364355
{
365356
"cell_type": "code",
366-
"execution_count": null,
357+
"execution_count": 5,
367358
"metadata": {},
368359
"outputs": [],
369360
"source": [
370361
"fp.EvaluateFIM(main_dir, method_name, output_dir) #It uses the default Permanent Water Bodies (PWB) dataset for United States.\n",
371362
"\n",
372-
"#If the User has their PWB shapefile, then give the following argument\n",
363+
"# #If the User has their PWB shapefile, then give the following argument\n",
373364
"fp.EvaluateFIM(main_dir, method_name, output_dir, PWB_dir = PWD_dir)"
374365
]
375366
},
@@ -434,6 +425,13 @@
434425
"# fp.EvaluationWithBuildingFootprint(main_dir, method_name, output_dir, building_footprint = building_footprint, shapefile_dir= AOI)"
435426
]
436427
},
428+
{
429+
"cell_type": "markdown",
430+
"metadata": {},
431+
"source": [
432+
"**For building automation, need to install java runtime (preferred version is 8: https://www.java.com/en/download/manual.jsp). For Windows need to setup the path and environmental variables carefully to avoid the RunTimeError**"
433+
]
434+
},
437435
{
438436
"cell_type": "code",
439437
"execution_count": null,
@@ -453,7 +451,7 @@
453451
],
454452
"metadata": {
455453
"kernelspec": {
456-
"display_name": "fimpef",
454+
"display_name": "fimeval",
457455
"language": "python",
458456
"name": "python3"
459457
},
@@ -467,7 +465,7 @@
467465
"name": "python",
468466
"nbconvert_exporter": "python",
469467
"pygments_lexer": "ipython3",
470-
"version": "3.11.13"
468+
"version": "3.10.18"
471469
}
472470
},
473471
"nbformat": 4,

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "fimeval"
3-
version = "0.1.53"
3+
version = "0.1.54"
44
description = "A Framework for Automatic Evaluation of Flood Inundation Mapping Predictions Evaluation"
55
readme = "README.md"
66
requires-python = ">=3.10"
@@ -29,7 +29,8 @@ dependencies = [
2929
"pyproj>=3.7.0,<4.0.0",
3030
"notebook>=7.3.2,<8.0.0",
3131
"boto3>=1.36.16,<2.0.0",
32-
"geemap"
32+
"geemap",
33+
"uv"
3334
]
3435

3536
[project.optional-dependencies]

src/fimeval.egg-info/PKG-INFO

Lines changed: 0 additions & 233 deletions
This file was deleted.

src/fimeval.egg-info/SOURCES.txt

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/fimeval.egg-info/dependency_links.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/fimeval.egg-info/requires.txt

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/fimeval.egg-info/top_level.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/fimeval/BuildingFootprint/evaluationwithBF.py

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ def Changeintogpkg(input_path, output_dir, layer_name):
2020
gdf.to_file(output_gpkg, driver="GPKG")
2121
return output_gpkg
2222

23-
2423
def GetFloodedBuildingCountInfo(
2524
building_fp_path,
2625
study_area_path,
@@ -31,7 +30,6 @@ def GetFloodedBuildingCountInfo(
3130
basename,
3231
):
3332
output_dir = os.path.dirname(building_fp_path)
34-
3533
building_fp_gpkg = Changeintogpkg(
3634
building_fp_path, output_dir, "building_footprint"
3735
)
@@ -42,7 +40,6 @@ def GetFloodedBuildingCountInfo(
4240
with rasterio.open(raster1_path) as src:
4341
target_crs = str(src.crs)
4442

45-
# Reproject all GeoDataFrames to the target CRS
4643
if building_gdf.crs != target_crs:
4744
building_gdf = building_gdf.to_crs(target_crs)
4845
print("reproject building_gdf")
@@ -55,43 +52,32 @@ def GetFloodedBuildingCountInfo(
5552
clipped_buildings["centroid"] = clipped_buildings.geometry.centroid
5653

5754
centroid_counts = {
58-
"Benchmark": 0,
59-
"Candidate": 0,
6055
"False Positive": 0,
6156
"False Negative": 0,
6257
"True Positive": 0,
6358
}
6459

65-
def count_centroids_in_raster(raster_path, label):
60+
# Count centroids in the contingency map
61+
def count_centroids_in_contingency(raster_path):
6662
with rasterio.open(raster_path) as src:
6763
raster_data = src.read(1)
68-
transform = src.transform
69-
7064
for centroid in clipped_buildings["centroid"]:
7165
row, col = src.index(centroid.x, centroid.y)
7266
if 0 <= row < raster_data.shape[0] and 0 <= col < raster_data.shape[1]:
7367
pixel_value = raster_data[row, col]
74-
if label in ["Benchmark", "Candidate"]:
75-
if pixel_value == 2: # False Positive
76-
centroid_counts[label] += 1
77-
else:
78-
if pixel_value == 2:
79-
centroid_counts["False Positive"] += 1
80-
elif pixel_value == 3:
81-
centroid_counts["False Negative"] += 1
82-
elif pixel_value == 4:
83-
centroid_counts["True Positive"] += 1
68+
if pixel_value == 2:
69+
centroid_counts["False Positive"] += 1
70+
elif pixel_value == 3:
71+
centroid_counts["False Negative"] += 1
72+
elif pixel_value == 4:
73+
centroid_counts["True Positive"] += 1
8474

85-
if "bm" in str(raster1_path).lower():
86-
count_centroids_in_raster(raster1_path, "Benchmark")
87-
count_centroids_in_raster(raster2_path, "Candidate")
75+
count_centroids_in_contingency(contingency_map)
8876

89-
elif "candidate" in str(raster2_path).lower():
90-
count_centroids_in_raster(raster1_path, "Candidate")
91-
count_centroids_in_raster(raster2_path, "Benchmark")
77+
# Calculate Candidate and Benchmark counts from the contingency map counts
78+
centroid_counts["Candidate"] = centroid_counts["True Positive"] + centroid_counts["False Positive"]
79+
centroid_counts["Benchmark"] = centroid_counts["True Positive"] + centroid_counts["False Negative"]
9280

93-
if "contingency" in str(contingency_map).lower():
94-
count_centroids_in_raster(contingency_map, "Contingency")
9581

9682
total_buildings = len(clipped_buildings)
9783
percentages = {
@@ -107,10 +93,14 @@ def count_centroids_in_raster(raster_path, label):
10793
FAR = FP / (TP + FP) if (TP + FP) > 0 else 0
10894
POD = TP / (TP + FN) if (TP + FN) > 0 else 0
10995

110-
BDR = (
111-
centroid_counts["Candidate"] - centroid_counts["Benchmark"]
112-
) / centroid_counts["Benchmark"]
113-
96+
if centroid_counts["Benchmark"] > 0:
97+
BDR = (
98+
(centroid_counts["Candidate"] - centroid_counts["Benchmark"])
99+
/ centroid_counts["Benchmark"]
100+
)
101+
else:
102+
BDR = 0
103+
114104
counts_data = {
115105
"Category": [
116106
"Candidate",
@@ -290,15 +280,19 @@ def detect_shapefile(folder):
290280
def ensure_pyspark(version: str | None = "3.5.4") -> None:
291281
"""Install pyspark at runtime via `uv pip` into this env (no-op if present)."""
292282
import importlib, shutil, subprocess, sys, re
283+
293284
try:
294285
import importlib.util
286+
295287
if importlib.util.find_spec("pyspark"):
296288
return
297289
except Exception:
298290
pass
299291
uv = shutil.which("uv")
300292
if not uv:
301-
raise RuntimeError("`uv` not found on PATH. Please install uv or add it to PATH.")
293+
raise RuntimeError(
294+
"`uv` not found on PATH. Please install uv or add it to PATH."
295+
)
302296
if version is None:
303297
spec = "pyspark"
304298
else:
@@ -307,7 +301,6 @@ def ensure_pyspark(version: str | None = "3.5.4") -> None:
307301
subprocess.check_call([uv, "pip", "install", "--python", sys.executable, spec])
308302

309303

310-
311304
def EvaluationWithBuildingFootprint(
312305
main_dir,
313306
method_name,
@@ -338,11 +331,11 @@ def EvaluationWithBuildingFootprint(
338331
boundary = detect_shapefile(main_dir)
339332

340333
building_footprintMS = building_footprint
341-
334+
342335
if building_footprintMS is None:
343336
ensure_pyspark()
344337
from .microsoftBF import BuildingFootprintwithISO
345-
338+
346339
out_dir = os.path.join(method_path, "BuildingFootprint")
347340
if not os.path.exists(out_dir):
348341
os.makedirs(out_dir)
@@ -398,11 +391,11 @@ def EvaluationWithBuildingFootprint(
398391
boundary = detect_shapefile(os.path.join(main_dir, folder))
399392

400393
building_footprintMS = building_footprint
401-
394+
402395
if building_footprintMS is None:
403396
ensure_pyspark()
404397
from .microsoftBF import BuildingFootprintwithISO
405-
398+
406399
out_dir = os.path.join(method_path, "BuildingFootprint")
407400
if not os.path.exists(out_dir):
408401
os.makedirs(out_dir)

src/fimeval/BuildingFootprint/microsoftBF.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
# Authenticate and initialize Earth Engine
1919
ee.Authenticate()
2020

21+
2122
# %%
2223
def split_into_tiles(boundary, tile_size=0.1):
2324
bounds = boundary.total_bounds

src/fimeval/ContingencyMap/evaluationFIM.py

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,35 @@ def is_writable(path):
3131

3232
def fix_permissions(path):
3333
path = Path(path).resolve()
34-
script_path = Path(__file__).parent / "fix_permissions.sh"
35-
36-
if not script_path.exists():
37-
raise FileNotFoundError(f"Shell script not found: {script_path}")
3834

3935
if is_writable(path):
4036
return
4137

38+
uname = platform.system()
39+
4240
try:
43-
result = subprocess.run(
44-
["bash", str(script_path), str(path)],
45-
check=True,
46-
capture_output=True,
47-
text=True,
48-
)
49-
print(result.stdout)
41+
if uname in ["Darwin", "Linux"]:
42+
subprocess.run(
43+
["chmod", "-R", "u+rwX", str(path)],
44+
check=True,
45+
capture_output=True,
46+
text=True,
47+
)
48+
print(f"Permissions granted for user (u+rwX): {path}")
49+
50+
elif "MINGW" in uname or "MSYS" in uname or "CYGWIN" in uname:
51+
subprocess.run(
52+
["icacls", str(path), "/grant", "Everyone:F", "/T"],
53+
check=True,
54+
capture_output=True,
55+
text=True,
56+
)
57+
print(f"Permissions granted for working folder: {path}")
58+
59+
else:
60+
print(f"Unsupported OS: {uname}")
5061
except subprocess.CalledProcessError as e:
51-
print(f"Shell script failed:\n{e.stderr}")
62+
print(f"Failed to fix permissions for {path}:\n{e.stderr}")
5263

5364

5465
# Function for the evalution of the model

0 commit comments

Comments
 (0)