Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IMPRO-1779 get local day #1375

Merged
merged 36 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0de840f
Starts to add a TimezoneExtraction plugin
MoseleyS Nov 19, 2020
cd4be78
Sets up output_cube
MoseleyS Nov 20, 2020
76e772f
Sets up output_cube
MoseleyS Nov 20, 2020
455d417
Removes xy-coord function (unnecessary)
MoseleyS Nov 23, 2020
dc891a3
Completes plugin and unit-tests.
MoseleyS Nov 23, 2020
2ab2c7d
Adds check for spatial coords
MoseleyS Nov 23, 2020
6fd2c20
Improves doc-string
MoseleyS Nov 23, 2020
a91862e
isort
MoseleyS Nov 23, 2020
8654be1
Improves documentation
MoseleyS Nov 23, 2020
a7b9c1d
Adds dtype checking
MoseleyS Nov 24, 2020
6365972
Merge remote-tracking branch 'upstream/master' into impro-1779-get-lo…
MoseleyS Nov 24, 2020
82e5428
generate_timezone_mask now outputs masks as int8, not int32
MoseleyS Nov 24, 2020
8533ca4
generate_timezone_mask now outputs cubes with UTC_offset coords that …
MoseleyS Nov 24, 2020
aa81b1f
generate_timezone_mask now outputs cubes with correctly-defined UTC_o…
MoseleyS Nov 24, 2020
37c87be
Adds CLI and acceptance tests
MoseleyS Nov 24, 2020
4d2ad7e
Adds unit-test for TypeError
MoseleyS Nov 24, 2020
0bae2b8
Adds handling for time-bounds on input_cube and refactors create_outp…
MoseleyS Nov 24, 2020
395dbc4
Bug fix and update of checksums following inclusion of time-bounds.
MoseleyS Nov 24, 2020
4738508
Removes the trailing Z from input local-time argument.
MoseleyS Nov 24, 2020
98c6a4e
Extends unit-test coverage
MoseleyS Nov 25, 2020
163ad72
Changes coord representation of local time from "utc" to "time_in_loc…
MoseleyS Nov 26, 2020
2e764d1
Merge remote-tracking branch 'remotes/upstream/master' into impro-177…
MoseleyS Nov 26, 2020
0d54976
Updates acceptance-test checksums following merge with least-signific…
MoseleyS Nov 26, 2020
0d1efa6
Simplifies creation of time_in_local_timezone coord to avoid using ad…
MoseleyS Nov 26, 2020
10570fe
First review
MoseleyS Nov 30, 2020
a154384
Second review
MoseleyS Dec 2, 2020
56abfd7
Second review
MoseleyS Dec 2, 2020
5f3f5ad
Second review
MoseleyS Dec 2, 2020
b3b3460
Modifies code to handle an extra dimension (e.g. percentile) on the i…
MoseleyS Dec 4, 2020
6065e42
Second review
MoseleyS Dec 4, 2020
ada985e
isort eyesore a puddy tat
MoseleyS Dec 4, 2020
7abe666
Methods that aren't tested directly are now private methods.
MoseleyS Dec 4, 2020
bdc578c
Second review: Moves call to spatial_coords_match into check_input_cu…
MoseleyS Dec 7, 2020
34886a1
Updates checksums for cell-method change.
MoseleyS Dec 7, 2020
b51a641
Merge remote-tracking branch 'remotes/upstream/master' into impro-177…
MoseleyS Dec 7, 2020
17bb94b
Corrects test for spatial coords mismatch so that it raises an error …
MoseleyS Dec 7, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Sets up output_cube
- Adds method and test to build the output_cube with appropriate meta-data
  • Loading branch information
MoseleyS committed Nov 20, 2020
commit cd4be7846af6e9c5d5bd0aec17bb288689f655cb
1 change: 1 addition & 0 deletions improver/metadata/constants/time_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

TIME_COORDS = {
"time": _TIME_REFERENCE_SPEC,
"utc": _TIME_REFERENCE_SPEC,
"forecast_reference_time": _TIME_REFERENCE_SPEC,
"forecast_period": _TIME_INTERVAL_SPEC,
}
60 changes: 38 additions & 22 deletions improver/utilities/temporal.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,40 +266,49 @@ def extract_nearest_time_point(cube, dt, time_name="time", allowed_dt_difference
class TimezoneExtraction(PostProcessingPlugin):
"""Plugin to extract local time offsets"""

def __init__(self):
self.time_coord_standards = TIME_COORDS["time"]
self.time_points = None
self.output_cube = None

def create_output_cube(self, cube, utc_time_list):
"""
Constructs the output cube and an array that will be come the time coord

Args:
cube:
utc_time_list:

Returns:

"""
template_cube = cube.slices("time").next()
template_cube = cube.slices_over("time").next().copy()
template_cube.remove_coord("time")
template_cube.remove_coord("forecast_period")
cube = create_new_diagnostic_cube(
cube.name(),
cube.units,
cube,
generate_mandatory_attributes(cube),
optional_attributes=cube.attributes,
data=np.ma.masked_all_like(cube.data).astype(cube.dtype),
self.output_cube = create_new_diagnostic_cube(
template_cube.name(),
template_cube.units,
template_cube,
generate_mandatory_attributes([template_cube]),
optional_attributes=template_cube.attributes,
data=np.ma.masked_all_like(template_cube.data).astype(template_cube.dtype),
)
time_coord_standards = TIME_COORDS["time"]
time_coord = AuxCoord(
np.ma.masked_all_like(cube.data).astype(time_coord_standards["dtype"]),
standard_name="time",
units=time_coord_standards["units"],
attributes={"calendar": time_coord_standards["calendar"]},
self.time_points = np.ma.masked_all_like(
cube.slices(self.get_xy_dims(template_cube)).next().data
).astype(self.time_coord_standards.dtype)

# Create a single valued time coordinate to help with plotting data.
utc_coord_standards = TIME_COORDS["utc"]
utc_units = cf_units.Unit(
utc_coord_standards.units, calendar=utc_coord_standards.calendar,
)
return cube
points = utc_units.date2num(utc_time_list)
points = np.round(points).astype(utc_coord_standards.dtype)
utc = AuxCoord(points, long_name="utc", units=utc_units,)
self.output_cube.add_aux_coord(utc)

@staticmethod
def get_xy_dims(cube):
dims = []
for dim in ['y', 'x']:
for dim in ["y", "x"]:
crd_name = cube.coord(axis=dim).name()
dims.append(*cube.coord_dims(crd_name))
return tuple(dims)
Expand Down Expand Up @@ -349,10 +358,17 @@ def process(self, input_cube, timezone_cube, output_utc_time_list):
The utc coord will match the output_utc_time_list supplied. All other
coords and attributes will match those found on input_cube.
"""
output_cube = self.create_output_cube(input_cube, output_utc_time_list)
self.create_output_cube(input_cube, output_utc_time_list)

self.fill_timezones(input_cube, output_cube, timezone_cube)
self.fill_timezones(input_cube, timezone_cube)

time_units = cf_units.Unit(
self.time_coord_standards.units,
calendar=self.time_coord_standards.calendar,
)
time_coord = AuxCoord(self.time_points, standard_name="time", units=time_units,)
self.output_cube.add_aux_coord(time_coord, self.get_xy_dims(self.output_cube))

self.check_all_valid(output_cube)
self.check_all_valid()

return output_cube
return self.output_cube
Empty file.
89 changes: 89 additions & 0 deletions improver_tests/utilities/temporal/test_TimezoneExtraction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# (C) British Crown Copyright 2017-2020 Met Office.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
"""Unit tests for TimezoneExtraction plugin."""

import pytest
from datetime import datetime, timedelta

import iris
import numpy as np
from iris.cube import Cube, CubeList
from iris.tests import IrisTest
from iris.time import PartialDateTime

from improver.synthetic_data.set_up_test_cubes import (
add_coordinate,
set_up_variable_cube,
)
from improver.utilities.temporal import TimezoneExtraction
from improver.utilities.warnings_handler import ManageWarnings
from improver.metadata.check_datatypes import check_mandatory_standards
from improver.metadata.constants.time_types import TIME_COORDS


def test_create_output_cube():
"""Tests that the create_output_cube method builds a cube with appropriate
meta-data"""
data_shape = (3, 3, 3)
cube = set_up_variable_cube(
np.zeros(data_shape).astype(np.float32),
standard_grid_metadata="gl_ens",
attributes={
"institution": "unknown",
"source": "IMPROVER",
"title": "Unit test",
},
)
cube = add_coordinate(
cube,
[datetime(2017, 11, 10, 4, 0) + timedelta(hours=h) for h in range(3)],
"time",
coord_units=TIME_COORDS["time"].units,
dtype=TIME_COORDS["time"].dtype,
is_datetime=True,
)
utc_time = datetime(2017, 11, 9, 12, 0)
plugin = TimezoneExtraction()
plugin.create_output_cube(cube, [utc_time])
result = plugin.output_cube
assert isinstance(result, Cube)
assert result.name() == cube.name()
assert result.units == cube.units
assert result.shape == data_shape
assert result.attributes == cube.attributes
check_mandatory_standards(result)
result_time = plugin.time_points
assert result_time.shape == (3, 3)
assert np.ma.is_masked(result_time)
assert result_time.mask.all()
result_utc = result.coord("utc")
assert [cell.point for cell in result_utc.cells()] == [datetime(2017, 11, 9, 12, 0)]
# assert result.coord_dims("time") == plugin.get_xy_dims(result)