Skip to content

Commit

Permalink
Merge branch 'release/0.19.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
floriankrb committed Dec 15, 2023
2 parents 7be631c + 5aa09fa commit 224179c
Show file tree
Hide file tree
Showing 9 changed files with 1,387 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ repos:
rev: 23.1.0
hooks:
- id: black
language_version: python3.9
language_version: python3.10
- repo: https://github.com/pycqa/isort
rev: 5.12.0
hooks:
Expand Down
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true
}
9 changes: 9 additions & 0 deletions climetlab/readers/grib/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,18 @@ def resolution(self):
y = self["DyInDegrees"]
assert x == y, (x, y)
return x
if grid_type == "lambert":
x = self["DxInMetres"]
y = self["DyInMetres"]
assert x == y, (x, y)
return x

raise ValueError(f"Unknown gridType={grid_type}")

@property
def grid_type(self):
return self.get("gridType")

def datetime(self):
date = self.handle.get("date")
time = self.handle.get("time")
Expand Down
12 changes: 12 additions & 0 deletions climetlab/readers/grib/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ def update_metadata(self, handle, metadata, compulsary):
except ValueError:
metadata["shortName"] = param

# levtype is a readOnly key in ecCodes >= 2.33.0
levtype_remap = {
"pl": "isobaricInhPa",
"ml": "hybrid",
"pt": "theta",
"pv": "potentialVorticity",
"sfc": "surface",
}
if "levtype" in metadata:
v = metadata.pop("levtype")
metadata["typeOfLevel"] = levtype_remap[v]

def handle_from_metadata(self, values, metadata, compulsary):
from .codes import CodesHandle # Lazy loading of eccodes

Expand Down
4 changes: 3 additions & 1 deletion climetlab/sources/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,9 @@ def find_numbers(source_or_dataset):
source_or_dataset, "unique_values"
), f"{source_or_dataset} (type '{type(source_or_dataset).__name__}') is not a proper source or dataset"

return source_or_dataset.unique_values("number")["number"]
return source_or_dataset.unique_values(
"number", patches={"number": {None: 0}}
)["number"]

def find_dates(source_or_dataset):
if "date" not in self.request and "time" in self.request:
Expand Down
4 changes: 4 additions & 0 deletions climetlab/sources/mars.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,5 +67,9 @@ def service(self):

raise

@classmethod
def get_datetimes(cls, request):
return None


source = MarsRetriever
109 changes: 109 additions & 0 deletions climetlab/sources/oper_accumulations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# (C) Copyright 2020 ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation
# nor does it submit to any jurisdiction.
#

import datetime
import itertools

import climetlab as cml
from climetlab import Source
from climetlab.decorators import normalize


class OperAccumulations(Source):
def __init__(self, *args, **kwargs):
request = {}
for a in args:
request.update(self.requests(**a))
request = self.requests(**kwargs)

param = request["param"]

if not isinstance(param, (list, tuple)):
param = [param]

for p in param:
assert p in ["cp", "lsp", "tp"], p

user_dates = request["date"]
user_times = request["time"]

requests = {
"oper": {"dates": set(), "times": set()},
"scda": {"dates": set(), "times": set()},
}

step = 6
requested = set()

for user_date, user_time in itertools.product(user_dates, user_times):
assert isinstance(user_date, datetime.datetime), (
type(user_date),
user_dates,
user_times,
)
assert isinstance(user_time, int), (type(user_time), user_dates, user_times)
assert user_time in [0, 6, 12, 18], user_time

when = user_date + datetime.timedelta(hours=user_time)

requested.add(when)

when -= datetime.timedelta(hours=step)
date = datetime.datetime(when.year, when.month, when.day)
time = when.hour

stream = {0: "oper", 6: "scda", 12: "oper", 18: "scda"}[time]
requests[stream]["dates"].add(date)
requests[stream]["times"].add(time)
print(requests)

dataset = dict(oper=cml.load_source("empty"), scda=cml.load_source("empty"))

for stream in ["oper", "scda"]:
dates = sorted(requests[stream]["dates"])
times = sorted(requests[stream]["times"])

if not dates and not times:
continue

assert dates, (stream, dates, times)

oper_request = dict(**request)

oper_request.update(
{
"class": "od",
"type": "fc",
"levtype": "sfc",
"stream": stream,
"date": [d.strftime("%Y-%m-%d") for d in dates],
"time": sorted(times),
"step": step,
}
)

ds = cml.load_source("mars", **oper_request)
index = [d.valid_datetime() in requested for d in ds]
dataset[stream] = ds[index]

self.ds = dataset["oper"] + dataset["scda"]

def mutate(self):
return self.ds

@normalize("date", "date-list(datetime.datetime)")
@normalize("time", "int-list")
@normalize("area", "bounding-box(list)")
def requests(self, **kwargs):
result = dict(**kwargs)

return result


source = OperAccumulations
Loading

0 comments on commit 224179c

Please sign in to comment.