示例#1
0
    def __init__(
        self,
        start_date: datetime = None,
        rnday: Union[int, float, timedelta] = timedelta(days=5.),
        product='medium_range_mem1',
        verbose=False,
        fallback=True,
    ):
        """This will download the latest National Water Model data.

        NetCDF files are saved to the system's temporary directory.
        The AWS data goes back 30 days. For requesting hindcast data from
        before we need a different data source
        """
        self.start_date = nearest_cycle_date() if start_date is None \
            else localize_datetime(start_date).astimezone(pytz.utc)
        self.rnday = rnday if isinstance(rnday, timedelta) \
            else timedelta(days=rnday)
        self.product = product
        self.fallback = fallback

        # if the model start_date aligns to a  "zero" with the NWM data, then
        # fetching the data is trivial
        self._files = {dt: None for dt in self.timevector}
        if self.start_date == nearest_cycle_date(self.start_date):
            self._fetch_data()

        # if they don't align then we need to inject a "zero" entry at the
        # beginning. My suggestion is to repeat the first value. Program will
        # raise if that is the case, so we can address this special case later.
        # TODO: Put a "zero" entry if start_date and NWM dates do not align.
        else:
            raise NotImplementedError(
                f'Model start_date={str(self.start_date)} is not a "pivot" '
                'time.')
示例#2
0
    def __init__(self, start_date=None, rnday=2, bbox=None):
        self.start_date = nearest_cycle_date() if start_date is None else \
            localize_datetime(start_date).astimezone(pytz.utc)
        self.rnday = rnday if isinstance(rnday, timedelta) else \
            timedelta(days=rnday)
        if self.start_date != nearest_cycle_date(self.start_date):
            raise NotImplementedError(
                'Argment start_date is does not align with any HRRR cycle '
                'times.')
        self._files = {_: None for _ in np.arange(
            self.start_date,
            self.start_date + self.rnday + self.output_interval,
            self.output_interval
        ).astype(datetime)}

        for dt in self.pivot_times:
            if None not in list(self._files.values()):
                break
            base_url = BASE_URL + f'/{self.product}' + \
                f'/hrrr{pivot_time(dt).strftime("%Y%m%d")}'
            # cycle
            for cycle in reversed(range(0, 24, int(self.output_interval.total_seconds() / 3600))):
                test_url = f'{base_url}/' + \
                           f'hrrr_sfc.t{cycle:02d}z'
                try:
                    logger.info(f'Checking url: {test_url}')
                    nc = Dataset(test_url)
                    logger.info('Success!')
                except OSError as e:
                    if e.errno == -70:
                        print()
                        continue
                    elif e.errno == -73:
                        nc = False

                        def retry():
                            try:
                                return Dataset(test_url)
                            except Exception:
                                return False

                        while not isinstance(nc, Dataset):
                            nc = retry()
                    else:
                        raise e
                file_dates = self.get_nc_datevector(nc)
                for _datetime in reversed(list(self._files.keys())):
                    if _datetime in file_dates:
                        if self._files[_datetime] is None:
                            self._files[_datetime] = nc
                if not any(nc is None for nc in self._files.values()):
                    break

        missing_records = [dt for dt, nc in self._files.items() if nc is None]
        if len(missing_records) > 0:
            raise ValueError(f'No HRRR data for dates: {missing_records}.')

        self._bbox = self._modified_bbox(bbox)
示例#3
0
 def nearest_cycle_date(self) -> datetime:
     return nearest_cycle_date(self.start_date)
示例#4
0
    def fetch_data(
            self,
            start_date: datetime = None,
            rnday: Union[float, timedelta] = 4,
            air: bool = True,
            prc: bool = True,
            rad: bool = True,
            bbox: Bbox = None,
    ):
        """Fetches HRRR data from NOMADS server. """
        logger.info('Fetching HRRR data.')
        self.start_date = nearest_cycle_date() if start_date is None else \
            localize_datetime(start_date).astimezone(pytz.utc)
        self.rnday = rnday if isinstance(rnday, timedelta) else \
            timedelta(days=rnday)
        inventory = HRRRInventory(
            self.start_date,
            self.rnday + self.output_interval,
            bbox
        )
        nx_grid, ny_grid = inventory.xy_grid()
        if air is True:
            with Dataset(
                self.tmpdir /
                f"air_{inventory.product}_"
                f"{str(self.start_date)}.nc",
                'w', format='NETCDF3_CLASSIC'
                    ) as dst:

                # global attributes
                dst.setncatts({"Conventions": "CF-1.0"})
                # dimensions
                dst.createDimension('nx_grid', nx_grid.shape[1])
                dst.createDimension('ny_grid', ny_grid.shape[0])
                dst.createDimension('time', None)
                # variables
                # lon
                dst.createVariable('lon', 'f4', ('ny_grid', 'nx_grid'))
                dst['lon'].long_name = "Longitude"
                dst['lon'].standard_name = "longitude"
                dst['lon'].units = "degrees_east"
                dst['lon'][:] = nx_grid
                # lat
                dst.createVariable('lat', 'f4', ('ny_grid', 'nx_grid'))
                dst['lat'].long_name = "Latitude"
                dst['lat'].standard_name = "latitude"
                dst['lat'].units = "degrees_north"
                dst['lat'][:] = ny_grid
                # time
                dst.createVariable('time', 'f4', ('time',))
                dst['time'].long_name = 'Time'
                dst['time'].standard_name = 'time'
                date = pivot_time(self.start_date)
                dst['time'].units = f'days since {date.year}-{date.month}'\
                                    f'-{date.day} 00:00'\
                                    f'{date.tzinfo}'
                dst['time'].base_date = (date.year, date.month, date.day, 0)
                dst['time'][:] = inventory.get_sflux_timevector()

                for var in AirComponent.var_types:
                    dst.createVariable(
                        var,
                        'f4',
                        ('time', 'ny_grid', 'nx_grid')
                    )
                    logger.info(f'Put field {var}')
                    inventory.put_sflux_field(getattr(self, f'{var}_name'), dst, var)

                # prmsl
                dst['prmsl'].long_name = "Pressure reduced to MSL"
                dst['prmsl'].standard_name = "air_pressure_at_sea_level"
                dst['prmsl'].units = "Pa"

                # spfh
                dst['spfh'].long_name = "Surface Specific Humidity "\
                                        "(2m AGL)"
                dst['spfh'].standard_name = "specific_humidity"
                dst['spfh'].units = "1"

                # stmp
                dst['stmp'].long_name = "Surface Air Temperature (2m AGL)"
                dst['stmp'].standard_name = "air_temperature"
                dst['stmp'].units = "K"

                # uwind
                dst['uwind'].long_name = "Surface Eastward Air Velocity "\
                    "(10m AGL)"
                dst['uwind'].standard_name = "eastward_wind"
                dst['uwind'].units = "m/s"

                # vwind
                dst['vwind'].long_name = "Surface Northward Air Velocity "\
                    "(10m AGL)"
                dst['vwind'].standard_name = "northward_wind"
                dst['vwind'].units = "m/s"

        if prc is True:
            with Dataset(
                self.tmpdir /
                f"prc_{inventory.product}_"
                f"{str(self.start_date)}.nc",
                'w', format='NETCDF3_CLASSIC'
                    ) as dst:

                # global attributes
                dst.setncatts({"Conventions": "CF-1.0"})
                # dimensions
                dst.createDimension('nx_grid', nx_grid.shape[1])
                dst.createDimension('ny_grid', ny_grid.shape[0])
                dst.createDimension('time', None)
                # lon
                dst.createVariable('lon', 'f4', ('ny_grid', 'nx_grid'))
                dst['lon'].long_name = "Longitude"
                dst['lon'].standard_name = "longitude"
                dst['lon'].units = "degrees_east"
                dst['lon'][:] = nx_grid
                # lat
                dst.createVariable('lat', 'f4', ('ny_grid', 'nx_grid'))
                dst['lat'].long_name = "Latitude"
                dst['lat'].standard_name = "latitude"
                dst['lat'].units = "degrees_north"
                dst['lat'][:] = ny_grid
                # time
                dst.createVariable('time', 'f4', ('time',))
                dst['time'].long_name = 'Time'
                dst['time'].standard_name = 'time'
                date = pivot_time(self.start_date)
                dst['time'].units = f'days since {date.year}-{date.month}'\
                                    f'-{date.day} 00:00'\
                                    f'{date.tzinfo}'
                dst['time'].base_date = (date.year, date.month, date.day, 0)
                dst['time'][:] = inventory.get_sflux_timevector()

                for var in PrcComponent.var_types:
                    dst.createVariable(var, float,
                                       ('time', 'ny_grid', 'nx_grid'))
                    logger.info(f'Put field {var}')
                    inventory.put_sflux_field(getattr(self, f'{var}_name'), dst, var)
                # prate
                dst['prate'].long_name = "Surface Precipitation Rate"
                dst['prate'].standard_name = "air_pressure_at_sea_level"
                dst['prate'].units = "kg/m^2/s"

        if rad is True:
            with Dataset(
                self.tmpdir /
                f"rad_{inventory.product}_"
                f"{str(self.start_date)}.nc",
                'w', format='NETCDF3_CLASSIC'
                    ) as dst:
                # global attributes
                dst.setncatts({"Conventions": "CF-1.0"})
                # dimensions
                dst.createDimension('nx_grid', nx_grid.shape[1])
                dst.createDimension('ny_grid', ny_grid.shape[0])
                dst.createDimension('time', None)
                # lon
                dst.createVariable('lon', 'f4', ('ny_grid', 'nx_grid'))
                dst['lon'].long_name = "Longitude"
                dst['lon'].standard_name = "longitude"
                dst['lon'].units = "degrees_east"
                dst['lon'][:] = nx_grid
                # lat
                dst.createVariable('lat', 'f4', ('ny_grid', 'nx_grid'))
                dst['lat'].long_name = "Latitude"
                dst['lat'].standard_name = "latitude"
                dst['lat'].units = "degrees_north"
                dst['lat'][:] = ny_grid
                # time
                dst.createVariable('time', 'f4', ('time',))
                dst['time'].long_name = 'Time'
                dst['time'].standard_name = 'time'
                date = pivot_time(self.start_date)
                dst['time'].units = f'days since {date.year}-{date.month}'\
                                    f'-{date.day} 00:00'\
                                    f'{date.tzinfo}'
                dst['time'].base_date = (date.year, date.month, date.day, 0)
                dst['time'][:] = inventory.get_sflux_timevector()

                for var in RadComponent.var_types:
                    dst.createVariable(var, float,
                                       ('time', 'ny_grid', 'nx_grid'))
                    logger.info(f'Put field {var}')
                    inventory.put_sflux_field(getattr(self, f'{var}_name'), dst, var)

                # dlwrf
                dst['dlwrf'].long_name = "Downward Long Wave Radiation "\
                                         "Flux"
                dst['dlwrf'].standard_name = "surface_downwelling_"\
                                             "longwave_flux_in_air"
                dst['dlwrf'].units = "W/m^2"

                # dswrf
                dst['dswrf'].long_name = "Downward Short Wave Radiation "\
                                         "Flux"
                dst['dswrf'].standard_name = "surface_downwelling_"\
                                             "shortwave_flux_in_air"
                dst['dswrf'].units = "W/m^2"

        self.resource = self.tmpdir
        self.air = AirComponent(self.fields)
        self.prc = PrcComponent(self.fields)
        self.rad = RadComponent(self.fields)