Skip to content

Orchestration: One Code To Rule Them in The DaCeness Bind Them

"Orchestration" refers to the concept of parsing stencil code & pythonc code together into a single dace.program. This system allows for full-context optimization and is the basis of the most performant version of the NDSL delivered code.

Orchestrating code: a partial guide to a sea of potholes

The parser wants simple things

The python parser of DaCe hates dynamicity. No allocations must be done in the runtime code. We superseed a lot of the python actions or guide them to be resolved but there's still a (ongoing) list of failure that could be triggered.

Original documentation provides some introduction with very simple examples.

The List of Issues

Conditional code on input

You shall not use boolean variable to switch between code

class Input_Conditional_Function_Call:
    def __init__(self, stencil_factory: StencilFactory):
        orchestrate(obj=self, config=stencil_factory.config.dace_config)
        self._stencil_A = stcil_fctry.from_dims_halo(
            func=stencil_A,
            compute_dims=[X_DIM, Y_DIM, Z_DIM],
        )
        self._stencil_B = stcil_fctry.from_dims_halo(
            func=stencil_B,
            compute_dims=[X_DIM, Y_DIM, Z_DIM],
        )
        self._tmp_field = np.zeros(domain)

    def _internal_computation_no_scalar(self, in_field, out_field):
        out_field[:] = in_field[:] + 2

    def _internal_computation_scalar(self, in_field, out_field, scalar_field):
        out_field[:] = in_field[:] + scalar_field[:]

    def __call__(
        self,
        in_field: FloatField,
        out_field: FloatField,
        cond_flag: bool = False,
    ):
        if cond_flag:
            self._internal_computation_no_scalar(in_field, out_field)
        else:
            self._internal_computation_scalar(in_field, out_field, self._tmp_field)

class Faulty_Code_No_Stencils:
    def __init__(self, stencil_factory: StencilFactory):
        orchestrate(obj=self, config=stencil_factory.config.dace_config)
        self._subclass_build_A = Input_Conditional_Function_Call(stencil_factory)
        self._subclass_build_B = Input_Conditional_Function_Call(stencil_factory)

    def __call__(self, in_field: FloatField, out_field: FloatField):
        self._subclass_build_A(in_field, out_field)
        self._subclass_build_B(in_field, out_field, cond_flag=True)

if __name__ == "__main__":
    domain = (3, 3, 4)

    stcil_fctry, ijk_qty_fctry = get_factories_single_tile_orchestrated(
        domain[0], domain[1], domain[2], 0, on_cpu=True
    )

    arr_I = ijk_qty_fctry._numpy.arange(
        domain[0] * domain[1] * domain[2], dtype=np.float64
    ).reshape(domain)
    arr_O = ijk_qty_fctry._numpy.zeros(domain)

    code = Faulty_Code_No_Stencils(stcil_fctry)
    code(arr_I, arr_O)

This also fails when you mix in stencils. Issue: https://github.com/NOAA-GFDL/NDSL/issues/146