Closed
Description
The qx_edge_west
stencil in the FV3 dycore produces invalid GridTools code (see #136)
def qx_edge_west2(qin: sd, dxa: sd, qx: sd):
with computation(PARALLEL), interval(...):
g_in = dxa / dxa[-1, 0, 0]
qx0 = qx
qx = (
3.0 * (g_in * qin[-1, 0, 0] + qin) - (g_in * qx0[-1, 0, 0] + qx0[1, 0, 0])
) / (2.0 + 2.0 * g_in)
A simplified example is
def trigger_bug(qx: sd):
with computation(PARALLEL), interval(...):
qx0 = qx
qx = qx0[-1, 0, 0]
Here, the stage of qx0 = qx
gets an extended compute domain because of the read with offset in the next line.
Currently the following GridTool code is generated:
computation_t gt_computation = gt::make_computation<backend_t>(
make_grid(domain),
gt::make_multistage(gt::execute::parallel(),
gt::make_stage<stage__9_func>(
p_qx(), p_qx0()
),
gt::make_stage<stage__12_func>(
p_qx0(), p_qx()
)
)
);
This is illegal as qx
is read outside the compute domain (because extended), resulting in a data race in the write. The stages would have to live in separate multistages.
A fix would be to improve the multistage merge to check for the following conditions:
A read before write in the same multi-stage is only allowed if the read is in a non-extended stage and the read is without offset. (Here, the first condition is violated.)