diff --git a/docs/gridspec.rst b/docs/gridspec.rst index 3cfda6d..f7485c9 100644 --- a/docs/gridspec.rst +++ b/docs/gridspec.rst @@ -88,3 +88,19 @@ Example: {"grid": "H512", "ordering": "ring"} {"grid": "H512"} + + +ORCA grid +------------------------------------------ + +The ``grid`` format is:: + + eORCAXXX_subtype + +The ``subtype`` must be "T", "U", "V" or "W". + +Example: + +.. code-block:: + + {"grid": "eORCA025_T"} diff --git a/docs/inventory/index.rst b/docs/inventory/index.rst index 055ef21..22788fb 100644 --- a/docs/inventory/index.rst +++ b/docs/inventory/index.rst @@ -15,3 +15,4 @@ The pages below contain all the **source and target gridspec** combinations for healpix_ring healpix_nested regular_ll + orca diff --git a/docs/inventory/orca.rst b/docs/inventory/orca.rst new file mode 100644 index 0000000..e9c6dac --- /dev/null +++ b/docs/inventory/orca.rst @@ -0,0 +1,9 @@ +.. _orca_inventory: + +orca +============== + +.. note:: + Currently, only the ``linear`` and ``nearest-neighbour`` interpolation methods are supported for ORCA grids. + +.. module-output:: generate_inventory_rst orca "ORCA" diff --git a/docs/release_notes/version_0.3_updates.rst b/docs/release_notes/version_0.3_updates.rst index 8ab9571..541f0be 100644 --- a/docs/release_notes/version_0.3_updates.rst +++ b/docs/release_notes/version_0.3_updates.rst @@ -1,6 +1,14 @@ Version 0.3 Updates ///////////////////////// +Version 0.3.5 +=============== + +Fixes +++++++++++++++++ +- added support for ORCA input grids in :func:`interpolate`. See the :ref:`ORCA inventory ` for the list of available ORCA source grids. + + Version 0.3.4 =============== diff --git a/src/earthkit/regrid/db.py b/src/earthkit/regrid/db.py index 9ce6d51..c9e046c 100644 --- a/src/earthkit/regrid/db.py +++ b/src/earthkit/regrid/db.py @@ -262,8 +262,8 @@ def load(self, path): ) for name, entry in index["matrix"].items(): - # it is possible that the inventory is already updated with new - # a gridspecs type, but a given earthkit-regrid version is not + # it is possible that the inventory is already updated with a new + # gridspecs type, but a given earthkit-regrid version is not # yet supporting it. In this case loading the index should not crash. try: in_gs = GridSpec.from_dict(entry["input"]) diff --git a/src/earthkit/regrid/gridspec.py b/src/earthkit/regrid/gridspec.py index fe1966e..21cd078 100644 --- a/src/earthkit/regrid/gridspec.py +++ b/src/earthkit/regrid/gridspec.py @@ -20,7 +20,7 @@ HEALPIX_PATTERN = re.compile(r"[Hh]\d+") RGG_PATTERN = re.compile(r"[OoNn]\d+") - +ORCA_PATTERN = re.compile(r"eORCA\d+_[TUVW]") # NOTE: this is a temporary code until the full gridspec # implementation is available via earthkit-geo. @@ -424,8 +424,24 @@ def type_match(grid): return False +class NamedGridSpec(GridSpec): + @staticmethod + def type_match(grid): + return isinstance(grid, str) + + +class OrcaGridSpec(GridSpec): + @staticmethod + def type_match(grid): + if isinstance(grid, str): + return ORCA_PATTERN.match(grid) + return False + + GRIDSPEC_TYPES = { "regular_ll": LLGridSpec, "reduced_gg": ReducedGGGridSpec, "healpix": HealpixGridSpec, + "orca": OrcaGridSpec, + # "_named": NamedGridSpec, } diff --git a/src/earthkit/regrid/utils/matrix.py b/src/earthkit/regrid/utils/matrix.py index 55a52c1..26cd467 100644 --- a/src/earthkit/regrid/utils/matrix.py +++ b/src/earthkit/regrid/utils/matrix.py @@ -53,6 +53,11 @@ def healpix(entry): return d +def orca(entry): + d = {"grid": entry["unstructuredGridType"] + "_" + entry["unstructuredGridSubtype"]} + return d + + def make_sha(d): m = hashlib.sha256() m.update(json.dumps(d, sort_keys=True).encode("utf-8")) diff --git a/tests/data/local/db/index.json b/tests/data/local/db/index.json index b3f7022..1ce015e 100644 --- a/tests/data/local/db/index.json +++ b/tests/data/local/db/index.json @@ -540,6 +540,33 @@ "version": 16, "method": "grid-box-average" } + }, + "df20c8b83afc369370e615d3380482d384cedf033af66d3962b40292c83cbb9f": { + "input": { + "grid": "eORCA025_T", + "shape": [ + 1740494 + ], + "global": 1 + }, + "output": { + "grid": "O96", + "shape": [ + 40320 + ], + "area": [ + 89.2842, + 0, + -89.2842, + 359.1 + ], + "global": 1 + }, + "interpolation": { + "engine": "mir", + "version": 16, + "method": "linear" + } } } } diff --git a/tests/test_gridspec.py b/tests/test_gridspec.py index 2b2d32b..37142c2 100644 --- a/tests/test_gridspec.py +++ b/tests/test_gridspec.py @@ -83,6 +83,7 @@ ({"grid": "H128"}, {"grid": [1, 1]}), ({"grid": "H128", "ordering": "ring"}, {"grid": [1, 1]}), ({"grid": (5, 5)}, {"grid": (10, 10)}), + ({"grid": "eORCA025_T"}, {"grid": "O96"}), ], ) def test_gridspec_ok(gs_in, gs_out): @@ -117,6 +118,8 @@ def test_gridspec_ok(gs_in, gs_out): ({"grid": "N32", "shape": 6599680}, {"grid": [10, 10]}, None), ({"grid": "N32", "area": [90, 0, -90, 359.999]}, {"grid": [10, 10]}, None), ({"grid": "N32", "area": [90, -0.1, -90, 360]}, {"grid": [10, 10]}, None), + ({"grid": "ORCA025_T"}, {"grid": "O96"}, ValueError), + ({"grid": "eORCA025_U"}, {"grid": "O96"}, None), ], ) def test_gridspec_bad(gs_in, gs_out, err): diff --git a/tests/test_local.py b/tests/test_local.py index b598bac..0dbfb60 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -47,9 +47,9 @@ def test_local_index(): index_path = DB.index_file_path() with open(index_path, "r") as f: d = json.load(f) - assert len(d["matrix"]) == 16 + assert len(d["matrix"]) == 17 - assert len(DB) == 15 + assert len(DB) == 16 # r = DB.find_entry({"grid": [5, 5]}, {"grid": [10, 10]}, method) # assert r @@ -63,6 +63,9 @@ def test_local_index(): r = DB.find_entry({"grid": "O64"}, {"grid": [10, 10]}, method) assert r is None + r = DB.find_entry({"grid": "eORCA025_T"}, {"grid": "O96"}, method) + assert r + @pytest.mark.parametrize("method", METHODS) def test_local_ll_to_ll(method): @@ -136,6 +139,23 @@ def test_local_healpix_nested_to_ll(method): assert np.allclose(v_res.flatten(), v_ref) +# TODO: implement this test +# @pytest.mark.parametrize("method", ["linear", "nearest-neighbour"]) +# def test_local_orca_to_ll(method): +# v_in = np.load(file_in_testdir("in_eorca025_t.npz"))["arr_0"] +# v_ref = np.load(file_in_testdir(f"out_eorca025_t_10x10_{method}.npz"))["arr_0"] +# v_res = interpolate( +# v_in, +# {"grid": "eORCA025_T"}, +# {"grid": [10, 10]}, +# matrix_source=DB_PATH, +# method=method, +# ) + +# assert v_res.shape == (19, 36) +# assert np.allclose(v_res.flatten(), v_ref) + + @pytest.mark.parametrize( "gs_in, gs_out", [ @@ -181,6 +201,7 @@ def test_local_healpix_nested_to_ll(method): ), ({"grid": "H4"}, {"grid": [10, 10]}), ({"grid": "H4", "ordering": "ring"}, {"grid": [10, 10]}), + ({"grid": "eORCA025_T"}, {"grid": "O96"}), ], ) def test_local_gridspec_ok(gs_in, gs_out): @@ -217,6 +238,8 @@ def test_local_gridspec_ok(gs_in, gs_out): ({"grid": "N32", "area": [90, 0, -90, 359.999]}, {"grid": [10, 10]}, None), ({"grid": "N32", "area": [90, -0.1, -90, 360]}, {"grid": [10, 10]}, None), ({"grid": "H4", "ordering": "any"}, {"grid": [10, 10]}, ValueError), + ({"grid": "ORCA025_T"}, {"grid": "O96"}, ValueError), + ({"grid": "eORCA025_U"}, {"grid": "O96"}, None), ], ) def test_local_gridspec_bad(gs_in, gs_out, err): diff --git a/tools/manage/build_db.py b/tools/manage/build_db.py index 3af6fdd..cc97820 100644 --- a/tools/manage/build_db.py +++ b/tools/manage/build_db.py @@ -94,15 +94,14 @@ ] } -in_grids = { - "N_rgg": [256], -} +in_grids = {"orca": ["eORCA025_T"]} out_grids = { - "O_rgg": [400], + # "O_rgg": [96], + "N_rgg": [320], } -build_root_dir = "_build_20241123" +build_root_dir = "_build_20241208" build_dir = os.path.join(build_root_dir, "db") # extra = [["0.25x0.25", "N320"], ["O1280", "N320"], ["5x5", "10x10"]] diff --git a/tools/manage/test_db.py b/tools/manage/test_db.py index ae07e98..a9e674f 100644 --- a/tools/manage/test_db.py +++ b/tools/manage/test_db.py @@ -29,16 +29,16 @@ This script generates and runs tests for newly built (partial) matrix inventory. """ -build_root_dir = "_build_20241021" +build_root_dir = "_build_20241208" db_dir = os.path.join(build_root_dir, "db") index_file = os.path.join(build_root_dir, "index", "index.json") test_dir = os.path.join(build_root_dir, "test") -# methods = ["linear", "nearest-neighbour"] -# build_matrix_dirs = ["matrices_linear", "matrices_nn"] +methods = ["linear", "nearest-neighbour"] +build_matrix_dirs = ["matrices_linear", "matrices_nn"] -methods = ["grid-box-average"] -build_matrix_dirs = ["matrices_grid-box-average"] +# methods = ["grid-box-average"] +# build_matrix_dirs = ["matrices_grid-box-average"] def build_test_dir(): @@ -49,6 +49,7 @@ def build_test_dir(): count = 0 for m_dir in build_matrix_dirs: m_dir = os.path.join(db_dir, m_dir) + print(f"Looking for matrices in {m_dir}") for d in glob.glob(m_dir + "/*"): if os.path.isdir(d): print(f"Linking {d}") @@ -71,15 +72,15 @@ def build_test_dir(): build_test_dir() # TODO: make the tests automatic -gs_in = {"grid": "N256"} -gs_out = {"grid": "O400"} +gs_in = {"grid": "eORCA025_T"} +gs_out = {"grid": "O96"} cnt = 0 for method in methods: - v = np.ones(348528) + v = np.ones(1740494) r = earthkit.regrid.interpolate( v, gs_in, gs_out, matrix_source=test_dir, method=method ) - assert len(r) == 654400 + assert len(r) == 40320 cnt += 1 print(f"Tests passed: {cnt}") diff --git a/tools/utils/grid.py b/tools/utils/grid.py index 0d3e41c..e7bb0f3 100644 --- a/tools/utils/grid.py +++ b/tools/utils/grid.py @@ -28,6 +28,10 @@ def make_H_nested(g): return f"H{g}_nested" +def make_other(g): + return f"{g}" + + makers = { k: globals()[f"make_{k}"] for k in ["ll", "O_rgg", "N_rgg", "H_ring", "H_nested"] } @@ -36,7 +40,7 @@ def make_H_nested(g): def make_grid_id(grids): r = [] for k, v in grids.items(): - m = makers[k] + m = makers.get(k, make_other) for x in v: r.append(m(x)) return r