def __getattr__(self, key): """Return a grib key, or one of our extra keys.""" # is it in the grib message? try: # we just get <type 'float'> as the type of the "values" array...special case here... if key in ["values", "pv", "latitudes", "longitudes"]: res = gribapi.grib_get_double_array(self.grib_message, key) elif key in ('typeOfFirstFixedSurface', 'typeOfSecondFixedSurface'): res = np.int32(gribapi.grib_get_long(self.grib_message, key)) else: key_type = gribapi.grib_get_native_type(self.grib_message, key) if key_type == int: res = np.int32(gribapi.grib_get_long(self.grib_message, key)) elif key_type == float: # Because some computer keys are floats, like # longitudeOfFirstGridPointInDegrees, a float32 is not always enough... res = np.float64(gribapi.grib_get_double(self.grib_message, key)) elif key_type == str: res = gribapi.grib_get_string(self.grib_message, key) else: raise ValueError("Unknown type for %s : %s" % (key, str(key_type))) except gribapi.GribInternalError: res = None #...or is it in our list of extras? if res is None: if key in self.extra_keys: res = self.extra_keys[key] else: #must raise an exception for the hasattr() mechanism to work raise AttributeError("Cannot find GRIB key %s" % key) return res
def _compute_extra_keys(self): """Compute our extra keys.""" global unknown_string self.extra_keys = {} # work out stuff based on these values from the message edition = self.edition # time-processed forcast time is from reference time to start of period if edition == 2: forecastTime = self.forecastTime uft = np.uint32(forecastTime) BILL = 2**30 # Workaround grib api's assumption that forecast time is positive. # Handles correctly encoded -ve forecast times up to one -1 billion. if hindcast_workaround: if 2 * BILL < uft < 3 * BILL: msg = "Re-interpreting negative forecastTime from " \ + str(forecastTime) forecastTime = -(uft - 2 * BILL) msg += " to " + str(forecastTime) warnings.warn(msg) else: 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 if edition == 1: # 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 elif edition == 2: # Don't attempt to interpret params if 'master tables version' is # 255, as local params may then have same codes as standard ones. if self.tablesVersion != 255: # Look for a known grib2-to-cf translation (or None). cf_data = gptx.grib2_phenom_to_cf_info( param_discipline=self.discipline, param_category=self.parameterCategory, param_number=self.parameterNumber) 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"): if self.edition == 1: 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]) elif self.edition == 2: endYear = self.yearOfEndOfOverallTimeInterval endMonth = self.monthOfEndOfOverallTimeInterval endDay = self.dayOfEndOfOverallTimeInterval endHour = self.hourOfEndOfOverallTimeInterval endMinute = self.minuteOfEndOfOverallTimeInterval # 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'] = \ iris.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'] = \ iris.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" if self.edition == 1: flag_name = "projectionCenterFlag" else: flag_name = "projectionCentreFlag" if getattr(self, flag_name) == 0: pole_lat = 90 elif getattr(self, flag_name) == 1: pole_lat = -90 else: raise TranslationError("Unhandled projectionCentreFlag") LambertConformal = iris.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")
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")
file = open('z500.grb') #Getting the first message from the file field = grib.grib_new_from_file(file) nj = grib.grib_get(field, "Nj") ni = grib.grib_get(field, "Ni") metadata = { "paramId": grib.grib_get(field, "paramId"), "units": grib.grib_get(field, "units"), "typeOfLevel": grib.grib_get(field, "typeOfLevel"), "marsType": grib.grib_get(field, "marsType"), "marsClass": grib.grib_get(field, "marsClass"), "marsStream": grib.grib_get_string(field, "marsStream"), "level": grib.grib_get(field, "level") } firstlat = grib.grib_get(field, "latitudeOfFirstGridPointInDegrees") steplat = -grib.grib_get(field, "jDirectionIncrementInDegrees") firstlon = grib.grib_get(field, "longitudeOfFirstGridPointInDegrees") steplon = grib.grib_get(field, "iDirectionIncrementInDegrees") #Getting the field values values = grib.grib_get_values(field).reshape(grib.grib_get(field, "Nj"), grib.grib_get(field, "Ni")) #Convert from Kelvin to Celsius values = values
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")