fimserve 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. fimserve/FIMsubset/__init__.py +7 -0
  2. fimserve/FIMsubset/shpsubset.py +58 -0
  3. fimserve/FIMsubset/xycoord.py +101 -0
  4. fimserve/__init__.py +87 -0
  5. fimserve/datadownload.py +163 -0
  6. fimserve/enhancement_withSM/SM_prediction.py +301 -0
  7. fimserve/enhancement_withSM/SM_preprocess.py +139 -0
  8. fimserve/enhancement_withSM/__init__.py +31 -0
  9. fimserve/enhancement_withSM/building_exposure.py +170 -0
  10. fimserve/enhancement_withSM/interactS3.py +137 -0
  11. fimserve/enhancement_withSM/pop_exposure.py +500 -0
  12. fimserve/enhancement_withSM/preprocessFIM.py +830 -0
  13. fimserve/enhancement_withSM/surrogate_model.py +194 -0
  14. fimserve/enhancement_withSM/utlis.py +28 -0
  15. fimserve/fimevaluation/__init__.py +4 -0
  16. fimserve/fimevaluation/fims_setup.py +723 -0
  17. fimserve/fimevaluation/run_fimeval.py +110 -0
  18. fimserve/fimevaluation/utils.py +724 -0
  19. fimserve/intersectedHUC.py +194 -0
  20. fimserve/plot/__init__.py +19 -0
  21. fimserve/plot/comparestreamflow.py +176 -0
  22. fimserve/plot/nwmfid.py +219 -0
  23. fimserve/plot/src.py +93 -0
  24. fimserve/plot/usgs.py +177 -0
  25. fimserve/plot/usgsandfid.py +35 -0
  26. fimserve/runFIM.py +152 -0
  27. fimserve/statistics/__init__.py +3 -0
  28. fimserve/statistics/calculatestatistics.py +131 -0
  29. fimserve/streamflowdata/__init__.py +15 -0
  30. fimserve/streamflowdata/forecasteddata.py +444 -0
  31. fimserve/streamflowdata/geoglows.py +94 -0
  32. fimserve/streamflowdata/nwmretrospective.py +270 -0
  33. fimserve/streamflowdata/usgsdata.py +192 -0
  34. fimserve/vizualizationFIM.py +111 -0
  35. fimserve-0.1.2.dist-info/METADATA +220 -0
  36. fimserve-0.1.2.dist-info/RECORD +39 -0
  37. fimserve-0.1.2.dist-info/WHEEL +5 -0
  38. fimserve-0.1.2.dist-info/licenses/LICENSE +661 -0
  39. fimserve-0.1.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,7 @@
1
+ import warnings
2
+
3
+ warnings.simplefilter("ignore")
4
+
5
+ from .xycoord import subsetFIM
6
+
7
+ __all__ = ["subsetFIM"]
@@ -0,0 +1,58 @@
1
+ import os
2
+ import rasterio
3
+ from rasterio.mask import mask
4
+ from pathlib import Path
5
+ import geopandas as gpd
6
+
7
+
8
+ def checkSHP(input_file):
9
+ if isinstance(input_file, Path):
10
+ input_file = str(input_file)
11
+
12
+ if input_file.endswith(".shp"):
13
+ gdf = gpd.read_file(input_file)
14
+ elif input_file.endswith(".gpkg"):
15
+ gdf = gpd.read_file(input_file)
16
+ elif input_file.endswith(".geojson"):
17
+ gdf = gpd.read_file(input_file)
18
+ elif input_file.endswith(".kml"):
19
+ gdf = gpd.read_file(input_file)
20
+ else:
21
+ raise ValueError(
22
+ "Unsupported file format. Please provide a shapefile GeoPackage, GeoJSON, or KML."
23
+ )
24
+ return gdf
25
+
26
+
27
+ def clipFIMforboundary(inundation_raster, shapefile_geom, output_directory, huc):
28
+ with rasterio.open(inundation_raster) as src:
29
+ geometries = shapefile_geom.geometry.tolist()
30
+ if src.crs != shapefile_geom.crs:
31
+ print("CRS mismatch. Reprojecting geometry to match raster.")
32
+ geometries = [geom.to_crs(src.crs) for geom in geometries]
33
+
34
+ out_image, out_transform = mask(src, geometries, crop=True)
35
+ out_meta = src.meta.copy()
36
+ out_meta.update(
37
+ {
38
+ "driver": "GTiff",
39
+ "count": 1,
40
+ "crs": src.crs,
41
+ "transform": out_transform,
42
+ "width": out_image.shape[2],
43
+ "height": out_image.shape[1],
44
+ }
45
+ )
46
+
47
+ output_directory = os.path.join(output_directory, "subsetFIM")
48
+ if not os.path.exists(output_directory):
49
+ os.makedirs(output_directory)
50
+
51
+ file_basename = os.path.basename(inundation_raster).split("_")[0]
52
+ output_file = os.path.join(output_directory, f"{file_basename}_subsetFIM.tif")
53
+
54
+ if not os.path.exists(output_directory):
55
+ os.makedirs(output_directory)
56
+ with rasterio.open(output_file, "w", **out_meta) as dest:
57
+ dest.write(out_image)
58
+ print(f"Clipped raster saved to {output_file}")
@@ -0,0 +1,101 @@
1
+ import os
2
+ import glob
3
+ import geopandas as gpd
4
+ from shapely.geometry import Point
5
+ import rasterio
6
+ from rasterio.mask import mask
7
+
8
+ from ..datadownload import setup_directories
9
+ from .shpsubset import checkSHP, clipFIMforboundary
10
+
11
+
12
+ def checkifWGS(x, y):
13
+ """Check if coordinates are in WGS84 (EPSG:4326) range."""
14
+ if -180 <= x <= 180 and -90 <= y <= 90:
15
+ return True
16
+ else:
17
+ return False
18
+
19
+
20
+ def reproject_coordinates(x, y, target_crs="EPSG:5070"):
21
+ """Reproject coordinates to target CRS."""
22
+ if checkifWGS(x, y):
23
+ from pyproj import CRS, Transformer
24
+
25
+ crs_wgs84 = CRS("EPSG:4326")
26
+ crs_target = CRS(target_crs)
27
+ transformer = Transformer.from_crs(crs_wgs84, crs_target, always_xy=True)
28
+ x_new, y_new = transformer.transform(x, y)
29
+ return x_new, y_new
30
+ else:
31
+ return x, y
32
+
33
+
34
+ def clipFIM(inundation_raster, shapefile_geom, output_directory, huc):
35
+ with rasterio.open(inundation_raster) as src:
36
+ out_image, out_transform = mask(src, [shapefile_geom], crop=True)
37
+ out_meta = src.meta.copy()
38
+ out_meta.update(
39
+ {
40
+ "driver": "GTiff",
41
+ "count": 1,
42
+ "crs": src.crs,
43
+ "transform": out_transform,
44
+ "width": out_image.shape[2],
45
+ "height": out_image.shape[1],
46
+ }
47
+ )
48
+ file_basename = os.path.basename(inundation_raster).split("_")[0]
49
+ output_file = os.path.join(output_directory, f"{file_basename}_subsetFIM.tif")
50
+
51
+ if not os.path.exists(output_directory):
52
+ os.makedirs(output_directory)
53
+
54
+ with rasterio.open(output_file, "w", **out_meta) as dest:
55
+ dest.write(out_image)
56
+
57
+ print(f"Clipped raster saved to {output_file}")
58
+ return out_image, out_transform
59
+
60
+
61
+ def withininWatershed(x, y, geopackage_path, inundation_raster, huc, output_directory):
62
+ point = Point(x, y)
63
+ watersheds = gpd.read_file(geopackage_path)
64
+
65
+ # Watershed containing the point
66
+ watershed_containing_point = None
67
+ for _, watershed in watersheds.iterrows():
68
+ if watershed["geometry"].contains(point):
69
+ watershed_containing_point = watershed
70
+ break
71
+ output_directory = os.path.join(output_directory, "subsetFIM")
72
+ if not os.path.exists(output_directory):
73
+ os.makedirs(output_directory)
74
+
75
+ if watershed_containing_point is None:
76
+ raise ValueError(f"Point is not within any watershed boundary for {huc}")
77
+ return clipFIM(
78
+ inundation_raster, watershed_containing_point["geometry"], output_directory, huc
79
+ )
80
+
81
+
82
+ def subsetFIM(location, huc, method):
83
+ code_dir, data_dir, output_dir = setup_directories()
84
+ gpkg_path = os.path.join(
85
+ output_dir, f"flood_{huc}", huc, "nwm_catchments_proj_subset.gpkg"
86
+ )
87
+ out_dir = os.path.join(output_dir, f"flood_{huc}", f"{huc}_inundation")
88
+ inundation_rasters = os.path.join(out_dir, "*_inundation.tif")
89
+ print(inundation_rasters)
90
+ files = glob.glob(inundation_rasters)
91
+ if method == "xy":
92
+ x, y = location
93
+ print("point", x, y)
94
+ x, y = reproject_coordinates(x, y)
95
+ for file in files:
96
+ print(f"Clipping {file} to watershed containing point {x}, {y}")
97
+ withininWatershed(x, y, gpkg_path, file, huc, out_dir)
98
+ elif method == "boundary":
99
+ shapefile = checkSHP(location)
100
+ for file in files:
101
+ clipFIMforboundary(file, shapefile, out_dir, huc)
fimserve/__init__.py ADDED
@@ -0,0 +1,87 @@
1
+ import warnings
2
+
3
+ warnings.simplefilter("ignore")
4
+
5
+ from .datadownload import DownloadHUC8
6
+ from .streamflowdata.nwmretrospective import getNWMretrospectivedata
7
+ from .runFIM import runOWPHANDFIM
8
+
9
+ from .streamflowdata.forecasteddata import getNWMForecasteddata
10
+ from .streamflowdata.geoglows import getGEOGLOWSstreamflow
11
+
12
+ # plots
13
+ from .plot.nwmfid import plotNWMStreamflow
14
+ from .streamflowdata.usgsdata import getUSGSsitedata
15
+ from .plot.comparestreamflow import CompareNWMnUSGSStreamflow
16
+ from .plot.usgs import plotUSGSStreamflow
17
+ from .plot.src import plotSRC
18
+
19
+ # For table
20
+ from .plot.usgsandfid import GetUSGSIDandCorrFID
21
+
22
+ # subsetting
23
+ from .FIMsubset.xycoord import subsetFIM
24
+
25
+ # Fim visualization
26
+ from .vizualizationFIM import vizualizeFIM
27
+
28
+ # Statistics
29
+ from .statistics.calculatestatistics import CalculateStatistics
30
+
31
+ # For intersected HUC8 boundary
32
+ from .intersectedHUC import getIntersectedHUC8ID
33
+
34
+ # evaluation of FIM
35
+ from .fimevaluation.fims_setup import FIMService, fim_lookup
36
+ from .fimevaluation.run_fimeval import run_evaluation
37
+
38
+
39
+ # Enhancement using surrogate models [Importing those only if they are called]
40
+ def prepare_FORCINGs(*args, **kwargs):
41
+ from .enhancement_withSM.preprocessFIM import prepare_FORCINGs as _impl
42
+
43
+ return _impl(*args, **kwargs)
44
+
45
+
46
+ def enhanceFIM(*args, **kwargs):
47
+ from .enhancement_withSM.SM_prediction import enhanceFIM as _impl
48
+
49
+ return _impl(*args, **kwargs)
50
+
51
+
52
+ def getbuilding_exposure(*args, **kwargs):
53
+ from .enhancement_withSM.building_exposure import getbuilding_exposure as _impl
54
+
55
+ return _impl(*args, **kwargs)
56
+
57
+
58
+ def getpopulation_exposure(*args, **kwargs):
59
+ from .enhancement_withSM.pop_exposure import getpopulation_exposure as _impl
60
+
61
+ return _impl(*args, **kwargs)
62
+
63
+
64
+ __all__ = [
65
+ "DownloadHUC8",
66
+ "getNWMretrospectivedata",
67
+ "runOWPHANDFIM",
68
+ "getNWMForecasteddata",
69
+ "getGEOGLOWSstreamflow",
70
+ "plotNWMStreamflow",
71
+ "getUSGSsitedata",
72
+ "CompareNWMnUSGSStreamflow",
73
+ "plotUSGSStreamflow",
74
+ "plotSRC",
75
+ "GetUSGSIDandCorrFID",
76
+ "subsetFIM",
77
+ "vizualizeFIM",
78
+ "CalculateStatistics",
79
+ "getIntersectedHUC8ID",
80
+ "FIMService",
81
+ "fim_lookup",
82
+ "run_evaluation",
83
+ "prepare_FORCINGs",
84
+ "enhanceFIM",
85
+ "getbuilding_exposure",
86
+ "getpopulation_exposure",
87
+ ]
@@ -0,0 +1,163 @@
1
+ import os
2
+ import csv
3
+ import pandas as pd
4
+ import subprocess
5
+
6
+
7
+ def setup_directories():
8
+ parent_dir = os.getcwd()
9
+ code_dir = os.path.join(parent_dir, "code", "inundation-mapping")
10
+ data_dir = os.path.join(parent_dir, "data", "inputs")
11
+ output_dir = os.path.join(parent_dir, "output")
12
+
13
+ # Create the directories if not exist
14
+ os.makedirs(code_dir, exist_ok=True)
15
+ os.makedirs(data_dir, exist_ok=True)
16
+ os.makedirs(output_dir, exist_ok=True)
17
+
18
+ return code_dir, data_dir, output_dir
19
+
20
+
21
+ def clone_repository(code_dir, version=None):
22
+ repo_path = os.path.join(code_dir)
23
+ repo_url = "https://github.com/NOAA-OWP/inundation-mapping.git"
24
+
25
+ # Map version strings to git tags
26
+ version_tag_map = {
27
+ "4.5": "v4.6.1.4",
28
+ "default": "main",
29
+ }
30
+
31
+ # Determine tag to checkout
32
+ version_tag = version_tag_map.get(version, version_tag_map["default"])
33
+ if os.path.exists(repo_path) and os.listdir(repo_path):
34
+ print(f"Repository already exists at {repo_path}. Skipping clone.")
35
+ return
36
+
37
+ # Clone repo
38
+ subprocess.run(["git", "clone", repo_url, repo_path], check=True)
39
+
40
+ # Checkout specific version/tag (only if not main)
41
+ if version_tag != "main":
42
+ try:
43
+ subprocess.run(["git", "checkout", version_tag], cwd=repo_path, check=True)
44
+ except subprocess.CalledProcessError:
45
+ subprocess.run(["git", "tag"], cwd=repo_path) # List available tags
46
+ raise
47
+ print(f"Repository cloned into: {repo_path} (version: {version_tag})")
48
+
49
+
50
+ def download_data(huc_number, base_dir, version=None):
51
+ output_dir = os.path.join(base_dir, f"flood_{huc_number}", str(huc_number))
52
+ os.makedirs(output_dir, exist_ok=True)
53
+
54
+ # Determine S3 path based on version — default to 4.9
55
+ if version == "4.5":
56
+ s3_path = f"s3://ciroh-owp-hand-fim/hand_fim_4_5_2_11/{huc_number}/"
57
+ elif version == "4.8":
58
+ s3_path = f"s3://ciroh-owp-hand-fim/hand_fim_4_8_7_2/{huc_number}/"
59
+ else:
60
+ s3_path = f"s3://ciroh-owp-hand-fim/hand_fim_4_9_9_0/{huc_number}/"
61
+
62
+ # Run the AWS CLI command with no-sign-request
63
+ cmd = f"aws s3 sync {s3_path} {output_dir} --no-sign-request"
64
+ os.system(cmd)
65
+ print(f"Data for HUC {huc_number} downloaded to {output_dir}")
66
+
67
+ # Copy branch_ids.csv to fim_inputs.csv
68
+ hydrotable_path = os.path.join(output_dir, "branch_ids.csv")
69
+ fim_inputs_path = os.path.join(base_dir, f"flood_{huc_number}", "fim_inputs.csv")
70
+
71
+ with (
72
+ open(hydrotable_path, "r") as infile,
73
+ open(fim_inputs_path, "w", newline="") as outfile,
74
+ ):
75
+ reader = csv.reader(infile)
76
+ writer = csv.writer(outfile)
77
+ for row in reader:
78
+ writer.writerow(row)
79
+
80
+ print(f"Copied {hydrotable_path} to {fim_inputs_path} as fim_inputs.csv.")
81
+
82
+
83
+ def uniqueFID(hydrotable, fid_dir, stream_order=None):
84
+ hydrotable_df = pd.read_csv(hydrotable)
85
+
86
+ if stream_order:
87
+ if isinstance(stream_order, str) and (
88
+ ">=" in stream_order
89
+ or "<=" in stream_order
90
+ or ">" in stream_order
91
+ or "<" in stream_order
92
+ ):
93
+ # Handle conditions like ">=3", "<=4", etc.
94
+ operator, value = None, None
95
+ if ">=" in stream_order:
96
+ operator, value = ">=", int(stream_order.split(">=")[1])
97
+ elif "<=" in stream_order:
98
+ operator, value = "<=", int(stream_order.split("<=")[1])
99
+ elif ">" in stream_order:
100
+ operator, value = ">", int(stream_order.split(">")[1])
101
+ elif "<" in stream_order:
102
+ operator, value = "<", int(stream_order.split("<")[1])
103
+
104
+ hydrotable_df["order_"] = hydrotable_df["order_"].astype(int)
105
+ if operator == ">=":
106
+ hydrotable_df_filtered = hydrotable_df[hydrotable_df["order_"] >= value]
107
+ elif operator == "<=":
108
+ hydrotable_df_filtered = hydrotable_df[hydrotable_df["order_"] <= value]
109
+ elif operator == ">":
110
+ hydrotable_df_filtered = hydrotable_df[hydrotable_df["order_"] > value]
111
+ elif operator == "<":
112
+ hydrotable_df_filtered = hydrotable_df[hydrotable_df["order_"] < value]
113
+
114
+ elif isinstance(stream_order, (list, int)):
115
+ if isinstance(stream_order, int):
116
+ stream_order = [stream_order]
117
+ stream_order = [str(order) for order in stream_order]
118
+ hydrotable_df["order_"] = hydrotable_df["order_"].astype(str)
119
+ hydrotable_df_filtered = hydrotable_df[
120
+ hydrotable_df["order_"].isin(stream_order)
121
+ ]
122
+ else:
123
+ raise ValueError(
124
+ "Invalid stream_order format. Use a list of values, a single value, or a condition like '>=3'."
125
+ )
126
+ else:
127
+ # No filter, use the whole dataset
128
+ hydrotable_df_filtered = hydrotable_df
129
+
130
+ unique_FIDs = hydrotable_df_filtered["feature_id"].drop_duplicates()
131
+ unique_FIDs_df = pd.DataFrame(unique_FIDs, columns=["feature_id"])
132
+ unique_FIDs_df.to_csv(fid_dir, index=False)
133
+ print(f"Unique feature IDs saved to {fid_dir}.")
134
+
135
+
136
+ # IN the replacement of Docker, the environement variables are set in the .env file
137
+ def EnvFile(code_dir):
138
+ env_dir = os.path.join(code_dir, ".env")
139
+ env_content = """
140
+ inputsDir=inputs
141
+ outputsDir=output
142
+ """
143
+ os.makedirs(os.path.dirname(env_dir), exist_ok=True)
144
+
145
+ with open(env_dir, "w") as f:
146
+ f.write(env_content)
147
+
148
+
149
+ def DownloadHUC8(huc, stream_order=None, version=None):
150
+ code_dir, data_dir, output_dir = setup_directories()
151
+ clone_repository(code_dir, version)
152
+
153
+ # if huc is not str:
154
+ huc = str(huc)
155
+ download_data(huc, output_dir, version)
156
+ EnvFile(code_dir)
157
+ HUC_dir = os.path.join(output_dir, f"flood_{huc}")
158
+ hydrotable_dir = os.path.join(HUC_dir, str(huc), "hydrotable.csv")
159
+ featureID_dir = os.path.join(HUC_dir, "feature_IDs.csv")
160
+ if stream_order is None:
161
+ uniqueFID(hydrotable_dir, featureID_dir)
162
+ else:
163
+ uniqueFID(hydrotable_dir, featureID_dir, stream_order)