Skip to content

Commit 7dfb174

Browse files
authored
Merge pull request #23 from andrewdnolan/periodic_planar
Add support for planar periodic meshes by adding wrapping functionality that's applicable to both planar periodic and spherical meshes.
2 parents 7e0d993 + 2a198a4 commit 7dfb174

File tree

12 files changed

+415
-76
lines changed

12 files changed

+415
-76
lines changed

.github/workflows/build_workflow.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ jobs:
110110
conda activate mosaic_dev
111111
pip check
112112
python -c "import mosaic"
113-
#pytest tests
113+
pytest tests -v
114114
115115
- if: ${{ steps.skip_check.outputs.should_skip != 'true' }}
116116
name: Build Sphinx Docs

dev-environment.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ numpy
88
pooch
99
pyproj
1010
scipy
11+
shapely
1112
tqdm
1213
xarray
1314

@@ -17,6 +18,7 @@ setuptools >=60
1718
# Linting and tesing
1819
pip
1920
pytest
21+
pytest-timeout
2022
isort
2123
flake8
2224
mypy

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def setup(app):
6464
'matplotlib': ('https://matplotlib.org/stable', None),
6565
'numpy': ('https://numpy.org/doc/stable', None),
6666
'python': ('https://docs.python.org/3/', None),
67+
'shapely': ('https://shapely.readthedocs.io/en/stable/', None),
6768
'xarray': ('https://xarray.pydata.org/en/stable', None),
6869
}
6970

docs/developers_guide/api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,10 @@ Properties
3939
Descriptor.vertex_patches
4040
Descriptor.transform
4141
42+
Helper Functions
43+
----------------
44+
.. autosummary::
45+
:toctree: generated/
46+
47+
utils.get_invalid_patches
4248
```

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Currently `mosaic` only supports [MPAS](https://mpas-dev.github.io/) meshes, but
1212
:caption: User Guide:
1313
1414
user_guide/quick_start
15+
user_guide/wrapping
1516
```
1617

1718
```{toctree}

docs/user_guide/quick_start.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ ds = mosaic.datasets.open_dataset("QU.240km")
3535
# define a map projection for our figure
3636
projection = ccrs.InterruptedGoodeHomolosine()
3737
# define the transform that describes our dataset
38-
transform = ccrs.PlateCarree()
38+
transform = ccrs.Geodetic()
3939
4040
# create the figure and a GeoAxis
4141
fig, ax = plt.subplots(1, 1, figsize=(9,7), facecolor="w",
@@ -54,13 +54,16 @@ ax.coastlines()
5454
fig.colorbar(collection, fraction=0.1, shrink=0.5, label="Cell Index");
5555
```
5656

57-
### Planar Non-Periodic
57+
For more information about how spherical meshes are handled and a list of supported
58+
map projections, see: <project:#wrapping>.
59+
60+
### Planar Non-Periodic
5861

5962
In this case the underlying coordinate arrays (i.e. `xCell/yCell`)
6063
correspond to a South Polar Stereographic projection, which is also the map projection we
6164
want to us. Therefore, the `projection` and the `transform` will be equivalent
6265
for this example. When instantiating the `mosaic.Descriptor` object we have to
63-
careful to set `use_latlon=False` to ensure the `xCell`/`yCell` coordinate
66+
be careful to set `use_latlon=False` to ensure the `xCell`/`yCell` coordinate
6467
arrays are parsed (c.f. `lonCell`/`latCell`).
6568

6669
```{code-cell} ipython3
@@ -101,13 +104,13 @@ fig.colorbar(collection, fraction=0.1, label="Thickness [m]");
101104
In the case where we do not know what projection the coordinate arrays of the
102105
mesh correspond to we can use the `lonCell`/`latCell` coordinates and `mosaic`
103106
will handle the transformation to the requested map projection under the hood.
104-
In this scenario the `transform` should correspond to `ccrs.PlateCarree()`
107+
In this scenario the `transform` should correspond to `ccrs.Geodetic()`
105108
and `use_latlon=True` must be set in the `mosaic.Descriptor` object
106109
instantiation. Nearly all the lines would be the same as the above example,
107110
with the exception of the transform definition:
108111
```python
109112
# define the transform that describes our dataset
110-
transform = ccrs.PlateCarree()
113+
transform = ccrs.Geodetic()
111114
```
112115
and the `mosaic.Descriptor` instantiation:
113116
```python

docs/user_guide/wrapping.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
file_format: mystnb
3+
kernelspec:
4+
name: python3
5+
---
6+
7+
# Periodic Mesh Support
8+
9+
We currently make the simplifying assumption that spherical meshes are a
10+
special instance of periodic meshes, which are periodic across the antimeridian.
11+
We support both planar periodic and map projected spherical meshes, using the
12+
same methods, by assuming that the period (in the x and y directions
13+
respectively) is constant. This assumption is valid for planar periodic meshes
14+
and for some map projections, but falls apart for certain map projection where
15+
the antimeridian does not follow a strait line. Therefore we only support a
16+
subset of `cartopy` projections, which are listed below. Future work will
17+
develop a more elaborate method of dealing with spherical mesh periodicity,
18+
which in turn will expand the list supported map projections.
19+
20+
For patches that cross a periodic boundary we simply correct the coordinates to
21+
remove the periodicity, which enables plotting. Future work will mirror the
22+
patches across the periodic boundary, so as to more accurately demonstrate the
23+
periodic nature of the mesh.
24+
25+
<!--
26+
## Planar Periodic Meshes
27+
28+
```{code-cell} ipython3
29+
---
30+
mystnb:
31+
remove_code_source: true
32+
---
33+
import mosaic
34+
import matplotlib.pyplot as plt
35+
36+
# download and read the mesh from lcrc
37+
ds = mosaic.datasets.open_dataset("doubly_periodic_4x4")
38+
39+
# create the figure and a GeoAxis
40+
fig, ax = plt.subplots(constrained_layout=True,)
41+
42+
descriptor = mosaic.Descriptor(ds)
43+
44+
pc = mosaic.polypcolor(
45+
ax, descriptor, ds.indexToCellID, alpha=0.8, antialiaseds=True, ec="k"
46+
)
47+
48+
ax.scatter(descriptor.ds.xCell, descriptor.ds.yCell, c='k')
49+
ax.scatter(*descriptor.cell_patches.T, c='tab:blue', marker='^')
50+
ax.scatter(ds.xVertex, ds.yVertex, ec='tab:orange', fc='none', marker='o', s=5.)
51+
ax.set_aspect('equal')
52+
```
53+
-->
54+
55+
## Supported Map Projections for Spherical Meshes
56+
57+
Currently, the only support map projection are:
58+
- <inv:#*.PlateCarree>
59+
- <inv:#*.LambertCylindrical>
60+
- <inv:#*.Mercator>
61+
- <inv:#*.Miller>
62+
- <inv:#*.Robinson>
63+
- <inv:#*.Stereographic>
64+
- <inv:#*.RotatedPole>
65+
- <inv:#*.InterruptedGoodeHomolosine>
66+
- <inv:#*.EckertI>
67+
- <inv:#*.EckertII>
68+
- <inv:#*.EckertIII>
69+
- <inv:#*.EckertIV>
70+
- <inv:#*.EckertV>
71+
- <inv:#*.EckertVI>
72+
- <inv:#*.EqualEarth>
73+
- <inv:#*.NorthPolarStereo>
74+
- <inv:#*.SouthPolarStereo>
75+
76+
It is important to note that planer (non-periodic) meshes are not limited to
77+
this list of map projections and can choose from the full list of `cartopy`
78+
[projections](https://scitools.org.uk/cartopy/docs/latest/reference/projections.html).

mosaic/datasets.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@
2626
"mpasli.AIS8to30": {
2727
"lcrc_path": "inputdata/glc/mpasli/mpas.ais8to30km/ais_8to30km.20221027.nc",
2828
"sha256_hash": "sha256:932a1989ff8e51223413ef3ff0056d6737a1fc7f53e440359884a567a93413d2"
29-
}
29+
},
30+
31+
"doubly_periodic_4x4": {
32+
"lcrc_path": "mpas_standalonedata/mpas-ocean/mesh_database/doubly_periodic_1920km_7680x7680km.151124.nc",
33+
"sha256_hash": "sha256:5409d760845fb682ec56e30d9c6aa6dfe16b5d0e0e74f5da989cdaddbf4303c7"
34+
},
3035
}
3136

3237
# create a parsable registry for pooch from human friendly one
@@ -55,8 +60,9 @@ def open_dataset(
5560
5661
* ``"QU.960km"`` : Quasi-uniform spherical mesh, with approximately 960km horizontal resolution
5762
* ``"QU.240km"`` : Quasi-uniform spherical mesh, with approximately 240km horizontal resolution
58-
* ``"mpaso.IcoswISC30E3r5"`` : Icosahedral 30 km MPAS-Ocean mesh with ice shelf cavaties
63+
* ``"mpaso.IcoswISC30E3r5"`` : Icosahedral 30 km MPAS-Ocean mesh with ice shelf cavities
5964
* ``"mpasli.AIS8to30"`` : 8-30 km resolution planar non-periodic MALI mesh of Antarctica
65+
* ``"doubly_periodic_4x4"``: Doubly periodic planar mesh that is four cells wide in both the x and y dimensions.
6066
6167
Parameters
6268
----------

0 commit comments

Comments
 (0)