---
# System prepended metadata

title: ICON4Py developer workshop - Cycle 17
tags: [gt4py team workshops]

---

Tuesday, October 17th

## Agenda

- ICON4Py structure
    - summarize which interfaces/contracts we have in icon4py
        - idea: explain icon4py in a top-down way
    - icon4py-driver: as we build up the python model and add features and lot of infrastructure: what are good approaches to keep it clean, modular, well structured.
        - goal: outline for structuring
- interfaces for components/granules (again):
    - topics:
        - python view
        - interoperability between python components
        - interoperability with other (Fortran) components 
    - options discussed so far
        - simple fields: interoperable, but long arg list
        - data manager/dictionary approach: obfuscated?, how to avoid duplicate calculation?
- How do we write stencils
    - slicing vs domain
    - do we need to add programs for every field_operator?


## ICON4Py structure

### Notes

- 2 main packages: `model` and `tools`, rest is infrastructure CI, packaging, ...
- in `model/atmosphere` each component contains a `stencil` directory
    - blue line: only wants the `stencil` directory
    - green line: the component root contains the granule glue code (e.g. control flow between stencils): `diffusion` and `dycore` have it; `advection` doesn't have it yet
    - important: each of the model components should be separated (not import each other)
    - in tests directory separated `stencil_tests` (only basic dependencies) and `dycore_tests` (have more dependencies e.g. `ghex`)
- fusing stencils:
    - Christoph: we should not inline single line field operators into the fused stencils now, because we want to not duplicate the single stencil code.
- important detail: there are several `stencil_tests` directories. If they contain an `__init__.py`, they will produce a conflict because pytest would see several modules with the same name.
    - Short term: don't do this (make the name unique)
    - Longer term: make all the names unique or make the tests directory a module (put `__init__.py` everywhere)

### Questions for discussion
- [x] Can `tools` be a separate repo? Yes. Should it be? Probably not now.
- [x] Why do `icon4pytools` depend on model?
    - Enrique: maybe for convenience in installation to avoid having a meta package that installs both (now we just install tools and get everything)
    - or maybe just a left-over after several iterations of decoupling
- [x] What does "driver" mean?
    - Will/Hannes: something you can run.
- [x] How can we make the dream of composing a model come true? Is it too early?
    - Tasmania
    - Warm bubble experiment could be a vehicle to study this

### Cleanup tasks
- [ ] Why do we have in `liskov.external.gt4py` some hard-coded strings for model components?
- [ ] Advection imports something from dycore or diffusion. Should we restructure that?
- [ ] Extract `common/interpolation` into a separate directory (than common)
- [ ] How should we resolve the problem of clashing test modules `stencil_tests`?
- [ ] How/where/who do we write down all the interfaces/contracts that the different pieces of ICON4Py have.

### Action items
- [ ] Invite Stefano to give an intro to tasmania.
    - and try to start a collaboration around FVM & EXCLAIM Python models

## How do we write stencils?

### Notes

- Can we get rid of the programs?
    - currently we need it for liskov to figure out the output fields
- Should we have the explicit domain?

### The solution

```python
mo_solve_nonhydro_stencil_54 = make_blue_line_program(_mo_solve_nonhydro_stencil_54, out ="w")
```

- [ ] do it in the icon4py cleanup

### Scratch

```python
@field_operator
def _mo_solve_nonhydro_stencil_54(
    z_raylfac: Field[[KDim], float],
    w_1: Field[[CellDim], float],
    w: Field[[CellDim, KDim], float],
) -> Field[[CellDim, KDim], float]:
    z_raylfac = broadcast(z_raylfac, (CellDim, KDim))
    w = z_raylfac * w + (1.0 - z_raylfac) * w_1
    return w

mo_solve_nonhydro_stencil_54 = make_blue_line_program(_mo..., out ="w")


@program(grid_type=GridType.UNSTRUCTURED)
def mo_solve_nonhydro_stencil_54(
    z_raylfac: Field[[KDim], float],
    w_1: Field[[CellDim], float],
    w: Field[[CellDim, KDim], float],
    # horizontal_start: int32,
    # horizontal_end: int32,
    # vertical_start: int32,
    # vertical_end: int32,
):
    _mo_solve_nonhydro_stencil_54(
        z_raylfac,
        w_1,
        w,
        out=w[:, :-1],
        # out=w[{
        #     CellDim: (horizontal_start, horizontal_end),
        #     KDim: (vertical_start, vertical_end - 1),
        # }]
        # domain={
        #     CellDim: (horizontal_start, horizontal_end),
        #     KDim: (vertical_start, vertical_end - 1),
        # },
    )
```