h5gears 0.1.0__tar.gz
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.
- h5gears-0.1.0/LICENSE +21 -0
- h5gears-0.1.0/MANIFEST.in +3 -0
- h5gears-0.1.0/PKG-INFO +76 -0
- h5gears-0.1.0/README.md +58 -0
- h5gears-0.1.0/h5gears/__init__.py +15 -0
- h5gears-0.1.0/h5gears/cli.py +44 -0
- h5gears-0.1.0/h5gears/describe.py +53 -0
- h5gears-0.1.0/h5gears/h52nc.py +295 -0
- h5gears-0.1.0/h5gears.egg-info/PKG-INFO +76 -0
- h5gears-0.1.0/h5gears.egg-info/SOURCES.txt +15 -0
- h5gears-0.1.0/h5gears.egg-info/dependency_links.txt +1 -0
- h5gears-0.1.0/h5gears.egg-info/entry_points.txt +4 -0
- h5gears-0.1.0/h5gears.egg-info/requires.txt +3 -0
- h5gears-0.1.0/h5gears.egg-info/top_level.txt +1 -0
- h5gears-0.1.0/pyproject.toml +35 -0
- h5gears-0.1.0/requirements.txt +3 -0
- h5gears-0.1.0/setup.cfg +4 -0
h5gears-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Aaron 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.
|
h5gears-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: h5gears
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A collection of tools for converting HDF5 model files to other mesh/model formats
|
|
5
|
+
Author-email: aaronchh <aaronhsu219@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AaronOET/h5gears
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: numpy>=1.20.0
|
|
15
|
+
Requires-Dist: h5py>=3.0.0
|
|
16
|
+
Requires-Dist: netCDF4>=1.5.0
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# H5GEARS
|
|
20
|
+
|
|
21
|
+
A collection of Python tools for converting HDF5 model/mesh files to other mesh/model formats.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install h5gears
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or from source:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **h52nc**: Convert an SRH-2D mesh file (`.h5`) to a Delft3D FM (D-Flow FM) UGRID `net.nc` mesh file
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### Command-line
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# List all available commands
|
|
45
|
+
h5gears-info
|
|
46
|
+
|
|
47
|
+
# Convert every mesh in a single SRH-2D mesh file
|
|
48
|
+
h52nc -i mesh.h5
|
|
49
|
+
|
|
50
|
+
# Convert every mesh in all matching files (glob expansion supported)
|
|
51
|
+
h52nc -i *.h5
|
|
52
|
+
|
|
53
|
+
# Convert only a specific mesh by name
|
|
54
|
+
h52nc -i mesh.h5 -n Mesh001
|
|
55
|
+
|
|
56
|
+
# Write outputs to a specific directory, including node elevation (z)
|
|
57
|
+
h52nc -i mesh.h5 -o out/ -d 3
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Python API
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from h5gears import h52nc
|
|
64
|
+
|
|
65
|
+
# List the mesh names contained in an SRH-2D file
|
|
66
|
+
h52nc.list_meshes("mesh.h5")
|
|
67
|
+
|
|
68
|
+
# Convert every mesh in a file to net.nc, returning the output paths
|
|
69
|
+
h52nc.convert_file("mesh.h5", out_dir="out/", dim=2)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
|
|
74
|
+
- `h52nc` reads mesh geometry from the `2DMeshModule` group of SRH-2D HDF5 mesh files (node coordinates and element connectivity) and writes it out as a UGRID-style `net.nc` file compatible with Delft3D FM / D-Flow FM.
|
|
75
|
+
- By default, every mesh found in an input file is converted; use `-n`/`--name` to restrict conversion to specific mesh names.
|
|
76
|
+
- Output files are written alongside each input file by default; use `-o`/`--outdir` to choose a different destination directory.
|
h5gears-0.1.0/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# H5GEARS
|
|
2
|
+
|
|
3
|
+
A collection of Python tools for converting HDF5 model/mesh files to other mesh/model formats.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install h5gears
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or from source:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install -e .
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **h52nc**: Convert an SRH-2D mesh file (`.h5`) to a Delft3D FM (D-Flow FM) UGRID `net.nc` mesh file
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Command-line
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# List all available commands
|
|
27
|
+
h5gears-info
|
|
28
|
+
|
|
29
|
+
# Convert every mesh in a single SRH-2D mesh file
|
|
30
|
+
h52nc -i mesh.h5
|
|
31
|
+
|
|
32
|
+
# Convert every mesh in all matching files (glob expansion supported)
|
|
33
|
+
h52nc -i *.h5
|
|
34
|
+
|
|
35
|
+
# Convert only a specific mesh by name
|
|
36
|
+
h52nc -i mesh.h5 -n Mesh001
|
|
37
|
+
|
|
38
|
+
# Write outputs to a specific directory, including node elevation (z)
|
|
39
|
+
h52nc -i mesh.h5 -o out/ -d 3
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Python API
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from h5gears import h52nc
|
|
46
|
+
|
|
47
|
+
# List the mesh names contained in an SRH-2D file
|
|
48
|
+
h52nc.list_meshes("mesh.h5")
|
|
49
|
+
|
|
50
|
+
# Convert every mesh in a file to net.nc, returning the output paths
|
|
51
|
+
h52nc.convert_file("mesh.h5", out_dir="out/", dim=2)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
|
|
56
|
+
- `h52nc` reads mesh geometry from the `2DMeshModule` group of SRH-2D HDF5 mesh files (node coordinates and element connectivity) and writes it out as a UGRID-style `net.nc` file compatible with Delft3D FM / D-Flow FM.
|
|
57
|
+
- By default, every mesh found in an input file is converted; use `-n`/`--name` to restrict conversion to specific mesh names.
|
|
58
|
+
- Output files are written alongside each input file by default; use `-o`/`--outdir` to choose a different destination directory.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
H5GEARS - A collection of tools for converting HDF5 model files to other
|
|
3
|
+
mesh/model formats.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
__version__ = '0.1.0'
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'h52nc',
|
|
10
|
+
'describe',
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
from . import h52nc
|
|
14
|
+
from . import describe
|
|
15
|
+
from . import cli
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Top-level `h5gears` command. Running `h5gears -h` (or with no arguments)
|
|
4
|
+
prints the same information shown by `h5gears-info`. Running `h5gears -v`
|
|
5
|
+
prints the installed h5gears version.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
from . import __version__, describe
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _print_info(tool=None):
|
|
14
|
+
argv_backup = sys.argv
|
|
15
|
+
try:
|
|
16
|
+
sys.argv = ['h5gears-info'] + ([tool] if tool else [])
|
|
17
|
+
describe.main()
|
|
18
|
+
finally:
|
|
19
|
+
sys.argv = argv_backup
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def main():
|
|
23
|
+
args = sys.argv[1:]
|
|
24
|
+
|
|
25
|
+
if not args or args[0] in ('-h', '--help'):
|
|
26
|
+
_print_info()
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
if args[0] in ('-v', '--version'):
|
|
30
|
+
print(f"h5gears {__version__}")
|
|
31
|
+
return
|
|
32
|
+
|
|
33
|
+
tool = args[0]
|
|
34
|
+
if tool in describe.TOOL_DESCRIPTIONS:
|
|
35
|
+
_print_info(tool)
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
print(f"Unknown option or tool: {tool}", file=sys.stderr)
|
|
39
|
+
print("Run 'h5gears -h' to see available tools.", file=sys.stderr)
|
|
40
|
+
sys.exit(2)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
Command-line utility to display descriptions of h5gears functionality.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
from textwrap import dedent
|
|
8
|
+
|
|
9
|
+
TOOL_DESCRIPTIONS = {
|
|
10
|
+
'h52nc': """
|
|
11
|
+
Convert SRH-2D HDF5 mesh files (*.h5) to Delft3D FM (D-Flow FM)
|
|
12
|
+
UGRID net.nc files.
|
|
13
|
+
|
|
14
|
+
This tool reads the node coordinates and element connectivity of
|
|
15
|
+
every mesh in a SRH-2D '2DMeshModule' HDF5 file (read-only, no
|
|
16
|
+
modification) and writes one UGRID net.nc file per mesh.
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
h52nc -i mesh.h5 # Convert every mesh in mesh.h5
|
|
20
|
+
h52nc -i *.h5 # Convert every mesh in all matches
|
|
21
|
+
h52nc -i mesh.h5 -n Mesh001 # Convert only mesh 'Mesh001'
|
|
22
|
+
h52nc -i mesh.h5 -o out/ -d 3 # Write to out/, include elevation
|
|
23
|
+
""",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def main():
|
|
28
|
+
parser = argparse.ArgumentParser(
|
|
29
|
+
prog='h5gears-info',
|
|
30
|
+
description='Display descriptions of h5gears commands',
|
|
31
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
32
|
+
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
'tool',
|
|
35
|
+
nargs='?',
|
|
36
|
+
choices=list(TOOL_DESCRIPTIONS.keys()),
|
|
37
|
+
help='Tool name to describe (omit to list all tools)',
|
|
38
|
+
)
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
|
|
41
|
+
if args.tool:
|
|
42
|
+
print(f"\n--- {args.tool} ---")
|
|
43
|
+
print(dedent(TOOL_DESCRIPTIONS[args.tool]))
|
|
44
|
+
else:
|
|
45
|
+
print("\nH5GEARS — HDF5 mesh conversion commands\n")
|
|
46
|
+
for tool, desc in TOOL_DESCRIPTIONS.items():
|
|
47
|
+
first_line = dedent(desc).strip().splitlines()[0]
|
|
48
|
+
print(f" {tool:<14} {first_line}")
|
|
49
|
+
print("\nRun 'h5gears-info <tool>' for details on a specific command.")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
h52nc - Convert SRH-2D HDF5 mesh files (*.h5) to Delft3D FM (D-Flow FM)
|
|
4
|
+
UGRID net.nc files.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import glob
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
import h5py
|
|
13
|
+
import numpy as np
|
|
14
|
+
import netCDF4 as nc
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def list_meshes(h5_path):
|
|
18
|
+
"""
|
|
19
|
+
List the mesh names contained in an SRH-2D .h5 mesh file.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
h5_path (str): Path to the SRH-2D mesh file
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
list[str]: Names of the meshes found under '2DMeshModule'
|
|
26
|
+
"""
|
|
27
|
+
with h5py.File(h5_path, 'r') as f:
|
|
28
|
+
if '2DMeshModule' not in f:
|
|
29
|
+
return []
|
|
30
|
+
return list(f['2DMeshModule'].keys())
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def read_mesh(h5_path, mesh_name):
|
|
34
|
+
"""
|
|
35
|
+
Read node coordinates and element connectivity for one mesh.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
h5_path (str): Path to the SRH-2D mesh file
|
|
39
|
+
mesh_name (str): Mesh name within the file (e.g. 'Mesh001')
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
tuple: (x, y, z, links)
|
|
43
|
+
x, y, z (np.ndarray): 1-D node coordinate arrays, one entry per
|
|
44
|
+
node, ordered to match the file's 1-indexed node ids.
|
|
45
|
+
links (np.ndarray): (n_links, 2) array of unique, 1-indexed
|
|
46
|
+
node-id pairs describing each element boundary edge.
|
|
47
|
+
"""
|
|
48
|
+
with h5py.File(h5_path, 'r') as f:
|
|
49
|
+
mesh = f['2DMeshModule'][mesh_name]
|
|
50
|
+
node_locs = mesh['Nodes']['NodeLocs'][:]
|
|
51
|
+
node_ids = mesh['Elements']['Nodeids'][:]
|
|
52
|
+
|
|
53
|
+
x = node_locs[:, 0]
|
|
54
|
+
y = node_locs[:, 1]
|
|
55
|
+
z = node_locs[:, 2] if node_locs.shape[1] > 2 else np.zeros_like(x)
|
|
56
|
+
|
|
57
|
+
links = _extract_links(node_ids)
|
|
58
|
+
return x, y, z, links
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _extract_links(node_ids):
|
|
62
|
+
"""
|
|
63
|
+
Derive unique, undirected element-boundary links from an element/node-id
|
|
64
|
+
array.
|
|
65
|
+
|
|
66
|
+
Each row of `node_ids` lists the corner node ids of one element (SRH-2D
|
|
67
|
+
elements are triangles or quadrilaterals); unused corners in a mixed
|
|
68
|
+
tri/quad array are marked with -1. Node ids are 1-indexed, matching the
|
|
69
|
+
convention used by D-Flow FM's `NetLink` (start_index=1).
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
node_ids (np.ndarray): (n_elements, 3) or (n_elements, 4) array of
|
|
73
|
+
1-indexed node ids bounding each element
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
np.ndarray: (n_links, 2) array of unique 1-indexed node-id pairs
|
|
77
|
+
"""
|
|
78
|
+
links = []
|
|
79
|
+
for elem in node_ids:
|
|
80
|
+
corners = [int(node) for node in elem if node != -1]
|
|
81
|
+
n = len(corners)
|
|
82
|
+
for i in range(n):
|
|
83
|
+
links.append((corners[i], corners[(i + 1) % n]))
|
|
84
|
+
|
|
85
|
+
links = np.array(links, dtype=np.int32)
|
|
86
|
+
links_sorted = np.sort(links, axis=1)
|
|
87
|
+
return np.unique(links_sorted, axis=0)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def write_ugrid_net(x, y, links, out_path, z=None):
|
|
91
|
+
"""
|
|
92
|
+
Write a D-Flow FM UGRID net.nc file from node coordinates and links.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
x, y (np.ndarray): 1-D node coordinate arrays
|
|
96
|
+
links (np.ndarray): (n_links, 2) array of 1-indexed node-id pairs
|
|
97
|
+
out_path (str): Output .nc file path
|
|
98
|
+
z (np.ndarray, optional): 1-D node elevation array; included as
|
|
99
|
+
NetNode_z when provided
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
str: The output file path
|
|
103
|
+
"""
|
|
104
|
+
with nc.Dataset(out_path, 'w', format='NETCDF4') as ds:
|
|
105
|
+
ds.createDimension('nNetNode', len(x))
|
|
106
|
+
ds.createDimension('nNetLink', len(links))
|
|
107
|
+
ds.createDimension('nNetLinkPts', 2)
|
|
108
|
+
|
|
109
|
+
var_x = ds.createVariable('NetNode_x', 'f8', ('nNetNode',))
|
|
110
|
+
var_x.axis = 'X'
|
|
111
|
+
var_x.long_name = 'x-coordinate in Cartesian system'
|
|
112
|
+
var_x.units = 'metre'
|
|
113
|
+
var_x.standard_name = 'projection_x_coordinate'
|
|
114
|
+
var_x[:] = x
|
|
115
|
+
|
|
116
|
+
var_y = ds.createVariable('NetNode_y', 'f8', ('nNetNode',))
|
|
117
|
+
var_y.axis = 'Y'
|
|
118
|
+
var_y.long_name = 'y-coordinate in Cartesian system'
|
|
119
|
+
var_y.units = 'metre'
|
|
120
|
+
var_y.standard_name = 'projection_y_coordinate'
|
|
121
|
+
var_y[:] = y
|
|
122
|
+
|
|
123
|
+
if z is not None:
|
|
124
|
+
var_z = ds.createVariable('NetNode_z', 'f8', ('nNetNode',))
|
|
125
|
+
var_z.long_name = 'z-coordinate in Cartesian system'
|
|
126
|
+
var_z.units = 'metre'
|
|
127
|
+
var_z.standard_name = 'sea_floor_depth'
|
|
128
|
+
var_z[:] = z
|
|
129
|
+
|
|
130
|
+
var_link_type = ds.createVariable('NetLinkType', 'i4', ('nNetLink',))
|
|
131
|
+
var_link_type.long_name = 'type of netlink'
|
|
132
|
+
var_link_type[:] = 0
|
|
133
|
+
|
|
134
|
+
var_link = ds.createVariable('NetLink', 'i4', ('nNetLink', 'nNetLinkPts'))
|
|
135
|
+
var_link.long_name = 'link between two netnodes'
|
|
136
|
+
var_link.start_index = 1
|
|
137
|
+
var_link[:] = links
|
|
138
|
+
|
|
139
|
+
return out_path
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def convert_file(h5_path, mesh_names=None, out_dir=None, dim=2):
|
|
143
|
+
"""
|
|
144
|
+
Convert one SRH-2D .h5 mesh file to one net.nc file per mesh.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
h5_path (str): Path to the SRH-2D mesh file
|
|
148
|
+
mesh_names (list[str], optional): Restrict conversion to these mesh
|
|
149
|
+
names (default: convert every mesh found in the file)
|
|
150
|
+
out_dir (str, optional): Directory to write net.nc files to
|
|
151
|
+
(default: alongside the input file)
|
|
152
|
+
dim (int): 2 for x/y only, 3 to also write node elevation (z)
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
list[str]: Paths of the net.nc files written
|
|
156
|
+
"""
|
|
157
|
+
available = list_meshes(h5_path)
|
|
158
|
+
if not available:
|
|
159
|
+
raise ValueError(f"No '2DMeshModule' meshes found in {h5_path}")
|
|
160
|
+
|
|
161
|
+
if mesh_names:
|
|
162
|
+
missing = [m for m in mesh_names if m not in available]
|
|
163
|
+
if missing:
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"Mesh(es) {missing} not found in {h5_path}; "
|
|
166
|
+
f"available: {available}"
|
|
167
|
+
)
|
|
168
|
+
targets = mesh_names
|
|
169
|
+
else:
|
|
170
|
+
targets = available
|
|
171
|
+
|
|
172
|
+
base = os.path.splitext(os.path.basename(h5_path))[0]
|
|
173
|
+
out_dir = out_dir or os.path.dirname(os.path.abspath(h5_path))
|
|
174
|
+
|
|
175
|
+
outputs = []
|
|
176
|
+
for mesh_name in targets:
|
|
177
|
+
x, y, z, links = read_mesh(h5_path, mesh_name)
|
|
178
|
+
|
|
179
|
+
if len(available) > 1 or mesh_names:
|
|
180
|
+
out_name = f"{base}_{mesh_name}_net.nc"
|
|
181
|
+
else:
|
|
182
|
+
out_name = f"{base}_net.nc"
|
|
183
|
+
out_path = os.path.join(out_dir, out_name)
|
|
184
|
+
|
|
185
|
+
write_ugrid_net(x, y, links, out_path, z=z if dim == 3 else None)
|
|
186
|
+
outputs.append(out_path)
|
|
187
|
+
print(f" {mesh_name}: {len(x)} nodes, {len(links)} links -> {out_path}")
|
|
188
|
+
|
|
189
|
+
return outputs
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _expand_inputs(patterns):
|
|
193
|
+
"""Expand glob patterns / literal paths into a de-duplicated file list."""
|
|
194
|
+
files = []
|
|
195
|
+
for pattern in patterns:
|
|
196
|
+
matches = sorted(glob.glob(pattern))
|
|
197
|
+
if matches:
|
|
198
|
+
files.extend(matches)
|
|
199
|
+
elif os.path.exists(pattern):
|
|
200
|
+
files.append(pattern)
|
|
201
|
+
else:
|
|
202
|
+
print(f"Warning: no file matches '{pattern}'", file=sys.stderr)
|
|
203
|
+
|
|
204
|
+
seen = set()
|
|
205
|
+
unique = []
|
|
206
|
+
for f in files:
|
|
207
|
+
if f not in seen:
|
|
208
|
+
seen.add(f)
|
|
209
|
+
unique.append(f)
|
|
210
|
+
return unique
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def main():
|
|
214
|
+
parser = argparse.ArgumentParser(
|
|
215
|
+
prog='h52nc',
|
|
216
|
+
description=(
|
|
217
|
+
'Convert SRH-2D HDF5 mesh files (*.h5) to Delft3D FM '
|
|
218
|
+
'(D-Flow FM) UGRID net.nc files'
|
|
219
|
+
),
|
|
220
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
221
|
+
epilog="""
|
|
222
|
+
Examples:
|
|
223
|
+
h52nc -i mesh.h5 # Convert every mesh in mesh.h5
|
|
224
|
+
h52nc -i *.h5 # Convert every mesh in all matching files
|
|
225
|
+
h52nc -i mesh.h5 -n Mesh001 # Convert only mesh 'Mesh001'
|
|
226
|
+
h52nc -i mesh.h5 -o out/ -d 3 # Write to out/, include node elevation
|
|
227
|
+
"""
|
|
228
|
+
)
|
|
229
|
+
parser.add_argument(
|
|
230
|
+
'-i', '--input',
|
|
231
|
+
dest='inputs',
|
|
232
|
+
nargs='+',
|
|
233
|
+
required=True,
|
|
234
|
+
metavar='FILE',
|
|
235
|
+
help='One or more SRH-2D .h5 mesh files (glob patterns supported)',
|
|
236
|
+
)
|
|
237
|
+
parser.add_argument(
|
|
238
|
+
'-n', '--name',
|
|
239
|
+
dest='mesh_names',
|
|
240
|
+
nargs='+',
|
|
241
|
+
default=None,
|
|
242
|
+
metavar='MESH',
|
|
243
|
+
help='Restrict conversion to specific mesh name(s) '
|
|
244
|
+
'(default: convert every mesh found)',
|
|
245
|
+
)
|
|
246
|
+
parser.add_argument(
|
|
247
|
+
'-o', '--outdir',
|
|
248
|
+
dest='outdir',
|
|
249
|
+
default=None,
|
|
250
|
+
metavar='DIR',
|
|
251
|
+
help='Output directory for net.nc files '
|
|
252
|
+
'(default: alongside each input file)',
|
|
253
|
+
)
|
|
254
|
+
parser.add_argument(
|
|
255
|
+
'-d', '--dim',
|
|
256
|
+
dest='dim',
|
|
257
|
+
type=int,
|
|
258
|
+
choices=[2, 3],
|
|
259
|
+
default=2,
|
|
260
|
+
help='Mesh dimension: 2 (x, y only) or 3 (also write node '
|
|
261
|
+
'elevation z) (default: 2)',
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
args = parser.parse_args()
|
|
265
|
+
|
|
266
|
+
files = _expand_inputs(args.inputs)
|
|
267
|
+
if not files:
|
|
268
|
+
print("No input .h5 files found.", file=sys.stderr)
|
|
269
|
+
sys.exit(1)
|
|
270
|
+
|
|
271
|
+
if args.outdir:
|
|
272
|
+
os.makedirs(args.outdir, exist_ok=True)
|
|
273
|
+
|
|
274
|
+
print(f"h52nc: converting {len(files)} file(s)")
|
|
275
|
+
print("=" * 60)
|
|
276
|
+
|
|
277
|
+
exit_code = 0
|
|
278
|
+
for h5_path in files:
|
|
279
|
+
print(f"Processing: {h5_path}")
|
|
280
|
+
try:
|
|
281
|
+
convert_file(
|
|
282
|
+
h5_path,
|
|
283
|
+
mesh_names=args.mesh_names,
|
|
284
|
+
out_dir=args.outdir,
|
|
285
|
+
dim=args.dim,
|
|
286
|
+
)
|
|
287
|
+
except Exception as exc:
|
|
288
|
+
print(f" Error: {exc}", file=sys.stderr)
|
|
289
|
+
exit_code = 1
|
|
290
|
+
|
|
291
|
+
sys.exit(exit_code)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
if __name__ == "__main__":
|
|
295
|
+
main()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: h5gears
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A collection of tools for converting HDF5 model files to other mesh/model formats
|
|
5
|
+
Author-email: aaronchh <aaronhsu219@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AaronOET/h5gears
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: numpy>=1.20.0
|
|
15
|
+
Requires-Dist: h5py>=3.0.0
|
|
16
|
+
Requires-Dist: netCDF4>=1.5.0
|
|
17
|
+
Dynamic: license-file
|
|
18
|
+
|
|
19
|
+
# H5GEARS
|
|
20
|
+
|
|
21
|
+
A collection of Python tools for converting HDF5 model/mesh files to other mesh/model formats.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install h5gears
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or from source:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Features
|
|
36
|
+
|
|
37
|
+
- **h52nc**: Convert an SRH-2D mesh file (`.h5`) to a Delft3D FM (D-Flow FM) UGRID `net.nc` mesh file
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
### Command-line
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# List all available commands
|
|
45
|
+
h5gears-info
|
|
46
|
+
|
|
47
|
+
# Convert every mesh in a single SRH-2D mesh file
|
|
48
|
+
h52nc -i mesh.h5
|
|
49
|
+
|
|
50
|
+
# Convert every mesh in all matching files (glob expansion supported)
|
|
51
|
+
h52nc -i *.h5
|
|
52
|
+
|
|
53
|
+
# Convert only a specific mesh by name
|
|
54
|
+
h52nc -i mesh.h5 -n Mesh001
|
|
55
|
+
|
|
56
|
+
# Write outputs to a specific directory, including node elevation (z)
|
|
57
|
+
h52nc -i mesh.h5 -o out/ -d 3
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Python API
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from h5gears import h52nc
|
|
64
|
+
|
|
65
|
+
# List the mesh names contained in an SRH-2D file
|
|
66
|
+
h52nc.list_meshes("mesh.h5")
|
|
67
|
+
|
|
68
|
+
# Convert every mesh in a file to net.nc, returning the output paths
|
|
69
|
+
h52nc.convert_file("mesh.h5", out_dir="out/", dim=2)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Notes
|
|
73
|
+
|
|
74
|
+
- `h52nc` reads mesh geometry from the `2DMeshModule` group of SRH-2D HDF5 mesh files (node coordinates and element connectivity) and writes it out as a UGRID-style `net.nc` file compatible with Delft3D FM / D-Flow FM.
|
|
75
|
+
- By default, every mesh found in an input file is converted; use `-n`/`--name` to restrict conversion to specific mesh names.
|
|
76
|
+
- Output files are written alongside each input file by default; use `-o`/`--outdir` to choose a different destination directory.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
requirements.txt
|
|
6
|
+
h5gears/__init__.py
|
|
7
|
+
h5gears/cli.py
|
|
8
|
+
h5gears/describe.py
|
|
9
|
+
h5gears/h52nc.py
|
|
10
|
+
h5gears.egg-info/PKG-INFO
|
|
11
|
+
h5gears.egg-info/SOURCES.txt
|
|
12
|
+
h5gears.egg-info/dependency_links.txt
|
|
13
|
+
h5gears.egg-info/entry_points.txt
|
|
14
|
+
h5gears.egg-info/requires.txt
|
|
15
|
+
h5gears.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
h5gears
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "h5gears"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "aaronchh", email = "aaronhsu219@gmail.com" },
|
|
10
|
+
]
|
|
11
|
+
description = "A collection of tools for converting HDF5 model files to other mesh/model formats"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
dependencies = [
|
|
16
|
+
"numpy>=1.20.0",
|
|
17
|
+
"h5py>=3.0.0",
|
|
18
|
+
"netCDF4>=1.5.0",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/AaronOET/h5gears"
|
|
28
|
+
|
|
29
|
+
[tool.setuptools]
|
|
30
|
+
packages = ["h5gears"]
|
|
31
|
+
|
|
32
|
+
[project.scripts]
|
|
33
|
+
h5gears = "h5gears.cli:main"
|
|
34
|
+
h5gears-info = "h5gears.describe:main"
|
|
35
|
+
h52nc = "h5gears.h52nc:main"
|
h5gears-0.1.0/setup.cfg
ADDED