Source code for nes.nes_formats.cams_ra_format

#!/usr/bin/env python

import sys
import nes
from numpy import float64, float32, int32, array
from warnings import warn
from netCDF4 import Dataset
from mpi4py import MPI
from copy import copy


# noinspection DuplicatedCode
[docs] def to_netcdf_cams_ra(self, path): """ Horizontal methods from one grid to another one. Parameters ---------- self : nes.Nes Source projection Nes Object. path : str Path to the output netCDF file. """ if not isinstance(self, nes.LatLonNes): raise TypeError("CAMS Re-Analysis format must have Regular Lat-Lon projection") if "<level>" not in path: raise ValueError(f"AMS Re-Analysis path must contain '<level>' as pattern; current: '{path}'") orig_path = copy(path) for i_lev, level in enumerate(self.lev["data"]): path = orig_path.replace("<level>", "l{0}".format(i_lev)) # Open NetCDF if self.info: print("Rank {0:03d}: Creating {1}".format(self.rank, path)) if self.size > 1: netcdf = Dataset(path, format="NETCDF4", mode="w", parallel=True, comm=self.comm, info=MPI.Info()) else: netcdf = Dataset(path, format="NETCDF4", mode="w", parallel=False) if self.info: print("Rank {0:03d}: NetCDF ready to write".format(self.rank)) self.to_dtype(data_type=float32) # Create dimensions create_dimensions(self, netcdf) # Create variables create_variables(self, netcdf, i_lev) # Create dimension variables create_dimension_variables(self, netcdf) if self.info: print("Rank {0:03d}: Dimensions done".format(self.rank)) # Close NetCDF if self.global_attrs is not None: for att_name, att_value in self.global_attrs.items(): netcdf.setncattr(att_name, att_value) netcdf.close() return None
[docs] def create_dimensions(self, netcdf): """ Create "time", "time_bnds", "lev", "lon" and "lat" dimensions. Parameters ---------- self : nes.Nes Source projection Nes Object. netcdf : Dataset netcdf4-python open dataset. """ # Create time dimension netcdf.createDimension("time", None) # Create lev, lon and lat dimensions netcdf.createDimension("lat", len(self.get_full_latitudes()["data"])) netcdf.createDimension("lon", len(self.get_full_longitudes()["data"])) return None
[docs] def create_dimension_variables(self, netcdf): """ Create the "time", "time_bnds", "lev", "lat", "lat_bnds", "lon" and "lon_bnds" variables. Parameters ---------- self : nes.Nes Source projection Nes Object. netcdf : Dataset netcdf4-python open dataset. """ # LATITUDES lat = netcdf.createVariable("lat", float64, ("lat",)) lat.standard_name = "latitude" lat.long_name = "latitude" lat.units = "degrees_north" lat.axis = "Y" if self.size > 1: lat.set_collective(True) lat[:] = self.get_full_latitudes()["data"] # LONGITUDES lon = netcdf.createVariable("lon", float64, ("lon",)) lon.long_name = "longitude" lon.standard_name = "longitude" lon.units = "degrees_east" lon.axis = "X" if self.size > 1: lon.set_collective(True) lon[:] = self.get_full_longitudes()["data"] # TIMES time_var = netcdf.createVariable("time", float64, ("time",)) time_var.standard_name = "time" time_var.units = "day as %Y%m%d.%f" time_var.calendar = "proleptic_gregorian" time_var.axis = "T" if self.size > 1: time_var.set_collective(True) time_var[:] = __date2num(self.get_full_times()[self._get_time_id(self.hours_start, first=True): self._get_time_id(self.hours_end, first=False)]) return None
# noinspection DuplicatedCode
[docs] def create_variables(self, netcdf, i_lev): """ Create and write variables to a netCDF file. Parameters ---------- self : nes.Nes Source projection Nes Object. netcdf : Dataset netcdf4-python open dataset. i_lev : int The specific level index to write data for. """ for i, (var_name, var_dict) in enumerate(self.variables.items()): if var_dict["data"] is not None: if self.info: print("Rank {0:03d}: Writing {1} var ({2}/{3})".format(self.rank, var_name, i + 1, len(self.variables))) try: var = netcdf.createVariable(var_name, float32, ("time", "lat", "lon",), zlib=True, complevel=7, least_significant_digit=3) if self.info: print("Rank {0:03d}: Var {1} created ({2}/{3})".format( self.rank, var_name, i + 1, len(self.variables))) if self.size > 1: var.set_collective(True) if self.info: print("Rank {0:03d}: Var {1} collective ({2}/{3})".format( self.rank, var_name, i + 1, len(self.variables))) if self.info: print("Rank {0:03d}: Filling {1})".format(self.rank, var_name)) var[self.write_axis_limits["t_min"]:self.write_axis_limits["t_max"], self.write_axis_limits["y_min"]:self.write_axis_limits["y_max"], self.write_axis_limits["x_min"]:self.write_axis_limits["x_max"]] = var_dict["data"][:, i_lev, :, :] if self.info: print("Rank {0:03d}: Var {1} data ({2}/{3})".format( self.rank, var_name, i + 1, len(self.variables))) var.long_name = var_dict["long_name"] var.units = var_dict["units"] var.number_of_significant_digits = int32(3) if self.info: print("Rank {0:03d}: Var {1} completed ({2}/{3})".format(self.rank, var_name, i + 1, len(self.variables))) except Exception as e: print(f"**ERROR** an error has occurred while writing the '{var_name}' variable") raise e else: msg = "WARNING!!! " msg += "Variable {0} was not loaded. It will not be written.".format(var_name) warn(msg) sys.stderr.flush() return None
def __date2num(time_array): """ Convert an array of datetime objects to numerical values. Parameters ---------- time_array : List[datetime.datetime] List of datetime objects to be converted. Returns ------- numpy.ndarray Array of numerical time values, with each date represented as a float. Notes ----- The conversion represents each datetime as a float in the format YYYYMMDD.HH/24. """ time_res = [] for aux_time in time_array: time_res.append(float(aux_time.strftime("%Y%m%d")) + (float(aux_time.strftime("%H")) / 24)) time_res = array(time_res, dtype=float64) return time_res