Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
745b238
added optional simplification and densification argument for lines, b…
oscarfasanchez Dec 8, 2025
decd562
added option for no densification of lines or custom densification if…
oscarfasanchez Dec 8, 2025
28d8324
added test and debugged the tests, fixed bug on line implementation
oscarfasanchez Dec 8, 2025
4a39c8e
Merge branch 'main' of https://github.com/oscarfasanchez/vorflow_os i…
oscarfasanchez Dec 8, 2025
145bd21
added fixes and recommendations to pull request of optional densify a…
oscarfasanchez Dec 9, 2025
a848493
adding second round of refinements from copilot, mainly grammar and s…
oscarfasanchez Dec 10, 2025
bb499e4
added some functions to use flexible fields
oscarfasanchez Dec 12, 2025
728765d
deleted the simplify default and standardized the densify keyword
oscarfasanchez Dec 14, 2025
c47ad11
added the frame in fields and blueprint mainly to set later the field…
oscarfasanchez Dec 14, 2025
61554ac
Merge branch 'optional_densify_simplify' into feat_flex_fields
oscarfasanchez Dec 14, 2025
16ef1db
added the not embedded features
oscarfasanchez Dec 14, 2025
750a65e
adding some framing for fields, added independent field distance, and…
oscarfasanchez Dec 16, 2025
2630007
set new engine to setup fields
oscarfasanchez Dec 17, 2025
8f40378
fixed bug sampling
oscarfasanchez Dec 17, 2025
a8e283b
got only field polygon out of the cleaning process
oscarfasanchez Dec 17, 2025
c293371
updated test with the new API
oscarfasanchez Dec 17, 2025
6b8bd75
added solution to handle many non embededd when retrieving the final …
oscarfasanchez Dec 17, 2025
87ca5b1
typo fix
oscarfasanchez Jan 9, 2026
137706e
simplifying examples to identify problems
oscarfasanchez Jan 12, 2026
2bde61b
convert one box to polyline to test behavior
oscarfasanchez Jan 12, 2026
b785330
added explicit embedding, which doesnt work yet
oscarfasanchez Jan 12, 2026
678edcc
solver silly bug with the conflict in field example
oscarfasanchez Feb 19, 2026
310c3e7
solved bug that caused after fragmentation embedding not to work
oscarfasanchez Feb 19, 2026
0de2797
asume surfaces are used for the field generation to solve bug about e…
oscarfasanchez Feb 20, 2026
6be208a
fixed how the gmsh gui is displayed for debugging
oscarfasanchez Feb 20, 2026
7711696
updating examples with the new field capabilities
oscarfasanchez Feb 20, 2026
c7d1b9d
hotfix for collapsed geometries
oscarfasanchez Feb 20, 2026
b66832f
Default snapping tolerance now can be changed to help topology proble…
oscarfasanchez Apr 16, 2026
0452179
added some cleaning helpers and some tests to be sure of the bookkeep…
oscarfasanchez Apr 17, 2026
5cebc4d
fix to embedded features and and fields, remove features outside doma…
oscarfasanchez Jun 2, 2026
220778a
make polygon fields constant inside field only polygons as well
oscarfasanchez Jun 5, 2026
ff5fcac
Bump version to 0.0.2
oscarfasanchez Jun 6, 2026
4a292a7
updated quality metrics
oscarfasanchez Jun 7, 2026
6844ea7
Improve quality metrics example
oscarfasanchez Jun 7, 2026
7666238
Document active-domain quality workflow
oscarfasanchez Jun 7, 2026
b6efe04
Add opt-in boundary inset mirror points
oscarfasanchez Jun 7, 2026
cba7d92
Add gmsh element grid exporter
oscarfasanchez Jun 7, 2026
541b40c
Add structured quad buffer workflow
oscarfasanchez Jun 7, 2026
dbba4f3
Checkpoint structured-buffer work; add z_order crossing-priority param
oscarfasanchez Jun 13, 2026
5fb4fcb
Resolve quad-buffer crossings by priority instead of mutual trimming
oscarfasanchez Jun 13, 2026
56802eb
Add tests for quad-buffer crossing priority and refinement
oscarfasanchez Jun 13, 2026
9087846
Update structured buffer example for crossing priority
oscarfasanchez Jun 13, 2026
58d1df5
Default feature size transitions to AutoExponentialField
oscarfasanchez Jun 13, 2026
ad915cb
Clean repo hygiene: untrack junk, remove empty modules, strip noteboo…
oscarfasanchez Jul 13, 2026
0c2d61f
Fix packaging metadata; make matplotlib optional
oscarfasanchez Jul 13, 2026
ed76c72
Remove dead placeholder code in post-fragment diagnostics
oscarfasanchez Jul 13, 2026
39595be
Clarify internal field classes; drop unused ThresholdField.create param
oscarfasanchez Jul 13, 2026
1aa6b9e
Update docs: install instructions, CRS guidance, license link, milest…
oscarfasanchez Jul 13, 2026
b31744e
Migrate all console output from print() to logging
oscarfasanchez Jul 13, 2026
e948e92
Make silently-swallowed exceptions observable via debug logging
oscarfasanchez Jul 13, 2026
0bf44ae
Emit real warnings when returning empty results instead of failing si…
oscarfasanchez Jul 13, 2026
db536e2
Warn on geographic CRS; default ConceptualMesh crs to None
oscarfasanchez Jul 13, 2026
fe3b6d7
Make straddle-point tangent probe proportional to line length
oscarfasanchez Jul 13, 2026
19f6ac7
Add 'from __future__ import annotations'; standardize on PEP 604 hints
oscarfasanchez Jul 13, 2026
880520c
Strengthen test suite: conftest, field-class tests, utils coverage, s…
oscarfasanchez Jul 13, 2026
0a49825
Add lint job and coverage to CI; fix all ruff findings
oscarfasanchez Jul 13, 2026
cb731d9
Replace quadratic geometry scans with KD-tree and prepared-geometry p…
oscarfasanchez Jul 13, 2026
13d3181
Extract dedup/heal tag-remapping stages out of _add_geometry
oscarfasanchez Jul 13, 2026
c8acfbf
Replace auto growth fields with explicit GeometricGrowthField, fixed …
oscarfasanchez Jul 19, 2026
ec0964d
docs: design TestPyPI release rehearsal
oscarfasanchez Jul 20, 2026
612eab8
docs: clarify release roadmap and account ownership
oscarfasanchez Jul 20, 2026
796d8fa
docs: plan TestPyPI release rehearsal
oscarfasanchez Jul 20, 2026
4e20914
docs: focus roadmap on TestPyPI release
oscarfasanchez Jul 21, 2026
23247e7
build: prepare 0.1.0rc1 metadata
oscarfasanchez Jul 21, 2026
3855945
docs: add release candidate usage and changelog
oscarfasanchez Jul 21, 2026
a0134bb
build: validate release archives
oscarfasanchez Jul 23, 2026
3996c42
ci: test minimum supported dependencies
oscarfasanchez Jul 23, 2026
aa84509
ci: add trusted TestPyPI publishing
oscarfasanchez Jul 23, 2026
31af58c
build: harden release validation after review
oscarfasanchez Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,31 @@ name: pytest

on:
push:
branches: ["feat_tests", "main", "master"]
branches: ["main", "master"]
pull_request:
schedule:
- cron: "0 0 * * 0"

jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install ruff
run: pip install ruff
- name: Ruff check
run: ruff check src tests

test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4
Expand All @@ -25,6 +37,39 @@ jobs:
create-args: >-
python=${{ matrix.python-version }}
cache-environment: true
- name: Run pytest
- name: Run pytest with coverage
shell: bash -l {0}
run: pytest
run: pytest --cov=vorflow --cov-report=term-missing

minimum-dependencies:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.10"
cache: pip
- name: Install Gmsh system library
run: sudo apt-get update && sudo apt-get install --yes libglu1-mesa
- name: Install minimum runtime dependencies
run: >-
python -m pip install
numpy==1.24.0
pandas==1.5.0
geopandas==0.13.0
shapely==2.0.0
scipy==1.10.0
gmsh==4.11.1
- name: Install vorflow development tools
run: python -m pip install --no-deps -e . && python -m pip install pytest pytest-cov tomli
- name: Verify installed dependency versions
run: >-
python -c "import geopandas, gmsh, numpy, pandas, scipy, shapely;
assert numpy.__version__ == '1.24.0';
assert pandas.__version__ == '1.5.0';
assert geopandas.__version__ == '0.13.0';
assert shapely.__version__ == '2.0.0';
assert scipy.__version__ == '1.10.0';
assert gmsh.__version__ == '4.11.1'"
- name: Run tests at dependency floors
run: pytest --cov=vorflow --cov-report=term-missing
66 changes: 66 additions & 0 deletions .github/workflows/testpypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: Publish release candidate to TestPyPI

on:
push:
tags:
- "v*rc*"

permissions:
contents: read

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.12"
cache: pip
- name: Install Gmsh system library
run: sudo apt-get update && sudo apt-get install --yes libglu1-mesa
- name: Install build and test tools
run: python -m pip install -e ".[dev]"
- name: Run Ruff
run: ruff check src tests scripts
- name: Run pytest
run: pytest --cov=vorflow --cov-report=term-missing
- name: Build wheel and source distribution
run: python -m build
- name: Check package metadata rendering
run: python -m twine check dist/*
- name: Validate tag, metadata, and archive contents
env:
RELEASE_TAG: ${{ github.ref_name }}
run: python scripts/check_dist.py dist --expected-tag "$RELEASE_TAG"
- name: Smoke-test the built wheel
run: |
python -m venv "$RUNNER_TEMP/vorflow-smoke"
"$RUNNER_TEMP/vorflow-smoke/bin/python" -m pip install dist/*.whl
"$RUNNER_TEMP/vorflow-smoke/bin/python" -m pip check
"$RUNNER_TEMP/vorflow-smoke/bin/python" -c "import vorflow; assert vorflow.__version__ == '0.1.0rc1'"
cd "$RUNNER_TEMP"
"$RUNNER_TEMP/vorflow-smoke/bin/python" "$GITHUB_WORKSPACE/examples/basic_usage.py"
- uses: actions/upload-artifact@v7
with:
name: python-package-distributions
path: dist/
if-no-files-found: error

publish-testpypi:
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/vorflow
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
name: python-package-distributions
path: dist/
- name: Publish package distributions to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,18 @@ __marimo__/
.DS_Store

# vscode
.code-workspace
*.code-workspace

#
.pyc
__pycache__

# Internal benchmarks / scratch experiments (not tracked)
benchmarks/

# Local conda environment in repo root
.conda/

# Superpowers visual brainstorming state
.superpowers/

26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Changelog

All notable changes to `vorflow` are documented in this file.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and the project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.1.0rc1]

### Added

- Voronoi and triangular/mixed-element grid generation for MODFLOW 6 workflows.
- Mesh-quality and connectivity diagnostics.
- Optional boundary inset/mirror points and structured quad buffers.
- Explicit mesh-size growth fields and runnable examples.
- Cross-platform tests and TestPyPI release automation.

### Changed

- Prepared project metadata, installation documentation, and dependency floors
for the first public release candidate.

[Unreleased]: https://github.com/oscarfasanchez/vorflow_os/compare/v0.1.0rc1...HEAD
[0.1.0rc1]: https://github.com/oscarfasanchez/vorflow_os/tree/v0.1.0rc1
6 changes: 6 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
prune .conda
prune benchmarks
prune docs
global-exclude *.code-workspace
global-exclude __pycache__
global-exclude *.py[cod]
101 changes: 84 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# vorflow

Voronoi mesh generation for MODFLOW 6 using Gmsh and Geopandas.
Voronoi mesh generation for MODFLOW 6 using Gmsh and GeoPandas.

`vorflow` is a Python package for creating 2D unstructured Voronoi cell meshes for groundwater modeling, particularly for MODFLOW 6. It leverages the power of `Gmsh` for robust triangular meshing and `Shapely`/`Geopandas` for geometric operations.
`vorflow` is a Python package for creating 2D unstructured Voronoi cell meshes for groundwater modeling, particularly for MODFLOW 6. It leverages the power of `Gmsh` for robust triangular meshing and `Shapely`/`GeoPandas` for geometric operations.

The process is designed to translate a conceptual model—defined by geometric features like polygons, lines, and points—into a high-quality Voronoi grid suitable for numerical simulation.

Expand All @@ -28,49 +28,116 @@ The typical workflow follows these steps:

## Installation

The package dependencies are listed in `pyproject.toml`. You can install them using pip:
Install the latest published release:

```bash
pip install numpy pandas geopandas shapely scipy gmsh matplotlib
pip install vorflow
```

To install `vorflow` itself, you can install it in editable mode from the root of the repository:
`vorflow` requires Python 3.10 or newer.

### Development installation

Clone the repository and install it in editable mode:

```bash
pip install -e .[dev]
```

For plotting examples and notebooks without all development tools:

```bash
pip install -e .
pip install -e .[examples]
```

Alternatively, create the Conda development environment from
[`etc/environment.yml`](https://github.com/oscarfasanchez/vorflow_os/blob/main/etc/environment.yml).

## Basic Usage

Here is a simple example of how to generate a grid:
Here is a simple example of how to generate a non-empty Voronoi grid:

The complete runnable version is
[examples/basic_usage.py](https://github.com/oscarfasanchez/vorflow_os/blob/main/examples/basic_usage.py).

```python
from shapely.geometry import LineString, Point, box

from vorflow import ConceptualMesh, MeshGenerator, VoronoiTessellator
from shapely.geometry import box, Point, LineString

# 1. Define conceptual model features
domain = box(0, 0, 200, 200)
well_point = Point(25, 25)
fault_line = LineString([(100, 0), (100, 150)])

# 2. Create a blueprint
blueprint = ConceptualMesh(crs="EPSG:3857")
blueprint.add_polygon(domain, zone_id=1)
blueprint.add_point(well_point, point_id="Well-A", resolution=2, dist_max=300)
blueprint.add_line(fault_line, line_id="Fault-1", resolution=1, is_barrier=True)
blueprint.add_point(
well_point,
point_id="Well-A",
resolution=2,
growth_factor=1.2,
)
blueprint.add_line(
fault_line,
line_id="Fault-1",
resolution=1,
is_barrier=True,
)

clean_polys, clean_lines, clean_pts = blueprint.generate()

# 3. Generate the triangular mesh
mesher = MeshGenerator(background_lc=100)
mesher.generate(clean_polys, clean_lines, clean_pts)

# 4. Convert to Voronoi grid
tessellator = VoronoiTessellator(mesher, blueprint, clip_to_boundary=True)
grid_gdf = tessellator.generate()
if grid_gdf.empty:
raise RuntimeError("Basic Usage generated an empty Voronoi grid")
```

### Optional file export

GeoPandas writes formats such as Shapefile and GeoPackage through an I/O engine
such as Pyogrio or Fiona. Install one of those engines before calling:

# 5. Save the output
grid_gdf.to_file("mf6_grid.shp")
```python
grid_gdf.to_file("mf6_grid.gpkg", driver="GPKG")
```

### Mesh gradation

print("Grid generation complete.")
Feature resolutions use `GeometricGrowthField` by default. Its
`growth_factor` is an upper target for neighboring characteristic edge-length
growth, not cell area growth and not an exact guarantee for every generated
neighbor pair. The default `growth_factor=1.2` uses the transparent spatial law

```text
h(d) = feature_lc + (growth_factor - 1) * d.
```

For the continuous-metric convention, pass an explicit
`GeometricGrowthField(growth_model="continuous_metric")`; this uses the gentler
gradient `log(growth_factor)`. In normal `MeshGenerator` use, the global
background field caps either result at `background_lc`.

> **Coordinate systems:** always work in a *projected* CRS (e.g. UTM or a
> national grid) so mesh sizes are in real length units (meters/feet).
> Geographic coordinates (lat/lon degrees, e.g. EPSG:4326) produce
> physically meaningless MODFLOW grids — reproject your data first with
> `GeoDataFrame.to_crs()`.

## Examples

The [examples/](https://github.com/oscarfasanchez/vorflow_os/tree/main/examples)
folder contains runnable scripts and notebooks
covering field-based refinement, mesh quality diagnostics, structured quad
buffers, active-domain workflows, and triangular element-grid export.

## Roadmap

See [ROADMAP.md](https://github.com/oscarfasanchez/vorflow_os/blob/main/ROADMAP.md)
for planned and completed milestones.

## License

MIT — see [LICENSE](https://github.com/oscarfasanchez/vorflow_os/blob/main/LICENSE).
Loading