-
Notifications
You must be signed in to change notification settings - Fork 4
Updated version to work with spectral element files, and support for current CMIP7 time and bounds format #31
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
base: main
Are you sure you want to change the base?
Changes from all commits
9364eaa
7d17673
7ecfc87
4e381ae
f3ec334
cb93d80
f39d4d3
a0d14cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,47 @@ | ||
| import numpy as np | ||
| import xesmf as xe | ||
| import xarray as xr | ||
|
|
||
| def RegridConservative(ds_to_regrid, ds_regrid_target, regridder_weights, regrid_reuse): | ||
| import sys | ||
|
|
||
| from .utils import ImportRegridTarget | ||
|
|
||
| class TwoStepRegridder: | ||
|
|
||
| def __init__(self, ds_to_regrid, regridder_steptwo_weights, intermediate_regridding_file, regrid_method="conservative"): | ||
|
|
||
| self.se_regridder = make_se_regridder(regridder_steptwo_weights, regrid_method=regrid_method) | ||
| intermediate_ds = ImportRegridTarget(intermediate_regridding_file) | ||
| #print(intermediate_ds) | ||
| self.step_one_regridder = xe.Regridder(ds_to_regrid, intermediate_ds, regrid_method) | ||
| #print(self.step_one_regridder) | ||
|
|
||
| def two_step_regridding(self, ds_to_regrid): | ||
| ds_intermediate = self.step_one_regridder(ds_to_regrid) | ||
| ds_se = self.se_regridder(ds_intermediate).squeeze("lat", drop=True) | ||
| #print(ds_se) | ||
| return ds_se.rename({"lon":"lndgrid"}).drop_vars("lndgrid") | ||
|
|
||
|
|
||
| def RegridConservative(ds_to_regrid, ds_regrid_target, regridder_weights, regrid_reuse, regrid_method="conservative", intermediate_regridding_file=None): | ||
|
|
||
| # define the regridder transformation | ||
| regridder = GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights, regrid_reuse) | ||
| regridder = GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights, regrid_reuse, regrid_method=regrid_method, intermediate_regridding_file=intermediate_regridding_file) | ||
|
|
||
| # Loop through the variables to regrid | ||
| ds_regrid = RegridLoop(ds_to_regrid, regridder) | ||
|
|
||
| return (ds_regrid, regridder) | ||
|
|
||
| def GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights_file, regrid_reuse): | ||
|
|
||
| regrid_method = "conservative" | ||
| def GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights_file, regrid_reuse, regrid_method = "conservative", intermediate_regridding_file=None): | ||
|
|
||
| print("\nDefining regridder, method: ", regrid_method) | ||
| #print(ds_to_regrid.dims) | ||
| if 'lat' not in ds_regrid_target.dims: | ||
| two_step_regridder = TwoStepRegridder(ds_to_regrid, regridder_weights_file, intermediate_regridding_file, regrid_method=regrid_method) | ||
| regridder = two_step_regridder.two_step_regridding #make_se_regridder(regridder_weights_file, regrid_method=regrid_method) | ||
|
|
||
| if (regrid_reuse): | ||
| elif (regrid_reuse): | ||
| regridder = xe.Regridder(ds_to_regrid, ds_regrid_target, | ||
| regrid_method, weights=regridder_weights_file) | ||
| else: | ||
|
|
@@ -27,6 +53,69 @@ def GenerateRegridder(ds_to_regrid, ds_regrid_target, regridder_weights_file, re | |
|
|
||
| return(regridder) | ||
|
|
||
|
|
||
| def make_se_regridder(weight_file, regrid_method): | ||
| weights = xr.open_dataset(weight_file) | ||
| in_shape = weights.src_grid_dims.load().data.tolist()[::-1] | ||
|
Comment on lines
+57
to
+59
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @maritsandstad I'm hitting an error here when I try and supply a weight file during the two-step process: I'm using the output from using the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I don't think that would work, you need a map file that defines both the source grid dimensions and the destination grid, but it might very well be that the code could work with other things than what I used, but then there might have to be some hooks for testing the type of weight-file that's in use... Also, if you can do the transition without the two-step regridding. That would be preferable, but I did not manage to make weight files to make that work... |
||
|
|
||
| # Since xESMF expects 2D vars, we'll insert a dummy dimension of size-1 | ||
| if len(in_shape) == 1: | ||
| in_shape = [1, in_shape.item()] | ||
|
|
||
| # output variable shape | ||
| out_shape = weights.dst_grid_dims.load().data#.tolist()[::-1] | ||
| if len(out_shape) == 1: | ||
| out_shape = [1, out_shape.item()] | ||
|
|
||
| #print(in_shape, out_shape) | ||
| #print(weights) | ||
| #print(len(weights.yc_a.data.reshape(in_shape)[:, 0])) | ||
| #print(weights.yc_a.data.reshape(in_shape)[:, 0]) | ||
| #print(len((weights.xc_a.data.reshape(in_shape)[0, :]))) | ||
| #print((weights.xc_a.data.reshape(in_shape)[0, :])) | ||
| #sys.exit(4) | ||
| # Making some bounds inputs: | ||
| #print(in_shape) | ||
| lat_b_in = np.zeros(in_shape[0]+1) | ||
| lon_b_in = weights.xv_a.data[:in_shape[1]+1, 0] | ||
| #print(lon_b_in[0:10]) | ||
| #print(weights.yv_a.data.shape) | ||
| #print(np.arange(in_shape[0]+1)*in_shape[1],) | ||
| #print(weights.yv_a.data[-5:-1, :]) | ||
| lat_b_in[:-1] = weights.yv_a.data[np.arange(in_shape[0])*in_shape[1],0] | ||
| lat_b_in[-1] = weights.yv_a.data[-1,-1] | ||
| #print(lat_b_in) | ||
| #sys.exit(4) | ||
|
|
||
| dummy_out = xr.Dataset( | ||
| { | ||
| "lat": ("lat", np.empty((out_shape[0],))), | ||
| "lon": ("lon", np.empty((out_shape[1],))), | ||
| "lat_b": ("lat_b", np.empty((out_shape[0]+1,))), | ||
| "lon_b": ("lon_b", np.empty((out_shape[1]+1,))) | ||
| } | ||
| ) | ||
| dummy_in= xr.Dataset( | ||
| { | ||
| "lat": ("lat", weights.yc_a.data.reshape(in_shape)[:, 0]), | ||
| "lon": ("lon", weights.xc_a.data.reshape(in_shape)[0, :]), | ||
| "lat_b": ("lat_b", lat_b_in), | ||
| "lon_b": ("lon_b", lon_b_in) | ||
| } | ||
| ) | ||
|
|
||
| regridder = xe.Regridder( | ||
| dummy_in, | ||
| dummy_out, | ||
| weights=weight_file, | ||
| #method="conservative_normed", | ||
| method=regrid_method, | ||
| #method="bilinear", | ||
| reuse_weights=True, | ||
| periodic=True, | ||
| ) | ||
| return regridder | ||
|
|
||
| def RegridLoop(ds_to_regrid, regridder): | ||
|
|
||
| # To Do: implement this with dask | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@maritsandstad can you describe the workflow for using the intermediate regridding target?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I wasn't able to coax ESMF into making a regridding file directly from 0.5by0.5 degree to the ne30 spectral resolution. Therefore, I needed to regrid from that to the regular grid I was able to get ESMF to make a file for regridding to spectral resolution for (0.9x1.25 degrees), and then I regrid over to the spectral grid from there using my map definition file (which I wasn't allowed to upload so far.) Not ideal, I guess. Do you want me to comment the code better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explanation @maritsandstad. Does the interstitial regular grid just need to be a grid close in resolution to the final spectral grid resolution? I'm not familiar with the nomeclature for the spectral grids; what's the
30inne30refer to and what resolution in degrees is it close to?Code comments are always welcome, but in this case I think it'd be best to add a section to the readme explaining the workflow for the spectral grid option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it would be good to get an explanation of how to generate the map definition file and what tool you used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am also not a resolution expert, but I think ne30 is around 1 degree resolution. I also don't actually know exactly how close the resolution needs to be for ESMF to be able to make a scripgrid file to define the transition. BTW I used ESMF (which is the regridding backend to xesmf) to define the grid file map definition using one of its command line prompts, I'll add the details in the README.