Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cda104c
Add single-rank test for lsq_pseudoinv factory
msimberg Mar 9, 2026
0c2ec7d
Only run some tests in ci
msimberg Mar 9, 2026
37f70ab
modified np strict references with broader array_ns
nfarabullini Mar 4, 2026
95a75d8
Update interpolation_fields.py
nfarabullini Mar 5, 2026
2e3c5b6
ran pre-commit
nfarabullini Mar 5, 2026
663ed91
removed additional but unused return val
nfarabullini Mar 5, 2026
173fcf0
Update interpolation_fields.py
nfarabullini Mar 5, 2026
a623b48
ran pre-commit
nfarabullini Mar 5, 2026
925e7cf
small fix to tuple
nfarabullini Mar 6, 2026
903a56d
Add custom dimensions for lsq coeffs field
msimberg Mar 11, 2026
f93312f
Skip Lsq dims in test that checks connectivities
msimberg Mar 16, 2026
821c5ef
Update dimensions for lsq fields from serialized data
msimberg Mar 16, 2026
3190933
Merge remote-tracking branch 'origin/main' into lsq-pseudoinv-factory…
msimberg Mar 16, 2026
81b68af
Fix lsq_pseudoinv computation in distributed setups and add test
msimberg Mar 16, 2026
cbd1495
Remove todo
msimberg Mar 17, 2026
957f10d
Uncomment testing
msimberg Mar 17, 2026
e452029
Update model/common/tests/common/grid/unit_tests/test_icon.py
msimberg Mar 17, 2026
908d971
Merge branch 'main' into lsq-pseudoinv-factory-test
nfarabullini Mar 17, 2026
e069401
Update model/common/tests/common/interpolation/unit_tests/test_interp…
msimberg Mar 17, 2026
fd0c55c
Simplify test
msimberg Mar 17, 2026
d1168ea
Move lsq dimensions
msimberg Mar 17, 2026
10974eb
Merge branch 'main' into lsq-pseudoinv-factory-test
nfarabullini Mar 17, 2026
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
54 changes: 28 additions & 26 deletions ci/default.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
include:
- local: 'ci/base.yml'

.test_model_stencils:
stage: test
script:
- nox -s "test_model-3.10(stencils, $COMPONENT)" -- --backend=$BACKEND --grid=$GRID
rules:
- if: $BACKEND == 'dace_gpu' || $BACKEND == 'gtfn_gpu'
variables:
NUM_PROCESSES: 8
SLURM_TIMELIMIT: '00:30:00'
- if: $COMPONENT == 'dycore'
variables:
SLURM_TIMELIMIT: '00:15:00'
- when: on_success
variables:
SLURM_TIMELIMIT: '00:05:00'
parallel:
matrix:
- COMPONENT: [diffusion, dycore, microphysics, muphys, common, driver]
BACKEND: [gtfn_gpu]
GRID: [simple, icon_regional]
# test_model_stencils_x86_64:
# extends: [.test_model_stencils, .test_template_x86_64]
test_model_stencils_aarch64:
extends: [.test_model_stencils, .test_template_aarch64]
# .test_model_stencils:
# stage: test
# script:
# - nox -s "test_model-3.10(stencils, $COMPONENT)" -- --backend=$BACKEND --grid=$GRID
# rules:
# - if: $BACKEND == 'dace_gpu' || $BACKEND == 'gtfn_gpu'
# variables:
# NUM_PROCESSES: 8
# SLURM_TIMELIMIT: '00:30:00'
# - if: $COMPONENT == 'dycore'
# variables:
# SLURM_TIMELIMIT: '00:15:00'
# - when: on_success
# variables:
# SLURM_TIMELIMIT: '00:05:00'
# parallel:
# matrix:
# - COMPONENT: [diffusion, dycore, microphysics, muphys, common, driver]
# BACKEND: [gtfn_gpu]
# GRID: [simple, icon_regional]
# # test_model_stencils_x86_64:
# # extends: [.test_model_stencils, .test_template_x86_64]
# test_model_stencils_aarch64:
# extends: [.test_model_stencils, .test_template_aarch64]


.test_tools_datatests:
Expand Down Expand Up @@ -57,8 +57,10 @@ test_tools_datatests_aarch64:
SLURM_TIMELIMIT: '00:15:00'
parallel:
matrix:
- COMPONENT: [advection, diffusion, dycore, microphysics, muphys, common, driver, standalone_driver]
BACKEND: [embedded, dace_gpu, gtfn_cpu, gtfn_gpu]
# - COMPONENT: [advection, diffusion, dycore, microphysics, muphys, common, driver, standalone_driver]
- COMPONENT: [common]
# BACKEND: [embedded, dace_gpu, gtfn_cpu, gtfn_gpu]
BACKEND: [dace_gpu, gtfn_cpu, gtfn_gpu]
LEVEL: [integration]
# test_model_datatests_x86_64:
# extends: [.test_model_datatests, .test_template_x86_64]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def _register_computed_fields(self) -> None:
array_ns=self._xp,
),
fields=(attrs.LSQ_PSEUDOINV,),
domain=(),
domain=(dims.CellDim, dims.KDim, dims.C2E2CDim), # TODO(msimberg): What dims to use?
deps={
"cell_center_x": geometry_attrs.CELL_CENTER_X,
"cell_center_y": geometry_attrs.CELL_CENTER_Y,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from typing import Final

import numpy as np
import scipy
from gt4py import next as gtx
from gt4py.next import where

Expand Down Expand Up @@ -1163,11 +1162,12 @@ def compute_lsq_pseudoinv(
min_rlcell_int: int,
lsq_dim_unk: int,
lsq_dim_c: int,
array_ns: ModuleType = np,
) -> data_alloc.NDArray:
for jjb in range(lsq_dim_c):
for jjk in range(lsq_dim_unk):
for jc in range(start_idx, min_rlcell_int):
u, s, v_t, _ = scipy.linalg.lapack.dgesdd(z_lsq_mat_c[jc, :, :])
u, s, v_t = array_ns.linalg.svd(z_lsq_mat_c[jc, :, :])
if cell_owner_mask[jc]:
lsq_pseudoinv[jc, :lsq_dim_unk, jjb] = (
lsq_pseudoinv[jc, :lsq_dim_unk, jjb]
Expand All @@ -1181,11 +1181,12 @@ def compute_lsq_weights_c(
lsq_weights_c_jc: data_alloc.NDArray,
lsq_dim_stencil: int,
lsq_wgt_exp: int,
array_ns: ModuleType = np,
) -> data_alloc.NDArray:
for js in range(lsq_dim_stencil):
z_norm = np.sqrt(np.dot(z_dist_g[js, :], z_dist_g[js, :]))
z_norm = array_ns.sqrt(array_ns.dot(z_dist_g[js, :], z_dist_g[js, :]))
lsq_weights_c_jc[js] = 1.0 / (z_norm**lsq_wgt_exp)
return lsq_weights_c_jc / np.max(lsq_weights_c_jc)
return lsq_weights_c_jc / array_ns.max(lsq_weights_c_jc)


def compute_z_lsq_mat_c(
Expand Down Expand Up @@ -1234,9 +1235,13 @@ def compute_lsq_coeffs(
match base_grid.GeometryType(geometry_type):
case base_grid.GeometryType.ICOSAHEDRON:
for js in range(lsq_dim_stencil):
z_dist_g[:, js, :] = np.asarray(
z_dist_g[:, js, :] = array_ns.asarray(
gnomonic_proj(
cell_lon[:], cell_lat[:], cell_lon[c2e2c[:, js]], cell_lat[c2e2c[:, js]]
cell_lon[:],
cell_lat[:],
cell_lon[c2e2c[:, js]],
cell_lat[c2e2c[:, js]],
array_ns,
)
).T

Expand All @@ -1251,21 +1256,23 @@ def compute_lsq_coeffs(
ilc_s = c2e2c[jc, :lsq_dim_stencil]
cc_cell = array_ns.zeros((lsq_dim_stencil, 2))

cc_cv = (cell_center_x[jc], cell_center_y[jc])
cc_cv = array_ns.asarray((cell_center_x[jc], cell_center_y[jc]))
for js in range(lsq_dim_stencil):
cc_cell[js, :] = diff_on_edges_torus_numpy(
cell_center_x[jc],
cell_center_y[jc],
cell_center_x[ilc_s][js],
cell_center_y[ilc_s][js],
domain_length,
domain_height,
cc_cell[js, :] = array_ns.asarray(
diff_on_edges_torus_numpy(
cell_center_x[jc],
cell_center_y[jc],
cell_center_x[ilc_s][js],
cell_center_y[ilc_s][js],
domain_length,
domain_height,
)
)
z_dist_g[jc, :, :] = cc_cell - cc_cv

for jc in range(start_idx, min_rlcell_int):
lsq_weights_c[jc, :] = compute_lsq_weights_c(
z_dist_g[jc, :, :], lsq_weights_c[jc, :], lsq_dim_stencil, lsq_wgt_exp
z_dist_g[jc, :, :], lsq_weights_c[jc, :], lsq_dim_stencil, lsq_wgt_exp, array_ns
)
z_lsq_mat_c[jc, js, :lsq_dim_unk] = compute_z_lsq_mat_c(
cell_owner_mask,
Expand All @@ -1289,6 +1296,7 @@ def compute_lsq_coeffs(
min_rlcell_int,
lsq_dim_unk,
lsq_dim_c,
array_ns,
)
if exchange != decomposition.single_node_default:
exchange(lsq_pseudoinv[:, 0, :])
Expand Down
14 changes: 10 additions & 4 deletions model/common/src/icon4py/model/common/math/projection.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#
# Please, refer to the LICENSE file in the root directory.
# SPDX-License-Identifier: BSD-3-Clause

from types import ModuleType

import numpy as np

Expand All @@ -17,6 +17,7 @@ def gnomonic_proj(
lat_c: data_alloc.NDArray,
lon: data_alloc.NDArray,
lat: data_alloc.NDArray,
array_ns: ModuleType = np,
) -> tuple[data_alloc.NDArray, data_alloc.NDArray]:
"""
Compute gnomonic projection.
Expand All @@ -38,11 +39,16 @@ def gnomonic_proj(
TODO:
replace this with a suitable library call
Comment on lines 39 to 40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we still need this TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect it's still as valid as before (this PR doesn't change the validity).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but do we need it at all? I'm just confused of what kinf of library call should be used here instead of this function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a fair question though I'll leave that consideration out of this PR.

It looks like @ajocksch added this functionality and the TODO, maybe you can comment if you think the TODO is still useful? If not, we can remove it separately.

"""
cosc = np.sin(lat_c) * np.sin(lat) + np.cos(lat_c) * np.cos(lat) * np.cos(lon - lon_c)
cosc = array_ns.sin(lat_c) * array_ns.sin(lat) + array_ns.cos(lat_c) * array_ns.cos(
lat
) * array_ns.cos(lon - lon_c)
zk = 1.0 / cosc

x = zk * np.cos(lat) * np.sin(lon - lon_c)
y = zk * (np.cos(lat_c) * np.sin(lat) - np.sin(lat_c) * np.cos(lat) * np.cos(lon - lon_c))
x = zk * array_ns.cos(lat) * array_ns.sin(lon - lon_c)
y = zk * (
array_ns.cos(lat_c) * array_ns.sin(lat)
- array_ns.sin(lat_c) * array_ns.cos(lat) * array_ns.cos(lon - lon_c)
)

return x, y

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,10 @@ def test_distributed_interpolation_lsq_pseudoinv(
parallel_helpers.log_process_properties(processor_props)
parallel_helpers.log_local_field_size(decomposition_info)
factory = interpolation_factory_from_savepoint
field_ref_1 = interpolation_savepoint.__getattribute__("lsq_pseudoinv_1")().asnumpy()
field_ref_2 = interpolation_savepoint.__getattribute__("lsq_pseudoinv_2")().asnumpy()
field_1 = factory.get(attrs.LSQ_PSEUDOINV)[:, 0, :]
field_2 = factory.get(attrs.LSQ_PSEUDOINV)[:, 1, :]
assert test_utils.dallclose(field_1, field_ref_1, atol=1e-15) # type: ignore[arg-type] # mypy does not recognize sliced array as still an array
assert test_utils.dallclose(field_2, field_ref_2, atol=1e-15) # type: ignore[arg-type] # mypy does not recognize sliced array as still an array
field_ref_1 = interpolation_savepoint.lsq_pseudoinv_1().asnumpy()
field_ref_2 = interpolation_savepoint.lsq_pseudoinv_2().asnumpy()
field = factory.get(attrs.LSQ_PSEUDOINV).asnumpy()
field_1 = field[:, 0, :]
field_2 = field[:, 1, :]
assert test_utils.dallclose(field_1, field_ref_1, atol=1e-15)
assert test_utils.dallclose(field_2, field_ref_2, atol=1e-15)
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,20 @@ def test_rbf_interpolation_coeffs_vertex(
field_v2[horizontal_start:],
atol=RBF_TOLERANCES[dims.VertexDim][experiment.name],
)


@pytest.mark.level("integration")
@pytest.mark.datatest
def test_lsq_pseudoinv(
interpolation_savepoint: serialbox.InterpolationSavepoint,
experiment: definitions.Experiment,
backend: gtx_typing.Backend | None,
) -> None:
field_ref_1 = interpolation_savepoint.lsq_pseudoinv_1().asnumpy()
field_ref_2 = interpolation_savepoint.lsq_pseudoinv_2().asnumpy()
factory = _get_interpolation_factory(backend, experiment)
field = factory.get(attrs.LSQ_PSEUDOINV).asnumpy()
field_1 = field[:, 0, :]
field_2 = field[:, 1, :]
assert test_helpers.dallclose(field_ref_1, field_1, atol=1e-15)
assert test_helpers.dallclose(field_ref_2, field_2, atol=1e-15)