コード例 #1
0
    def _test_rotated(
        self,
        grid_north_pole_latitude=90,
        grid_north_pole_longitude=0,
        north_pole_grid_longitude=0,
    ):
        cs = ics.RotatedGeogCS(
            grid_north_pole_latitude,
            grid_north_pole_longitude,
            north_pole_grid_longitude,
        )
        glon = coords.AuxCoord([359, 1],
                               "grid_longitude",
                               units="degrees",
                               coord_system=cs)
        glat = coords.AuxCoord([0, 0],
                               "grid_latitude",
                               units="degrees",
                               coord_system=cs)
        expected_path = Path([[-1, 0], [1, 0]], [Path.MOVETO, Path.LINETO])

        plt.figure()
        lines = iplt.plot(glon, glat)
        # Matplotlib won't immediately set up the correct transform to allow us
        # to compare paths. Calling set_global(), which calls set_xlim() and
        # set_ylim(), will trigger Matplotlib to set up the transform.
        ax = plt.gca()
        ax.set_global()

        crs = cs.as_cartopy_crs()
        self.check_paths(expected_path, crs, lines, ax)
コード例 #2
0
ファイル: test_netcdf.py プロジェクト: lengyanyanjing/iris
    def test_netcdf_save_gridmapping(self):
        # Test saving CF-netCDF from a cubelist with various grid mappings.

        c1 = self.cubell
        c2 = self.cubell.copy()
        c3 = self.cubell.copy()

        coord_system = icoord_systems.GeogCS(6371229)
        coord_system2 = icoord_systems.GeogCS(6371228)
        coord_system3 = icoord_systems.RotatedGeogCS(30, 30)

        c1.add_dim_coord(
            iris.coords.DimCoord(np.arange(1, 3),
                                 'latitude',
                                 long_name='1',
                                 units='degrees',
                                 coord_system=coord_system), 1)
        c1.add_dim_coord(
            iris.coords.DimCoord(np.arange(1, 3),
                                 'longitude',
                                 long_name='1',
                                 units='degrees',
                                 coord_system=coord_system), 0)

        c2.add_dim_coord(
            iris.coords.DimCoord(np.arange(1, 3),
                                 'latitude',
                                 long_name='2',
                                 units='degrees',
                                 coord_system=coord_system2), 1)
        c2.add_dim_coord(
            iris.coords.DimCoord(np.arange(1, 3),
                                 'longitude',
                                 long_name='2',
                                 units='degrees',
                                 coord_system=coord_system2), 0)

        c3.add_dim_coord(
            iris.coords.DimCoord(np.arange(1, 3),
                                 'grid_latitude',
                                 long_name='3',
                                 units='degrees',
                                 coord_system=coord_system3), 1)
        c3.add_dim_coord(
            iris.coords.DimCoord(np.arange(1, 3),
                                 'grid_longitude',
                                 long_name='3',
                                 units='degrees',
                                 coord_system=coord_system3), 0)

        cubes = iris.cube.CubeList([c1, c2, c3])
        with self.temp_filename(suffix='.nc') as file_out:
            iris.save(cubes, file_out)

            # Check the netCDF file against CDL expected output.
            self.assertCDL(file_out,
                           ('netcdf', 'netcdf_save_gridmapmulti.cdl'))
コード例 #3
0
ファイル: __init__.py プロジェクト: m1dr/iris-grib
    def _compute_extra_keys(self):
        """Compute our extra keys."""
        global unknown_string

        self.extra_keys = {}
        forecastTime = self.startStep

        # regular or rotated grid?
        try:
            longitudeOfSouthernPoleInDegrees = \
                self.longitudeOfSouthernPoleInDegrees
            latitudeOfSouthernPoleInDegrees = \
                self.latitudeOfSouthernPoleInDegrees
        except AttributeError:
            longitudeOfSouthernPoleInDegrees = 0.0
            latitudeOfSouthernPoleInDegrees = 90.0

        centre = gribapi.grib_get_string(self.grib_message, "centre")

        # default values
        self.extra_keys = {
            '_referenceDateTime': -1.0,
            '_phenomenonDateTime': -1.0,
            '_periodStartDateTime': -1.0,
            '_periodEndDateTime': -1.0,
            '_levelTypeName': unknown_string,
            '_levelTypeUnits': unknown_string,
            '_firstLevelTypeName': unknown_string,
            '_firstLevelTypeUnits': unknown_string,
            '_firstLevel': -1.0,
            '_secondLevelTypeName': unknown_string,
            '_secondLevel': -1.0,
            '_originatingCentre': unknown_string,
            '_forecastTime': None,
            '_forecastTimeUnit': unknown_string,
            '_coord_system': None,
            '_x_circular': False,
            '_x_coord_name': unknown_string,
            '_y_coord_name': unknown_string,
            # These are here to avoid repetition in the rules
            # files, and reduce the very long line lengths.
            '_x_points': None,
            '_y_points': None,
            '_cf_data': None
        }

        # cf phenomenon translation
        # Get centre code (N.B. self.centre has default type = string)
        centre_number = gribapi.grib_get_long(self.grib_message, "centre")
        # Look for a known grib1-to-cf translation (or None).
        cf_data = gptx.grib1_phenom_to_cf_info(
            table2_version=self.table2Version,
            centre_number=centre_number,
            param_number=self.indicatorOfParameter)
        self.extra_keys['_cf_data'] = cf_data

        # reference date
        self.extra_keys['_referenceDateTime'] = \
            datetime.datetime(int(self.year), int(self.month), int(self.day),
                              int(self.hour), int(self.minute))

        # forecast time with workarounds
        self.extra_keys['_forecastTime'] = forecastTime

        # verification date
        processingDone = self._get_processing_done()
        # time processed?
        if processingDone.startswith("time"):
            validityDate = str(self.validityDate)
            validityTime = "{:04}".format(int(self.validityTime))
            endYear = int(validityDate[:4])
            endMonth = int(validityDate[4:6])
            endDay = int(validityDate[6:8])
            endHour = int(validityTime[:2])
            endMinute = int(validityTime[2:4])

            # fixed forecastTime in hours
            self.extra_keys['_periodStartDateTime'] = \
                (self.extra_keys['_referenceDateTime'] +
                 datetime.timedelta(hours=int(forecastTime)))
            self.extra_keys['_periodEndDateTime'] = \
                datetime.datetime(endYear, endMonth, endDay, endHour,
                                  endMinute)
        else:
            self.extra_keys['_phenomenonDateTime'] = \
                self._get_verification_date()

        # originating centre
        # TODO #574 Expand to include sub-centre
        self.extra_keys['_originatingCentre'] = CENTRE_TITLES.get(
            centre, "unknown centre %s" % centre)

        # forecast time unit as a cm string
        # TODO #575 Do we want PP or GRIB style forecast delta?
        self.extra_keys['_forecastTimeUnit'] = self._timeunit_string()

        # shape of the earth

        # pre-defined sphere
        if self.shapeOfTheEarth == 0:
            geoid = coord_systems.GeogCS(semi_major_axis=6367470)

        # custom sphere
        elif self.shapeOfTheEarth == 1:
            geoid = coord_systems.GeogCS(
                self.scaledValueOfRadiusOfSphericalEarth *
                10**-self.scaleFactorOfRadiusOfSphericalEarth)

        # IAU65 oblate sphere
        elif self.shapeOfTheEarth == 2:
            geoid = coord_systems.GeogCS(6378160, inverse_flattening=297.0)

        # custom oblate spheroid (km)
        elif self.shapeOfTheEarth == 3:
            geoid = coord_systems.GeogCS(
                semi_major_axis=self.scaledValueOfEarthMajorAxis *
                10**-self.scaleFactorOfEarthMajorAxis * 1000.,
                semi_minor_axis=self.scaledValueOfEarthMinorAxis *
                10**-self.scaleFactorOfEarthMinorAxis * 1000.)

        # IAG-GRS80 oblate spheroid
        elif self.shapeOfTheEarth == 4:
            geoid = coord_systems.GeogCS(6378137, None, 298.257222101)

        # WGS84
        elif self.shapeOfTheEarth == 5:
            geoid = \
                coord_systems.GeogCS(6378137, inverse_flattening=298.257223563)

        # pre-defined sphere
        elif self.shapeOfTheEarth == 6:
            geoid = coord_systems.GeogCS(6371229)

        # custom oblate spheroid (m)
        elif self.shapeOfTheEarth == 7:
            geoid = coord_systems.GeogCS(
                semi_major_axis=self.scaledValueOfEarthMajorAxis *
                10**-self.scaleFactorOfEarthMajorAxis,
                semi_minor_axis=self.scaledValueOfEarthMinorAxis *
                10**-self.scaleFactorOfEarthMinorAxis)

        elif self.shapeOfTheEarth == 8:
            raise ValueError("unhandled shape of earth : grib earth shape = 8")

        else:
            raise ValueError("undefined shape of earth")

        gridType = gribapi.grib_get_string(self.grib_message, "gridType")

        if gridType in [
                "regular_ll", "regular_gg", "reduced_ll", "reduced_gg"
        ]:
            self.extra_keys['_x_coord_name'] = "longitude"
            self.extra_keys['_y_coord_name'] = "latitude"
            self.extra_keys['_coord_system'] = geoid
        elif gridType == 'rotated_ll':
            # TODO: Confirm the translation from angleOfRotation to
            # north_pole_lon (usually 0 for both)
            self.extra_keys['_x_coord_name'] = "grid_longitude"
            self.extra_keys['_y_coord_name'] = "grid_latitude"
            southPoleLon = longitudeOfSouthernPoleInDegrees
            southPoleLat = latitudeOfSouthernPoleInDegrees
            self.extra_keys['_coord_system'] = \
                coord_systems.RotatedGeogCS(
                    -southPoleLat,
                    math.fmod(southPoleLon + 180.0, 360.0),
                    self.angleOfRotation, geoid)
        elif gridType == 'polar_stereographic':
            self.extra_keys['_x_coord_name'] = "projection_x_coordinate"
            self.extra_keys['_y_coord_name'] = "projection_y_coordinate"

            if self.projectionCentreFlag == 0:
                pole_lat = 90
            elif self.projectionCentreFlag == 1:
                pole_lat = -90
            else:
                raise TranslationError("Unhandled projectionCentreFlag")

            # Note: I think the grib api defaults LaDInDegrees to 60 for grib1.
            self.extra_keys['_coord_system'] = \
                coord_systems.Stereographic(
                    pole_lat, self.orientationOfTheGridInDegrees, 0, 0,
                    self.LaDInDegrees, ellipsoid=geoid)

        elif gridType == 'lambert':
            self.extra_keys['_x_coord_name'] = "projection_x_coordinate"
            self.extra_keys['_y_coord_name'] = "projection_y_coordinate"

            flag_name = "projectionCenterFlag"

            if getattr(self, flag_name) == 0:
                pole_lat = 90
            elif getattr(self, flag_name) == 1:
                pole_lat = -90
            else:
                raise TranslationError("Unhandled projectionCentreFlag")

            LambertConformal = coord_systems.LambertConformal
            self.extra_keys['_coord_system'] = LambertConformal(
                self.LaDInDegrees,
                self.LoVInDegrees,
                0,
                0,
                secant_latitudes=(self.Latin1InDegrees, self.Latin2InDegrees),
                ellipsoid=geoid)
        else:
            raise TranslationError("unhandled grid type: {}".format(gridType))

        if gridType in ["regular_ll", "rotated_ll"]:
            self._regular_longitude_common()
            j_step = self.jDirectionIncrementInDegrees
            if not self.jScansPositively:
                j_step = -j_step
            self._y_points = (np.arange(self.Nj, dtype=np.float64) * j_step +
                              self.latitudeOfFirstGridPointInDegrees)

        elif gridType in ['regular_gg']:
            # longitude coordinate is straight-forward
            self._regular_longitude_common()
            # get the distinct latitudes, and make sure they are sorted
            # (south-to-north) and then put them in the right direction
            # depending on the scan direction
            latitude_points = gribapi.grib_get_double_array(
                self.grib_message, 'distinctLatitudes').astype(np.float64)
            latitude_points.sort()
            if not self.jScansPositively:
                # we require latitudes north-to-south
                self._y_points = latitude_points[::-1]
            else:
                self._y_points = latitude_points

        elif gridType in ["polar_stereographic", "lambert"]:
            # convert the starting latlon into meters
            cartopy_crs = self.extra_keys['_coord_system'].as_cartopy_crs()
            x1, y1 = cartopy_crs.transform_point(
                self.longitudeOfFirstGridPointInDegrees,
                self.latitudeOfFirstGridPointInDegrees, ccrs.Geodetic())

            if not np.all(np.isfinite([x1, y1])):
                raise TranslationError("Could not determine the first latitude"
                                       " and/or longitude grid point.")

            self._x_points = x1 + self.DxInMetres * np.arange(self.Nx,
                                                              dtype=np.float64)
            self._y_points = y1 + self.DyInMetres * np.arange(self.Ny,
                                                              dtype=np.float64)

        elif gridType in ["reduced_ll", "reduced_gg"]:
            self._x_points = self.longitudes
            self._y_points = self.latitudes

        else:
            raise TranslationError("unhandled grid type")
コード例 #4
0
    def test_netcdf_save_gridmapping(self):
        # Test saving CF-netCDF from a cubelist with various grid mappings.

        c1 = self.cubell
        c2 = self.cubell.copy()
        c3 = self.cubell.copy()

        coord_system = icoord_systems.GeogCS(6371229)
        coord_system2 = icoord_systems.GeogCS(6371228)
        coord_system3 = icoord_systems.RotatedGeogCS(30, 30)

        c1.add_dim_coord(
            iris.coords.DimCoord(
                np.arange(1, 3),
                "latitude",
                long_name="1",
                units="degrees",
                coord_system=coord_system,
            ),
            1,
        )
        c1.add_dim_coord(
            iris.coords.DimCoord(
                np.arange(1, 3),
                "longitude",
                long_name="1",
                units="degrees",
                coord_system=coord_system,
            ),
            0,
        )

        c2.add_dim_coord(
            iris.coords.DimCoord(
                np.arange(1, 3),
                "latitude",
                long_name="2",
                units="degrees",
                coord_system=coord_system2,
            ),
            1,
        )
        c2.add_dim_coord(
            iris.coords.DimCoord(
                np.arange(1, 3),
                "longitude",
                long_name="2",
                units="degrees",
                coord_system=coord_system2,
            ),
            0,
        )

        c3.add_dim_coord(
            iris.coords.DimCoord(
                np.arange(1, 3),
                "grid_latitude",
                long_name="3",
                units="degrees",
                coord_system=coord_system3,
            ),
            1,
        )
        c3.add_dim_coord(
            iris.coords.DimCoord(
                np.arange(1, 3),
                "grid_longitude",
                long_name="3",
                units="degrees",
                coord_system=coord_system3,
            ),
            0,
        )

        cubes = iris.cube.CubeList([c1, c2, c3])
        with self.temp_filename(suffix=".nc") as file_out:
            iris.save(cubes, file_out)

            # Check the netCDF file against CDL expected output.
            self.assertCDL(file_out,
                           ("netcdf", "netcdf_save_gridmapmulti.cdl"))
コード例 #5
0
ファイル: __init__.py プロジェクト: marqh/iris-grib
    def _compute_extra_keys(self):
        """Compute our extra keys."""
        global unknown_string

        self.extra_keys = {}
        forecastTime = self.startStep

        # regular or rotated grid?
        try:
            longitudeOfSouthernPoleInDegrees = \
                self.longitudeOfSouthernPoleInDegrees
            latitudeOfSouthernPoleInDegrees = \
                self.latitudeOfSouthernPoleInDegrees
        except AttributeError:
            longitudeOfSouthernPoleInDegrees = 0.0
            latitudeOfSouthernPoleInDegrees = 90.0

        centre = gribapi.grib_get_string(self.grib_message, "centre")

        # default values
        self.extra_keys = {'_referenceDateTime': -1.0,
                           '_phenomenonDateTime': -1.0,
                           '_periodStartDateTime': -1.0,
                           '_periodEndDateTime': -1.0,
                           '_levelTypeName': unknown_string,
                           '_levelTypeUnits': unknown_string,
                           '_firstLevelTypeName': unknown_string,
                           '_firstLevelTypeUnits': unknown_string,
                           '_firstLevel': -1.0,
                           '_secondLevelTypeName': unknown_string,
                           '_secondLevel': -1.0,
                           '_originatingCentre': unknown_string,
                           '_forecastTime': None,
                           '_forecastTimeUnit': unknown_string,
                           '_coord_system': None,
                           '_x_circular': False,
                           '_x_coord_name': unknown_string,
                           '_y_coord_name': unknown_string,
                           # These are here to avoid repetition in the rules
                           # files, and reduce the very long line lengths.
                           '_x_points': None,
                           '_y_points': None,
                           '_cf_data': None}

        # cf phenomenon translation
        # Get centre code (N.B. self.centre has default type = string)
        centre_number = gribapi.grib_get_long(self.grib_message, "centre")
        # Look for a known grib1-to-cf translation (or None).
        cf_data = gptx.grib1_phenom_to_cf_info(
            table2_version=self.table2Version,
            centre_number=centre_number,
            param_number=self.indicatorOfParameter)
        self.extra_keys['_cf_data'] = cf_data

        # reference date
        self.extra_keys['_referenceDateTime'] = \
            datetime.datetime(int(self.year), int(self.month), int(self.day),
                              int(self.hour), int(self.minute))

        # forecast time with workarounds
        self.extra_keys['_forecastTime'] = forecastTime

        # verification date
        processingDone = self._get_processing_done()
        # time processed?
        if processingDone.startswith("time"):
            validityDate = str(self.validityDate)
            validityTime = "{:04}".format(int(self.validityTime))
            endYear = int(validityDate[:4])
            endMonth = int(validityDate[4:6])
            endDay = int(validityDate[6:8])
            endHour = int(validityTime[:2])
            endMinute = int(validityTime[2:4])

            # fixed forecastTime in hours
            self.extra_keys['_periodStartDateTime'] = \
                (self.extra_keys['_referenceDateTime'] +
                 datetime.timedelta(hours=int(forecastTime)))
            self.extra_keys['_periodEndDateTime'] = \
                datetime.datetime(endYear, endMonth, endDay, endHour,
                                  endMinute)
        else:
            self.extra_keys['_phenomenonDateTime'] = \
                self._get_verification_date()

        # originating centre
        # TODO #574 Expand to include sub-centre
        self.extra_keys['_originatingCentre'] = CENTRE_TITLES.get(
            centre, "unknown centre %s" % centre)

        # forecast time unit as a cm string
        # TODO #575 Do we want PP or GRIB style forecast delta?
        self.extra_keys['_forecastTimeUnit'] = self._timeunit_string()

        # shape of the earth
        soe_code = self.shapeOfTheEarth
        # As this class is now *only* for GRIB1, 'shapeOfTheEarth' is not a
        # value read from the actual file :  It is really a GRIB2 param, and
        # the value is merely what eccodes (gribapi) gives as the default.
        # This was always = 6, until eccodes 0.19, when it changed to 0.
        # See https://jira.ecmwf.int/browse/ECC-811
        # The two represent different sized spherical earths.
        if soe_code not in (6, 0):
            raise ValueError('Unexpected shapeOfTheEarth value =', soe_code)

        soe_code = 6
        # *FOR NOW* maintain the old behaviour (radius=6371229) in all cases,
        # for backwards compatibility.
        # However, this does not match the 'radiusOfTheEarth' default from the
        # gribapi so is probably incorrect (see above issue ECC-811).
        # So we may change this in future.

        if soe_code == 0:
            # New supposedly-correct default value, matches 'radiusOfTheEarth'.
            geoid = coord_systems.GeogCS(semi_major_axis=6367470)
        elif soe_code == 6:
            # Old value, does *not* match the 'radiusOfTheEarth' parameter.
            geoid = coord_systems.GeogCS(6371229)

        gridType = gribapi.grib_get_string(self.grib_message, "gridType")

        if gridType in ["regular_ll", "regular_gg", "reduced_ll",
                        "reduced_gg"]:
            self.extra_keys['_x_coord_name'] = "longitude"
            self.extra_keys['_y_coord_name'] = "latitude"
            self.extra_keys['_coord_system'] = geoid
        elif gridType == 'rotated_ll':
            # TODO: Confirm the translation from angleOfRotation to
            # north_pole_lon (usually 0 for both)
            self.extra_keys['_x_coord_name'] = "grid_longitude"
            self.extra_keys['_y_coord_name'] = "grid_latitude"
            southPoleLon = longitudeOfSouthernPoleInDegrees
            southPoleLat = latitudeOfSouthernPoleInDegrees
            self.extra_keys['_coord_system'] = \
                coord_systems.RotatedGeogCS(
                    -southPoleLat,
                    math.fmod(southPoleLon + 180.0, 360.0),
                    self.angleOfRotation, geoid)
        elif gridType == 'polar_stereographic':
            self.extra_keys['_x_coord_name'] = "projection_x_coordinate"
            self.extra_keys['_y_coord_name'] = "projection_y_coordinate"

            if self.projectionCentreFlag == 0:
                pole_lat = 90
            elif self.projectionCentreFlag == 1:
                pole_lat = -90
            else:
                raise TranslationError("Unhandled projectionCentreFlag")

            # Note: I think the grib api defaults LaDInDegrees to 60 for grib1.
            self.extra_keys['_coord_system'] = \
                coord_systems.Stereographic(
                    pole_lat, self.orientationOfTheGridInDegrees, 0, 0,
                    self.LaDInDegrees, ellipsoid=geoid)

        elif gridType == 'lambert':
            self.extra_keys['_x_coord_name'] = "projection_x_coordinate"
            self.extra_keys['_y_coord_name'] = "projection_y_coordinate"

            flag_name = "projectionCenterFlag"

            if getattr(self, flag_name) == 0:
                pole_lat = 90
            elif getattr(self, flag_name) == 1:
                pole_lat = -90
            else:
                raise TranslationError("Unhandled projectionCentreFlag")

            LambertConformal = coord_systems.LambertConformal
            self.extra_keys['_coord_system'] = LambertConformal(
                self.LaDInDegrees, self.LoVInDegrees, 0, 0,
                secant_latitudes=(self.Latin1InDegrees, self.Latin2InDegrees),
                ellipsoid=geoid)
        else:
            raise TranslationError("unhandled grid type: {}".format(gridType))

        if gridType in ["regular_ll", "rotated_ll"]:
            self._regular_longitude_common()
            j_step = self.jDirectionIncrementInDegrees
            if not self.jScansPositively:
                j_step = -j_step
            self._y_points = (np.arange(self.Nj, dtype=np.float64) * j_step +
                              self.latitudeOfFirstGridPointInDegrees)

        elif gridType in ['regular_gg']:
            # longitude coordinate is straight-forward
            self._regular_longitude_common()
            # get the distinct latitudes, and make sure they are sorted
            # (south-to-north) and then put them in the right direction
            # depending on the scan direction
            latitude_points = gribapi.grib_get_double_array(
                    self.grib_message, 'distinctLatitudes').astype(np.float64)
            latitude_points.sort()
            if not self.jScansPositively:
                # we require latitudes north-to-south
                self._y_points = latitude_points[::-1]
            else:
                self._y_points = latitude_points

        elif gridType in ["polar_stereographic", "lambert"]:
            # convert the starting latlon into meters
            cartopy_crs = self.extra_keys['_coord_system'].as_cartopy_crs()
            x1, y1 = cartopy_crs.transform_point(
                self.longitudeOfFirstGridPointInDegrees,
                self.latitudeOfFirstGridPointInDegrees,
                ccrs.Geodetic())

            if not np.all(np.isfinite([x1, y1])):
                raise TranslationError("Could not determine the first latitude"
                                       " and/or longitude grid point.")

            self._x_points = x1 + self.DxInMetres * np.arange(self.Nx,
                                                              dtype=np.float64)
            self._y_points = y1 + self.DyInMetres * np.arange(self.Ny,
                                                              dtype=np.float64)

        elif gridType in ["reduced_ll", "reduced_gg"]:
            self._x_points = self.longitudes
            self._y_points = self.latitudes

        else:
            raise TranslationError("unhandled grid type")