# Further Develop icon-liskov
###### tags: `functional cycle 13`
Developers: Samuel
Support: Matthias, (Christoph)
Appetite: Full Cycle
## Background
In cycle 12, icon-liskov, a DSL preprocessor was developed. It is currently albe to support ~70% of the icon-exclaim stencils. Hence, the goal of this project is to extend support of DSL preprocesor to the complete icon-exclaim codebase and make icon-liskov used in the integration.
This enables running CPU and plain OpenACC with the dsl branch.
## Known Steps
* Elicit requirements for the 30% missing stencils
* Come up with a plan to implement those requirements
* Make the icon-exclaim integration use icon-liskov
* Might be not so easy because icon-liskov generates new `*.f90` files. The icon build system itself needs to be instruted to disregard the old files but compile the new ones
* Maybe pp_ser can be used as a reference
## Non Goals
Do not try to solve stencil fusion
## Integration Code Targets
total: 111/111
### mo_nh_diffusion
17/17
**Supported**
- [x] IMPORTS statement
- [x] DECLARE statement
- [x] DATA CREATE statement
- [x] temporary_fields_for_turbulance_diagnostics
- [x] calculate_nabla4
- [x] apply_nabla2_and_nabla4_to_vn
- [x] apply_nabla2_to_vn_in_lateral_boundary
- [x] calculate_nabla2_for_w
- [x] calculate_horizontal_gradients_for_turbulance
- [x] apply_nabla2_to_w
- [x] apply_nabla2_to_w_in_upper_damping_layer
- [x] calculate_nabla2_for_z
- [x] calculate_nabla2_of_theta
- [x] update_theta_and_exner
- [x] calculate_nabla2_and_smag_coefficients_for_vn
- [x] calculate_diagnostics_for_turbulance
- [x] temporary_field_for_grid_point_cold_pools_enhancement
- [x] enhance_diffusion_coefficient_for_grid_point_cold_pools
- [x] mo_nh_diffusion_stencil_15
- [x] apply_nabla2_and_nabla4_global_to_vn
### Subroutine stencils
6/6
- [x] mo_math_divrot_rot_vertex_ri_dsl - src/shr_horizontal/mo_math_divrot.f90
- [x] mo_icon_interpolation_scalar_cells2verts_scalar_ri_dsl
- [x] mo_intp_rbf_rbf_vec_interpol_vertex - src/shr_horizontal/mo_intp_rbf.f90
- [x] mo_math_gradients_grad_green_gauss_cell_dsl - src/shr_horizontal/mo_math_gradients.f90
- [x] mo_advection_traj_btraj_compute_o1_dsl - src/advection/mo_advection_traj.f90
### mo_solve_nonhydro
70/70
**Supported**
- [x] IMPORTS statement
- [x] DATA CREATE statement
- [x] mo_solve_nonhydro_02
- [x] mo_solve_nonhydro_03
- [x] mo_solve_nonhydro_04
- [x] mo_solve_nonhydro_05
- [x] mo_solve_nonhydro_09
- [x] mo_solve_nonhydro_10
- [x] mo_solve_nonhydro_11_lower
- [x] mo_solve_nonhydro_11_upper
- [x] mo_solve_nonhydro_14
- [x] mo_solve_nonhydro_15
- [x] mo_solve_nonhydro_17
- [x] mo_solve_nonhydro_18
- [x] mo_solve_nonhydro_19
- [x] mo_solve_nonhydro_25
- [x] mo_solve_nonhydro_30
- [x] mo_solve_nonhydro_31
- [x] mo_solve_nonhydro_32
- [x] mo_solve_nonhydro_33
- [x] mo_solve_nonhydro_34
- [x] mo_solve_nonhydro_35
- [x] mo_solve_nonhydro_36
- [x] mo_solve_nonhydro_39
- [x] mo_solve_nonhydro_40
- [x] mo_solve_nonhydro_41
- [x] mo_solve_nonhydro_42
- [x] mo_solve_nonhydro_43
- [x] mo_solve_nonhydro_44
- [x] mo_solve_nonhydro_48
- [x] mo_solve_nonhydro_49
- [x] mo_solve_nonhydro_50
- [x] mo_solve_nonhydro_56_63
- [x] mo_solve_nonhydro_57
- [x] mo_solve_nonhydro_58
- [x] mo_solve_nonhydro_59
- [x] mo_solve_nonhydro_60
- [x] mo_solve_nonhydro_64
- [x] mo_solve_nonhydro_65
- [x] mo_solve_nonhydro_68
- [x] mo_solve_nonhydro_67
- [x] mo_solve_nonhydro_62
- [x] mo_solve_nonhydro_61
- [x] mo_solve_nonhydro_55
- [x] mo_solve_nonhydro_54
- [x] mo_solve_nonhydro_27
- [x] mo_solve_nonhydro_29
- [x] mo_solve_nonhydro_28
- [x] mo_solve_nonhydro_26
- [x] mo_solve_nonhydro_24
- [x] mo_solve_nonhydro_23
- [x] mo_solve_nonhydro_56_63
- [x] mo_solve_nonhydro_01
- [x] mo_solve_nonhydro_07
- [x] mo_solve_nonhydro_08
- [x] mo_solve_nonhydro_12
- [x] mo_solve_nonhydro_47
- [x] mo_solve_nonhydro_46
- [x] mo_solve_nonhydro_06
- [x] mo_solve_nonhydro_13
- [x] mo_solve_nonhydro_22
- [x] mo_solve_nonhydro_66
- [x] mo_solve_nonhydro_16
- [x] mo_solve_nonhydro_20
- [x] mo_solve_nonhydro_52
- [x] mo_solve_nonhydro_53
- [x] mo_solve_nonhydro_4th_order_divdamp
- [x] mo_solve_nonhydro_45
- [x] mo_solve_nonhydro_45_b
- [x] mo_solve_nonhydro_37
- [x] mo_solve_nonhydro_38
- [x] mo_solve_nonhydro_21
### mo_velocity_advection
20/20
**supported**
- [x] IMPORT statement
- [x] DATA CREATE statement
- [x] mo_velocity_advection_stencil_01
- [x] mo_velocity_advection_stencil_02
- [x] mo_velocity_advection_stencil_03
- [x] mo_velocity_advection_stencil_04
- [x] mo_velocity_advection_stencil_08
- [x] mo_velocity_advection_stencil_09
- [x] mo_velocity_advection_stencil_10
- [x] mo_velocity_advection_stencil_11
- [x] mo_velocity_advection_stencil_12
- [x] mo_velocity_advection_stencil_13
- [x] mo_velocity_advection_stencil_15
- [x] wrap_run_mo_velocity_advection_stencil_16
- [x] wrap_run_mo_velocity_advection_stencil_17
- [x] wrap_run_mo_velocity_advection_stencil_19
- [x] wrap_run_mo_velocity_advection_stencil_20
- [x] mo_velocity_advection_stencil_07
- [x] wrap_run_mo_velocity_advection_stencil_05
- [x] wrap_run_mo_velocity_advection_stencil_06
- [x] wrap_run_mo_velocity_advection_stencil_18
- [x] wrap_run_mo_velocity_advection_stencil_14
## Todo
- [x] Move setting `dsl_verify` to `START DATA CREATE`.
- [x] Research requirements for the implementation of the remaining stencil patterns.
- [x] Improve UnbalancedDirectiveError message.
- [x] Allow start and end stencil directives to be repeated.
- [x] Add `noendif` kwarg to `END STENCIL DATA`
- [x] Add `ENDIF` directive.
- [x] Rename stencils according to renaming changes in icon4py.
- [x] Ensure fields generated in `START DATA CREATE` are unique.
- [x] Ensure fields generated in `IMPORTS` are unique.
- [x] Add test for stencil with wrong kwargs for noendif, noprofile.
- [x] Improve UnknownStencilError message.
- [x] Use decorator for pipeline functions.
- [x] Update README.
- [x] Add generation metadata.
- [x] Build integration.
- [x] Add last remaining stencil.
- [x] Add metadata and profile flag to configure.ac
## Notes
- In Fortran variables must be declared before they are used. So setting `dsl_verify` should be done as part of `START CREATE()`.
- Should icon-liskov generate these includes as well?
```fortran
USE cudafor
USE nvtx
```
## Currently unsupported patterns
### Call to func in DO loop *(fixed)*
```fortran=
CALL get_indices_e(p_patch, jb, i_startblk, i_endblk, i_startidx, i_endidx, rl_start, rl_end)
call nvtxStartRange("enhance_diffusion_coefficient_for_grid_point_cold_pools")
!$ACC PARALLEL LOOP DEFAULT(NONE) GANG VECTOR COLLAPSE(2) ASYNC(1) IF( i_am_accel_node .AND. acc_on )
DO jk = nlev-1, nlev
DO je = i_startidx, i_endidx
kh_smag_e(je,jk,jb) = MAX(kh_smag_e(je,jk,jb), enh_diffu_3d(iecidx(je,jb,1),jk,iecblk(je,jb,1)), &
enh_diffu_3d(iecidx(je,jb,2),jk,iecblk(je,jb,2)) )
ENDDO
ENDDO
```
```fortran=
call nvtxEndRange()
ENDDO
#endif
#endif
rl_start = grf_bdywidth_e+1
rl_end = min_rledge_int
i_startblk = p_patch%edges%start_block(rl_start)
i_endblk = p_patch%edges%end_block(rl_end)
DO jb = i_startblk,i_endblk
CALL get_indices_e(p_patch, jb, i_startblk, i_endblk, i_startidx, i_endidx, rl_start, rl_end)
call wrap_run_enhance_diffusion_coefficient_for_grid_point_cold_pools(kh_smag_e=kh_smag_e(:,:,1), &
enh_diffu_3d=enh_diffu_3d(:,:,1), kh_smag_e_before=kh_smag_e_before(:,:,1), &
vertical_lower=nlev-1, vertical_upper=nlev, horizontal_lower=i_startidx, &
horizontal_upper=i_endidx)
ENDDO
```
- call wrap_run inside `DO` loop.
*Affected stencils*:
- enhance_diffusion_coefficient_for_grid_point_cold_pools
### Not yet ported to gt4py
A number of stencils are not yet ported to gt4py.
### Unterminated DO loops (in substitution mode)
```fortran
call nvtxEndRange()
#endif
ENDDO
!$OMP END DO
! <wrap run func>
```
**Affected stencils**
- calculate_nabla2_and_smag_coefficients_for_vn
- wrap_run_calculate_diagnostics_for_turbulance
- wrap_run_temporary_field_for_grid_point_cold_pools_enhancement
- wrap_run_enhance_diffusion_coefficient_for_grid_point_cold_pools
- wrap_run_calculate_nabla2_for_z
- wrap_run_calculate_nabla2_of_theta
- wrap_run_update_theta_and_exner
- wrap_run_mo_velocity_advection_stencil_07
### Call to subroutine
```fortran=
CALL rbf_vec_interpol_vertex( p_nh_prog%vn, p_patch, p_int, &
u_vert, v_vert, opt_rlend=min_rlvert_int, &
opt_acc_async=.TRUE. )
```
*Affected stencils:*
- wrap_run_mo_intp_rbf_rbf_vec_interpol_vertex `-->` rbf_vec_interpol_vertex
- wrap_run_mo_math_divrot_rot_vertex_ri_dsl `-->` rot_vertex_ri
### DECLARE DATA: Fields with suffix
```fortran=
REAL(wp), DIMENSION(nproma,p_patch%nlev,p_patch%nblks_e) :: z_hydro_corr_dsl
REAL(wp), DIMENSION(nproma,p_patch%nblks_c) :: w_1
REAL(wp), DIMENSION(nproma, p_patch%nlev, p_patch%nblks_c) :: z_th_ddz_exner_c_before_new
```
- does not have `_before` suffix
*Affected modules:*
- mo_solve_nonhydro.f90
- mo_velocity_advection.f90
### DECLARE DATA: Fields with custom types
```fortran=
REAL(wp), DIMENSION(:,:,:,:), POINTER :: ikidx_dsl
```
- pattern of generated code is different uses pointer.
*Affected modules:*
- mo_solve_nonhydro.f90
### Stencil is used twice
- The exact same stencils can be found more than once in the source code. Currently this is not supported by icon-liskov triggering a `RepeatedDirectiveError`.
*Affected stencils*:
- wrap_run_mo_solve_nonhydro_stencil_56_63
### Invalid parsing of output field due to parentheses *(fixed)*
When parsed to generate the before field copies the following:
```fortran
theta_v_new=p_nh%prog(nnew)%theta_v(:,:,1)
```
is turned into
```fortran
theta_v_new_before(nno:)=p_nh%prog(nnow)%theta_v(:, :, 1(nno:)
```
when it should be
```fortran
theta_v_new_before(:,:,:) = p_nh%prog(nnow)%theta_v(:, :, :)
```
The output fields in the wrap_fun call are also wrongly generated as:
```fortran!
theta_v_new_before=theta_v_new_before(nnew)
```
when it should be:
```fortran!
theta_v_new_before=theta_v_new_before(:, :, :)
```
### Custom output fields
Cases:
wrap_run_mo_solve_nonhydro_stencil_06
```fortran
! wrap_run_field
z_dexner_dz_c_1=z_dexner_dz_c(:,:,1,1)
! before copy field:
z_dexner_dz_c_1_before(:,:,:) = z_dexner_dz_c(:,:,:,1)
```
wrap_run_mo_solve_nonhydro_stencil_01
wrap_run_mo_solve_nonhydro_stencil_07
wrap_run_mo_solve_nonhydro_stencil_08
wrap_run_mo_solve_nonhydro_stencil_13
```fortran
! wrap_run_field
z_rth_pr_1_before(:,:,:) = z_rth_pr(:,:,:,1)
z_rth_pr_2_before(:,:,:) = z_rth_pr(:,:,:,2)
! before copy field:
z_rth_pr_1=z_rth_pr(:,:,1,1)
z_rth_pr_2=z_rth_pr(:,:,1,2)
```
wrap_run_mo_solve_nonhydro_stencil_12
```fortran
! wrap_run_field
z_dexner_dz_c_2=z_dexner_dz_c(:,:,1,2)
! before copy field:
z_dexner_dz_c_2_before(:,:,:) = z_dexner_dz_c(:,:,:,2)
```
wrap_run_mo_solve_nonhydro_stencil_21
```fortran
! wrap_run field
z_hydro_corr=z_hydro_corr_dsl(:,:,1), z_hydro_corr_before=z_hydro_corr_before(:,:,1)
! before copy field
z_hydro_corr_dsl(:,:,:) = 0._wp
z_hydro_corr_before(:,:,:) = 0._wp
z_hydro_corr_before(:,nlev,:) = z_hydro_corr(:,:)
```
wrap_run_mo_velocity_advection_stencil_16
wrap_run_mo_velocity_advection_stencil_17
wrap_run_mo_velocity_advection_stencil_18
wrap_run_mo_velocity_advection_stencil_19
wrap_run_mo_velocity_advection_stencil_20
```fortran
! wrap_run field
ddt_w_adv = p_diag%ddt_w_adv_pc(:,:,1,ntnd)
! before copy field
ddt_w_adv_pc_before(:,:,:) = p_diag%ddt_w_adv_pc(:,:,:,ntnd)
```
- mo_solve_nonhydro_47 (int index)
- mo_solve_nonhydro_46 (int index)
### nvtx after get_indices
```fortran=
call nvtxEndRange()
#endif
rl_start_2 = grf_bdywidth_e+1
rl_end_2 = min_rledge
i_startblk_2 = p_patch%edges%start_block(rl_start_2)
i_endblk_2 = p_patch%edges%end_block(rl_end_2)
CALL get_indices_e(p_patch, 1, i_startblk_2, i_endblk_2, &
i_startidx_2, i_endidx_2, rl_start_2, rl_end_2)
call wrap_run_mo_solve_nonhydro_stencil_22( &
ipeidx_dsl=p_nh%metrics%pg_edgeidx_dsl(:,:,1), &
pg_exdist=p_nh%metrics%pg_exdist_dsl(:,:,1), &
z_hydro_corr=z_hydro_corr_dsl(:,nlev,1), &
z_gradh_exner=z_gradh_exner(:,:,1), &
z_gradh_exner_before=z_gradh_exner_before(:,:,1), &
vertical_lower=1, &
vertical_upper=nlev, &
horizontal_lower=i_startidx_2, &
horizontal_upper=i_endidx_2 &
)
```
*Affected stencils:*
- mo_solve_nonhydro_22
- mo_solve_nonhydro_66
### Two consecutive stencils
```fortran=
call wrap_run_mo_solve_nonhydro_stencil_37(vn=p_nh%prog(nnew)%vn(:,:,1), vt=p_nh%diag%vt(:,:,1), &
vn_ie=p_nh%diag%vn_ie(:,:,1), z_vt_ie=z_vt_ie(:,:,1), z_kin_hor_e=z_kin_hor_e(:,:,1), vn_ie_before=vn_ie_before(:,:,1), &
z_vt_ie_before=z_vt_ie_before(:,:,1), z_kin_hor_e_before=z_kin_hor_e_before(:,:,1), vertical_lower=1, &
vertical_upper=1, horizontal_lower=i_startidx, horizontal_upper=i_endidx)
call wrap_run_mo_solve_nonhydro_stencil_38(vn=p_nh%prog(nnew)%vn(:,:,1), wgtfacq_e=p_nh%metrics%wgtfacq_e_dsl(:,:,1), &
vn_ie=p_nh%diag%vn_ie(:,:,1), vn_ie_before=vn_ie_before(:,:,1), vn_ie_rel_tol=1e-10_wp, vertical_lower=nlevp1, &
vertical_upper=nlevp1, horizontal_lower=i_startidx, horizontal_upper=i_endidx)
```
*Affected stencils*
- mo_solve_nonhydro_37
- mo_solve_nonhydro_38
- mo_solve_nonhydro_45
- mo_solve_nonhydro_45_b
- wrap_run_mo_velocity_advection_stencil_05
- wrap_run_mo_velocity_advection_stencil_06
### Custom variables & pattern
wrap_run_mo_velocity_advection_stencil_14
```fortran=
! before fields
z_w_con_c_before(:,:) = z_w_con_c(:,:)
cfl_clipping(:,:) = .FALSE.
cfl_clipping_dsl(:,:) = 0._wp
cfl_clipping_before(:,:) = 0._wp
pre_levmask(:,:,:) = .FALSE.
pre_levelmask_dsl(:,:) = 0._wp
pre_levelmask_before(:,:) = 0._wp
vcfl_dsl(:,:) = 0._wp
vcfl_before(:,:) = 0._wp
```
- custom variables as before fields
```fortran=
call nvtxEndRange()
!$ACC PARALLEL IF( i_am_accel_node .AND. acc_on ) DEFAULT(NONE) ASYNC(1)
cfl_clipping_dsl(:,:) = real(cfl_clipping(:,:), wp)
!$ACC END PARALLEL
!DSL: Have to copy through explicit loop since the following:
!pre_levelmask_dsl(:,:) = real(pre_levmask(:,1,:), wp)
!results in -1.0 instead of 1.0 entries when the original logical is .TRUE.
!$ACC PARALLEL IF( i_am_accel_node .AND. acc_on ) DEFAULT(NONE) ASYNC(1)
DO jk = MAX(3,nrdmax_jg-2), nlev-3
DO jc = i_startidx, i_endidx
IF (pre_levmask(jc,1,jk)) THEN
pre_levelmask_dsl(jc,jk) = 1._wp
ENDIF
ENDDO
ENDDO
!$ACC END PARALLEL
#endif
call wrap_run_mo_velocity_advection_stencil_14(cfl_w_limit=cfl_w_limit, dtime=dtime, &
ddqz_z_half=p_metrics%ddqz_z_half(:,:,1), z_w_con_c=z_w_con_c(:,:), &
cfl_clipping=cfl_clipping_dsl(:,:), pre_levelmask=pre_levelmask_dsl(:,:), &
vcfl=vcfl_dsl(:,:), z_w_con_c_before=z_w_con_c_before(:,:), &
cfl_clipping_before=cfl_clipping_before(:,:), &
pre_levelmask_before=pre_levelmask_before(:,:), vcfl_before=vcfl_before(:,:), &
vertical_lower=MAX(3,nrdmax_jg-2), vertical_upper=nlev-3, horizontal_lower=i_startidx, &
horizontal_upper=i_endidx)
maxvcfl_dsl = 0
!$ACC PARALLEL IF( i_am_accel_node .AND. acc_on ) PRIVATE(vcfl) DEFAULT(NONE) ASYNC(1)
!$ACC LOOP GANG VECTOR COLLAPSE(2) REDUCTION( max:maxvcfl_dsl )
DO jk = MAX(3,nrdmax_jg-2), nlev-3
DO jc = i_startidx, i_endidx
IF (pre_levelmask_dsl(jc,jk)) THEN
levelmask_dsl(jk) = 1.0_wp
ENDIF
IF ( cfl_clipping(jc,jk) ) THEN
vcfl = vcfl_dsl(jc,jk)
maxvcfl_dsl = MAX(maxvcfl_dsl, ABS(vcfl))
ENDIF
ENDDO
ENDDO
!$ACC END PARALLEL
```
- custom pattern in wrap function call.
mo_solve_nonhydro_21:
- Custom before fields
- Custom Assign after Fortran stencil
```fortran=
#ifdef __DSL_VERIFY
!$ACC PARALLEL IF( i_am_accel_node .AND. acc_on ) DEFAULT(NONE) ASYNC(1)
z_hydro_corr_dsl(:,:,:) = 0._wp
z_hydro_corr_before(:,:,:) = 0._wp
z_hydro_corr_before(:,nlev,:) = z_hydro_corr(:,:)
!$ACC END PARALLEL
call nvtxStartRange("mo_solve_nonhydro_stencil_21")
!$ACC PARALLEL IF( i_am_accel_node .AND. acc_on ) DEFAULT(NONE) ASYNC(1)
!$ACC LOOP GANG VECTOR PRIVATE(z_theta1,z_theta2)
DO je = i_startidx, i_endidx
z_theta1 = &
p_nh%prog(nnow)%theta_v(icidx(je,jb,1),ikidx(1,je,nlev,jb),icblk(je,jb,1)) + &
p_nh%metrics%zdiff_gradp(1,je,nlev,jb)* &
(p_nh%diag%theta_v_ic(icidx(je,jb,1),ikidx(1,je,nlev,jb), icblk(je,jb,1)) - &
p_nh%diag%theta_v_ic(icidx(je,jb,1),ikidx(1,je,nlev,jb)+1,icblk(je,jb,1))) * &
p_nh%metrics%inv_ddqz_z_full(icidx(je,jb,1),ikidx(1,je,nlev,jb),icblk(je,jb,1))
z_theta2 = &
p_nh%prog(nnow)%theta_v(icidx(je,jb,2),ikidx(2,je,nlev,jb),icblk(je,jb,2)) + &
p_nh%metrics%zdiff_gradp(2,je,nlev,jb)* &
(p_nh%diag%theta_v_ic(icidx(je,jb,2),ikidx(2,je,nlev,jb), icblk(je,jb,2)) - &
p_nh%diag%theta_v_ic(icidx(je,jb,2),ikidx(2,je,nlev,jb)+1,icblk(je,jb,2))) * &
p_nh%metrics%inv_ddqz_z_full(icidx(je,jb,2),ikidx(2,je,nlev,jb),icblk(je,jb,2))
z_hydro_corr(je,jb) = grav_o_cpd*p_patch%edges%inv_dual_edge_length(je,jb)* &
(z_theta2-z_theta1)*4._wp/(z_theta1+z_theta2)**2
ENDDO
!$ACC END PARALLEL
call nvtxEndRange()
!$ACC PARALLEL IF( i_am_accel_node .AND. acc_on ) DEFAULT(NONE) ASYNC(1)
z_hydro_corr_dsl(:,nlev,:) = z_hydro_corr(:,:) !put fortran result in "blown up" dsl version of z_hydro_corr
!$ACC END PARALLEL
#endif
call wrap_run_mo_solve_nonhydro_stencil_21(grav_o_cpd=grav_o_cpd, theta_v=p_nh%prog(nnow)%theta_v(:,:,1), ikidx=ikidx_dsl(:,:,:,1), &
zdiff_gradp=p_nh%metrics%zdiff_gradp_dsl(:,:,:,1), theta_v_ic=p_nh%diag%theta_v_ic(:,:,1), inv_ddqz_z_full=p_nh%metrics%inv_ddqz_z_full(:,:,1), &
inv_dual_edge_length=p_patch%edges%inv_dual_edge_length(:,1), z_hydro_corr=z_hydro_corr_dsl(:,:,1), z_hydro_corr_before=z_hydro_corr_before(:,:,1))
```