Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed online regridding code (file_regrid.py) for restart-to-restart file regridding only #266

Merged
merged 21 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f3572bc
Add new inquiry functions to cstools.py; Cleaned up code
yantosca Sep 28, 2023
93c44bf
Updated and cleaned up code in regrid.py
yantosca Sep 28, 2023
a859a96
Update example scripts to handle GCHP restart files properly
yantosca Sep 29, 2023
967c673
Add to_gchp argument in reverse_lev function of regrid_restart_file.py
yantosca Sep 29, 2023
4d08d9f
Update CHANGELOG.md for prior commit
yantosca Sep 29, 2023
dbf58db
Improved file_regrid.py: Specify weightsdir; add internal functions
yantosca Sep 29, 2023
2eb6bce
Restore original code in regrid.py and util.py
yantosca Oct 2, 2023
d84f92c
Further streamline the file_regrid.py module
yantosca Oct 2, 2023
9b33eef
Bug fixes in cstools.py inquiry functions
yantosca Oct 2, 2023
5044201
Fix if tset in file_regrid.py; also use a single dset variable
yantosca Oct 2, 2023
ad6bc3c
Add get_lev_and_ilev function to grid.py
yantosca Oct 3, 2023
87116b8
Split get_lev_and_ilev into separate functions in grid.py
yantosca Oct 3, 2023
2da1d4a
Make sure "lev" is properly saved when regridding from CS/SG -> LL
yantosca Oct 3, 2023
d12d767
get_ilev_coord and get_lev_coord now return numpy.ndarray
yantosca Oct 3, 2023
55bdb8a
Additional fixes for CS/SG -> CS/SG regridding
yantosca Oct 3, 2023
c62afa8
Fix remaining issues in file_regrid.py and grid.py
yantosca Oct 5, 2023
b27a601
Checkpoint to diagnostic regridding now saves "lons" and "lats"
yantosca Oct 5, 2023
55822c9
Add is_gchp_lev_positive_down function to cstools.py
yantosca Oct 5, 2023
9c3bd0d
More fixes in file_regrid.py
yantosca Oct 5, 2023
4500943
Fix algorithm to check for GCHP lev positive down; Update comments
yantosca Oct 10, 2023
922f233
Add update to resolve comments on PR #266
yantosca Oct 11, 2023
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
20 changes: 7 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Added statement `from dask.array import Array as DaskArray` in `gcpy plot.py`
- Added SLURM run script `gcpy/benchmark/benchmark_slurm.sh`
- Added `gcpy/gcpy_plot_style` style sheet for title and label default settings
- Added new cubed-sphere grid inquiry functions to `gcpy/cstools.py`
- Added functions `get_ilev_coord` and `get_lev_coord` to `gcpy/grid.py`

### Changed
- Simplified the Github issues templates into two options: `new-feature-or-discussion.md` and `question-issue.md`
Expand Down Expand Up @@ -61,6 +63,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Now allow `plot_val` to be of type `dask.array.Array` in `plot.py` routines `six_plot` and `single_panel`
- Now add `if` statements to turn of `Parallel()` commands when `n_jobs==1`.
- Do not hardwire fontsize in `gcpy/plot.py`; get defaults from `gcpy_plot_style`
- Updated and cleaned up code in `gcpy/regrid.py`
- Example scripts`plot_single_level` and `plot_comparisons` can now accept command-line arguments
- Example scripts `plot_single_level.py`, `plot_comparisons.py`, `compare_diags.py` now handle GCHP restart files properly

### Fixed
- Generalized test for GCHP or GCClassic restart file in `regrid_restart_file.py`
Expand All @@ -69,6 +74,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Prevent plot panels from overlapping in six-panel plots
- Prevent colorbar tick labels from overlapping in dynamic-range ratio plots
- Updated `seaborn` plot style names to conform to the latest matplotlib
- Set `lev:positive` and/or `ilev:positive` properly in `regrid_restart_file.py` and `file_regrid.py`
- Prevent overwriting of `lev` coord in `file_regrid.py` at netCDF write time

### Removed
- Removed `gchp_is_pre_13_1` arguments & code from benchmarking routines
Expand Down Expand Up @@ -365,16 +372,3 @@ This is the first labeled version of GCPy. The primary functionality of GCPy is
- Support for plotting benchmark output for both GEOS-Chem Classic (lat/lon data) and GCHP (cubed-sphere data).

The first official release version of GCPy, v1.0.0, will correspond with the release of GEOS-Chem 13.0.0.


## [Unreleased]

### Added

### Changed

### Deprecated

### Fixed

### Removed
163 changes: 134 additions & 29 deletions gcpy/cstools.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,10 @@
import pyproj
import shapely.ops
import shapely.geometry
# HOTFIX: Don't raise an ImportError until we can add pyproj to
# the AWS cloud container. This is causing errors that prevent
# benchmark plotting jobs from finishing. -- Bob Y. (01 Aug 2023)
#except ImportError as exc:
# raise ImportError(
# "gcpy.cstools needs packages 'pyproj' and 'shapely'!"
# ) from exc
except:
print("pyproj is not available")
except ImportError as exc:
raise ImportError(
"gcpy.cstools needs packages 'pyproj' and 'shapely'!"
) from exc

# Constants
RAD_TO_DEG = 180.0 / np.pi
Expand Down Expand Up @@ -74,8 +69,8 @@ def extract_grid(
if not is_cubed_sphere(data):
return None

n_cs = data["Xdim"].shape[-1]
return gen_grid(n_cs)
cs_res = get_cubed_sphere_res(data)
return gen_grid(cs_res)


def read_gridspec(gs_obj):
Expand Down Expand Up @@ -111,21 +106,23 @@ def read_gridspec(gs_obj):
area[i,...] = tile.area[...]

data = xr.Dataset(
data_vars=dict(
area=(['nf','Ydim','Xdim'],area),
lon=(['nf','Ydim','Xdim'],lon),
lat=(['nf','Ydim','Xdim'],lat),
lon_b=(['nf','Ydim_b','Xdim_b'],lon_b),
lat_b=(['nf','Ydim_b','Xdim_b'],lat_b),
),
coords=dict(
nf=(['nf'],list(range(6))),
Ydim=(['Ydim'],list(range(n_cs))),
Xdim=(['Xdim'],list(range(n_cs))),
Ydim_b=(['Ydim_b'],list(range(n_cs+1))),
Xdim_b=(['Xdim_b'],list(range(n_cs+1))),
),
attrs=dict(description=f'c{n_cs:d} grid data'),
data_vars={
"area": (['nf','Ydim','Xdim'], area),
"lon": (['nf','Ydim','Xdim'], lon),
"lat": (['nf','Ydim','Xdim'], lat),
"lon_b": (['nf','Ydim_b','Xdim_b'], lon_b),
"lat_b": (['nf','Ydim_b','Xdim_b'], lat_b),
},
coords={
"nf": (['nf'], list(range(6))),
"Ydim": (['Ydim'], list(range(n_cs))),
"Xdim": (['Xdim'], list(range(n_cs))),
"Ydim_b": (['Ydim_b'], list(range(n_cs+1))),
"Xdim_b": (['Xdim_b'], list(range(n_cs+1))),
},
attrs={
"description": f"c{n_cs:d} grid data"
},
)
return data

Expand Down Expand Up @@ -348,7 +345,7 @@ def gen_grid(
where each value has an extra face dimension of length 6.
"""
if stretch_factor is not None:
cs_temp, ignore = gcpy.make_grid_SG(
cs_temp, _ = gcpy.make_grid_SG(
n_cs,
stretch_factor,
target_lon,
Expand Down Expand Up @@ -680,7 +677,7 @@ def is_cubed_sphere(
):
"""
Given an xarray Dataset or DataArray object, determines if the
data is placed on a cubed-sphere grid
data is placed on a cubed-sphere grid.

Args:
-----
Expand All @@ -692,10 +689,118 @@ def is_cubed_sphere(
is_gchp : bool
Returns True if data is placed on a cubed-sphere grid,
and False otherwise.

Remarks:
--------
A cubed-sphere data file has one of the following attributes
(1) A dimension named "nf" (GCHP/GEOS diagnostic files)
(2) The lat/lon ratio is exactly 6 (GCHP/GEOS checkpoints)
"""
gcpy.util.verify_variable_type(data, (xr.DataArray, xr.Dataset))

if is_cubed_sphere_diag_grid(data):
return True
if is_cubed_sphere_rst_grid(data):
return True
return False


def is_cubed_sphere_diag_grid(data):
"""
Determines if a cubed-sphere grid has History file dimensions.
(i.e. a dimension named "nf", aka number of grid faces).

Args:
-----
data : xarray.DataArray or xarray.Dataset
The input data.

Returns:
--------
True if the grid has History diagnostic dimensions,
False otherwise.
"""
if "nf" in data.dims:
return True
return False


def is_cubed_sphere_rst_grid(data):
"""
Determines if a cubed-sphere grid has restart file dimensions.
(i.e. lat and lon, with lat = lon*6).

Args:
-----
data : xarray.DataArray or xarray.Dataset
The input data.

Returns:
--------
True if the grid has restart dimensions, False otherwise.
"""
gcpy.util.verify_variable_type(data, (xr.DataArray, xr.Dataset))

if "nf" in data.dims: # nf = number of cubed-sphere faces
if "lat" in data.dims:
if data.dims["lat"] == data.dims["lon"] * 6:
return True
if "SPC_" in data.data_vars.keys():
lizziel marked this conversation as resolved.
Show resolved Hide resolved
return True
return False


def get_cubed_sphere_res(data):
"""
Given a Dataset or DataArray object, returns the number of
grid cells along one side of the cubed-sphere grid face
(e.g. 24 for grid resolution C24, which has 24x25 grid cells
per face).

Args:
-----
data : xarray.DataArray or xarray.Dataset
The input data.

Returns:
--------
cs_res : int
The cubed-sphere resolution. Will return 0 if the data
is not placed on a cubed-sphere grid.
"""
gcpy.util.verify_variable_type(data, (xr.DataArray, xr.Dataset))

if not is_cubed_sphere(data):
return 0
if is_cubed_sphere_rst_grid(data):
return data.dims["lon"]
return data.dims["Xdim"]


def is_gchp_lev_positive_down(data):
"""
Determines if GCHP data is arranged vertically from the top of the
atmosphere downwards or from the surface upwards, according to:

(1) Checkpoint files: lev:positive="down
(2) Emissions collection: lev:positive="down"
(3) Other collections lev:positive="up"

Args:
-----
data : xarray.DataArray or xarray.Dataset
The input data

Returns:
--------
True if the data is arranged from top-of-atm downwards.
False if the data is arranged from the surface upwards.
"""
gcpy.util.verify_variable_type(data, (xr.DataArray, xr.Dataset))

if is_cubed_sphere_rst_grid(data):
return True
if is_cubed_sphere_diag_grid(data):
emis_vars = [var for var in data.data_vars if var.startswith("Emis")]
if len(emis_vars) > 0:
return True
return False
9 changes: 5 additions & 4 deletions gcpy/examples/diagnostics/compare_diags.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
collections. Similar to compute_diagnostics.ipynb, but can be used
without having to open a Jupyter notebook.
"""

# Imports
import os
import sys
import warnings
Expand Down Expand Up @@ -99,6 +97,10 @@ def read_data(config):
msg = "Error reading " + dev_file
raise Exception(msg) from exc

# Special handling for GCHP restart files
refdata = util.rename_and_flip_gchp_rst_vars(refdata)
devdata = util.rename_and_flip_gchp_rst_vars(devdata)

# Define dictionary for return
data = {
"ref": refdata,
Expand Down Expand Up @@ -303,8 +305,7 @@ def compare_data(config, data):
# ==================================================================
# Print totals for each quantity
# ==================================================================
if config["options"]["totals_and_diffs"]["create_table"] or \
config["options"]["totals_and_diffs"]["print_to_screen"]:
if config["options"]["totals_and_diffs"]["create_table"]:
print('... Printing totals and differences')
print_totals_and_diffs(
config,
Expand Down
Loading