---
# System prepended metadata

title: '[Greenline] Torus implementation'
tags: [cycle 31 08/25, cycle 30 07/25]

---

# [Greenline] Torus implementation

<!-- Add the tag for the current cycle number in the top bar -->

- Shaped by: Magdalena
- Appetite (FTEs, weeks):
- Developers: <!-- Filled in at the betting table unless someone is specifically required here -->

## Problem
<!-- The raw idea, a use case, or something we’ve seen that motivates us to work on this -->
ICON supports spherical (icosahedron) or torus domains. The geometry of these two domains is different. Icon4py currently implements only implements the spherical geometry properly.
As some users needed torus features some have been added in a rather hacky way.

The goal of this project is to implement the Torus consistently.









## Appetite
<!-- Explain how much time we want to spend and how that constrains the solution -->

## Solution
<!-- The core elements we came up with, presented in a form that’s easy for people to immediately understand -->
Based on the information from the grid file ICON4py should implement the necessary geometry for Torus or Sphere.

### Implementation draft
```
- GridManager: 
    - read grid file and provide an IconGrid instance with the correct GlobalGridParams`
    - read the coordinates needed to setup the Geometry (lat/lon or cartesian base on GeometryType)
- instantiate the correct GridGeometry based on the IconGrid and the using the CoordinateDict in a factory method:  
```
```python
def create_geometry(grid:IconGrid, coordinates:CoordinateDict)-> GridGeometry:
    """Factory function to issue the right geometry implementation based on the GeometryType"""
    if grid.geometry_type == GeometryType.Torus:
        return TorusGeometry(grid, coordinates)
    else:
        return SphericalGeometry(grid, coordinates:CoordinateDict)
```




```mermaid
classDiagram
    class GridGeometry
    <<abstract>> GridGeometry
    class FieldSource 
    <<interface>> FieldSource
    class TorusGeometry
    class SphericalGeometry
FieldSource <|-- GridGeometry    
GridGeometry <|-- TorusGeometry
GridGeometry <|-- SphericalGeometry

```
The `TorusGeometry` and the `SphericalGeometry` should provide the same set of fields. Practically implementing the same interface even though technically that might not be a real interface as fields are queried for with string names 


### Gridfiles
The `geometry_type` of the domain is determined by the grid file. However the exact properties depend on the origin of the grid file:
- Torus grid files are only generated by
https://gitlab.dkrz.de/mpim-sw/grid-generator/-/blob/master/src/grid_generator/mo_create_torus_grid.f90?ref_type=heads


- the icosahedron grid files are generated by both the MPI-M grid_generator or in DWD `icontools`. (standalone or web interface https://webservice.dwd.de/cgi-bin/spp1167/webservice.cgi) or downloadable here (http://icon-downloads.mpimet.mpg.de/dwd_grids.xml)


MPI-M grid generator adds a global propert `grid_geometry` that directly encodes the geometry reflecting the ICON value `t_grid_geometry_info::geometry_type` variable in ICON.
In addition they encode the torus by artificial values of `grid_root == 2 (R)` and `grid_level == 0 (B)` which are the also present in the DWD files and represent the icosahedron construction parameter `R` and `B`.


| name          | Torus (MPI-M) | Sphere (MPI-M) | Sphere (DWD) |
| ------------- | ------------- | -------------- |:------------ |
| grid_root     | 2             | R              | R            |
| grid_level    | 0             | B              | B            |
| grid_geometry | 2             | 1              | -            |

In addition, the MPI-M files contain a couple of additional numerical global attributes, which for the DWD files are computed in ICON only:


| name                  | torus                                                       | Sphere (DWD)                    | Sphere (MPI-M)                                      |     |
| --------------------- |:----------------------------------------------------------- | ------------------------------- | --------------------------------------------------- | --- |
| mean_cell_area        | edge_length^2 * sqrt(3) / 2 == edge_length^2 * sqrt(0.1875) *[i.e. area of an equal sized triangle]* | global reduction over cell_area | (surface of the sphere)/(#triangles in icosahedron) |     |
| mean_dual_edge_length | mean_dual_edge_length: edge_length * (1. / sqrt(3.0)        |                                 |                                                     |     |
| mean_edge_length      | edge_length = x_length / num_cols_x                         | -                               | Text                                                |     |

The only one currently implemented (and needed) in `icon4py` is the `mean_cell_area` for the icosahedron (see `common/grids/icon.py::compute_mean_cell_area_for_sphere`.

### Known Issues
- Computation of geometry fields in `GridGeometry` is based on lat/lon coordinates read from the grid file. The torus files contain wrong lat/lon for cell centers (@jcanton knows the details) but the cartesian coordinates are correct.
- (Probably irrelevant as the `icon4py_driver` is deprecated anyway) in the `icon4py_driver` the "special" grid_root and grid_level values are used to determine whether it is a torus or sphere (these values are passed to the cli, as we have no way to determine it from the serialize data still used in the driver). The values for `grid_root` and `grid_level` are then interchanged somewhere in the code. (@jcanton knows the details)


## Rabbit holes
<!-- Details about the solution worth calling out to avoid problems -->

## No-gos
<!-- Anything specifically excluded from the concept: functionality or use cases we intentionally aren’t covering to fit the ## appetite or make the problem tractable -->

## Progress
<!-- Don't fill during shaping. This area is for collecting TODOs during building. As first task during building add a preliminary list of coarse-grained tasks for the project and refine them with finer-grained items when it makes sense as you work on them. -->

- [x] Task 1 ([PR#xxxx](https://github.com/GridTools/gt4py/pulls))
    - [x] Subtask A
    - [x] Subtask X
- [ ] Task 2
    - [x] Subtask H
    - [ ] Subtask J
- [ ] Discovered Task 3
    - [ ] Subtask L
    - [ ] Subtask S
- [ ] Task 4

