---
# System prepended metadata

title: ICON stencils in field view examples
tags: [for_deletion]

---

# ICON stencils in field view examples

## Diffusion stencil 5

### Dusk version
```python=

from dusk.script import *

lb, nudging, interior, halo, end = HorizontalDomains(0, 1000, 2000, 3000, 4000)

@stencil
def mo_nh_diffusion_stencil_05(
    u_vert: Field[Vertex, K],
    v_vert: Field[Vertex, K],
    primal_normal_vert_v1: Field[Edge > Cell > Vertex],
    primal_normal_vert_v2: Field[Edge > Cell > Vertex],
    z_nabla2_e: Field[Edge, K],
    inv_vert_vert_length: Field[Edge],
    inv_primal_edge_length: Field[Edge],
    z_nabla4_e2: Field[Edge, K]
):
    nabv_tang: Field[Edge, K]
    nabv_norm: Field[Edge, K]
    with domain.upward.across[nudging:halo]:
        nabv_tang = sum_over(
            Edge > Cell > Vertex,
            u_vert * primal_normal_vert_v1 + v_vert * primal_normal_vert_v2,
            weights=[1.0, 1.0, 0.0, 0.0],
        )
        nabv_norm = sum_over(
            Edge > Cell > Vertex,
            u_vert * primal_normal_vert_v1 + v_vert * primal_normal_vert_v2,
            weights=[0.0, 0.0, 1.0, 1.0],
        )
        z_nabla4_e2 = 4.0 * (
            (nabv_norm - 2.0 * z_nabla2_e) * inv_vert_vert_length ** 2
            + (nabv_tang - 2.0 * z_nabla2_e) * inv_primal_edge_length ** 2
        )

```

### Field view with functions

```python=
import gt4py as gt

domain = {K: range(0,65), Edge: range(nudging, halo)}

@stencil
def vn_vert(
    weights: Field[Diamond],
    u_vert: Field[Vertex, K],
    v_vert: Field[Vertex, K],
    primal_normal_vert_v1: Field[Edge, Diamond],
    primal_normal_vert_v2: Field[Edge, Diamond]
) -> Field[Edge, Diamond]:

    return gt.sum(
            (
                u_vert(Diamond) * primal_normal_vert_v1
                + v_vert(Diamond) * primal_normal_vert_v2
            )
            * weights, # TODO need to discuss if we implicitly broadcast here or not
            axis=Diamond,
        )

@stencil
def nabv_tang(
    u_vert: Field[Vertex, K],
    v_vert: Field[Vertex, K],
    primal_normal_vert_v1: Field[Edge, Diamond],
    primal_normal_vert_v2: Field[Edge, Diamond]
) -> Field[Edge, K]:

    weights: Field[Diamond] = gt.weights([[1.0, 1.0, 0.0, 0.0]])
    return vn_vert(weights, u_vert, v_vert, primal_normal_vert_v1, primal_normal_vert_v2)

@stencil
def nabv_norm(
    u_vert: Field[Vertex, K],
    v_vert: Field[Vertex, K],
    primal_normal_vert_v1: Field[Edge, Diamond],
    primal_normal_vert_v2: Field[Edge, Diamond]
) -> Field[Edge, K]:

    weights: Field[Diamond] = gt.weights([[0.0, 0.0, 1.0, 1.0]])
    return vn_vert(weights, u_vert, v_vert, primal_normal_vert_v1, primal_normal_vert_v2)

@stencil
def z_nabla4_e2(
    nabv_norm: Field[Edge, K],
    nabv_tang: Field[Edge, K],
    z_nabla2_e: Field[Edge, K],
    inv_vert_vert_length: Field[Edge],
    inv_primal_edge_length: Field[Edge]
) -> Field[Edge, K]:

    return 4.0 * (
        (nabv_norm - 2.0 * z_nabla2_e) * inv_vert_vert_length ** 2
        + (nabv_tang - 2.0 * z_nabla2_e) * inv_primal_edge_length ** 2
    )

@fencil
def mo_nh_diffusion_stencil_05(
    u_vert: Field[Vertex, K],
    v_vert: Field[Vertex, K],
    primal_normal_vert_v1: Field[Edge, Diamond],
    primal_normal_vert_v2: Field[Edge, Diamond],
    z_nabla2_e: Field[Edge, K],
    inv_vert_vert_length: Field[Edge],
    inv_primal_edge_length: Field[Edge],
    z_nabla4_e2: Field[Edge, K]
) -> Field[Edge, K]:

    nabv_tang = nabv_tang(u_vert, v_vert, primal_normal_vert_v1, primal_normal_vert_v2)
    nabv_norm = nabv_norm(u_vert, v_vert, primal_normal_vert_v1, primal_normal_vert_v2)
    z_nabla4_e2 = z_nabla4_e2(
        nabv_norm, nabv_tang, z_nabla2_e, inv_vert_vert_length, inv_primal_edge_length
    )

    return z_nabla4_e2[domain]
```

### Field view closest to dusk

```python=
Diamond = gt.ICON.nbhdChain(Edge, Cell, Vertex)
# Hannes: currently
Diamond = offset("Diamond")

@stencil
def mo_nh_diffusion_stencil_05(
    u_vert: Field[Vertex, K],
    v_vert: Field[Vertex, K],
    primal_normal_vert_v1: Field[Diamond],
    primal_normal_vert_v2: Field[Diamond],
    z_nabla2_e: Field[Edge, K],
    inv_vert_vert_length: Field[Edge],
    inv_primal_edge_length: Field[Edge],
):
    nabv_tang = sum(
        (
            u_vert(Diamond) * primal_normal_vert_v1
            + v_vert(Diamond) * primal_normal_vert_v2
        )
        * Field(Diamond)([1.0, 1.0, 0.0, 0.0]),
        axis=Diamond,
    )
    nabv_norm = sum(
        (
            u_vert(Diamond) * primal_normal_vert_v1
            + v_vert(Diamond) * primal_normal_vert_v2
        )
        * (Field(Diamond)([0.0, 0.0, 1.0, 1.0])),
        axis=Diamond,
    )
    z_nabla4_e2 = 4.0 * (
        (nabv_norm - 2.0 * z_nabla2_e) * inv_vert_vert_length ** 2
        + (nabv_tang - 2.0 * z_nabla2_e) * inv_primal_edge_length ** 2
    )
    return z_nabla4_e2


def main(
    k_size,
    nudging,
    halo,
    u_vert,
    v_vert,
    primal_normal_vert_v1,
    primal_normal_vert_v2,
    z_nabla2_e,
    inv_vert_vert_length,
    inv_primal_edge_length,
    z_nabla4_e2,
):
    domain = {K: range(0, k_size), Edge: range(nudging, halo)}
    mo_nh_diffusion_stencil_05[domain](
        u_vert,
        v_vert,
        primal_normal_vert_v1,
        primal_normal_vert_v2,
        z_nabla2_e,
        inv_vert_vert_length,
        inv_primal_edge_length,
        out=z_nabla4_e2,
    )
```

#### Alternative reduction syntax
This is a sketch and we can discuss if we can improve.
```python=
    nabv_tang = sum(
        (
            u_vert(v) * primal_normal_vert_v1[i]
            + v_vert(v) * primal_normal_vert_v2[i]
        )
        * [1.0, 1.0, 0.0, 0.0][i] for i, v in enumerate(EdgeCellVertex)
    )
```

## Diffusion stencil 14
### Dusk version

```python=
from dusk.script import *


lb, nudging, interior, halo, end = HorizontalDomains(0, 1000, 2000, 3000, 4000)
thresh_tdiff = Global("thresh_tdiff")


@stencil
def mo_nh_diffusion_stencil_14(
    theta_v: Field[Cell, K],
    theta_ref_mc: Field[Cell, K],
    enh_diffu_3d: Field[Cell, K],
):
    tdiff: Field[Cell, K]
    trefdiff: Field[Cell, K]

    with domain.upward[-2:].across[nudging-1:halo-1]:

        tdiff = theta_v - sum_over(Cell > Edge > Cell, theta_v[Cell > Edge > Cell]) / 3

        trefdiff = (
            theta_ref_mc
            - sum_over(Cell > Edge > Cell, theta_ref_mc[Cell > Edge > Cell]) / 3
        )

        if (
            tdiff - trefdiff < thresh_tdiff
            and trefdiff < 0
            # or tdiff - trefdiff < 1.5 * thresh_tdiff MR: can't find this conditional in the ICON code!?
        ):
            enh_diffu_3d = (thresh_tdiff - tdiff + trefdiff) * 5e-4
        else:
            enh_diffu_3d = -1.7976931348623157e+308

```

### Field view closest to dusk
As a test use full type notation here, including `float`.

```python=
Triforce = gt.ICON.nbhdChain(Cell, Edge, Cell)
# Hannes: currently
Triforce = offset("Triforce")

@stencil
def mo_nh_diffusion_stencil_14(
    theta_v: Field[[Cell, K], float],
    theta_ref_mc: Field[[Cell, K], float],
    thresh_tdiff: float,
    enh_diffu_3d: Field[[Cell, K], float],
):
    tdiff = theta_v - sum(theta_v[Triforce], axis=Triforce) / 3
    trefdiff = theta_ref_mc - sum(theta_ref_mc[Triforce], axis=Triforce) / 3

    enh_diff_3d = gt.ternary(
        tdiff - trefdiff < thresh_tdiff & trefdiff < 0,
        (thresh_tdiff - tdiff + trefdiff) * 5e-4,
        -1.7976931348623157e+308,
    )
    
    return enh_diffu_3d

def main(
    k_size,
    nudging,
    halo,
    theta_v,
    theta_ref_mc,
    thresh_tdiff,
    enh_diffu_3d,
):
    domain = {K: range(k_size - 2, k_size), Cell: range(nudging - 1, halo - 1)}
    mo_nh_diffusion_stencil_14[domain](
        theta_v,
        theta_ref_mc,
        thresh_tdiff,
        out=enh_diffu_3d,
    )
```

## Diffusion stencil 18
### Dusk version

```python=
from dusk.script import *
from dusk.test import stencil_test

lb, nudging, interior, halo, end = HorizontalDomains(0, 1000, 2000, 3000, 4000)


@stencil
def mo_nh_diffusion_stencil_18(
    # This mask field is not in the original Fortran, since it builds a generic index list that contains
    # the result of masking the entire domain
    mask: Field[Cell, K],
    zd_vertidx: IndexField[Origin+Cell > Edge > Cell, K],
    zd_vertidx_p1: IndexField[Origin+Cell > Edge > Cell, K],
    zd_diffcoef: Field[Cell, K],
    geofac_n2s: Field[Origin + Cell > Edge > Cell],
    # In fortran vcoef does not contain center. It will require copying it into a new sparse field
    # that contains center with value 1, before calling codegen.
    vcoef: Field[Origin+Cell > Edge > Cell, K],
    theta_v: Field[Cell, K],
    z_temp: Field[Cell, K]):

    with domain.upward.across[nudging:end]:
        if(mask):
            z_temp += zd_diffcoef * \
                sum_over(Origin+Cell > Edge > Cell, geofac_n2s *
                        (vcoef*theta_v[Origin+Cell > Edge > Cell, zd_vertidx] +
                        (1-vcoef)*theta_v[Origin+Cell > Edge > Cell, zd_vertidx_p1 + 1]))
```

### Field view closest to dusk
As a test use full type notation here, including `float`.

```python=
Triforce = gt.ICON.nbhdChain(Cell, Edge, Cell)
# Hannes: currently
Triforce = offset("Triforce")

@stencil
def mo_nh_diffusion_stencil_18(
    mask: Field[[Cell, K], bool],
    zd_vertidx: Field[[Triforce, K], int],
    zd_vertidx_p1: Field[[Triforce, K], int],
    zd_diffcoef: Field[[Cell, K], float],
    geofac_n2s: Field[[Triforce], float],
    vcoef: Field[[Triforce, K], float],
    theta_v: Field[[Cell, K], float],
    z_temp: Field[[Cell, K], float],
):
    z_temp = gt.where(
        mask,
        z_temp +
        zd_diffcoef *
        sum(
            geofac_n2s * (vcoef * theta_v[Triforce, zd_vertidx] + (1 - vcoef) * theta_v[Triforce, zd_vertidx_p1 + 1]),
            axis=Triforce
        ),
        z_temp
    )
    
    return z_temp

def main(
    k_size,
    nudging,
    end,
    mask,
    zd_vertidx,
    zd_vertidx_p1,
    zd_diffcoef,
    geofac_n2s,
    vcoef,
    theta_v,
    z_temp,
):
    domain = {K: range(0, k_size), Cell: range(nudging, end)}
    mo_nh_diffusion_stencil_18[domain](
        mask,
        zd_vertidx,
        zd_vertidx_p1,
        zd_diffcoef,
        geofac_n2s,
        vcoef,
        theta_v,
        out=z_temp,
    )
```