Skip to content

Easy regional & variable-resolution mesh creation#15

Open
daniloceano wants to merge 10 commits into
developfrom
feature/regional-mesh-creation
Open

Easy regional & variable-resolution mesh creation#15
daniloceano wants to merge 10 commits into
developfrom
feature/regional-mesh-creation

Conversation

@daniloceano

@daniloceano daniloceano commented Jun 21, 2026

Copy link
Copy Markdown

What this adds

Makes building MPAS-Atmosphere meshes much easier, especially regional (limited-area) ones, and simplifies + improves the existing variable-resolution global workflow and its documentation.

Headline: regional meshes are now trivial

A new create_regional_grid.py builds a true limited-area mesh in one command. Before, a regional mesh meant manually (1) generating a global variable-resolution mesh and (2) running the NCAR MPAS-Limited-Area tool by hand with a hand-written "points file". Now the script does both steps for you:

  1. builds a global mesh, fine over your region and coarse elsewhere;
  2. cuts out your area of interest with create_region.

Advantages

  • One command, no manual chaining of two separate tools.
  • No need to learn the points-file format — you describe the region with friendly options.
  • 4 region shapes: circle, ellipse, box (lat/lon) and custom polygon (from a file).
  • Smart-transition default (the part meteorologists most often get wrong): the background is coarse (200 km) by default, and the high-resolution zone is auto-sized to cover the whole kept domain including the 7-cell relaxation belt. So every cell inside the regional mesh is at the target spacing, while the coarse transition falls outside the cut and is discarded — minimising grid points that are generated but never used (faster, smaller).
  • Quick-look plot with -p (cartopy: coastlines, country and state borders) to visually verify the domain.

Also: simpler & better global variable-resolution workflow

The global script still does everything it did (uniform / icosahedral / locally-refined), but the mesh-building logic now lives in a shared, reusable function, so:

  • No duplicated code between the global and regional scripts.
  • Same quick-look plotting available for global meshes too.
  • Proper documentation: a new README explains global vs regional, documents every flag, and gives copy-paste examples for all grid types and region shapes.

Note on create_spherical_grid.py (changed, on purpose)

I refactored it into a thin CLI that calls the new shared jigsaw_util.build_global_mesh(). The grid options and behaviour are unchanged — anyone already using it keeps the same commands and results. Purpose: avoid duplicating the jigsaw→NetCDF→MPAS pipeline so the regional script can reuse it.

Two small, deliberate improvements while there:

  • -p is now a flag that saves a PNG of the final mesh resolution (next to the grid), instead of opening a blocking interactive window that only worked for localref and hung on headless servers.
  • removed a leftover debug print.

Files

  • New usp-utils/pre_proc/grid_creation_scripts/create_regional_grid.py — regional mesh CLI.
  • New usp-utils/libs/py/regional_util.py — region-spec writers + limited-area cut wrapper.
  • New usp-utils/pre_proc/grid_creation_scripts/README.md — full docs.
  • New usp-utils/pre_proc/grid_creation_scripts/install_limited_area.sh — one-shot installer for the MPAS-Limited-Area dependency (upstream has no setup.py, so pip install git+url does not work).
  • Changed usp-utils/libs/py/jigsaw_util.py — added shared build_global_mesh(), plot_resolution(), resolve_plot_path().
  • Changed usp-utils/pre_proc/grid_creation_scripts/create_spherical_grid.py — thin CLI on top of the shared code (see note above).

Dependency

The cut step needs the NCAR MPAS-Limited-Area tool (create_region). Run install_limited_area.sh once per machine (documented in the README). If it is missing, the script stops with clear instructions.

Update: interactive region drawing

Added draw_region.py — opens a cartopy map (coastlines, country and state borders) where you click the polygon vertices on the map instead of typing coordinates; it writes the lat, lon points file that create_regional_grid.py --shape polygon reads (auto-ordered counter-clockwise). Controls: left-click add, right-click undo, c clear, enter save, esc quit. Needs an interactive display (run locally or via ssh -X).

Testing

All region shapes (circle/ellipse/box/polygon) and both scripts were run end-to-end: meshes generate, the cut produces valid *.grid.nc + *.graph.info with the expected 7-layer relaxation belt, and the whole regional domain comes out at the target spacing. The model source code was not touched and the model was not run.

daniloceano and others added 5 commits June 11, 2026 21:49
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- setup_environment.sh: stop inferring env existence from 'conda activate's exit
  code (which gives a misleading "Couldn't find the environment" when the env
  exists but a transient activate returns non-zero). Now: ensure the 'conda'
  shell function is loaded (source conda.sh if only the binary is on PATH),
  check the env in 'conda env list', then activate. Clearer not-found message.
- install_conda_environment.sh: add '#!/usr/bin/env bash' shebang. It uses
  bash-only features (BASH_SOURCE, '[ == ]'); running it with sh/dash failed
  with "Bad substitution" / "unexpected operator" and left SCRIPT_DIR empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make it much easier for non-specialists to build MPAS-Atmosphere meshes,
especially regional (limited-area) ones.

New - create_regional_grid.py: one command builds a true regional mesh.
It generates a global locally-refined mesh and cuts out the area of
interest with the NCAR MPAS-Limited-Area tool. Supports circle, ellipse,
box and custom-polygon regions. A smart-transition default keeps the whole
kept domain (interior + the 7-cell relaxation belt) at the target spacing
while discarding the coarse transition outside the cut, minimising grid
points that are generated but never used.

Shared library (usp-utils/libs/py):
- jigsaw_util.build_global_mesh(): the jigsaw -> NetCDF -> MPAS pipeline,
  extracted so the global and regional scripts reuse it without
  duplicating code.
- jigsaw_util.plot_resolution()/resolve_plot_path(): optional cartopy
  quick-look plot of mesh resolution (coastlines + country borders, plus
  state borders for regional), shared by both scripts.
- regional_util.py: region-spec ("points file") writers (circle/ellipse/
  custom) and the limited-area cut wrapper.

create_spherical_grid.py: refactored into a thin CLI that calls
build_global_mesh. Same grid options and behaviour, with two improvements:
the old blocking interactive plot is gone (-p now saves a PNG next to the
grid), and a leftover debug print was removed.

Docs/tooling:
- grid_creation_scripts/README.md: global vs regional, every flag, and
  examples for all region shapes.
- install_limited_area.sh: one-shot installer for the MPAS-Limited-Area
  dependency (upstream ships no setup.py, so pip-from-URL does not work).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@daniloceano daniloceano requested a review from favba June 21, 2026 03:21
daniloceano and others added 3 commits June 21, 2026 14:02
Add a "Partitioning for parallel runs" section explaining how to split the
mesh graph.info with gpmetis (METIS) for both global and regional meshes,
plus the one-time conda-forge install. Note gpmetis in the env setup list.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document the higher-quality partitioning command recommended by the MPAS
docs and explain what each flag does, noting plain gpmetis still works.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New draw_region.py opens a cartopy map (coastlines, country and state
borders) where left-clicking places polygon vertices; it writes the
'lat, lon' points file that create_regional_grid.py --shape polygon reads
(auto-ordered counter-clockwise). Controls: left add, right undo, c clear,
enter save, esc quit. Needs an interactive display. README documents it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 3, 2026 18:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a streamlined workflow for generating MPAS-Atmosphere meshes, adding a one-command regional (limited-area) mesh creator and refactoring global mesh creation into shared utilities. It also adds documentation and helper tooling (plotting, dependency installer, interactive polygon drawing) to make both global variable-resolution and regional workflows easier and more reproducible.

Changes:

  • Added create_regional_grid.py + regional_util.py to automate the global locally-refined mesh + create_region cut workflow for true regional meshes.
  • Refactored global mesh creation into jigsaw_util.build_global_mesh() and added reusable resolution plotting helpers.
  • Added end-user docs (README.md), an installer for MPAS-Limited-Area (install_limited_area.sh), and an interactive polygon drawing tool (draw_region.py).

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
usp-utils/setup_environment.sh Improves conda detection/activation logic for the cgfd-usp-mpas environment.
usp-utils/pre_proc/grid_creation_scripts/README.md New comprehensive documentation for global + regional grid workflows and flags.
usp-utils/pre_proc/grid_creation_scripts/install_limited_area.sh Adds a one-shot installer for the external MPAS-Limited-Area create_region tool.
usp-utils/pre_proc/grid_creation_scripts/draw_region.py Adds an interactive cartopy-based tool to click-draw polygon region files.
usp-utils/pre_proc/grid_creation_scripts/create_spherical_grid.py Refactors global grid CLI into a thin wrapper around shared jigsaw_util code + non-interactive plotting.
usp-utils/pre_proc/grid_creation_scripts/create_regional_grid.py New CLI that builds a locally-refined global mesh then cuts a limited-area region in one command.
usp-utils/libs/py/regional_util.py New helpers to write MPAS-Limited-Area region specs and run create_region.
usp-utils/libs/py/jigsaw_util.py Adds shared build_global_mesh(), cleanup helpers, and a mesh-resolution plotting utility.
usp-utils/install_conda_environment.sh Adds bash shebang and clarifies that the installer must be run with bash.
.gitignore Ignores large WPS geog datasets and stray per-user HOME artifacts that shouldn’t be committed.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 30 to 33
out_dir=os.getenv('MPAS_ROOT')+"/grids/"+args.output
out_base=os.path.basename(args.output)
out_basepath=out_dir+"/"+out_base
out_filename=out_dir+"/"+out_base+".nc"
Comment on lines +387 to +391
write_netcdf(
convert(xarray.open_dataset(out_basepath + '_triangles.nc'),
dir=out_dir,
graphInfoFileName=out_basepath + "_graph.info"),
out_filename)
Comment on lines +444 to +450
# Approx. resolution from cell area. Meshes here live on a unit sphere
# (sphere_radius=1), so scale areas up to the real Earth before converting.
area = ds.variables['areaCell'][:]
sphere_radius = float(getattr(ds, 'sphere_radius', 1.0))
earth_radius_m = 6371220.0 if sphere_radius == 1.0 else 1.0
area_km2 = (area / 1.0e6) * earth_radius_m ** 2
resolution_km = 2.0 * np.sqrt(area_km2 / np.pi)
Comment on lines +371 to +375
if level > 11:
print("Please provide a reasonable refinment level - from 1 to 15."
" Current value too large ", level)
print(" Setting level to 4")
level = 4
if ! python -c "import jigsawpy, mpas_tools" >/dev/null 2>&1; then
echo "WARNING: 'jigsawpy'/'mpas_tools' not importable in the current python."
echo " You probably forgot to: conda activate cgfd-usp-mpas"
read -r -p "Continue anyway? [y/N] " ans
Comment on lines +64 to +65
echo "==> pip install -e $INSTALL_DIR"
pip install -e "$INSTALL_DIR"
Comment on lines +97 to +102
# use a user-given inside point, else the polygon centroid
if args.clat is not None and args.clon is not None:
clat, clon = args.clat, args.clon
else:
clat, clon = rutil.polygon_center(boundary_points)
area_radius = rutil.max_radius_km(clat, clon, boundary_points)
Comment on lines +9 to +11
These scripts run in the `cgfd-usp-mpas` conda env (it provides `jigsawpy`,
`mpas_tools`, the `jigsaw` binary, `create_region` for regional meshes, and
`gpmetis` for partitioning — see section 3).
daniloceano and others added 2 commits July 3, 2026 18:25
The env defaults matplotlib to the non-interactive 'Agg' backend, so the
window never opened and the tool exited immediately. Now it selects a GUI
backend at import (TkAgg then QtAgg), with a --backend override and a clear
error if no display is available. Also make the module docstring real (the
startup message printed 'None').

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Default view is now the whole world (zoom into any region, not just Brazil).
Add mouse-wheel zoom centred on the cursor and guard clicks so navigating
with the nav-toolbar pan/zoom does not drop stray vertices. Update the
docstring and README controls.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants