d3dtools 0.1.0__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.
d3dtools/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ """
2
+ D3DTOOLS - A collection of tools for working with shapefiles and converting them for Delft3D modeling.
3
+ """
4
+
5
+ __version__ = '0.1.0'
6
+
7
+ from . import ncrain
8
+ from . import shpbc2pli
9
+ from . import shpblock2pol
10
+ from . import shpdike2pliz
d3dtools/ncrain.py ADDED
@@ -0,0 +1,267 @@
1
+ """
2
+ Generate a NetCDF file from rainfall data and thiessen polygon shapefile.
3
+ """
4
+ import os
5
+ import numpy as np
6
+ import pandas as pd
7
+ import geopandas as gpd
8
+ import rasterio as rio
9
+ import shutil
10
+ from osgeo import gdal
11
+ from netCDF4 import Dataset
12
+ import pyproj
13
+ from datetime import datetime
14
+
15
+
16
+ def generate(
17
+ input_shp_folder='SHP',
18
+ input_tab_folder='TAB',
19
+ output_nc_folder='NC',
20
+ intermediate_ras_folder='RAS_RAIN',
21
+ intermediate_shp_folder='SHP_RAIN',
22
+ clean_intermediate=True,
23
+ raster_resolution=320):
24
+ """
25
+ Generate a NetCDF file from rainfall data and thiessen polygon shapefile.
26
+
27
+ Parameters:
28
+ -----------
29
+ input_shp_folder : str
30
+ Path to the folder containing input shapefiles (default: 'SHP')
31
+ input_tab_folder : str
32
+ Path to the folder containing input tabular data (CSV files) (default: 'TAB')
33
+ output_nc_folder : str
34
+ Path to the folder where NetCDF output will be saved (default: 'NC')
35
+ intermediate_ras_folder : str
36
+ Path to the folder where intermediate raster files will be saved (default: 'RAS_RAIN')
37
+ intermediate_shp_folder : str
38
+ Path to the folder where intermediate shapefile files will be saved (default: 'SHP_RAIN')
39
+ clean_intermediate : bool
40
+ Whether to clean up intermediate files after processing (default: True)
41
+ raster_resolution : float
42
+ Resolution of the raster in meters (default: 320)
43
+
44
+ Returns:
45
+ --------
46
+ str
47
+ Path to the generated NetCDF file
48
+ """
49
+
50
+ # Create output directories if they don't exist
51
+ if not os.path.exists(intermediate_ras_folder):
52
+ os.makedirs(intermediate_ras_folder)
53
+
54
+ if not os.path.exists(intermediate_shp_folder):
55
+ os.makedirs(intermediate_shp_folder)
56
+
57
+ if not os.path.exists(output_nc_folder):
58
+ os.makedirs(output_nc_folder)
59
+
60
+ # Read THIESSEN POLYGON shp file
61
+ thiessen = gpd.read_file(f'{input_shp_folder}/THIESSEN.shp')
62
+
63
+ # Add field rainfall to thiessen with datatype float
64
+ thiessen['rainfall'] = 0.0
65
+
66
+ # Read the rainfall data
67
+ # Search folder and get the first file name ending with '.csv', without the extension
68
+ for file in os.listdir(input_tab_folder):
69
+ if file.endswith('.csv'):
70
+ rainfall_ts = file[:-4]
71
+ break
72
+
73
+ rainfall = pd.read_csv(f'{input_tab_folder}/{rainfall_ts}.csv')
74
+
75
+ # Convert 'time' filed to datetime
76
+ rainfall['time'] = pd.to_datetime(rainfall['time'])
77
+
78
+ # List the stations
79
+ stations = rainfall.columns[1:].to_list()
80
+
81
+ # Assign rainfall at time steps to the thiessen polygons
82
+ # when the 'Station' field matches the station name
83
+ for i, timestep in enumerate(rainfall['time']):
84
+ for station in stations:
85
+ for j in range(len(thiessen)):
86
+ if thiessen.iloc[j, 1] == station:
87
+ # thiessen['rainfall'][j] = rainfall[station][i]
88
+ thiessen.loc[j, 'rainfall'] = rainfall[station][i]
89
+ # Save the rainfall data to the shapefile
90
+ thiessen.to_file(
91
+ f'{intermediate_shp_folder}/THIESSEN_{i}.shp')
92
+ # Open the shapefile
93
+ thiessen = gpd.read_file(
94
+ f'{intermediate_shp_folder}/THIESSEN_{i}.shp')
95
+ # Get the extent of the shapefile
96
+ xmin, ymin, xmax, ymax = thiessen.total_bounds
97
+ # Get the resolution of the raster
98
+ res = raster_resolution
99
+ # Create the raster
100
+ raster = f'{intermediate_ras_folder}/THIESSEN_{i}.tif'
101
+ # Create the raster, set nodata value to -9999
102
+ gdal.Rasterize(raster,
103
+ f'{intermediate_shp_folder}/THIESSEN_{i}.shp',
104
+ format='GTiff',
105
+ outputType=gdal.GDT_Float32,
106
+ xRes=res,
107
+ yRes=res,
108
+ attribute='rainfall',
109
+ outputSRS=thiessen.crs,
110
+ noData=-9999)
111
+
112
+ # Get timestamps, including hours, minutes, and seconds
113
+ timestamps = rainfall['time'].dt.strftime('%Y-%m-%d %H:%M:%S').to_list()
114
+
115
+ # Read the raster file
116
+ with rio.open(f'{intermediate_ras_folder}/THIESSEN_0.tif') as src:
117
+ # get the resolution of the raster
118
+ res = src.res[0]
119
+ # get the extent of the raster
120
+ xmin, ymin, xmax, ymax = src.bounds
121
+ # Find bounds for extend without bounding elements
122
+ xmin = xmin + res
123
+ ymin = ymin + res
124
+ xmax = xmax - res
125
+ ymax = ymax - res
126
+
127
+ # Get X coordinates of the raster
128
+ x = np.arange(xmin, xmax, res)
129
+ # Get Y coordinates of the raster
130
+ y = np.arange(ymin, ymax, res)
131
+
132
+ # Shift x, y by half of the resolution
133
+ x = x + res / 2
134
+ y = y + res / 2
135
+
136
+ lonList = []
137
+ latList = []
138
+
139
+ project = pyproj.Transformer.from_crs("epsg:3826", "epsg:4326")
140
+
141
+ # convert x to lat
142
+ for i in x:
143
+ lat, lon = project.transform(i, 0)
144
+ lonList.append(lon)
145
+
146
+ # convert y to lon
147
+ for i in y:
148
+ lat, lon = project.transform(0, i)
149
+ latList.append(lat)
150
+
151
+ # Create mesh grids
152
+ lonM, latM = np.meshgrid(lonList, latList)
153
+ X, Y = np.meshgrid(x, y)
154
+
155
+ # Create netcdf file
156
+ try:
157
+ # just to be safe, make sure dataset is not already open.
158
+ ncfile.close()
159
+ except:
160
+ pass
161
+
162
+ nc_file_path = f'{output_nc_folder}/{rainfall_ts}.nc'
163
+ ncFile = Dataset(nc_file_path, 'w', format='NETCDF4')
164
+
165
+ # Create the dimensions
166
+ x_dim = ncFile.createDimension('x', len(lonList))
167
+ y_dim = ncFile.createDimension('y', len(latList))
168
+ lat_dim = ncFile.createDimension('lat', len(latList))
169
+ lon_dim = ncFile.createDimension('lon', len(lonList))
170
+ time_dim = ncFile.createDimension('time', None)
171
+
172
+ # Creating variables
173
+ x2 = ncFile.createVariable('x', np.float64, ('x', ), fill_value=9.96921E36)
174
+ x2.standard_name = "projection_x_coordinate"
175
+ x2.long_name = "x coordinate according to TWD 1997"
176
+ x2.units = "m"
177
+ x2.axis = "X"
178
+ x2[:] = x
179
+
180
+ y2 = ncFile.createVariable('y', np.float64, ('y', ), fill_value=9.96921E36)
181
+ y2.standard_name = "projection_y_coordinate"
182
+ y2.long_name = "y coordinate according to TWD 1997"
183
+ y2.units = "m"
184
+ y2.axis = "Y"
185
+ y2[:] = y
186
+
187
+ lat2 = ncFile.createVariable('lat',
188
+ np.float64, ('y', 'x'),
189
+ fill_value=9.96921E36)
190
+ lat2.standard_name = "latitude"
191
+ lat2.long_name = "latitude"
192
+ lat2.units = "degrees_north"
193
+ lat2[:] = latM
194
+
195
+ lon2 = ncFile.createVariable('lon',
196
+ np.float64, ('y', 'x'),
197
+ fill_value=9.96921E36)
198
+ lon2.standard_name = "longitude"
199
+ lon2.long_name = "longitude"
200
+ lon2.units = "degrees_east"
201
+ lon2[:] = lonM
202
+
203
+ time = ncFile.createVariable('time', np.float64, ('time', ))
204
+ time.standard_name = "time"
205
+ time.long_name = "time"
206
+ time.units = "minutes since 1970-01-01 08:00:00.0 +0800"
207
+ time.axis = "T"
208
+
209
+ # Convert timestamp to minutes since 1970-01-01 08:00:00.0 +0800
210
+ timestamp = [datetime.strptime(i, '%Y-%m-%d %H:%M:%S') for i in timestamps]
211
+ time[:] = [(i - datetime(1970, 1, 1, 8, 0, 0)).total_seconds() / 60
212
+ for i in timestamp]
213
+
214
+ # CRS
215
+ crs = ncFile.createVariable('crs', np.int32)
216
+ crs.long_name = "coordinate reference system"
217
+ crs.crs_wkt = "PROJCS[\"TWD97 / TM2 zone 121\", \r\n GEOGCS[\"TWD97\", \r\n DATUM[\"Taiwan Datum 1997\", \r\n SPHEROID[\"GRS 1980\", 6378137.0, 298.257222101, AUTHORITY[\"EPSG\",\"7019\"]], \r\n TOWGS84[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], \r\n AUTHORITY[\"EPSG\",\"1026\"]], \r\n PRIMEM[\"Greenwich\", 0.0, AUTHORITY[\"EPSG\",\"8901\"]], \r\n UNIT[\"degree\", 0.017453292519943295], \r\n AXIS[\"Geodetic longitude\", EAST], \r\n AXIS[\"Geodetic latitude\", NORTH], \r\n AUTHORITY[\"EPSG\",\"3824\"]], \r\n PROJECTION[\"Transverse_Mercator\"], \r\n PARAMETER[\"central_meridian\", 121.00000000000001], \r\n PARAMETER[\"latitude_of_origin\", 0.0], \r\n PARAMETER[\"scale_factor\", 0.9999], \r\n PARAMETER[\"false_easting\", 250000.0], \r\n PARAMETER[\"false_northing\", 0.0], \r\n UNIT[\"m\", 1.0], \r\n AXIS[\"Easting\", EAST], \r\n AXIS[\"Northing\", NORTH], \r\n AUTHORITY[\"EPSG\",\"3826\"]]"
218
+ crs.epsg_code = "EPSG:3826"
219
+ # set crs value to 0
220
+ crs[:] = 0
221
+
222
+ # Create the grid mapping variable
223
+ rainfall = ncFile.createVariable('rainfall',
224
+ np.float32, ('time', 'y', 'x'),
225
+ fill_value=-999.0)
226
+ rainfall.long_name = "rainfall"
227
+ rainfall.units = "mm"
228
+ rainfall.coordinates = "lat lon"
229
+ rainfall.grid_mapping = "crs"
230
+
231
+ # Write rainfall data to the netcdf file
232
+ data_arr = np.zeros((len(timestamp), len(latList), len(lonList)))
233
+
234
+ for i in range(len(timestamp)):
235
+ with rio.open(f'{intermediate_ras_folder}/THIESSEN_{i}.tif') as src:
236
+ data_arr_tmp = src.read(1)
237
+ # Get raster data without bounding elements
238
+ data_arr_tmp = data_arr_tmp[1:-1, 1:-1]
239
+ # flip in y direction
240
+ data_arr[i, :, :] = np.flipud(data_arr_tmp)
241
+
242
+ rainfall[:] = data_arr
243
+
244
+ # Close the netcdf file
245
+ ncFile.close()
246
+
247
+ # Remove intermediate files if requested
248
+ if clean_intermediate:
249
+ try:
250
+ shutil.rmtree(intermediate_ras_folder)
251
+ shutil.rmtree(intermediate_shp_folder)
252
+ except Exception as e:
253
+ print(f"Warning: Could not clean up intermediate files: {e}")
254
+
255
+ return nc_file_path
256
+
257
+
258
+ def main():
259
+ """
260
+ Command line entry point
261
+ """
262
+ output_path = generate()
263
+ print(f"NetCDF file generated at: {output_path}")
264
+
265
+
266
+ if __name__ == "__main__":
267
+ main()
d3dtools/shpbc2pli.py ADDED
@@ -0,0 +1,83 @@
1
+ """
2
+ Convert boundary line shapefile to *.pli file
3
+ """
4
+ import os
5
+ import glob
6
+ import geopandas as gpd
7
+
8
+
9
+ def convert(input_folder='SHP_BC', output_folder='PLI_BC'):
10
+ """
11
+ Convert boundary line shapefile to *.pli file
12
+ Attribute table must contain 'Id' or 'id' field for boundary name
13
+
14
+ Parameters:
15
+ -----------
16
+ input_folder : str
17
+ Path to the folder containing shapefiles with MultiLineString geometry (default: 'SHP_BC')
18
+ output_folder : str
19
+ Path to the output folder for PLI files (default: 'PLI_BC')
20
+ """
21
+ # Specify file source
22
+ fileList = glob.glob(f'{input_folder}/*.shp')
23
+ print(f"Found {len(fileList)} shapefiles in {input_folder}")
24
+
25
+ gdfs = []
26
+ for i, item in enumerate(fileList):
27
+ gdf = gpd.read_file(item)
28
+ gdfs.append(gdf)
29
+
30
+ # Read wkt
31
+ ref_wkts = []
32
+ for i, gdf in enumerate(gdfs):
33
+ ref_wkt = [g.wkt for g in gdf['geometry'].values]
34
+ ref_wkts.append(ref_wkt)
35
+
36
+ print(f"Total features: {len(ref_wkts)}")
37
+
38
+ # Get boundary names
39
+ bcNames = []
40
+ for i, gdf in enumerate(gdfs):
41
+ try:
42
+ bcName = [name for name in gdf['Id'].values]
43
+ except:
44
+ bcName = [name for name in gdf['id'].values]
45
+ bcNames.append(bcName)
46
+
47
+ # Create output folder if not exist
48
+ if not os.path.exists(output_folder):
49
+ os.makedirs(output_folder)
50
+ print(f"Created output folder: {output_folder}")
51
+
52
+ # For loop gdfs, create a .pli file with id as its name
53
+ file_count = 0
54
+ for i, ref_wkt in enumerate(ref_wkts):
55
+ for j, item in enumerate(ref_wkt):
56
+ with open(f'{output_folder}/{bcNames[i][j]}.pli', 'w',
57
+ encoding='utf-8') as f:
58
+ f.write('{}\n'.format(bcNames[i][j]))
59
+ points = [
60
+ point.split() for point in item.replace(
61
+ "LINESTRING (", "").replace(")", "").split(',')
62
+ ]
63
+ f.write('{} {}\n'.format(len(points), 2))
64
+ for k, ktem in enumerate(points):
65
+ f.write(
66
+ f'{float(ktem[0]):.6f} {float(ktem[1]):.6f} {bcNames[i][j]}_{k+1:0>4}\n'
67
+ )
68
+ f.write('\n')
69
+ file_count += 1
70
+
71
+ print(f'Done! Generated {file_count} PLI files in {output_folder}')
72
+ return file_count
73
+
74
+
75
+ def main():
76
+ """
77
+ Command line entry point
78
+ """
79
+ convert()
80
+
81
+
82
+ if __name__ == "__main__":
83
+ main()
@@ -0,0 +1,78 @@
1
+ """
2
+ Convert shapefile blocks to *.pol files
3
+ """
4
+ import numpy as np
5
+ import pandas as pd
6
+ import geopandas as gpd
7
+ from glob import glob
8
+ import os
9
+ import shapely.wkt
10
+ import matplotlib.pyplot as plt
11
+ from shapely.geometry import Point, LineString
12
+
13
+
14
+ def convert(input_folder='SHP_BLOCK', output_folder='POL_BLOCK'):
15
+ """
16
+ Convert shapefile blocks to *.pol files
17
+
18
+ Parameters:
19
+ -----------
20
+ input_folder : str
21
+ Path to the folder containing shapefiles (default: 'SHP_BLOCK')
22
+ output_folder : str
23
+ Path to the folder where .pol files will be saved (default: 'POL_BLOCK')
24
+ """
25
+ # Read shapefile data
26
+ blockList = glob(f'{input_folder}/*.shp')
27
+ blockNameList = [os.path.basename(block).split('.')[0]
28
+ for block in blockList]
29
+
30
+ # Extract wkt from blocks and convert to pol
31
+ for i, block in enumerate(blockList):
32
+ # Read block
33
+ blockGdf = gpd.read_file(block)
34
+ # Remove data without geometry
35
+ blockGdf = blockGdf[blockGdf['geometry'].notnull()]
36
+ # Assign id (serial number) to each feature in block
37
+ blockGdf['id'] = range(1, len(blockGdf) + 1)
38
+ # Get blockName
39
+ blockName = blockGdf['id'].values
40
+ # Get wkt
41
+ ref_wkt = [g.wkt for g in blockGdf['geometry'].values]
42
+ print('Processing block: {}'.format(blockNameList[i]))
43
+
44
+ # If output folder does not exist, create it
45
+ if not os.path.exists(output_folder):
46
+ os.makedirs(output_folder)
47
+
48
+ try:
49
+ with open(f'{output_folder}/{blockNameList[i]}.pol', 'w') as f:
50
+ for j, wkt in enumerate(ref_wkt):
51
+ points = [
52
+ point.split() for point in wkt.replace("POLYGON ((", "").replace(
53
+ "))", "").split(',')
54
+ ]
55
+ # Write to *.pol
56
+ # Write blockName
57
+ f.write('{}\n'.format(blockName[j]))
58
+ f.write('{} {}\n'.format(len(points), 2))
59
+
60
+ for point in points:
61
+ # convert string to float and format
62
+ f.write(
63
+ f'{float(point[0]):.3f} {float(point[1]):.3f}\n')
64
+ except:
65
+ print('Error in block: {}'.format(blockNameList[i]))
66
+
67
+ return len(blockList)
68
+
69
+
70
+ def main():
71
+ """
72
+ Command line entry point
73
+ """
74
+ convert()
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
@@ -0,0 +1,89 @@
1
+ """
2
+ Convert bankline shapefile to PLIZ file
3
+ """
4
+ import os
5
+ import glob
6
+ import geopandas as gpd
7
+
8
+
9
+ def convert(input_folder='SHP_DIKE',
10
+ output_folder='PLIZ_DIKE',
11
+ output_filename='Dike'):
12
+ """
13
+ Convert shapefile to DIKE PLIZ file
14
+
15
+ Parameters:
16
+ -----------
17
+ input_folder : str
18
+ Path to the folder containing dike shapefiles with MultiLineStringZ geometry (default: 'SHP_DIKE')
19
+ output_folder : str
20
+ Output folder path (default: 'PLIZ_DIKE')
21
+ output_filename : str
22
+ Name of the output file without extension (default: 'Dike')
23
+
24
+ Returns:
25
+ --------
26
+ str
27
+ Path to the created PLIZ file
28
+ """
29
+ # Specify file source
30
+ fileList = glob.glob(f'{input_folder}/*.shp')
31
+ print(f"Found {len(fileList)} files: {fileList}")
32
+
33
+ # Read files
34
+ gdfs = []
35
+ for i, item in enumerate(fileList):
36
+ gdf = gpd.read_file(item)
37
+ gdfs.append(gdf)
38
+
39
+ # Read wkt
40
+ ref_wkts = []
41
+ for i, gdf in enumerate(gdfs):
42
+ ref_wkt = [g.wkt for g in gdf['geometry'].values]
43
+ ref_wkts.append(ref_wkt)
44
+
45
+ # Get dike name
46
+ dikeNames = []
47
+ for i, gdf in enumerate(gdfs):
48
+ try:
49
+ dikeName = [name for name in gdf['Id'].values]
50
+ except:
51
+ dikeName = [name for name in gdf['id'].values]
52
+ dikeNames.append(dikeName)
53
+
54
+ # Create output folder if not exist
55
+ if not os.path.exists(output_folder):
56
+ os.makedirs(output_folder)
57
+
58
+ # Write to .pliz
59
+ output_path = os.path.join(output_folder, f"{output_filename}.pliz")
60
+ with open(output_path, 'w', encoding='utf-8') as f:
61
+ for k in range(len(gdfs)):
62
+ for i, item in enumerate(ref_wkts[k]):
63
+ f.write('{}\n'.format(dikeNames[k][i]))
64
+ # Remove heading "LINESTRING Z (" and trailing ")" characters using replace
65
+ points = [
66
+ point.split() for point in item.replace(
67
+ "LINESTRING Z (", "").replace(")", "").split(',')
68
+ ]
69
+ f.write('{} {}\n'.format(len(points), 5))
70
+ for j, jtem in enumerate(points):
71
+ f.write('{:.6f} {:.6f} {} {} {}\n'.format(float(jtem[0]),
72
+ float(jtem[1]),
73
+ float(jtem[2]),
74
+ float(jtem[2]),
75
+ float(jtem[2])))
76
+ f.write('\n')
77
+ print(f'Done! PLIZ file created at: {output_path}')
78
+ return output_path
79
+
80
+
81
+ def main():
82
+ """
83
+ Command line entry point
84
+ """
85
+ convert()
86
+
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Chih-Hung Hsu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.2
2
+ Name: d3dtools
3
+ Version: 0.1.0
4
+ Summary: A collection of tools for working with shapefiles and converting them for Delft3D modeling
5
+ Home-page: https://github.com/AaronOET/d3dtools
6
+ Author: aaronchh
7
+ Author-email: aaronhsu219@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: numpy>=1.20.0
15
+ Requires-Dist: pandas>=1.3.0
16
+ Requires-Dist: geopandas>=0.10.0
17
+ Requires-Dist: rasterio>=1.2.0
18
+ Requires-Dist: netCDF4>=1.5.0
19
+ Requires-Dist: pyproj>=3.0.0
20
+ Requires-Dist: shapely>=1.8.0
21
+ Requires-Dist: matplotlib>=3.4.0
22
+ Dynamic: author
23
+ Dynamic: author-email
24
+ Dynamic: classifier
25
+ Dynamic: description
26
+ Dynamic: description-content-type
27
+ Dynamic: home-page
28
+ Dynamic: requires-dist
29
+ Dynamic: requires-python
30
+ Dynamic: summary
31
+
32
+ # D3DTOOLS
33
+
34
+ A collection of Python tools for working with shapefiles and converting them for Delft3D modeling.
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ pip install d3dtools
40
+ ```
41
+
42
+ ## Features
43
+
44
+ This package provides several utilities for converting shapefiles to various formats used in Delft3D modeling:
45
+
46
+ - **ncrain**: Generate a NetCDF file from rainfall data and thiessen polygon shapefiles
47
+ - **shpbc2pli**: Convert boundary line shapefiles to PLI files
48
+ - **shpblock2pol**: Convert shapefile blocks to POL files
49
+ - **shpdike2pliz**: Convert bankline shapefiles to PLIZ files
50
+
51
+ ## Usage Examples
52
+
53
+ ### Generate NetCDF from rainfall data
54
+
55
+ ```python
56
+ from d3dtools import ncrain
57
+
58
+ # Default usage
59
+ output_path = ncrain.generate()
60
+ print(f"NetCDF file generated at: {output_path}")
61
+
62
+ # With custom parameters
63
+ output_path = ncrain.generate(
64
+ input_shp_folder='custom/SHP',
65
+ input_tab_folder='custom/TAB',
66
+ output_nc_folder='custom/NC',
67
+ intermediate_ras_folder='custom/RAS_RAIN',
68
+ intermediate_shp_folder='custom/SHP_RAIN',
69
+ clean_intermediate=True,
70
+ raster_resolution=360
71
+ )
72
+ ```
73
+
74
+ ### Convert boundary shapefiles to PLI
75
+
76
+ ```python
77
+ from d3dtools import shpbc2pli
78
+
79
+ # Default usage
80
+ shpbc2pli.convert()
81
+
82
+ # With custom parameters
83
+ shpbc2pli.convert(
84
+ input_folder='custom/SHP_BC',
85
+ output_folder='custom/PLI_BC'
86
+ )
87
+ ```
88
+
89
+ ### Convert block shapefiles to POL
90
+
91
+ ```python
92
+ from d3dtools import shpblock2pol
93
+
94
+ # Default usage
95
+ shpblock2pol.convert()
96
+
97
+ # With custom parameters
98
+ shpblock2pol.convert(
99
+ input_folder='custom/SHP_BLOCK',
100
+ output_folder='custom/POL_BLOCK'
101
+ )
102
+ ```
103
+
104
+ ### Convert dike shapefiles to PLIZ
105
+
106
+ ```python
107
+ from d3dtools import shpdike2pliz
108
+
109
+ # Default usage
110
+ shpdike2pliz.convert()
111
+
112
+ # With custom parameters
113
+ shpdike2pliz.convert(
114
+ input_folder='custom/SHP_DIKE',
115
+ output_folder='custom/PLIZ_DIKE',
116
+ output_filename='CustomDike'
117
+ )
118
+ ```
119
+
120
+ ## Command-line Usage
121
+
122
+ The package also provides command-line utilities:
123
+
124
+ ```bash
125
+ # Generate NetCDF from rainfall data
126
+ ncrain
127
+
128
+ # Convert boundary shapefiles to PLI
129
+ shpbc2pli
130
+
131
+ # Convert block shapefiles to POL
132
+ shpblock2pol
133
+
134
+ # Convert dike shapefiles to PLIZ
135
+ shpdike2pliz
136
+ ```
137
+
138
+ ## Requirements
139
+
140
+ - numpy>=1.20.0
141
+ - pandas>=1.3.0
142
+ - geopandas>=0.10.0
143
+ - rasterio>=1.2.0
144
+ - netCDF4>=1.5.0
145
+ - pyproj>=3.0.0
146
+ - shapely>=1.8.0
147
+ - matplotlib>=3.4.0
148
+
149
+ ## License
150
+
151
+ MIT
@@ -0,0 +1,11 @@
1
+ d3dtools/__init__.py,sha256=FHIt7wSDhSLqCW2XyjAU6ovedC-3jKGjrMNzbsmT134,242
2
+ d3dtools/ncrain.py,sha256=NASYyddLn9T2YrrKvRZSBWLvgZ1LWK1TBGTUgtiexyE,10251
3
+ d3dtools/shpbc2pli.py,sha256=xMzv3fAGEsx16UmJvuf4-zW8Iz1ovci8jUkFqD87NSM,2546
4
+ d3dtools/shpblock2pol.py,sha256=qMVRdMJSX2F32mkBJlXAEbhn1ENDRzimt-JFfNJWHXk,2530
5
+ d3dtools/shpdike2pliz.py,sha256=d7bQncHdqOhXZ0mOQ2zlgyP1HDn9v7apzgRJFV4gVck,2878
6
+ d3dtools-0.1.0.dist-info/LICENSE,sha256=Y4E4BtkoFh6GfTSIMn7HvnEJfg5ITZldXCIjESEOaTE,1089
7
+ d3dtools-0.1.0.dist-info/METADATA,sha256=-TGMaeU7qh9v_wIv_DZl1rITQr_RdOj6qY7R71LTZK4,3370
8
+ d3dtools-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
9
+ d3dtools-0.1.0.dist-info/entry_points.txt,sha256=XmpphWSk1AUh7ISlOACKT_u94ZLeVu3eeK1OJZqdsEE,181
10
+ d3dtools-0.1.0.dist-info/top_level.txt,sha256=1FjGJxUu_zw__xOPcdP599x1LtGJDY22zLTjfuzSc7c,9
11
+ d3dtools-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.8.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,5 @@
1
+ [console_scripts]
2
+ ncrain = d3dtools.ncrain:generate
3
+ shpbc2pli = d3dtools.shpbc2pli:convert
4
+ shpblock2pol = d3dtools.shpblock2pol:convert
5
+ shpdike2pliz = d3dtools.shpdike2pliz:convert
@@ -0,0 +1 @@
1
+ d3dtools