Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
a7407fc
Add convergence study in horizontal advection
Oct 31, 2024
433f042
Refactor convergence study tests
Nov 8, 2024
ef89aa1
Address code style issues
Nov 26, 2024
0f8d8d0
Use lsq_dim_stencil instead of lsq_dim_c in compute_lsq_coeffs
jcanton Jul 14, 2026
ba8be0a
Fix wrong outer neighbor in SimpleGrid c2e2c2e2c_table
jcanton Jul 14, 2026
4d872fe
Add init-time WENO least-squares coefficients for miura_weno advection
jcanton Jul 14, 2026
1a49652
Add miura_weno candidate reconstruction and flux-weight stencils
jcanton Jul 14, 2026
95e9cc0
Add linear WENO reconstruction stencil for miura_weno
jcanton Jul 14, 2026
3ab145f
Wire linear WENO (ihadv_tracer=102) through the advection factory
jcanton Jul 14, 2026
c7a59af
Build linear WENO coefficients in the standalone driver
jcanton Jul 14, 2026
a4f370a
Add tracer_blob IC with prescribed advection mass fluxes
jcanton Jul 14, 2026
b5566b6
Write active tracers to the driver NetCDF output
jcanton Jul 14, 2026
08841a5
Add tracer blob translation test for miura_weno and miura
jcanton Jul 14, 2026
61494d1
Add plotting script for the tracer blob experiment
jcanton Jul 14, 2026
27df34a
Add miura3 quadratic Gauss quadrature stencil
jcanton Jul 14, 2026
5145ec8
Add miura3 WENO flux stencil
jcanton Jul 14, 2026
907f63b
Add init-time ffsl backtrajectory torus geometry for miura_weno
jcanton Jul 14, 2026
3fa8dc9
Validate compute_ffsl_backtrajectory on uniform torus flow
jcanton Jul 14, 2026
42cb37d
Add full-pipeline numpy cross-check for the miura3 WENO flux
jcanton Jul 15, 2026
797120e
Add ThirdOrderMiuraWeno quadratic WENO tracer flux (ihadv_tracer=103)
jcanton Jul 15, 2026
7aec96a
Wire quadratic WENO (ihadv_tracer=103) through the advection factory
jcanton Jul 15, 2026
54ed8fb
Build quadratic WENO coefficients in the standalone driver
jcanton Jul 15, 2026
fefb535
Extend the tracer blob test to quadratic WENO
jcanton Jul 15, 2026
278f43b
Address final whole-branch review of miura_weno
jcanton Jul 15, 2026
ac1fe10
add claude conversation
jcanton Jul 27, 2026
80c71e9
merge main
OngChia Jul 30, 2026
bb58355
mv advection test to initial condition
OngChia Aug 2, 2026
b3376fd
WIP: refactoring ic into linear_advection.py and test into linear_adv…
OngChia Aug 3, 2026
3ad0bd7
Merge branch 'main' into advection_convergence
OngChia Aug 3, 2026
23bab7b
merge main and use config yaml
OngChia Aug 6, 2026
11ecbf2
fix periodicity and add plot
OngChia Aug 7, 2026
c930b32
remove __init__.py in yaml folder
OngChia Aug 7, 2026
fa9cf46
fix a lot of bugs and achieve 1st and 0 order for hor adv
OngChia Aug 7, 2026
a290af3
WIP: add vertical advection test
OngChia Aug 7, 2026
f208481
WIP: trying to fix wrong convergence rate
OngChia Aug 10, 2026
f973e20
fix: compare advection reference at the time actually reached
jcanton Aug 10, 2026
b4cb962
fix: share one tracer-centre helper between IC and reference
jcanton Aug 10, 2026
e8afe76
feat: generate torus grids instead of downloading them
jcanton Aug 10, 2026
a630cd4
fix: correct the call signatures in the vertical advection test
jcanton Aug 11, 2026
2dd9f4f
fix bugs and updates and update vertical test
OngChia Aug 11, 2026
6f6c9bb
wip
jcanton Aug 11, 2026
34118df
docs: name the Fortran clat offset as a bug, not a convention
jcanton Aug 11, 2026
8072688
rewording
jcanton Aug 11, 2026
161a248
shorten
jcanton Aug 11, 2026
870d062
docs: draw the lattice and the slot orderings
jcanton Aug 11, 2026
4c7981c
fix bugs due to conflicts earlier
OngChia Aug 11, 2026
71faa2d
Revert "docs: draw the lattice and the slot orderings"
jcanton Aug 11, 2026
72a012c
feat: generate the torus grids with icon-grid-generator
jcanton Aug 11, 2026
99e1355
refactor: expose the torus grid generation as a fixture
jcanton Aug 11, 2026
5acb28b
build: depend on the released icon-grid-generator 0.8.0
jcanton Aug 12, 2026
9360ba3
remove plot scripts and adjust tol
OngChia Aug 13, 2026
33dde6e
merge main
OngChia Aug 13, 2026
948471e
clean uv lock
OngChia Aug 13, 2026
9b9a26c
fix unit test for linkage between dycore and adv prep adv state
OngChia Aug 13, 2026
873bf85
fix allocator in test
OngChia Aug 13, 2026
c890ae6
Merge origin/main into miura_weno
jcanton Aug 14, 2026
88ffa6c
fix float dtime and future annotation in test_driver_states
OngChia Aug 14, 2026
72e2d95
Merge advection_convergence into miura_weno
jcanton Aug 14, 2026
8472765
fix wrong import
OngChia Aug 14, 2026
52b29c9
Remove the Claude transcript committed at the repo root
jcanton Aug 14, 2026
b0571dd
Merge origin/advection_convergence into miura_weno
jcanton Aug 14, 2026
c93288f
fix float time in test_config_io
OngChia Aug 14, 2026
cdc2954
Port the monotonic horizontal flux limiter (itype_hlimit=3)
jcanton Aug 14, 2026
090307b
Glue the MIURA3 quadratic scheme together (ihadv_tracer=3)
jcanton Aug 14, 2026
fdab6e1
mv from standalone to driver
OngChia Aug 14, 2026
a8f3216
Port the subcycled MIURA (ihadv_tracer=20)
jcanton Aug 14, 2026
d3fdb68
Add the fused reconstruction+flux kernel and benchmark it against the…
jcanton Aug 14, 2026
2442f3a
Use the fused reconstruction+flux kernel in SecondOrderMiura
jcanton Aug 14, 2026
ed31aaa
Add the cubic (lsq_high_ord=3) least-squares coefficients
jcanton Aug 15, 2026
ffeae0b
Assert the measured convergence rates for the cylinder
jcanton Aug 15, 2026
cc9da9d
Add the E2C2E2C edge butterfly connectivity
jcanton Aug 15, 2026
6aa8f46
Emit a butterfly slot from the FFSL flux-area list instead of an abso…
jcanton Aug 15, 2026
ff75df1
Cover the butterfly connectivity in the grid tests, and pin the vn ==…
jcanton Aug 15, 2026
5e0f6a0
Assert the measured convergence rates for the smooth profile
jcanton Aug 15, 2026
f2c1aab
Validate the monotonic limiter against the ICON reference data
jcanton Aug 15, 2026
3f24c62
Merge remote-tracking branch 'origin/main' into miura_weno
jcanton Aug 17, 2026
35e7dd3
Merge origin/advection_convergence, and stop tracking the convergence…
jcanton Aug 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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,8 @@ venv.bak/
### Others ###
.obsidian
pyrightconfig.json

# Plots the idealized convergence studies used to write into whatever directory they were
# run from. The plotting helper itself is gone, but the pattern stays so a local run of an
# older revision cannot commit its output again.
*.pdf
39 changes: 39 additions & 0 deletions experiment_configs/linear_horizontal_advection_circle_2d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
geometry: {}
metrics: {}
interpolation: {}
vertical_grid:
num_levels: 5
model_top_height: 1000.0
lowest_layer_thickness: 0.0
topography:
config:
type: flat
initial_condition:
config:
type: lin_hor_adv
tracer_profile: circle_2d
velocity_field: constant
cfl_number: 0.11
initial_center: [0.5, 0.5]
prescribed_tendencies:
data_path:
driver:
experiment_name: horizontal_advection_convergence_test
profiling_options:
dtime: 1
start_of_simulation: 0001-01-01T00:00:00
start_of_timestepping: 0001-01-01T00:00:00
end_of_simulation:
type: relative
value: 1.0
nonhydrostatic:
diffusion:
tracer_config:
qv: true
tracer_advection:
horizontal_advection_type: linear_2nd_order
horizontal_advection_limiter: positive_definite
vertical_advection_type: no_advection
vertical_advection_limiter: no_limiter
graupel:
muphys:
40 changes: 40 additions & 0 deletions experiment_configs/linear_horizontal_advection_gaussian_2d.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
geometry: {}
metrics: {}
interpolation: {}
vertical_grid:
num_levels: 5
model_top_height: 1000.0
lowest_layer_thickness: 0.0
topography:
config:
type: flat
initial_condition:
config:
type: lin_hor_adv
tracer_profile: gaussian_2d
velocity_field: constant
cfl_number: 0.11
initial_center: [0.5, 0.5]
decay_radius: 0.25
prescribed_tendencies:
data_path:
driver:
experiment_name: horizontal_advection_convergence_test
profiling_options:
dtime: 1
start_of_simulation: 0001-01-01T00:00:00
start_of_timestepping: 0001-01-01T00:00:00
end_of_simulation:
type: relative
value: 1.0
nonhydrostatic:
diffusion:
tracer_config:
qv: true
tracer_advection:
horizontal_advection_type: linear_2nd_order
horizontal_advection_limiter: positive_definite
vertical_advection_type: no_advection
vertical_advection_limiter: no_limiter
graupel:
muphys:
39 changes: 39 additions & 0 deletions experiment_configs/linear_vertical_advection_box.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
geometry: {}
metrics: {}
interpolation: {}
vertical_grid:
num_levels: 100
model_top_height: 10000.0
lowest_layer_thickness: 0.0
topography:
config:
type: flat
initial_condition:
config:
type: lin_ver_adv
tracer_profile: box
velocity_field: constant_positive
cfl_number: 0.11
initial_center: 0.3
prescribed_tendencies:
data_path:
driver:
experiment_name: vertical_advection_convergence_test
profiling_options:
dtime: 1
start_of_simulation: 0001-01-01T00:00:00
start_of_timestepping: 0001-01-01T00:00:00
end_of_simulation:
type: relative
value: 0.4
nonhydrostatic:
diffusion:
tracer_config:
qv: true
tracer_advection:
horizontal_advection_type: no_advection
horizontal_advection_limiter: no_limiter
vertical_advection_type: ppm_3rd_order
vertical_advection_limiter: semi_monotonic
graupel:
muphys:
40 changes: 40 additions & 0 deletions experiment_configs/linear_vertical_advection_gaussian.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
geometry: {}
metrics: {}
interpolation: {}
vertical_grid:
num_levels: 100
model_top_height: 10000.0
lowest_layer_thickness: 0.0
topography:
config:
type: flat
initial_condition:
config:
type: lin_ver_adv
tracer_profile: gaussian
velocity_field: constant_positive
cfl_number: 0.11
initial_center: 0.3
decay_radius: 0.15
prescribed_tendencies:
data_path:
driver:
experiment_name: vertical_advection_convergence_test
profiling_options:
dtime: 1
start_of_simulation: 0001-01-01T00:00:00
start_of_timestepping: 0001-01-01T00:00:00
end_of_simulation:
type: relative
value: 0.4
nonhydrostatic:
diffusion:
tracer_config:
qv: true
tracer_advection:
horizontal_advection_type: no_advection
horizontal_advection_limiter: no_limiter
vertical_advection_type: ppm_3rd_order
vertical_advection_limiter: semi_monotonic
graupel:
muphys:
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
if TYPE_CHECKING:
import gt4py.next.typing as gtx_typing

from icon4py.model.common.grid import icon as icon_grid
from icon4py.model.common.grid import base as grid_base

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -234,7 +234,7 @@ class PrepAdvection:


def initialize_prep_advection(
grid: icon_grid.IconGrid, allocator: gtx_typing.Allocator
grid: grid_base.Grid, allocator: gtx_typing.Allocator
) -> PrepAdvection:
vn_traj = data_alloc.zero_field(
grid, dims.EdgeDim, dims.KDim, allocator=allocator, dtype=ta.wpfloat
Expand Down
1 change: 1 addition & 0 deletions model/atmosphere/tracer_advection/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies = [
"icon4py-common~=0.3.0",
# external dependencies
"gt4py==1.2.0",
"numpy>=1.23.3",
'packaging>=20.0'
]
description = "ICON advection."
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# ICON4Py - ICON inspired code in Python and GT4Py
#
# Copyright (c) 2022-2024, ETH Zurich and MeteoSwiss
# All rights reserved.
#
# Please, refer to the LICENSE file in the root directory.
# SPDX-License-Identifier: BSD-3-Clause

import gt4py.next as gtx
from gt4py.next import astype, where

from icon4py.model.common import dimension as dims, field_type_aliases as fa, type_alias as ta
from icon4py.model.common.dimension import E2C
from icon4py.model.common.type_alias import wpfloat


# f90 2509: literal `1d-20` regularization added to the smoothness before squaring. The gtfn
# backend does not fold a module-level constant referenced inside a field operator into the IR
# ("Symbols not found"), so the field operator inlines this literal; the tests import _WENO_EPS
# so both use one value.
_WENO_EPS = 1e-20


# WENO smoothness weighting for one of the 27 candidate stencils (mo_advection_hflux.f90
# 2497-2512). The Fortran loops over cells and scatters to the three edges owned by the upwind
# cell; here each edge gathers the candidate coefficients (and the area) of its upwind cell,
# selected by p_cell_rel_idx_dsl (0 or 1) into E2C. The weighted sums z_lsq_weighted and
# smooth_sum are accumulated over the 27 candidates, so the accumulators are read and written.


@gtx.field_operator
def _accumulate_weno_candidate_flux_weights(
p_coeff_1: fa.CellKField[ta.wpfloat],
p_coeff_2: fa.CellKField[ta.wpfloat],
p_coeff_3: fa.CellKField[ta.wpfloat],
p_coeff_4: fa.CellKField[ta.wpfloat],
p_coeff_5: fa.CellKField[ta.wpfloat],
p_coeff_6: fa.CellKField[ta.wpfloat],
cell_area: fa.CellField[ta.wpfloat],
p_cell_rel_idx_dsl: fa.EdgeKField[gtx.int32],
z_quad_vector_sum_1: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_2: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_3: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_4: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_5: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_6: fa.EdgeKField[ta.vpfloat],
z_lsq_weighted_1: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_2: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_3: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_4: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_5: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_6: fa.EdgeKField[ta.wpfloat],
smooth_sum: fa.EdgeKField[ta.wpfloat],
l_weight_s: ta.wpfloat,
) -> tuple[
fa.EdgeKField[ta.wpfloat],
fa.EdgeKField[ta.wpfloat],
fa.EdgeKField[ta.wpfloat],
fa.EdgeKField[ta.wpfloat],
fa.EdgeKField[ta.wpfloat],
fa.EdgeKField[ta.wpfloat],
fa.EdgeKField[ta.wpfloat],
]:
# gather the upwind cell's coefficients and area onto the edge (f90 backward trajectory:
# ptr_ilc/ptr_ibc select the upwind cell, mirrored by p_cell_rel_idx_dsl into E2C)
c1 = where(p_cell_rel_idx_dsl == 1, p_coeff_1(E2C[1]), p_coeff_1(E2C[0]))
c2 = where(p_cell_rel_idx_dsl == 1, p_coeff_2(E2C[1]), p_coeff_2(E2C[0]))
c3 = where(p_cell_rel_idx_dsl == 1, p_coeff_3(E2C[1]), p_coeff_3(E2C[0]))
c4 = where(p_cell_rel_idx_dsl == 1, p_coeff_4(E2C[1]), p_coeff_4(E2C[0]))
c5 = where(p_cell_rel_idx_dsl == 1, p_coeff_5(E2C[1]), p_coeff_5(E2C[0]))
c6 = where(p_cell_rel_idx_dsl == 1, p_coeff_6(E2C[1]), p_coeff_6(E2C[0]))
area = where(p_cell_rel_idx_dsl == 1, cell_area(E2C[1]), cell_area(E2C[0]))

# smoothness vector (f90 2497-2506); zlc == z_lsq_coeff, unknowns [c0, x, y, x^2, y^2, xy].
# smooth_2/3/6 use the raw c4/c5/c6, the rest use their squares (f90 squares zlc(4:6) in
# place at 2501-2503, i.e. after smooth_2/3/6 and before smooth_4/5/1).
smooth_2 = 2.0 * (c2 * c4 + c3 * c6)
smooth_3 = 2.0 * (c2 * c6 + c3 * c5)
smooth_6 = 2.0 * c6 * (c4 + c5)
c4_sq = c4 * c4
c5_sq = c5 * c5
c6_sq = c6 * c6
smooth_4 = 2.0 * (c4_sq + c6_sq)
smooth_5 = 2.0 * (c5_sq + c6_sq)
smooth_1 = c2 * c2 + c3 * c3 + area * (c4_sq + c5_sq + c6_sq)

# f90 2508-2509: smoothness = l_weights_s / (z_lsq_smooth . z_quad_vector_sum + eps)^2
beta = (
smooth_1 * astype(z_quad_vector_sum_1, wpfloat)
+ smooth_2 * astype(z_quad_vector_sum_2, wpfloat)
+ smooth_3 * astype(z_quad_vector_sum_3, wpfloat)
+ smooth_4 * astype(z_quad_vector_sum_4, wpfloat)
+ smooth_5 * astype(z_quad_vector_sum_5, wpfloat)
+ smooth_6 * astype(z_quad_vector_sum_6, wpfloat)
)
w = l_weight_s / ((beta + 1e-20) * (beta + 1e-20)) # 1e-20 == _WENO_EPS (see note above)

# f90 2510-2511: accumulate weighted coefficients and weights over the candidates
return (
z_lsq_weighted_1 + c1 * w,
z_lsq_weighted_2 + c2 * w,
z_lsq_weighted_3 + c3 * w,
z_lsq_weighted_4 + c4 * w,
z_lsq_weighted_5 + c5 * w,
z_lsq_weighted_6 + c6 * w,
smooth_sum + w,
)


@gtx.program(grid_type=gtx.GridType.UNSTRUCTURED)
def accumulate_weno_candidate_flux_weights(
p_coeff_1: fa.CellKField[ta.wpfloat],
p_coeff_2: fa.CellKField[ta.wpfloat],
p_coeff_3: fa.CellKField[ta.wpfloat],
p_coeff_4: fa.CellKField[ta.wpfloat],
p_coeff_5: fa.CellKField[ta.wpfloat],
p_coeff_6: fa.CellKField[ta.wpfloat],
cell_area: fa.CellField[ta.wpfloat],
p_cell_rel_idx_dsl: fa.EdgeKField[gtx.int32],
z_quad_vector_sum_1: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_2: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_3: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_4: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_5: fa.EdgeKField[ta.vpfloat],
z_quad_vector_sum_6: fa.EdgeKField[ta.vpfloat],
z_lsq_weighted_1: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_2: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_3: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_4: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_5: fa.EdgeKField[ta.wpfloat],
z_lsq_weighted_6: fa.EdgeKField[ta.wpfloat],
smooth_sum: fa.EdgeKField[ta.wpfloat],
l_weight_s: ta.wpfloat,
horizontal_start: gtx.int32,
horizontal_end: gtx.int32,
vertical_start: gtx.int32,
vertical_end: gtx.int32,
) -> None:
_accumulate_weno_candidate_flux_weights(
p_coeff_1=p_coeff_1,
p_coeff_2=p_coeff_2,
p_coeff_3=p_coeff_3,
p_coeff_4=p_coeff_4,
p_coeff_5=p_coeff_5,
p_coeff_6=p_coeff_6,
cell_area=cell_area,
p_cell_rel_idx_dsl=p_cell_rel_idx_dsl,
z_quad_vector_sum_1=z_quad_vector_sum_1,
z_quad_vector_sum_2=z_quad_vector_sum_2,
z_quad_vector_sum_3=z_quad_vector_sum_3,
z_quad_vector_sum_4=z_quad_vector_sum_4,
z_quad_vector_sum_5=z_quad_vector_sum_5,
z_quad_vector_sum_6=z_quad_vector_sum_6,
z_lsq_weighted_1=z_lsq_weighted_1,
z_lsq_weighted_2=z_lsq_weighted_2,
z_lsq_weighted_3=z_lsq_weighted_3,
z_lsq_weighted_4=z_lsq_weighted_4,
z_lsq_weighted_5=z_lsq_weighted_5,
z_lsq_weighted_6=z_lsq_weighted_6,
smooth_sum=smooth_sum,
l_weight_s=l_weight_s,
out=(
z_lsq_weighted_1,
z_lsq_weighted_2,
z_lsq_weighted_3,
z_lsq_weighted_4,
z_lsq_weighted_5,
z_lsq_weighted_6,
smooth_sum,
),
domain={
dims.EdgeDim: (horizontal_start, horizontal_end),
dims.KDim: (vertical_start, vertical_end),
},
)
Loading
Loading