#!/usr/bin/env python
import warnings
import sys
from netCDF4 import num2date
from mpi4py import MPI
from .nc_projections import PointsNes, LatLonNes, RotatedNes, RotatedNestedNes, LCCNes, MercatorNes
[docs]
def create_nes(comm=None, info=False, projection=None, parallel_method="Y", balanced=False,
times=None, avoid_first_hours=0, avoid_last_hours=0, first_level=0, last_level=None,
**kwargs):
"""
Create a Nes class from scratch.
Parameters
----------
comm : MPI.Comm, optional
MPI Communicator. If None, uses MPI.COMM_WORLD.
info : bool, optional
Indicates if reading/writing info should be provided. Default is False.
projection : str, optional
The projection type. Accepted values are None, "regular", "global", "rotated", "rotated-nested", "lcc",
"mercator".
parallel_method : str, optional
The parallelization method to use. Default is "Y". Accepted values are ["X", "Y", "T"].
balanced : bool, optional
Indicates if balanced parallelization is desired. Balanced datasets cannot be written in chunking mode.
Default is False.
times : list of datetime, optional
List of datetime objects representing the time dimension. If None, a default time array is created.
avoid_first_hours : int, optional
Number of hours to remove from the start of the time steps. Default is 0.
avoid_last_hours : int, optional
Number of hours to remove from the end of the time steps. Default is 0.
first_level : int, optional
Index of the first level to use. Default is 0.
last_level : int or None, optional
Index of the last level to use. If None, the last level is used. Default is None.
**kwargs : additional arguments
Additional parameters required for specific projections.
Returns
-------
nes : Nes
An instance of the Nes class based on the specified parameters and projection.
Raises
------
ValueError
If any required projection-specific parameters are missing or if invalid parameters are provided.
NotImplementedError
If an unsupported parallel method or projection type is specified.
Notes
-----
The function dynamically creates an instance of a specific Nes subclass based on the provided projection.
The required parameters for each projection type are:
- None: ["lat", "lon"]
- "regular": ["lat_orig", "lon_orig", "inc_lat", "inc_lon", "n_lat", "n_lon"]
- "global": ["inc_lat", "inc_lon"]
- "rotated": ["centre_lat", "centre_lon", "west_boundary", "south_boundary", "inc_rlat", "inc_rlon"]
- "rotated-nested": ["parent_grid_path", "parent_ratio", "i_parent_start", "j_parent_start", "n_rlat", "n_rlon"]
- "lcc": ["lat_1", "lat_2", "lon_0", "lat_0", "nx", "ny", "inc_x", "inc_y", "x_0", "y_0"]
- "mercator": ["lat_ts", "lon_0", "nx", "ny", "inc_x", "inc_y", "x_0", "y_0"]
Example
-------
>>> nes = create_nes(projection="regular", lat_orig=0, lon_orig=0, inc_lat=1, inc_lon=1, n_lat=180, n_lon=360)
"""
if comm is None:
comm = MPI.COMM_WORLD
else:
comm = comm
# Create time array
if times is None:
units = "days since 1996-12-31 00:00:00"
calendar = "standard"
times = num2date([0], units=units, calendar=calendar)
times = [aux.replace(second=0, microsecond=0) for aux in times]
else:
if not isinstance(times, list):
times = list(times)
# Check if the parameters that are required to create the object have been defined in kwargs
kwargs_list = []
for name, value in kwargs.items():
kwargs_list.append(name)
if projection is None:
required_vars = ["lat", "lon"]
elif projection == "regular":
required_vars = ["lat_orig", "lon_orig", "inc_lat", "inc_lon", "n_lat", "n_lon"]
elif projection == "global":
required_vars = ["inc_lat", "inc_lon"]
elif projection == "rotated":
required_vars = ["centre_lat", "centre_lon", "west_boundary", "south_boundary", "inc_rlat", "inc_rlon"]
elif projection == "rotated-nested":
required_vars = ["parent_grid_path", "parent_ratio", "i_parent_start", "j_parent_start", "n_rlat", "n_rlon"]
elif projection == "lcc":
required_vars = ["lat_1", "lat_2", "lon_0", "lat_0", "nx", "ny", "inc_x", "inc_y", "x_0", "y_0"]
elif projection == "mercator":
required_vars = ["lat_ts", "lon_0", "nx", "ny", "inc_x", "inc_y", "x_0", "y_0"]
else:
raise ValueError("Unknown projection: {0}".format(projection))
for var in required_vars:
if var not in kwargs_list:
msg = "Variable {0} has not been defined. ".format(var)
msg += "For a {} projection, it is necessary to define {}".format(projection, required_vars)
raise ValueError(msg)
for var in kwargs_list:
if var not in required_vars:
msg = "Variable {0} has been defined. ".format(var)
msg += "For a {} projection, you can only define {}".format(projection, required_vars)
raise ValueError(msg)
if projection is None:
if parallel_method == "Y":
warnings.warn("Parallel method cannot be 'Y' to create points NES. Setting it to 'X'")
sys.stderr.flush()
parallel_method = "X"
elif parallel_method == "T":
raise NotImplementedError("Parallel method T not implemented yet")
nessy = PointsNes(comm=comm, dataset=None, info=info, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, balanced=balanced,
create_nes=True, times=times, **kwargs)
elif projection in ["regular", "global"]:
nessy = LatLonNes(comm=comm, dataset=None, info=info, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, balanced=balanced,
create_nes=True, times=times, **kwargs)
elif projection == "rotated":
nessy = RotatedNes(comm=comm, dataset=None, info=info, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, balanced=balanced,
create_nes=True, times=times, **kwargs)
elif projection == "rotated-nested":
nessy = RotatedNestedNes(comm=comm, dataset=None, info=info, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, balanced=balanced,
create_nes=True, times=times, **kwargs)
elif projection == "lcc":
nessy = LCCNes(comm=comm, dataset=None, info=info, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, balanced=balanced,
create_nes=True, times=times, **kwargs)
elif projection == "mercator":
nessy = MercatorNes(comm=comm, dataset=None, info=info, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, balanced=balanced,
create_nes=True, times=times, **kwargs)
else:
raise NotImplementedError(projection)
return nessy
[docs]
def from_shapefile(path, method=None, parallel_method="Y", **kwargs):
"""
Create NES from shapefile data.
1. Create NES grid.
2. Create shapefile for grid.
3. Spatial join to add shapefile variables to NES variables.
Parameters
----------
path : str
Path to shapefile.
method : str
Overlay method. Accepted values: ["nearest", "intersection", None].
parallel_method : str
Indicates the parallelization method that you want. Default: "Y".
accepted values: ["X", "Y", "T"].
"""
# Create NES
nessy = create_nes(comm=None, info=False, parallel_method=parallel_method, **kwargs)
# Create shapefile for grid
nessy.create_shapefile()
# Make spatial join
nessy.spatial_join(path, method=method)
return nessy