コード例 #1
0
    def calc_lats_lons(cube: Cube) -> Tuple[ndarray, ndarray]:
        """
        Calculate the lats and lons of each point from a non-latlon cube,
        or output a 2d array of lats and lons, if the input cube has latitude
        and longitude coordinates.

        Args:
            cube:
                cube containing x and y axis

        Returns:
            - 2d Array of latitudes for each point.
            - 2d Array of longitudes for each point.
        """
        trg_crs = lat_lon_determine(cube)
        if trg_crs is not None:
            xycube = next(
                cube.slices([cube.coord(axis="y"),
                             cube.coord(axis="x")]))
            lats, lons = transform_grid_to_lat_lon(xycube)
        else:
            lats_row = cube.coord("latitude").points
            lons_col = cube.coord("longitude").points
            lats = np.repeat(lats_row[:, np.newaxis], len(lons_col), axis=1)
            lons = np.repeat(lons_col[np.newaxis, :], len(lats_row), axis=0)
        return lats, lons
コード例 #2
0
ファイル: grid.py プロジェクト: zfan001/improver
def calculate_input_grid_spacing(cube_in: Cube) -> Tuple[float, float]:
    """
    Calculate grid spacing in latitude and logitude.
    Check if input source grid is on even-spacing and ascending lat/lon system.

    Args:
        cube_in:
            Input source cube.

    Returns:
        - Grid spacing in latitude, in degree.
        - Grid spacing in logitude, in degree.

    Raises:
        ValueError:
            If input grid is not on a latitude/longitude system or
            input grid coordinates are not ascending.
    """
    # check if in lat/lon system
    if lat_lon_determine(cube_in) is not None:
        raise ValueError("Input grid is not on a latitude/longitude system")

    # calculate grid spacing
    lon_spacing = calculate_grid_spacing(cube_in,
                                         "degree",
                                         axis="x",
                                         rtol=1.0e-5)
    lat_spacing = calculate_grid_spacing(cube_in,
                                         "degree",
                                         axis="y",
                                         rtol=1.0e-5)

    if lon_spacing < 0 or lat_spacing < 0:
        raise ValueError("Input grid coordinates are not ascending.")
    return lat_spacing, lon_spacing
コード例 #3
0
    def calc_lats_lons(cube):
        """
        Calculate the lats and lons of each point from a non-latlon cube,
        or output a 2d array of lats and lons, if the input cube has latitude
        and longitude coordinates.

        Args:
            cube (iris.cube.Cube):
                cube containing x and y axis
        Returns:
            (tuple) : tuple containing:
                **lats** (np.array):
                    2d Array of latitudes for each point.
                **lons** (np.array):
                    2d Array of longitudes for each point.

        """
        trg_crs = lat_lon_determine(cube)
        if trg_crs is not None:
            xycube = next(
                cube.slices([cube.coord(axis='y'),
                             cube.coord(axis='x')]))
            lats, lons = transform_grid_to_lat_lon(xycube)
        else:
            lats_row = cube.coord('latitude').points
            lons_col = cube.coord('longitude').points
            lats = np.repeat(lats_row[:, np.newaxis], len(lons_col), axis=1)
            lons = np.repeat(lons_col[np.newaxis, :], len(lats_row), axis=0)
        return lats, lons
コード例 #4
0
    def _get_coordinate_pairs(cube):
        """
        Create an array containing all the pairs of coordinates that describe
        y-x points in the grid.

        Args:
            cube (iris.cube.Cube):
                The cube from which the y-x grid is being taken.
        Returns:
            numpy.array:
                A numpy array containing all the pairs of coordinates that describe
                the y-x points in the grid. This array is 2-dimensional, with
                shape (2,  (len(y-points) * len(x-points))).
        """
        if lat_lon_determine(cube) is not None:
            yy, xx = transform_grid_to_lat_lon(cube)
        else:
            latitudes = cube.coord("latitude").points
            longitudes = cube.coord("longitude").points.copy()

            # timezone finder works using -180 to 180 longitudes.
            if (longitudes > 180).any():
                longitudes[longitudes > 180] -= 180
                if ((longitudes > 180) | (longitudes < -180)).any():
                    msg = (
                        "TimezoneFinder requires longitudes between -180 "
                        "and 180 degrees. Longitude found outside that range."
                    )
                    raise ValueError(msg)
            yy, xx = np.meshgrid(latitudes, longitudes, indexing="ij")

        return np.stack([yy.flatten(), xx.flatten()], axis=1)
コード例 #5
0
    def process(self, cube):
        """
        Calculate the daynight mask for the provided cube. Note that only the
        hours and minutes of the dtval variable are used. To ensure consistent
        behaviour with changes of second or subsecond precision, the second
        component is added to the time object. This means that when the hours
        and minutes are used, we have correctly rounded to the nearest minute,
        e.g.::

           dt(2017, 1, 1, 11, 59, 59) -- +59 --> dt(2017, 1, 1, 12, 0, 58)
           dt(2017, 1, 1, 12, 0, 1)   -- +1  --> dt(2017, 1, 1, 12, 0, 2)
           dt(2017, 1, 1, 12, 0, 30)  -- +30 --> dt(2017, 1, 1, 12, 1, 0)

        Args:
            cube (iris.cube.Cube):
                input cube

        Returns:
            iris.cube.Cube:
                daynight mask cube, daytime set to self.day
                nighttime set to self.night.
                The resulting cube will be the same shape as
                the time, y, and x coordinate, other coordinates
                will be ignored although they might appear as attributes
                on the cube as it is extracted from the first slice.
        """
        daynight_mask = self._create_daynight_mask(cube)

        modified_masks = iris.cube.CubeList()
        for mask_cube in daynight_mask.slices_over("time"):
            dtval = mask_cube.coord("time").cell(0).point
            day_of_year = (dtval - dt.datetime(dtval.year, 1, 1)).days
            dtval = dtval + dt.timedelta(seconds=dtval.second)
            utc_hour = (dtval.hour * 60.0 + dtval.minute) / 60.0
            trg_crs = lat_lon_determine(mask_cube)
            # Grids that are not Lat Lon
            if trg_crs is not None:
                lats, lons = transform_grid_to_lat_lon(mask_cube)
                solar_el = calc_solar_elevation(lats, lons, day_of_year, utc_hour)
                mask_cube.data[np.where(solar_el > 0.0)] = self.day
            else:
                mask_cube = self._daynight_lat_lon_cube(
                    mask_cube, day_of_year, utc_hour
                )
            modified_masks.append(mask_cube)
        return modified_masks.merge_cube()
コード例 #6
0
    def process(self,
                target_grid: Cube,
                time: datetime,
                new_title: str = None) -> Cube:
        """Calculate the local solar time over the specified grid.

        Args:
            target_grid:
                A cube containing the desired spatial grid.
            time:
                The valid time at which to evaluate the local solar time.
            new_title:
                New title for the output cube attributes. If None, this attribute is
                left out since it has no prescribed standard.

        Returns:
            A cube containing local solar time, on the same spatial grid as target_grid.
        """

        if lat_lon_determine(target_grid) is not None:
            _, lons = transform_grid_to_lat_lon(target_grid)
        else:
            _, lons = get_grid_y_x_values(target_grid)

        day_of_year = get_day_of_year(time)
        utc_hour = get_hour_of_day(time)

        solar_time_data = calc_solar_time(lons,
                                          day_of_year,
                                          utc_hour,
                                          normalise=True)

        solar_time_cube = self._create_solar_time_cube(solar_time_data,
                                                       target_grid, time,
                                                       new_title)

        return solar_time_cube
コード例 #7
0
    def process(self, cube):
        """
        Calculate the daynight mask for the provided cube

        Args:
            cube (iris.cube.Cube):
                input cube

        Returns:
            daynight_mask (iris.cube.Cube):
                daynight mask cube, daytime set to self.day
                nighttime set to self.night.
                The resulting cube will be the same shape as
                the time, y, and x coordinate, other coordinates
                will be ignored although they might appear as attributes
                on the cube as it is extracted from the first slice.
        """
        daynight_mask = self._create_daynight_mask(cube)
        dtvalues = iris_time_to_datetime(daynight_mask.coord('time'))
        for i, dtval in enumerate(dtvalues):
            mask_cube = daynight_mask[i]
            day_of_year = (dtval - dt.datetime(dtval.year, 1, 1)).days
            utc_hour = (dtval.hour * 60.0 + dtval.minute) / 60.0
            trg_crs = lat_lon_determine(mask_cube)
            # Grids that are not Lat Lon
            if trg_crs is not None:
                lats, lons = transform_grid_to_lat_lon(mask_cube)
                solar_el = calc_solar_elevation(lats, lons, day_of_year,
                                                utc_hour)
                mask_cube.data[np.where(solar_el > 0.0)] = self.day
            else:
                mask_cube = self._daynight_lat_lon_cube(
                    mask_cube, day_of_year, utc_hour)
            daynight_mask.data[i, ::] = mask_cube.data

        return daynight_mask
コード例 #8
0
    def fast_nearest_neighbour(cube, sites, orography=None):
        """
        Use iris coord.nearest_neighbour_index function to locate the nearest
        grid point to the given latitude/longitude pair.

        Performed on a 2D-surface; consider using the much slower
        iris.analysis.trajectory.interpolate method for a more correct nearest
        neighbour search with projection onto a spherical surface; this is
        typically much slower.


        Args:
            cube/sites : See process() above.

            orography (numpy.array):
                Array of orography data extracted from an iris.cube.Cube that
                corresponds to the grids on which all other input diagnostics
                will be provided (iris.cube.Cube.data).

        Returns:
            neighbours (numpy.array):
                See process() above.

        """
        neighbours = np.empty(len(sites), dtype=[('i', 'i8'),
                                                 ('j', 'i8'),
                                                 ('dz', 'f8'),
                                                 ('edgepoint', 'bool_')])

        # Check cube coords are lat/lon, else transform lookup coordinates.
        trg_crs = lat_lon_determine(cube)

        imax = cube.coord(axis='y').shape[0]
        jmax = cube.coord(axis='x').shape[0]
        iname = cube.coord(axis='y').name()
        jname = cube.coord(axis='x').name()

        for i_site, site in enumerate(sites.values()):
            latitude, longitude, altitude = (site['latitude'],
                                             site['longitude'],
                                             site['altitude'])

            longitude, latitude = lat_lon_transform(trg_crs,
                                                    latitude, longitude)
            i_latitude, j_longitude = get_nearest_coords(
                cube, latitude, longitude, iname, jname)
            dz_site_grid = 0.

            # Calculate SpotData site vertical displacement from model
            # orography. If site altitude set with np.nan or orography data
            # is unavailable, assume site is at equivalent altitude to nearest
            # neighbour.
            if orography is not None and altitude != np.nan:
                dz_site_grid = altitude - orography[i_latitude, j_longitude]
            else:
                dz_site_grid = 0.

            neighbours[i_site] = (int(i_latitude), int(j_longitude),
                                  dz_site_grid,
                                  (i_latitude == imax or j_longitude == jmax))

        return neighbours
コード例 #9
0
    def _calc_clearsky_solar_radiation_data(
        self,
        target_grid: Cube,
        irradiance_times: List[datetime],
        surface_altitude: ndarray,
        linke_turbidity: ndarray,
        temporal_spacing: int,
    ) -> ndarray:
        """Evaluate the gridded clearsky solar radiation data over the specified period,
        calculated on the same spatial grid points as target_grid.

        Args:
            target_grid:
                Cube containing the target spatial grid on which to evaluate irradiance.
            irradiance_times:
                Datetimes at which to evaluate the irradiance data.
            surface_altitude:
                Surface altitude data, specified in metres.
            linke_turbidity:
                Linke turbidity data.
            temporal_spacing:
                The time stepping, specified in mins, used in the integration of solar
                irradiance to produce the accumulated solar radiation.

        Returns:
            Gridded irradiance values evaluated over the specified times.
        """
        if lat_lon_determine(target_grid) is not None:
            lats, lons = transform_grid_to_lat_lon(target_grid)
        else:
            lats, lons = get_grid_y_x_values(target_grid)
        irradiance_data = np.zeros(
            shape=(
                len(irradiance_times),
                target_grid.coord(axis="Y").shape[0],
                target_grid.coord(axis="X").shape[0],
            ),
            dtype=np.float32,
        )

        for time_index, time_step in enumerate(irradiance_times):

            day_of_year = get_day_of_year(time_step)
            utc_hour = get_hour_of_day(time_step)

            zenith_angle = 90.0 - calc_solar_elevation(lats, lons, day_of_year,
                                                       utc_hour)

            irradiance_data[time_index, :, :] = self._calc_clearsky_ineichen(
                zenith_angle,
                day_of_year,
                surface_altitude=surface_altitude,
                linke_turbidity=linke_turbidity,
            )

        # integrate the irradiance data along the time dimension to get the
        # accumulated solar irradiance.
        solar_radiation_data = np.trapz(irradiance_data,
                                        dx=SECONDS_IN_MINUTE *
                                        temporal_spacing,
                                        axis=0)

        return solar_radiation_data