-
Notifications
You must be signed in to change notification settings - Fork 143
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
Nemo 3d #463
Nemo 3d #463
Changes from 11 commits
58f8b53
857fd18
447ee39
38dc395
5a7458b
a80fcd8
6e14596
8cb5dd5
ddbff2f
85169c2
a79d001
7b914c9
e82cdd2
1be9bef
f594bb8
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 |
---|---|---|
|
@@ -33,7 +33,17 @@ | |
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We can create a `FieldSet` just like we do for normal grids. Note that we need to provide an extra filename for the `mesh_mask` file that holds information on the Curvilinear grid." | ||
"We can create a `FieldSet` just like we do for normal grids.\n", | ||
"Note that NEMO is discretised on a C-grid. U and V velocities are not located on the same grid (see https://www.nemo-ocean.eu/doc/node19.html).\n", | ||
"\n", | ||
"```\n", | ||
" __V1__\n", | ||
"| |\n", | ||
"U0 U1\n", | ||
"|__V0__|\n", | ||
"```\n", | ||
"\n", | ||
"To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes, which are located on the corners of the cells." | ||
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. change to 'lower-left corners' to be more explicit which corner? |
||
] | ||
}, | ||
{ | ||
|
@@ -52,9 +62,13 @@ | |
} | ||
], | ||
"source": [ | ||
"filenames = {'U': 'NemoCurvilinear_data/U_purely_zonal-ORCA025_grid_U.nc4',\n", | ||
" 'V': 'NemoCurvilinear_data/V_purely_zonal-ORCA025_grid_V.nc4',\n", | ||
" 'mesh_mask': 'NemoCurvilinear_data/mesh_mask.nc4'}\n", | ||
"data_path = 'NemoCurvilinear_data/'\n", | ||
"filenames = {'U': {'lon': data_path + 'mesh_mask.nc4',\n", | ||
" 'lat': data_path + 'mesh_mask.nc4',\n", | ||
" 'data': data_path + 'U_purely_zonal-ORCA025_grid_U.nc4'},\n", | ||
" 'V': {'lon': data_path + 'mesh_mask.nc4',\n", | ||
" 'lat': data_path + 'mesh_mask.nc4',\n", | ||
" 'data': data_path + 'V_purely_zonal-ORCA025_grid_V.nc4'}}\n", | ||
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. Does this new API for |
||
"variables = {'U': 'U',\n", | ||
" 'V': 'V'}\n", | ||
"dimensions = {'lon': 'glamf', 'lat': 'gphif', 'time': 'time_counter'}\n", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -140,6 +140,18 @@ def check_complete(self): | |
else: | ||
self.add_vector_field(VectorField('UVW', self.U, self.V, self.W)) | ||
|
||
@classmethod | ||
def parse_wildcards(cls, paths, filenames, var): | ||
if not isinstance(paths, list): | ||
paths = sorted(glob(str(paths))) | ||
if len(paths) == 0: | ||
notfound_paths = filenames[var] if type(filenames) is dict and var in filenames else filenames | ||
raise IOError("FieldSet files not found: %s" % str(notfound_paths)) | ||
for fp in paths: | ||
if not path.exists(fp): | ||
raise IOError("FieldSet file not found: %s" % str(fp)) | ||
return paths | ||
|
||
@classmethod | ||
def from_netcdf(cls, filenames, variables, dimensions, indices=None, | ||
mesh='spherical', allow_time_extrapolation=None, time_periodic=False, full_load=False, **kwargs): | ||
|
@@ -148,6 +160,9 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None, | |
:param filenames: Dictionary mapping variables to file(s). The | ||
filepath may contain wildcards to indicate multiple files, | ||
or be a list of file. | ||
filenames can be a list [files], a dictionary {var:[files]}, | ||
a dictionary {dim:[files]} (if lon, lat, depth not stored in same files as data), | ||
a dictionary of dictionaries {var:{dim:[files]}} | ||
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. add 'or' before the dictionary-of-dictionaries? |
||
:param variables: Dictionary mapping variables to variable | ||
names in the netCDF file(s). | ||
:param dimensions: Dictionary mapping data dimensions (lon, | ||
|
@@ -178,15 +193,12 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None, | |
fields = {} | ||
for var, name in variables.items(): | ||
# Resolve all matching paths for the current variable | ||
paths = filenames[var] if type(filenames) is dict else filenames | ||
if not isinstance(paths, list): | ||
paths = sorted(glob(str(paths))) | ||
if len(paths) == 0: | ||
notfound_paths = filenames[var] if type(filenames) is dict else filenames | ||
raise IOError("FieldSet files not found: %s" % str(notfound_paths)) | ||
for fp in paths: | ||
if not path.exists(fp): | ||
raise IOError("FieldSet file not found: %s" % str(fp)) | ||
paths = filenames[var] if type(filenames) is dict and var in filenames else filenames | ||
if type(paths) is not dict: | ||
paths = cls.parse_wildcards(paths, filenames, var) | ||
else: | ||
for dim, p in paths.items(): | ||
paths[dim] = cls.parse_wildcards(p, filenames, var) | ||
|
||
# Use dimensions[var] and indices[var] if either of them is a dict of dicts | ||
dims = dimensions[var] if var in dimensions else dimensions | ||
|
@@ -198,11 +210,19 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None, | |
for procvar, _ in fields.items(): | ||
procdims = dimensions[procvar] if procvar in dimensions else dimensions | ||
procinds = indices[procvar] if (indices and procvar in indices) else indices | ||
if (type(filenames) is not dict or filenames[procvar] == filenames[var]) \ | ||
and procdims == dims and procinds == inds: | ||
grid = fields[procvar].grid | ||
kwargs['dataFiles'] = fields[procvar].dataFiles | ||
break | ||
if procdims == dims and procinds == inds: | ||
sameGrid = False | ||
if (type(filenames) is not dict or filenames[procvar] == filenames[var]): | ||
sameGrid = True | ||
elif type(filenames[procvar]) == dict: | ||
sameGrid = True | ||
for dim in ['lon', 'lat', 'depth']: | ||
if dim in dimensions: | ||
sameGrid *= filenames[procvar][dim] == filenames[var][dim] | ||
if sameGrid: | ||
grid = fields[procvar].grid | ||
kwargs['dataFiles'] = fields[procvar].dataFiles | ||
break | ||
fields[var] = Field.from_netcdf(paths, var, dims, inds, grid=grid, mesh=mesh, | ||
allow_time_extrapolation=allow_time_extrapolation, | ||
time_periodic=time_periodic, full_load=full_load, **kwargs) | ||
|
@@ -215,19 +235,27 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric | |
allow_time_extrapolation=None, time_periodic=False, | ||
tracer_interp_method='linear', **kwargs): | ||
"""Initialises FieldSet object from NetCDF files of Curvilinear NEMO fields. | ||
Note that this assumes there is a variable mesh_mask that is used for the dimensions | ||
|
||
:param filenames: Dictionary mapping variables to file(s). The | ||
filepath may contain wildcards to indicate multiple files, | ||
or be a list of file. At least a 'mesh_mask' needs to be present | ||
or be a list of file. | ||
filenames can be a list [files], a dictionary {var:[files]}, | ||
a dictionary {dim:[files]} (if lon, lat, depth not stored in same files as data), | ||
a dictionary of dictionaries {var:{dim:[files]}} | ||
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. see comment above |
||
:param variables: Dictionary mapping variables to variable | ||
names in the netCDF file(s). Must include a variable 'mesh_mask' that | ||
holds the dimensions | ||
names in the netCDF file(s). | ||
:param dimensions: Dictionary mapping data dimensions (lon, | ||
lat, depth, time, data) to dimensions in the netCF file(s). | ||
Note that dimensions can also be a dictionary of dictionaries if | ||
dimension names are different for each variable | ||
(e.g. dimensions['U'], dimensions['V'], etc). | ||
dimension names are different for each variable. | ||
Watch out: NEMO is discretised on a C-grid: U and V are not located | ||
U and V velocities are not located on the same grid (see https://www.nemo-ocean.eu/doc/node19.html). | ||
__V1__ | ||
| | | ||
U0 U1 | ||
|__V0__| | ||
To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes, | ||
which are located on the corners of the cells. | ||
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. see minor comments on the jupyter notebook |
||
:param indices: Optional dictionary of indices for each dimension | ||
to read from file(s), to allow for reading of subset of data. | ||
Default is to read the full extent of each dimension. | ||
|
@@ -247,7 +275,8 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric | |
|
||
""" | ||
|
||
dimension_filename = filenames.pop('mesh_mask') if type(filenames) is dict else filenames | ||
if 'U' in dimensions and 'V' in dimensions and dimensions['U'] != dimensions['V']: | ||
raise RuntimeError("On a c-grid discretisation like NEMO, U and V should have the same dimensions") | ||
|
||
interp_method = {} | ||
for v in variables: | ||
|
@@ -257,8 +286,7 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric | |
interp_method[v] = tracer_interp_method | ||
|
||
return cls.from_netcdf(filenames, variables, dimensions, mesh=mesh, indices=indices, time_periodic=time_periodic, | ||
allow_time_extrapolation=allow_time_extrapolation, interp_method=interp_method, | ||
dimension_filename=dimension_filename, **kwargs) | ||
allow_time_extrapolation=allow_time_extrapolation, interp_method=interp_method, **kwargs) | ||
|
||
@classmethod | ||
def from_parcels(cls, basename, uvar='vozocrtx', vvar='vomecrty', indices=None, extra_fields=None, | ||
|
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.
Is 'grid' the right word here, is 'not located on the same grid'? Perhaps 'location'?