bluemesh2d 0.1.1.dev0__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 (74) hide show
  1. bluemesh2d/_version.py +24 -0
  2. bluemesh2d/aabb_tree/findball.py +121 -0
  3. bluemesh2d/aabb_tree/findtria.py +299 -0
  4. bluemesh2d/aabb_tree/maketree.py +147 -0
  5. bluemesh2d/aabb_tree/mapvert.py +72 -0
  6. bluemesh2d/aabb_tree/queryset.py +83 -0
  7. bluemesh2d/aabb_tree/scantree.py +124 -0
  8. bluemesh2d/dependencies.py +83 -0
  9. bluemesh2d/feedback.py +142 -0
  10. bluemesh2d/geom_util/boundary_util.py +216 -0
  11. bluemesh2d/geom_util/getiso.py +194 -0
  12. bluemesh2d/geom_util/poly_util.py +795 -0
  13. bluemesh2d/geom_util/proj_util.py +250 -0
  14. bluemesh2d/geomesh_util/border_util.py +283 -0
  15. bluemesh2d/geomesh_util/depth_field.py +333 -0
  16. bluemesh2d/geomesh_util/grd_util.py +1000 -0
  17. bluemesh2d/geomesh_util/interpolation_mesh.py +318 -0
  18. bluemesh2d/geomesh_util/merge_circumcenters.py +268 -0
  19. bluemesh2d/geomesh_util/water_polygon.py +406 -0
  20. bluemesh2d/hfun_util/build_hfun.py +589 -0
  21. bluemesh2d/hfun_util/hfun_dispersion.py +96 -0
  22. bluemesh2d/hfun_util/lfshfn.py +110 -0
  23. bluemesh2d/hfun_util/limhfn.py +65 -0
  24. bluemesh2d/hfun_util/make_constant_hfun.py +32 -0
  25. bluemesh2d/hfun_util/make_depth_hfun.py +51 -0
  26. bluemesh2d/hfun_util/smooth_and_precomput.py +188 -0
  27. bluemesh2d/hfun_util/trihfn.py +84 -0
  28. bluemesh2d/hjac_util/limgrad.py +105 -0
  29. bluemesh2d/mesh_ball/cdtbal1.py +38 -0
  30. bluemesh2d/mesh_ball/cdtbal2.py +104 -0
  31. bluemesh2d/mesh_ball/inv_2x2.py +61 -0
  32. bluemesh2d/mesh_ball/inv_3x3.py +72 -0
  33. bluemesh2d/mesh_ball/pwrbal2.py +134 -0
  34. bluemesh2d/mesh_ball/tribal2.py +27 -0
  35. bluemesh2d/mesh_cost/relhfn.py +62 -0
  36. bluemesh2d/mesh_cost/triang.py +59 -0
  37. bluemesh2d/mesh_cost/triarea.py +51 -0
  38. bluemesh2d/mesh_cost/trideg.py +44 -0
  39. bluemesh2d/mesh_cost/triscr.py +43 -0
  40. bluemesh2d/mesh_file/bnd_util.py +664 -0
  41. bluemesh2d/mesh_file/loadmsh.py +165 -0
  42. bluemesh2d/mesh_file/ugrid.py +308 -0
  43. bluemesh2d/mesh_util/cfmtri.py +118 -0
  44. bluemesh2d/mesh_util/deltri.py +131 -0
  45. bluemesh2d/mesh_util/idxtri.py +53 -0
  46. bluemesh2d/mesh_util/isfeat.py +90 -0
  47. bluemesh2d/mesh_util/minlen.py +46 -0
  48. bluemesh2d/mesh_util/setset.py +49 -0
  49. bluemesh2d/mesh_util/tricon.py +90 -0
  50. bluemesh2d/mesh_util/tridiv.py +187 -0
  51. bluemesh2d/meshgen.py +202 -0
  52. bluemesh2d/ortho_merge/constants.py +27 -0
  53. bluemesh2d/ortho_merge/geometry.py +64 -0
  54. bluemesh2d/ortho_merge/ortho_merge_iter.py +812 -0
  55. bluemesh2d/ortho_merge/orthogonalize.py +2989 -0
  56. bluemesh2d/pipeline.py +277 -0
  57. bluemesh2d/poly_data/airfoil.msh +958 -0
  58. bluemesh2d/poly_data/channel.msh +212 -0
  59. bluemesh2d/poly_data/islands.msh +13819 -0
  60. bluemesh2d/poly_data/lake.msh +612 -0
  61. bluemesh2d/poly_data/river.msh +690 -0
  62. bluemesh2d/poly_test/inpoly.py +105 -0
  63. bluemesh2d/poly_test/inpoly_mat.py +104 -0
  64. bluemesh2d/refine.py +972 -0
  65. bluemesh2d/smood.py +623 -0
  66. bluemesh2d/smooth.py +522 -0
  67. bluemesh2d/tricost.py +426 -0
  68. bluemesh2d/tridemo.py +723 -0
  69. bluemesh2d/triread.py +53 -0
  70. bluemesh2d-0.1.1.dev0.dist-info/METADATA +139 -0
  71. bluemesh2d-0.1.1.dev0.dist-info/RECORD +74 -0
  72. bluemesh2d-0.1.1.dev0.dist-info/WHEEL +5 -0
  73. bluemesh2d-0.1.1.dev0.dist-info/licenses/LICENSE +674 -0
  74. bluemesh2d-0.1.1.dev0.dist-info/top_level.txt +1 -0
bluemesh2d/pipeline.py ADDED
@@ -0,0 +1,277 @@
1
+ """Staged meshing pipeline: single import point for the Python interface.
2
+
3
+ Re-exports every stage of the raster -> coastline -> size function ->
4
+ boundary -> refine/smooth -> UGRID NetCDF workflow from its home module,
5
+ plus the all-in-one facade (:class:`MeshConfig` -> :func:`generate_mesh`
6
+ -> :class:`MeshResult`) defined here.
7
+
8
+ Stage homes
9
+ -----------
10
+ 1. ``bluemesh2d.geomesh_util.water_polygon`` -- extract_water_polygon
11
+ 2. ``bluemesh2d.hfun_util.build_hfun`` -- build_hfun_raster & co.
12
+ 3. ``bluemesh2d.geom_util.boundary_util`` -- resample_boundary, PSLG
13
+ 4. ``bluemesh2d.meshgen`` -- mesh_pslg
14
+ 5. ``bluemesh2d.mesh_file.ugrid`` -- export_ugrid, read_ugrid_mesh
15
+ 6. ``bluemesh2d.mesh_file.bnd_util`` -- boundary conditions, .grd/.pli
16
+ Support: ``bluemesh2d.feedback`` (progress/cancel), ``bluemesh2d.dependencies``.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ # pyproj must load before any pip rasterio wheel loads its own libproj
21
+ # (mixing the order breaks pyproj: "TypeError: expected bytes, str found").
22
+ try:
23
+ import pyproj # noqa: F401
24
+ # pyproj loads libproj lazily at the first CRS creation; force it now,
25
+ # before any rasterio wheel loads its own copy
26
+ pyproj.CRS.from_epsg(4326)
27
+ except Exception:
28
+ pass
29
+
30
+ from dataclasses import dataclass
31
+
32
+ from .dependencies import ( # noqa: F401
33
+ check_dependencies,
34
+ optional_dependencies,
35
+ smood_dependencies,
36
+ )
37
+ from .feedback import ( # noqa: F401
38
+ MeshCanceled,
39
+ _LogWriter,
40
+ _NullFeedback,
41
+ _SubProgress,
42
+ _available_ram_bytes,
43
+ _check,
44
+ _warn_if_ram_risk,
45
+ )
46
+ from .geom_util.boundary_util import ( # noqa: F401
47
+ _fixed_part_from_z,
48
+ pslg_from_segments,
49
+ resample_boundary,
50
+ )
51
+ from .geom_util.proj_util import _raster_crs # noqa: F401
52
+ from .geomesh_util.water_polygon import ( # noqa: F401
53
+ _corner_vertices,
54
+ _flag_fixed_vertices,
55
+ _prune_nonoriginal_fixed,
56
+ _valid_parts,
57
+ extract_water_polygon,
58
+ )
59
+ from .hfun_util.build_hfun import ( # noqa: F401
60
+ _compile_custom_hfun,
61
+ _make_depth_hfun,
62
+ build_hfun_constant_raster,
63
+ build_hfun_raster,
64
+ load_hfun_raster,
65
+ )
66
+ from .mesh_file.bnd_util import ( # noqa: F401
67
+ _boundary_loops,
68
+ boundary_lines_from_points,
69
+ classify_boundary_lines,
70
+ classify_boundary_points,
71
+ export_boundary_conditions,
72
+ export_grd,
73
+ export_grd_from_lines,
74
+ generate_boundary_condition_points,
75
+ generate_boundary_conditions,
76
+ write_open_boundary_files,
77
+ write_open_boundary_pli,
78
+ )
79
+ from .mesh_file.ugrid import ( # noqa: F401
80
+ _UGRID_FILL,
81
+ _WGS84_FILL,
82
+ _write_ugrid_netcdf,
83
+ apply_nc_metadata,
84
+ export_ugrid,
85
+ read_ugrid_mesh,
86
+ )
87
+ from .meshgen import ( # noqa: F401
88
+ _locate_fixed,
89
+ _warn_if_mesh_too_big,
90
+ mesh_pslg,
91
+ )
92
+
93
+
94
+ @dataclass
95
+ class MeshConfig:
96
+ """All tunable parameters of the full meshing pipeline (all-in-one run).
97
+
98
+ Attributes
99
+ ----------
100
+ raster_path : str
101
+ Path to the bathymetry raster (elevation, positive up).
102
+ output_path : str
103
+ Output UGRID NetCDF path.
104
+ coast_zmax : float
105
+ Wet threshold (m), see :func:`extract_water_polygon`. Default 2.0.
106
+ domain_buffer : float
107
+ Domain buffer factor, see :func:`extract_water_polygon`.
108
+ Default -0.05.
109
+ keep_largest : bool
110
+ Keep only the largest water polygon. Default ``True``.
111
+ detail_geom : shapely.geometry.base.BaseGeometry or None
112
+ Detail-region polygon in the raster CRS. Default ``None``.
113
+ detail_hmin : float
114
+ Element-size floor (m) inside `detail_geom`. Default 30.0.
115
+ a, b : float
116
+ Depth-polynomial sizing coefficients, see
117
+ :func:`_make_depth_hfun`. Defaults 0.14 and 28.0.
118
+ hmin, hmax : float
119
+ Element-size floor and cap (m). Defaults 100.0 and 10000.0.
120
+ max_gradient : float
121
+ Maximum allowed size gradient (m/m). Default 0.1.
122
+ min_angle_deg : float
123
+ Minimum boundary angle (deg), see :func:`resample_boundary`.
124
+ Default 25.0.
125
+ min_hole_vertices : int
126
+ Minimum hole vertex count, see :func:`resample_boundary`. Default 15.
127
+ kind : {'delaunay', 'delfront'}
128
+ Refinement scheme. Default ``'delaunay'``.
129
+ do_smooth : bool
130
+ Run mesh smoothing after refinement. Default ``True``.
131
+ do_smood : bool
132
+ Run smood orthogonalization after smoothing. Default ``False``.
133
+ smood_merge_small_links : bool
134
+ Enable small-link merging inside smood, see :func:`mesh_pslg`.
135
+ Default ``False``.
136
+ interp_order : int
137
+ Bathymetry sampling order (0=nearest, 1=bilinear, 3=bicubic).
138
+ Default 3.
139
+ """
140
+
141
+ raster_path: str
142
+ output_path: str
143
+
144
+ coast_zmax: float = 2.0
145
+ domain_buffer: float = -0.05
146
+ keep_largest: bool = True
147
+
148
+ detail_geom: object = None # shapely polygon in the raster CRS
149
+ detail_hmin: float = 30.0
150
+
151
+ a: float = 0.14
152
+ b: float = 28.0
153
+ hmin: float = 100.0
154
+ hmax: float = 10000.0
155
+ max_gradient: float = 0.1
156
+
157
+ min_angle_deg: float = 25.0
158
+ min_hole_vertices: int = 15
159
+
160
+ kind: str = "delaunay" # refine: 'delaunay' | 'delfront'
161
+ do_smooth: bool = True
162
+ do_smood: bool = False
163
+ smood_merge_small_links: bool = False
164
+
165
+ interp_order: int = 3 # bathy sampling: 0=nearest,1=bilinear,3=bicubic
166
+
167
+
168
+ @dataclass
169
+ class MeshResult:
170
+ """Result of a :func:`generate_mesh` run.
171
+
172
+ Attributes
173
+ ----------
174
+ output_path : str
175
+ Path to the written UGRID NetCDF.
176
+ n_nodes : int
177
+ Number of mesh nodes.
178
+ n_triangles : int
179
+ Number of mesh triangles.
180
+ utm_crs : str
181
+ String representation of the working CRS used.
182
+ """
183
+
184
+ output_path: str
185
+ n_nodes: int
186
+ n_triangles: int
187
+ utm_crs: str
188
+
189
+
190
+ def generate_mesh(config: MeshConfig, feedback=None) -> MeshResult:
191
+ """Run the full raster -> UGRID-NetCDF meshing pipeline headlessly.
192
+
193
+ Composes stages 1-4 (:func:`extract_water_polygon`, an in-memory
194
+ equivalent of :func:`build_hfun_raster`, :func:`resample_boundary`,
195
+ :func:`mesh_pslg`) and :func:`export_ugrid` in one call.
196
+
197
+ Parameters
198
+ ----------
199
+ config : MeshConfig
200
+ Pipeline parameters.
201
+ feedback : object or None, optional
202
+ Feedback sink, see :func:`extract_water_polygon`.
203
+
204
+ Returns
205
+ -------
206
+ result : MeshResult
207
+ Summary of the generated mesh.
208
+ """
209
+ feedback = feedback or _NullFeedback()
210
+
211
+ missing = check_dependencies()
212
+ if missing:
213
+ raise RuntimeError(
214
+ "Missing Python packages required by BlueMesh2D: "
215
+ + ", ".join(missing)
216
+ + ". Install them into this interpreter (see the plugin README).")
217
+ for mod in optional_dependencies():
218
+ feedback.pushInfo(
219
+ f"Optional package '{mod}' not installed - using the built-in "
220
+ "fallback (slower triangulation; install it for best performance).")
221
+
222
+ import pyproj
223
+ from bluemesh2d.geom_util.proj_util import reproject_geometry
224
+ from bluemesh2d.geomesh_util.depth_field import depth_field_from_tif
225
+ from bluemesh2d.hfun_util.smooth_and_precomput import smooth_precomput_hfun
226
+
227
+ feedback.setProgress(2)
228
+ poly, utm_crs, raster_crs = extract_water_polygon(
229
+ config.raster_path, coast_zmax=config.coast_zmax,
230
+ domain_buffer=config.domain_buffer,
231
+ keep_largest=config.keep_largest,
232
+ feedback=_SubProgress(feedback, 2, 25))
233
+ feedback.pushInfo(f"Working CRS: {utm_crs.to_string() if hasattr(utm_crs, 'to_string') else utm_crs}")
234
+
235
+ # In-memory hfun (no raster round-trip needed for the all-in-one run)
236
+ feedback.pushInfo("Building depth-based size function ...")
237
+ feedback.setProgress(25)
238
+ depth_field = depth_field_from_tif(config.raster_path, output_crs=utm_crs)
239
+ detail_u = None
240
+ if config.detail_geom is not None:
241
+ detail_u = reproject_geometry(config.detail_geom, raster_crs, utm_crs)
242
+ hfun = _make_depth_hfun(
243
+ depth_field, a=config.a, b=config.b,
244
+ hmin=config.hmin, hmax=config.hmax,
245
+ detail=detail_u,
246
+ detail_hmin=(config.detail_hmin if detail_u is not None else None))
247
+
248
+ feedback.pushInfo("Gradient-limiting the size function (this can take a moment) ...")
249
+ feedback.setProgress(35)
250
+ # limit the gradient-limiting grid to the water domain (poly is in utm_crs)
251
+ hfuns = smooth_precomput_hfun(hfun, domain=poly, max_gradient=config.max_gradient,
252
+ plot=False)
253
+ _check(feedback)
254
+
255
+ feedback.pushInfo("Resampling boundary to the size function ...")
256
+ feedback.setProgress(45)
257
+ poly_comput, node, edge = resample_boundary(
258
+ poly, hfuns, config.min_angle_deg, config.min_hole_vertices, feedback)
259
+
260
+ feedback.setProgress(55)
261
+ vert, tria = mesh_pslg(node, edge, hfuns, kind=config.kind,
262
+ do_smooth=config.do_smooth,
263
+ do_smood=config.do_smood,
264
+ smood_merge_small_links=config.smood_merge_small_links,
265
+ feedback=_SubProgress(feedback, 55, 88))
266
+
267
+ feedback.setProgress(88)
268
+ export_ugrid(vert, tria, config.raster_path, utm_crs,
269
+ config.output_path, config.interp_order, feedback=feedback)
270
+ feedback.setProgress(100)
271
+
272
+ return MeshResult(
273
+ output_path=config.output_path,
274
+ n_nodes=int(len(vert)),
275
+ n_triangles=int(len(tria)),
276
+ utm_crs=utm_crs.to_string() if hasattr(utm_crs, "to_string") else str(utm_crs),
277
+ )