コード例 #1
0
ファイル: mss_plot_driver.py プロジェクト: plant99/MSS
    def _set_time(self, init_time, fc_time):
        """Open the dataset that corresponds to a forecast field specified
           by an initialisation and a valid time.

        This method
          determines the files that correspond to an init time and forecast step
          checks if an open NetCDF dataset exists
            if yes, checks whether it contains the requested valid time
              if not, closes the dataset and opens the corresponding one
          loads dimension data if required.
        """
        if len(self.plot_object.required_datafields) == 0:
            logging.debug("no datasets required.")
            self.dataset = None
            self.init_time = None
            self.fc_time = None
            self.times = np.array([])
            self.lat_data = np.array([])
            self.lon_data = np.array([])
            self.lat_order = 1
            self.vert_data = None
            self.vert_order = None
            self.vert_units = None
            return

        if fc_time < init_time:
            msg = "Forecast valid time cannot be earlier than " \
                  "initialisation time."
            logging.error(msg)
            raise ValueError(msg)
        fc_step = fc_time - init_time
        fc_step = fc_step.days * 24 + (fc_step.seconds // 3600)
        self.fc_time = fc_time
        logging.debug("\trequested initialisation time %s", init_time)
        logging.debug("\trequested forecast valid time %s (step %s hrs)",
                      fc_time, fc_step)

        # Check if a dataset is open and if it contains the requested times.
        # (a dataset will only be open if the used layer has not changed,
        # i.e. the required variables have not changed as well).
        if self.dataset is not None:
            logging.debug("checking on open dataset.")
            if self.init_time == init_time:
                logging.debug("\tinitialisation time ok (%s).", init_time)
                if fc_time in self.times:
                    logging.debug("\tforecast valid time contained (%s).",
                                  fc_time)
                    return
            logging.debug("need to re-open input files.")
            self.dataset.close()
            self.dataset = None

        # Determine the input files from the required variables and the
        # requested time:

        # Create the names of the files containing the required parameters.
        filenames = []
        for vartype, var, _ in self.plot_object.required_datafields:
            filename = self.data_access.get_filename(var,
                                                     vartype,
                                                     init_time,
                                                     fc_time,
                                                     fullpath=True)
            if filename not in filenames:
                filenames.append(filename)
            logging.debug("\tvariable '%s' requires input file '%s'", var,
                          os.path.basename(filename))

        if len(filenames) == 0:
            raise ValueError("no files found that correspond to the specified "
                             "datafields. Aborting..")

        self.init_time = init_time

        # Open NetCDF files as one dataset with common dimensions.
        logging.debug("opening datasets.")
        dsKWargs = self.data_access.mfDatasetArgs()
        dataset = netCDF4tools.MFDatasetCommonDims(filenames, **dsKWargs)

        # Load and check time dimension. self.dataset will remain None
        # if an Exception is raised here.
        timename, timevar = netCDF4tools.identify_CF_time(dataset)
        times = netCDF4tools.num2date(timevar[:], timevar.units)
        # removed after discussion, see
        # https://mss-devel.slack.com/archives/emerge/p1486658769000007
        # if init_time != netCDF4tools.num2date(0, timevar.units):
        #     dataset.close()
        #     raise ValueError("wrong initialisation time in input")

        if fc_time not in times:
            msg = "Forecast valid time '{}' is not available.".format(fc_time)
            logging.error(msg)
            dataset.close()
            raise ValueError(msg)

        # Load lat/lon dimensions.
        try:
            lat_data, lon_data, lat_order = netCDF4tools.get_latlon_data(
                dataset)
        except Exception as ex:
            logging.error("ERROR: %s %s", type(ex), ex)
            dataset.close()
            raise

        _, vert_data, vert_orientation, vert_units, _ = netCDF4tools.identify_vertical_axis(
            dataset)
        self.vert_data = vert_data[:] if vert_data is not None else None
        self.vert_order = vert_orientation
        self.vert_units = vert_units

        self.dataset = dataset
        self.times = times
        self.lat_data = lat_data
        self.lon_data = lon_data
        self.lat_order = lat_order

        # Identify the variable objects from the NetCDF file that correspond
        # to the data fields required by the plot object.
        self._find_data_vars()
コード例 #2
0
 def test_num2date(self):
     date = num2date(0,
                     "hours since 2012-10-17T12:00:00.000Z",
                     calendar='standard')
     assert date == datetime.datetime(2012, 10, 17, 12, 0)
コード例 #3
0
    def _parse_file(self, filename):
        elevations = {"levels": [], "units": None}
        with netCDF4.Dataset(os.path.join(self._root_path,
                                          filename)) as dataset:

            time_name, time_var = netCDF4tools.identify_CF_time(dataset)
            init_time = netCDF4tools.num2date(0, time_var.units)
            if not self.uses_inittime_dimension():
                init_time = None
            valid_times = netCDF4tools.num2date(time_var[:], time_var.units)
            if not self.uses_validtime_dimension():
                if len(valid_times) > 0:
                    raise IOError(
                        "Skipping file '{}: no support for valid time, but multiple "
                        "time steps present".format(filename))
                valid_times = [None]
            lat_name, lat_var, lon_name, lon_var = netCDF4tools.identify_CF_lonlat(
                dataset)
            vert_name, vert_var, _, _, vert_type = netCDF4tools.identify_vertical_axis(
                dataset)

            if len(time_var.dimensions
                   ) != 1 or time_var.dimensions[0] != time_name:
                raise IOError("Problem with time coordinate variable")
            if len(lat_var.dimensions
                   ) != 1 or lat_var.dimensions[0] != lat_name:
                raise IOError("Problem with latitude coordinate variable")
            if len(lon_var.dimensions
                   ) != 1 or lon_var.dimensions[0] != lon_name:
                raise IOError("Problem with longitude coordinate variable")

            if vert_type != "sfc":
                elevations = {"levels": vert_var[:], "units": vert_var.units}
                if vert_type in self._elevations:
                    if len(vert_var[:]) != len(
                            self._elevations[vert_type]["levels"]):
                        raise IOError(
                            "Number of vertical levels does not fit to levels of "
                            "previous file '{}'.".format(
                                self._elevations[vert_type]["filename"]))
                    if not np.allclose(vert_var[:],
                                       self._elevations[vert_type]["levels"]):
                        raise IOError(
                            "vertical levels do not fit to levels of previous "
                            "file '{}'.".format(
                                self._elevations[vert_type]["filename"]))
                    if elevations["units"] != self._elevations[vert_type][
                            "units"]:
                        raise IOError(
                            "vertical level units do not match previous file '{}'"
                            .format(self._elevations[vert_type]["filename"]))

            standard_names = []
            for ncvarname, ncvar in dataset.variables.items():
                if hasattr(ncvar, "standard_name"):
                    if (len(ncvar.dimensions) >= 3
                            and (ncvar.dimensions[0] != time_name
                                 or ncvar.dimensions[-2] != lat_name
                                 or ncvar.dimensions[-1] != lon_name)):
                        logging.error(
                            "Skipping variable '%s' in file '%s': Incorrect order of dimensions",
                            ncvarname, filename)
                        continue
                    if not hasattr(ncvar, "units"):
                        logging.error(
                            "Skipping variable '%s' in file '%s': No units attribute",
                            ncvarname, filename)
                        continue
                    if ncvar.standard_name != "time":
                        try:
                            UR(ncvar.units)
                        except (ValueError, pint.UndefinedUnitError):
                            logging.error(
                                "Skipping variable '%s' in file '%s': unparseable units attribute '%s'",
                                ncvarname, filename, ncvar.units)
                            continue
                    if len(ncvar.shape) == 4 and vert_name in ncvar.dimensions:
                        standard_names.append(ncvar.standard_name)
                    elif len(ncvar.shape) == 3 and vert_type == "sfc":
                        standard_names.append(ncvar.standard_name)
        return {
            "vert_type": vert_type,
            "elevations": elevations,
            "init_time": init_time,
            "valid_times": valid_times,
            "standard_names": standard_names
        }