feat: add option to crop mesh nodes to convex hull of grid coordinates - #58
feat: add option to crop mesh nodes to convex hull of grid coordinates#58AdMub wants to merge 29 commits into
Conversation
|
Please add some suitable tests for this that will be run in the CI as well. |
joeloskarsson
left a comment
There was a problem hiding this comment.
This option needs to be made available for all types of graphs, and when making them using the different archetypes. You can have a look at my prototype implementation on https://github.com/joeloskarsson/weather-model-graphs/tree/mesh_chull_filtering for some inspiration.
|
Hi @joeloskarsson, thank you for the review! Looking at your I will also add comprehensive tests for the CI pipeline to verify that the Delaunay spatial cropping logic is accurately identifying and removing the out-of-bounds nodes. I'll push the updated commits to this branch shortly! |
|
I'm adding this to milestone |
|
can I add you @joeloskarsson as assignee to this PR? |
|
Hi @joeloskarsson and @leifdenby, I have pushed the requested updates! The @joeloskarsson — I would love to get your eyes on the updated implementation whenever you have a moment. I have re-requested a review. |
leifdenby
left a comment
There was a problem hiding this comment.
Looking good! Some comments for suggestions
|
|
||
|
|
||
| def create_single_level_2d_mesh_graph(xy, nx, ny): | ||
| def create_single_level_2d_mesh_graph(xy, nx, ny, crop_to_convex_hull=False): |
There was a problem hiding this comment.
need line in docstring that explains what crop_to_convex_hull does
|
|
||
| # Create graph with cropping | ||
| graph_crop = create_keisler_graph( | ||
| coords, mesh_node_distance=1, crop_to_convex_hull=True |
There was a problem hiding this comment.
I don't see where you are suggesting changes to the functions that create the archetypes :) So I think this will fail. Also, I think this argument should be related to either g2m m2m or something like that. Maybe it actually belongs with the mesh_layout/mesh_layout_kwargs being introduced in #81?
|
Hi @leifdenby, thank you for the approval and the great catches! You are completely right about the failing test—I updated the underlying mesh builders but missed exposing the parameter in the top-level archetype functions. I've gone ahead and added the missing docstring to Regarding PR #81: I completely agree! Since Would you prefer I update this PR to look for |
|
Sounds perfect, Leif! I'll put a pin in this and keep an eye on #81. Once that merges, I'll sync my branch, shift the |
|
Hey @AdMub , just a heads-up that PR #81 has now been merged into main! Since you were waiting on that merge before syncing your branch and pushing the updated version , that's now unblocked! It would be great if you could rebase off the updated main, move This PR is on the v0.4.0 milestone and it's a blocker for the release, so getting it moving again would really help. If you're currently busy or unable to continue, no worries at all , just let us know and I can take this forward so we don't hold up the v0.4.0 release. Thanks for all the work so far! |
|
Hi @prajwal-tech07, thanks for the heads-up! I am on it. |
c900914 to
83ced4f
Compare
|
@AdMub thanks for working on this! There is just one merge conflict to resolve, do you think you would have time to look at this? Once that is done I will get the tests to run through and give this a review :) Thanks again! |
|
Hi @leifdenby, apologies for that! |
83ced4f to
a477c8d
Compare
joeloskarsson
left a comment
There was a problem hiding this comment.
Happy to review this again when up to date with main. Please re-request a review from me.
There was a problem hiding this comment.
Nice, but should not be merged :)
|
Hi @AdMub! I took a look at why the CI is failing - there are two separate issues:
test_issue_44.py - imports weather_model_graphs.create.mesh.kinds.flat, which doesn't exist on this branch → ModuleNotFoundError, so pytest aborts collection and the whole suite fails before any test runs.
TypeError: create_keisler_graph() got an unexpected keyword argument One bigger-picture thing: the cropping code is added as a new src/.../mesh/mesh.py, but main reorganized mesh creation in #81 - so it'd be worth integrating into the current structure rather than a parallel module. Happy to help if useful! |
@AdMub might it be useful to add an inline comment for where this change would need to be made down the line to generalise the implementation? |
|
Hi @leifdenby, that is a great suggestion. That should leave a very clear breadcrumb for the follow-up PR. Let me know if that looks good to go! |
leifdenby
left a comment
There was a problem hiding this comment.
Hi @leifdenby, that is a great suggestion. I have just pushed a commit adding a detailed
TODOcomment right above theValueErrorinbase.py. It points specifically tocreate_flat_multiscale_from_coordinatesand documents the need to refactor the index-based array reshaping(nx, ny, 2)into a position-based spatial merge.That should leave a very clear breadcrumb for the follow-up PR. Let me know if that looks good to go!
great! Thank you 🌟 Do you fancy typing up an issue too describing the follow-up that should be done after we've merged this PR? It is good you implemented the exception to make it clear that "cropping to convex hull" doesn't work for flat-multiscale graphs.
I think something we're missing here is a jupyter notebook that demonstrates this new functionality. What it makes sense to introduce a subsection to the existing notebooks? Or do you think it would be good with a new separate notebook? I think if we don't add a notebook here this feature might simply go unnoticed which would be a shame.
leifdenby
left a comment
There was a problem hiding this comment.
One last suggestion :) Will you also add an entry to the CHANGELOG explaining your contribution? Thanks!
…into feat/issue-40-convex-hull
…ve changelog conflict
|
"Hi @leifdenby, that makes perfect sense! |
leifdenby
left a comment
There was a problem hiding this comment.
Hmm... I think something has gone wrong in the notebook or the implementation (see my comment).
Also, I think we should not expose the whole mesh_layout_kwargs in the archtype functions, let me know what you think :)
| graph_crs: pyproj.crs.CRS | None = None, | ||
| decode_mask: Iterable[bool] | None = None, | ||
| return_components: bool = False, | ||
| mesh_layout_kwargs: dict | None = None, |
There was a problem hiding this comment.
I don't think we should expose the whole mesh_layout_kwargs here, doing that exposes a lot of complexity the most people will not need and we will have to greatly increase the content of the docstring. Instead if you would like to expose crop_to_grid_nodes_convex_hull through the archetype functions I would expose just that argument and insert it into the mesh_layout_kwargs, just like what we do for mesh_node_spacing
There was a problem hiding this comment.
the pruned mesh nodes appear identical to the mesh nodes before pruning, did you inadvertently introduce a bug in your implementation here? :)
|
Hi @leifdenby, you were 100% right on both counts! |
| networkx.DiGraph or dict[networkx.DiGraph] | ||
| The graph or graph components. | ||
| """ | ||
| kwargs = dict( |
There was a problem hiding this comment.
can you revert the change here so that rather than creating a dict for the kwargs and calling it kwargs here we create the dict inline as before?
| networkx.DiGraph or dict[networkx.DiGraph] | ||
| The graph or graph components. | ||
| """ | ||
| kwargs = dict( |
There was a problem hiding this comment.
same comment as above, create the dict inline where passing arguments to create_all_graph_components rather than creating the intermediate kwargs variable
| networkx.DiGraph or dict[networkx.DiGraph] | ||
| The graph or graph components. | ||
| """ | ||
| kwargs = dict( |
| if m2m_connectivity == "flat_multiscale": | ||
| raise ValueError( | ||
| "crop_to_convex_hull is currently not supported for 'flat_multiscale' " | ||
| "(GraphCast) architectures because they assume a regular rectangular grid." | ||
| ) |
| (`save.base`, `save.neural_lam.torch_tensors`, `save.neural_lam.deprecated`) | ||
| with all existing entrypoints re-exported unchanged. | ||
| [\#123](https://github.com/mllam/weather-model-graphs/pull/123), @prajwal-tech07 | ||
| - Add support for writing benchmarking results to json, |
There was a problem hiding this comment.
You've deleted a changelog entry here, and you need to add a changelog entry for your own work too :)
|
I've moved this feature to the next release milestone ( |
|
Hi @leifdenby, |
Describe your changes
This PR adds a
crop_to_convex_hullboolean parameter tocreate_single_level_2d_mesh_graphandcreate_multirange_2d_mesh_graphs.When set to
True, the function computes thescipy.spatial.ConvexHullof the providedxycoordinates and uses ascipy.spatial.Delaunaytriangulation to efficiently identify and remove any generated mesh nodes that fall outside the spatial boundary of the actual data. This prevents the generation of "dead space" nodes in the corners of bounding boxes when working with irregular or circular spatial datasets.Testing performed:
The implementation was verified locally using two distinct spatial datasets to ensure the pruning logic correctly identifies the data perimeter:
Circle Test: Using a circular data cluster, the standard rectangular mesh generated 400 nodes, while the convex hull cropped mesh generated 316 nodes (successfully pruning 84 empty-space nodes).
Irregular Shape Test: To test robustness against more complex boundaries, an irregular "heart-shaped" dataset was used. The standard mesh generated 625 nodes, which was successfully pruned to 419 nodes.
Visualization
The plot below demonstrates the "Before" (standard bounding box) and "After" (convex hull cropped) results for the irregular test case. Note how the mesh nodes are strictly contained within the data boundary:
Issue Link
Closes #40
Type of change
🐛 Bug fix (non-breaking change that fixes an issue)
✨ New feature (non-breaking change that adds functionality)
💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
📖 Documentation (Addition or improvements to documentation)
Checklist before requesting a review
My branch is up-to-date with the target branch - if not update your fork with the changes from the target branch (use
pullwith--rebaseoption if possible).I have performed a self-review of my code
For any new/modified functions/classes I have added docstrings that clearly describe its purpose, expected inputs and returned values
I have placed in-line comments to clarify the intent of any hard-to-understand passages of my code
I have updated the documentation to cover introduced code changes
I have added tests that prove my fix is effective or that my feature works
I have given the PR a name that clearly describes the change, written in imperative form (context).
I have requested a reviewer and an assignee (assignee is responsible for merging)
Checklist for reviewers
Each PR comes with its own improvements and flaws. The reviewer should check the following:
the code is readable
the code is well tested
the code is documented (including return types and parameters)
the code is easy to maintain
Author checklist after completed review
Checklist for assignee
PR is up to date with the base branch
the tests pass
author has added an entry to the changelog (and designated the change as
added,changedorfixed)