Skip to content

Commit

Permalink
Ignore delete statements in fused mode (#266)
Browse files Browse the repository at this point in the history
This PR allows to use the DELETE statements only for the fused stencil mode.

---------

Co-authored-by: Samuel <[email protected]>
  • Loading branch information
huppd and samkellerhals authored Sep 26, 2023
1 parent 92e23fb commit 8dd6bd2
Show file tree
Hide file tree
Showing 3 changed files with 276 additions and 0 deletions.
70 changes: 70 additions & 0 deletions tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,66 @@ Additionally, there are the following keyword arguments:

- `noaccenddata`: Takes a boolean string input and controls whether a `!$ACC END DATA` directive is generated or not. Defaults to false.<br><br>

#### `!$DSL FUSED START STENCIL()`

This directive denotes the start of a fused stencil. Required arguments are `name`, `vertical_lower`, `vertical_upper`, `horizontal_lower`, `horizontal_upper`. The value for `name` must correspond to a stencil found in one of the stencil modules inside `icon4py`, and all fields defined in the directive must correspond to the fields defined in the respective icon4py stencil. Optionally, absolute and relative tolerances for the output fields can also be set using the `_tol` or `_abs` suffixes respectively. For each stencil, an ACC ENTER/EXIT DATA statements will be created. This ACC ENTER/EXIT DATA region contains the before fileds of the according stencil. An example call looks like this:

```fortran
!$DSL START FUSED STENCIL(name=calculate_diagnostic_quantities_for_turbulence; &
!$DSL kh_smag_ec=kh_smag_ec(:,:,1); vn=p_nh_prog%vn(:,:,1); e_bln_c_s=p_int%e_bln_c_s(:,:,1); &
!$DSL geofac_div=p_int%geofac_div(:,:,1); diff_multfac_smag=diff_multfac_smag(:); &
!$DSL wgtfac_c=p_nh_metrics%wgtfac_c(:,:,1); div_ic=p_nh_diag%div_ic(:,:,1); &
!$DSL hdef_ic=p_nh_diag%hdef_ic(:,:,1); &
!$DSL div_ic_abs_tol=1e-18_wp; vertical_lower=2; &
!$DSL vertical_upper=nlev; horizontal_lower=i_startidx; horizontal_upper=i_endidx)
```

#### `!$DSL END FUSED STENCIL()`

This directive denotes the end of a fused stencil. The required argument is `name`, which must match the name of the preceding `START STENCIL` directive.

Note that each `START STENCIL` and `END STENCIL` will be transformed into a `DELETE` section, when using the `--fused` mode.
Together, the `START FUSED STENCIL` and `END FUSED STENCIL` directives result in the following generated code at the start and end of a stencil respectively.

```fortran
!$ACC DATA CREATE( &
!$ACC kh_smag_e_before, &
!$ACC kh_smag_ec_before, &
!$ACC z_nabla2_e_before ) &
!$ACC IF ( i_am_accel_node )
#ifdef __DSL_VERIFY
!$ACC KERNELS IF( i_am_accel_node ) DEFAULT(PRESENT) ASYNC(1)
kh_smag_e_before(:, :, :) = kh_smag_e(:, :, :)
kh_smag_ec_before(:, :, :) = kh_smag_ec(:, :, :)
z_nabla2_e_before(:, :, :) = z_nabla2_e(:, :, :)
!$ACC END KERNELS
```

```fortran
call wrap_run_calculate_diagnostic_quantities_for_turbulence( &
kh_smag_ec=kh_smag_ec(:, :, 1), &
vn=p_nh_prog%vn(:, :, 1), &
e_bln_c_s=p_int%e_bln_c_s(:, :, 1), &
geofac_div=p_int%geofac_div(:, :, 1), &
diff_multfac_smag=diff_multfac_smag(:), &
wgtfac_c=p_nh_metrics%wgtfac_c(:, :, 1), &
div_ic=p_nh_diag%div_ic(:, :, 1), &
div_ic_before=div_ic_before(:, :, 1), &
hdef_ic=p_nh_diag%hdef_ic(:, :, 1), &
hdef_ic_before=hdef_ic_before(:, :, 1), &
div_ic_abs_tol=1e-18_wp, &
vertical_lower=2, &
vertical_upper=nlev, &
horizontal_lower=i_startidx, &
horizontal_upper=i_endidx)
!$ACC EXIT DATA DELETE( &
!$ACC div_ic_before, &
!$ACC hdef_ic_before ) &
!$ACC IF ( i_am_accel_node )
```

#### `!$DSL INSERT()`

This directive allows the user to generate any text that is placed between the parentheses. This is useful for situations where custom code generation is necessary.
Expand All @@ -204,6 +264,16 @@ This directive allows generating an nvtx start profile data statement, and takes

This directive allows generating an nvtx end profile statement.

#### `!$DSL START DELETE

This directive allows to disable code. The code is only disabled if both the fused mode and the substition mode are enabled.
The `START DELETE` indicates the starting line from which on code is deleted.

#### `!$DSL END DELETE`

This directive allows to disable code. The code is only disabled if both the fused mode and the substition mode are enabled.
The `END DELETE` indicates the ending line from which on code is deleted.

#### `!$DSL ENDIF()`

This directive generates an `#endif` statement.
Expand Down
5 changes: 5 additions & 0 deletions tools/src/icon4pytools/liskov/parsing/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def __call__(self, data: Any = None) -> IntegrationCodeInterface:
else:
logger.info("Removing fused stencils.")
self._remove_fused_stencils()
self._remove_delete()

return self.parsed

Expand Down Expand Up @@ -113,3 +114,7 @@ def _remove_stencils(self, stencils_to_remove: list[CodeGenInput]) -> None:
def _remove_fused_stencils(self) -> None:
self.parsed.StartFusedStencil = []
self.parsed.EndFusedStencil = []

def _remove_delete(self) -> None:
self.parsed.StartDelete = []
self.parsed.EndDelete = []
201 changes: 201 additions & 0 deletions tools/tests/liskov/test_transform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
# ICON4Py - ICON inspired code in Python and GT4Py
#
# Copyright (c) 2022, ETH Zurich and MeteoSwiss
# All rights reserved.
#
# This file is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or any later
# version. See the LICENSE.txt file at the top-level directory of this
# distribution for a copy of the license or check <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later


import pytest

from icon4pytools.liskov.codegen.integration.interface import (
BoundsData,
DeclareData,
EndCreateData,
EndDeleteData,
EndFusedStencilData,
EndIfData,
EndProfileData,
EndStencilData,
FieldAssociationData,
ImportsData,
InsertData,
IntegrationCodeInterface,
StartCreateData,
StartDeleteData,
StartFusedStencilData,
StartProfileData,
StartStencilData,
)
from icon4pytools.liskov.parsing.transform import StencilTransformer


@pytest.fixture
def integration_code_interface():
start_fused_stencil_data = StartFusedStencilData(
name="fused_stencil1",
fields=[
FieldAssociationData("scalar1", "scalar1", inp=True, out=False, dims=None),
FieldAssociationData("inp1", "inp1(:,:,1)", inp=True, out=False, dims=2),
FieldAssociationData("out1", "out1(:,:,1)", inp=False, out=True, dims=2, abs_tol="0.5"),
FieldAssociationData(
"out2",
"p_nh%prog(nnew)%out2(:,:,1)",
inp=False,
out=True,
dims=3,
abs_tol="0.2",
),
FieldAssociationData("out3", "p_nh%prog(nnew)%w(:,:,jb)", inp=False, out=True, dims=2),
FieldAssociationData("out4", "p_nh%prog(nnew)%w(:,:,1,2)", inp=False, out=True, dims=3),
FieldAssociationData(
"out5", "p_nh%prog(nnew)%w(:,:,:,ntnd)", inp=False, out=True, dims=3
),
FieldAssociationData(
"out6", "p_nh%prog(nnew)%w(:,:,1,ntnd)", inp=False, out=True, dims=3
),
],
bounds=BoundsData("1", "10", "-1", "-10"),
startln=1,
acc_present=False,
)
end_fused_stencil_data = EndFusedStencilData(name="stencil1", startln=4)
start_stencil_data1 = StartStencilData(
name="stencil1",
fields=[
FieldAssociationData("scalar1", "scalar1", inp=True, out=False, dims=None),
FieldAssociationData("inp1", "inp1(:,:,1)", inp=True, out=False, dims=2),
FieldAssociationData("out1", "out1(:,:,1)", inp=False, out=True, dims=2, abs_tol="0.5"),
FieldAssociationData(
"out2",
"p_nh%prog(nnew)%out2(:,:,1)",
inp=False,
out=True,
dims=3,
abs_tol="0.2",
),
FieldAssociationData("out3", "p_nh%prog(nnew)%w(:,:,jb)", inp=False, out=True, dims=2),
FieldAssociationData("out4", "p_nh%prog(nnew)%w(:,:,1,2)", inp=False, out=True, dims=3),
FieldAssociationData(
"out5", "p_nh%prog(nnew)%w(:,:,:,ntnd)", inp=False, out=True, dims=3
),
FieldAssociationData(
"out6", "p_nh%prog(nnew)%w(:,:,1,ntnd)", inp=False, out=True, dims=3
),
],
bounds=BoundsData("1", "10", "-1", "-10"),
startln=2,
acc_present=False,
mergecopy=False,
copies=True,
)
end_stencil_data1 = EndStencilData(
name="stencil1", startln=3, noendif=False, noprofile=False, noaccenddata=False
)
start_stencil_data2 = StartStencilData(
name="stencil2",
fields=[
FieldAssociationData("scalar1", "scalar1", inp=True, out=False, dims=None),
FieldAssociationData("inp1", "inp1(:,:,1)", inp=True, out=False, dims=2),
FieldAssociationData("out1", "out1(:,:,1)", inp=False, out=True, dims=2, abs_tol="0.5"),
FieldAssociationData(
"out2",
"p_nh%prog(nnew)%out2(:,:,1)",
inp=False,
out=True,
dims=3,
abs_tol="0.2",
),
FieldAssociationData("out3", "p_nh%prog(nnew)%w(:,:,jb)", inp=False, out=True, dims=2),
FieldAssociationData("out4", "p_nh%prog(nnew)%w(:,:,1,2)", inp=False, out=True, dims=3),
FieldAssociationData(
"out5", "p_nh%prog(nnew)%w(:,:,:,ntnd)", inp=False, out=True, dims=3
),
FieldAssociationData(
"out6", "p_nh%prog(nnew)%w(:,:,1,ntnd)", inp=False, out=True, dims=3
),
],
bounds=BoundsData("1", "10", "-1", "-10"),
startln=5,
acc_present=False,
mergecopy=False,
copies=True,
)
end_stencil_data2 = EndStencilData(
name="stencil2", startln=6, noendif=False, noprofile=False, noaccenddata=False
)
declare_data = DeclareData(
startln=7,
declarations={"field2": "(nproma, p_patch%nlev, p_patch%nblks_e)"},
ident_type="REAL(wp)",
suffix="before",
)
imports_data = ImportsData(startln=8)
start_create_data = StartCreateData(extra_fields=["foo", "bar"], startln=9)
end_create_data = EndCreateData(startln=11)
endif_data = EndIfData(startln=12)
start_profile_data = StartProfileData(startln=13, name="test_stencil")
end_profile_data = EndProfileData(startln=14)
insert_data = InsertData(startln=15, content="print *, 'Hello, World!'")
start_delete_data = StartDeleteData(startln=16)
end_delete_data = EndDeleteData(startln=17)

return IntegrationCodeInterface(
StartStencil=[start_stencil_data1, start_stencil_data2],
EndStencil=[end_stencil_data1, end_stencil_data2],
StartFusedStencil=[start_fused_stencil_data],
EndFusedStencil=[end_fused_stencil_data],
StartDelete=[start_delete_data],
EndDelete=[end_delete_data],
Declare=[declare_data],
Imports=imports_data,
StartCreate=[start_create_data],
EndCreate=[end_create_data],
EndIf=[endif_data],
StartProfile=[start_profile_data],
EndProfile=[end_profile_data],
Insert=[insert_data],
)


@pytest.fixture
def stencil_transform_fused(integration_code_interface):
return StencilTransformer(integration_code_interface, fused=True)


@pytest.fixture
def stencil_transform_unfused(integration_code_interface):
return StencilTransformer(integration_code_interface, fused=False)


def test_transform_fused(
stencil_transform_fused,
):
# Check that the transformed interface is as expected
transformed = stencil_transform_fused()
assert len(transformed.StartFusedStencil) == 1
assert len(transformed.EndFusedStencil) == 1
assert len(transformed.StartStencil) == 1
assert len(transformed.EndStencil) == 1
assert len(transformed.StartDelete) == 2
assert len(transformed.EndDelete) == 2


def test_transform_unfused(
stencil_transform_unfused,
):
# Check that the transformed interface is as expected
transformed = stencil_transform_unfused()

assert not transformed.StartFusedStencil
assert not transformed.EndFusedStencil
assert len(transformed.StartStencil) == 2
assert len(transformed.EndStencil) == 2
assert not transformed.StartDelete
assert not transformed.EndDelete

0 comments on commit 8dd6bd2

Please sign in to comment.