diff --git a/examples/NDSL/01_gt4py_basics.ipynb b/examples/NDSL/01_gt4py_basics.ipynb index a4e2a559..98b43922 100644 --- a/examples/NDSL/01_gt4py_basics.ipynb +++ b/examples/NDSL/01_gt4py_basics.ipynb @@ -4,34 +4,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# **GT4Py Tutorial : Stencil Basics**\n", + "# GT4Py Tutorial: Stencil Basics\n", "\n", - "## **Introduction**\n", + "## Introduction\n", "\n", "This notebook will show how to create a simple GT4Py stencil that copies data from one variable to another.\n", "\n", - "### **Notebook Requirements**\n", + "### Notebook Requirements\n", "\n", - "- Python v3.11.x to v3.12.x\n", + "- Python v3.11.x\n", "- [NOAA/NASA Domain Specific Language Middleware](https://github.com/NOAA-GFDL/NDSL)\n", - "- `ipykernel==6.1.0`\n", - "- [`ipython_genutils`](https://pypi.org/project/ipython_genutils/)\n", "\n", - "### **Quick GT4Py (Cartesian version) Overview**\n", + "### Quick GT4Py (Cartesian version) Overview\n", "\n", - "GT4Py is a Domain Specific Language (DSL) in Python that enables a developer to write stencil computations. Compared to simply running under Python, GT4Py achieves performance when the Python code is translated and compiled into a lower level language such as C++ and CUDA, which enables the codebase to execute on a multitude of architectures. In this notebook, we will cover the basics of creating GT4Py stencils and demonstrate several intracies of the DSL. Additional information about GT4Py can be found at the [GT4Py site](https://gridtools.github.io/gt4py/latest/index.html). One small note is that this tutorial covers and uses the Cartesian version of GT4Py and not the unstructured version.\n", + "GT4Py is a Domain Specific Language (DSL) in Python that enables a developer to write stencil computations. Compared to simply running under Python, GT4Py achieves performance when the Python code is transformed and compiled into a lower level language such as C++ and CUDA. This code transformation capability also enables GT4Py-based code to execute on multiple architectures. In this notebook, we will cover the basics of creating GT4Py stencils and demonstrate several intricacies of the DSL. Additional information about GT4Py can be found in the [GT4Py documentation](https://gridtools.github.io/gt4py/latest/index.html). One small note is that this tutorial covers and uses the Cartesian version of GT4Py and not the unstructured (\"next\") version.\n", "\n", - "### **GT4Py Parallel/Execution Model**\n", + "### GT4Py Parallel/Execution Model\n", "\n", - "Within a 3-dimensional domain, GT4Py considers computations in two parts. If we assume an `(I,J,K)` coordinate system as a reference, GT4Py separates computations in the Horizontal (`IJ`) spatial plane and Vertical (`K`) spatial interval. In the Horizontal spatial plane, computations are implicitly executed in parallel, which also means that there is no assumed calculation order within the plane. In the Vertical spatial interval, comptuations are specified by an iteration policy that will be discussed later through examples.\n", + "Within a 3-dimensional domain, GT4Py considers computations in two parts. If we assume an `(I,J,K)` coordinate system as the reference, GT4Py separates computations in the horizontal (`IJ`) spatial plane and vertical (`K`) spatial dimension. In the horizontal spatial plane, computations are implicitly executed in parallel, which also means that there is no assumed calculation order within the plane. In the vertical spatial dimension, computations are specified by an iteration policy that will be discussed later through examples.\n", "\n", - "Another quick note is that the computations are executed sequentially in the order they appear in code.\n", + "Another quick note is that the stencil computations are executed sequentially in the order they appear in code.\n", "\n", - "## **Tutorial**\n", + "## Tutorial\n", "\n", - "### **Copy Stencil example**\n", + "### Copy Stencil example\n", "\n", - "To demonstrate how to implement a GT4Py stencil, we'll step through an example that copies the values of one array into another array. First, we import several packages. " + "To demonstrate how to implement a GT4Py stencil, we'll step through a code example that copies the values of one array into another array. First, we import several packages." ] }, { @@ -50,7 +48,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As we walk through the example, we'll highlight different terms and such from the imported packages. Let's first define, in GT4Py terms, two arrays of size 5 by 5 by 2 (dimensionally `I` by `J` by `K`). These arrays are defined using a `Quantity` object, an NDSL data container for physical quantities. More detailed information about the `Quantity` object and its arguments can be found from the [`Quantity` docstring](https://github.com/NOAA-GFDL/NDSL/blob/develop/ndsl/quantity.py#L270). To make debugging easier, the `numpy` backend will be used." + "As we walk through the example, we'll highlight different terms and such from the imported packages. Let's first define, in GT4Py terms, two arrays of size 5 by 5 by 2 (dimensionally `I` by `J` by `K`). These arrays are defined using a `Quantity` object, an NDSL data container for physical quantities. More detailed information about the `Quantity` object and its arguments can be found from the [`Quantity` documentation](https://noaa-gfdl.github.io/NDSL/docstrings/quantity/quantity/#quantity.quantity.Quantity.__init__). To make debugging easier, we'll use the `numpy` backend." ] }, { @@ -82,7 +80,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We will next create a simple GT4Py stencil that copies values from one input to another. A stencil will look like a Python subroutine or function except that it uses specific GT4Py functionalities." + "Next, we will next create a simple GT4Py stencil that copies values from one argument to another. A stencil will look like a Python function except that it uses specific GT4Py functionalities." ] }, { @@ -92,7 +90,7 @@ "outputs": [], "source": [ "@stencil(backend=backend)\n", - "def copy_stencil(input_field: FloatField, output_field: FloatField):\n", + "def copy_stencil(input_field: FloatField, output_field: FloatField) -> None:\n", " with computation(PARALLEL), interval(...):\n", " output_field = input_field" ] @@ -101,18 +99,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "As mentioned before, GT4Py (cartesian version) was designed for stencil-based computation. Since stencil calculations generally are localized computations, GT4Py stencils are written using variables and the variable's relative location if it's an array. If there are no indices in brackets next to a GT4Py type (such as `FloatField`), it's implied to be at the [0] (for 1-dimension), [0,0] (for 2-dimension), or [0,0,0] (for 3-dimension) location. For the simple example `copy_stencil`, the value of `input_field` simply gets copied to `output_field` at every point in the domain of interest.\n", + "As mentioned before, GT4Py (the cartesian version) was designed for stencil-based computation. Since stencil calculations generally are localized computations, GT4Py stencils are written using variables and the variable's **relative location** if the variable is an array. For example, a stencil-based [Laplacian](https://en.wikipedia.org/wiki/Discrete_Laplace_operator#Finite_differences) calculation can be implemented as follows." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def laplacian(input_field: FloatField, output_field: FloatField):\n", + " with computation(PARALLEL), interval(...):\n", + " output_field = (\n", + " -4.0 * input_field[0, 0, 0]\n", + " + input_field[1, 0, 0]\n", + " + input_field[-1, 0, 0]\n", + " + input_field[0, 1, 0]\n", + " + input_field[0, -1, 0]\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the `laplacian` stencil, every value of `output_field` at a particular location is a function of `input_field` at that same location (`input_field[0,0,0]`), the adjacent `input_field` values in the `I`-direction (`input_field[1,0,0]` and `input_field[-1,0,0]`), and the adjacent `input_field` values in the `J`-direction (`input_field[0,1,0]` and `input_field[0,-1,0]`)\n", "\n", - "We see that this stencil does not contain any explicit loops. As mentioned above in the notebook, GT4Py has a particular computation policy that implicitly executes in parallel within an `IJ` plane and is user defined in the `K` interval. This execution policy in the `K` interval is dictated by the `computation` and `interval` keywords. \n", + "If there are no indices in brackets next to a GT4Py type (such as `FloatField`), it's implied to be at the `[0]` (for 1-dimension), `[0,0]` (for 2-dimension), or `[0,0,0]` (for 3-dimension) location. Note again that these locations are **relative**. In the `laplacian` stencil, `output_field` has an implied `[0,0,0]` location, and `input_field[0,0,0]` could have been written simply as `input_field`.\n", "\n", - "- `with computation(PARALLEL)` means that there's no order preference to executing the `K` interval. This also means that the `K` interval can be computed in parallel to potentially gain performance if computational resources are available.\n", + "We see that both, `copy_stencil` and the `laplacian` stencil, do not contain any explicit loops. As mentioned above, GT4Py has a particular computation policy that implicitly executes in parallel within the `IJ` plane and is user defined in the `K` dimension. This execution policy in the `K` dimension is dictated by the `computation` and `interval` keywords.\n", + "- `with computation(PARALLEL)` means that there's no order preference to executing the `K` dimension. This effectively means that the `K` dimension can be computed in parallel to potentially gain performance if computational resources are available.\n", "\n", - "- `interval(...)` means that the entire `K` interval is executed. Instead of `(...)`, more specific intervals can be specified using a tuple of two integers. For example... \n", + "- `interval(...)` means that the \"entire\" `K` dimension range is executed (as dictated by the keywords `origin` and `domain`, which will be covered [later in the notebook](#setting-domain-subsets-in-a-stencil-call)). Instead of `(...)`, more specific intervals can be specified using a tuple of two integers. For example...\n", "\n", - " - `interval(0,2)` : The interval `K` = 0 to 1 is executed.\n", - " - `interval(0,-1)` : The interval `K` = 0 to N-2 (where N is the size of `K`) is executed.\n", + " - `interval(0, 2)` : The interval `K` = 0 to 1 is executed.\n", + " - `interval(0, -1)` : The interval `K` = 0 to N-2 (where N is the size of `K`) is executed.\n", + " - Note: The actual intervals for the above two `interval` are also dictated by [`origin` and `domain`](#setting-domain-subsets-in-a-stencil-call)\n", "\n", - "The decorator `@stencil(backend=backend)` (Note: `stencil` comes from the package `ndsl.dsl.gt4py`) converts `copy_stencil` to use the specified `backend` to \"compile\" the stencil. `stencil` can also be a function call to create a stencil object." + "The decorator `@stencil(backend=backend)` (Note: `stencil` comes from the package `ndsl.dsl.gt4py`) converts `copy_stencil` to use the specified `backend` to \"compile\" the stencil. `stencil` can also be a function call to create a stencil object." ] }, { @@ -128,9 +152,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the input and output parameters to `copy_stencil` are of type `FloatField`, which can essentially be thought of as a 3-dimensional NumPy array of `float` types.\n", + "Note that the input and output parameters to `copy_stencil` and `laplacian` are of type `FloatField`, which can essentially be thought of as a 3-dimensional NumPy array of `float` types.\n", "\n", - "`plot_field_at_kN` plots the values within the `IJ` plane at `K = 0` if no integer is specified or at `K` equal to the integer that is specified as an argument. As we can see in the plots below, `copy_stencil` copies the values from `qty_in` into `qty_out`." + "`plot_field_at_kN` plots the values within the `IJ` plane at `K = 0` if no integer is specified or at `K` equal to the integer that is specified as an argument. As we can see in the plots below, `copy_stencil` copies the values from `qty_in` into `qty_out`." ] }, { @@ -155,15 +179,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Setting domain subsets in a stencil call**\n", + "### Setting domain subsets in a stencil call\n", + "\n", + "GT4Py also allows a subset to be specified from a stencil call and executed in a fashion similar to using `interval(...)` in the `K` dimension. This is done by setting the stencil call's `origin` and `domain` argument.\n", "\n", - "GT4Py also allows a subset to be specified from a stencil call and executed in a fashion similar to using `interval(...)` in the K interval. This is done by setting the stencil call's `origin` and `domain` argument.\n", + "- `origin`: This specifies the \"starting\" coordinate to perform computations.\n", "\n", - "- `origin` : This specifies the \"starting\" coordinate to perform computations. \n", + "- `domain`: This specifies the range of the stencil computation based on `origin` as the \"starting\" coordinate.\n", "\n", - "- `domain` : This specifies the range of the stencil computation based on `origin` as the \"starting\" coordinate (Note: May need to check whether this affects `interval()`)\n", + "- Note: May need to check whether `domain` and `origin` affect `interval()`\n", "\n", - "If these two parameters are not set, the stencil call by default will iterate over the entire input domain. The following demonstrates the effect of specifying different `origin` and `domain`." + "If these two parameters are not set, the stencil call by default will iterate over the entire input domain. The following demonstrates the effect of specifying different `origin` and `domain`." ] }, { @@ -242,13 +268,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **`FORWARD` and `BACKWARD` `computation` keywords and Offset Indexing within a stencil call**\n", + "### `FORWARD` and `BACKWARD` `computation` keywords and Offset Indexing within a stencil call\n", "\n", - "Besides `PARALLEL`, the developer can specify `FORWARD` or `BACKWARD` as the iteration policy in `K` for a stencil. Essentially, the `FORWARD` policy has `K` iterating consecutively starting from the lowest vertical index to the highest, while the `BACKWARD` policy performs the reverse.\n", + "Besides `PARALLEL`, the developer can specify `FORWARD` or `BACKWARD` as the iteration policy in `K` for a stencil. Essentially, the `FORWARD` policy has `K` iterating consecutively starting from the lowest vertical index to the highest, while the `BACKWARD` policy performs the reverse.\n", "\n", - "An array-based stencil variable can also have an integer dimensional offset if the array variable is on the right hand side of the `=` for the computation. When a computation is performed at a particular point, an offset variable's coordinate is based on that particular point plus (or minus) the offset in the offset dimension.\n", + "An array-based stencil variable can also have an integer dimensional offset if the array variable is on the right hand side of the `=` for the computation. When a computation is performed at a particular point, an offset variable's coordinate is based on that particular point plus (or minus) the offset in the offset dimension.\n", "\n", - "The following examples demonstrate the use of these two iteration policies and also offset indexing in the `K` dimension. Note that offsets can also be applied to the `I` or `J` dimension." + "The following examples demonstrate the use of these two iteration policies and also offset indexing in the `K` dimension. Note that offsets can also be applied to the `I` or `J` dimension." ] }, { @@ -336,7 +362,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Regarding offsets, GT4Py does not allow offsets to variables in the left hand side of the `=`. Uncomment and execute the below code to see the error `Assignment to non-zero offsets is not supported.`." + "Regarding offsets, GT4Py does only allow offsets to variables in the left hand side of the `=` in the `K` dimension. Uncomment and execute the below code to see the error message \"Assignment to non-zero offsets is not supported in IJ\"." ] }, { @@ -355,9 +381,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Limits to offset : Cannot set offset outside of usable domain**\n", + "### Limits to offset : Cannot set offset outside of usable domain\n", "\n", - "Note that there are limits to the offsets that can be applied in the stencil. An error will result if the specified shift results attemps to read data that is not available or allocated. In the example below, a shift of -2 in the `J` axis will shift `field_in` out of its possible range in `J`." + "Note that there are limits to the offsets that can be applied in the stencil. An error will result if the specified shift results attempts to read data that is not available or allocated. In the example below, a shift of -2 in the `J` axis will shift `field_in` out of its possible range in `J`." ] }, { @@ -406,9 +432,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **`if/else` statements**\n", + "### `if/else` statements\n", "\n", - "GT4Py allows for `if/else` statements to exist within a stencil. The following simple example shows a stencil `stencil_if_zero` modifing values of `in_out_field` depending on its initial value." + "GT4Py allows for `if/else` statements to exist within a stencil. The following simple example shows a stencil `stencil_if_zero` modifying values of `in_out_field` depending on its initial value." ] }, { @@ -463,9 +489,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Function calls**\n", + "### Function calls\n", "\n", - "GT4Py also has the capability to create functions in order to better organize code. The main difference between a GT4Py function call and a GT4Py stencil is that a function does not (and cannot) contain the keywords `computation` and `interval`. However, array index referencing within a GT4py function is the same as in a GT4Py stencil.\n", + "GT4Py also has the capability to create functions in order to better organize code. The main difference between a GT4Py function call and a GT4Py stencil is that a function does not (and cannot) contain the keywords `computation` and `interval`. However, array index referencing within a GT4py function is the same as in a GT4Py stencil.\n", "\n", "GT4Py functions can be created by using the decorator `function` (Note: `function` originates from the package `ndsl.dsl.gt4py`)." ] diff --git a/examples/NDSL/02_NDSL_basics.ipynb b/examples/NDSL/02_NDSL_basics.ipynb index 0ad8c7c6..b9d53dca 100644 --- a/examples/NDSL/02_NDSL_basics.ipynb +++ b/examples/NDSL/02_NDSL_basics.ipynb @@ -4,19 +4,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# **NDSL Basics** #\n", + "# NDSL Basics\n", "\n", - "### **Introduction**\n", - "After establishing the basics of using GT4Py, we'll take a look at developing an object-oriented coding approach with the NDSL middleware. Much of the object-oriented work comes from the development of [Pace](https://github.com/NOAA-GFDL/pace), the implementation of the FV3GFS / SHiELD atmospheric model using GT4Py and [DaCe](https://github.com/spcl/dace). The `StencilFactory` object will be introduced and demoed." + "### Introduction\n", + "After establishing the basics of using GT4Py, we will develop an object-oriented coding approach with the NDSL middleware. Much of the object-oriented work comes from the development of [Pace](https://github.com/NOAA-GFDL/pace), the implementation of the FV3GFS / SHiELD atmospheric model using GT4Py and [DaCe](https://github.com/spcl/dace). The `StencilFactory` object will be introduced and demoed." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### **Creating the `StencilFactory` object**\n", + "### Creating the `StencilFactory` object\n", "\n", - "The `StencilFactory` object enables the sharing of stencil properties across multiple stencils as well as \"build and execute\" the stencil. To help ease the introduction, the [`boilerplate` module](./boilerplate.py) contains a function `get_one_tile_factory` that takes the domain size, halo size, and backend of interest and returns a `StencilFactory` object. For more details about the objects needed to create the `StencilFactory`, the reader can view the [`get_one_tile_factory`](./boilerplate.py#get_one_tile_factory) function." + "The `StencilFactory` object enables the sharing of stencil properties across multiple stencils as well as \"build and execute\" the stencil. To help ease the introduction, the [`boilerplate` module](./basic_boilerplate.py) contains a function `get_one_tile_factory` that takes the domain size, halo size, and backend of interest and returns a `StencilFactory` object. For more details about the objects needed to create the `StencilFactory`, the reader can view the [`get_one_tile_factory`](./basic_boilerplate.py#get_one_tile_factory) function." ] }, { @@ -40,13 +40,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Creating the Copy stencil**\n", + "### Creating the Copy stencil\n", "\n", - "The `NDSL` and `gt4py` module contain key terms that will be used to create the stencil. Many terms are covered in the [GT4Py basic tutorial](./01_gt4py_basics.ipynb) notebook, but we'll briefly recap.\n", + "The `NDSL` and `gt4py` module contain key terms that will be used to create the stencil. Many terms are covered in the [GT4Py basic tutorial](./01_gt4py_basics.ipynb) notebook, but we'll briefly recap.\n", "\n", "- `FloatField` : This type can generally can be thought of as a `gt4py` 3-dimensional `numpy` array of floating point values.\n", "\n", - "- `computation(PARALLEL)` : This keyword combination means that there is no assumed order to perform calculations in the `K` (3rd) dimension of a `gt4py` storage. `PARALLEL` can be replaced by `FORWARD` or `BACKWARD` for serialized calculations in the `K` dimension.\n", + "- `computation(PARALLEL)` : This keyword combination means that there is no assumed order to perform calculations in the `K` (3rd) dimension of a `gt4py` storage. `PARALLEL` can be replaced by `FORWARD` or `BACKWARD` for serialized calculations in the `K` dimension.\n", "\n", "- `interval(...)` : This keyword specifies the range of computation in the `K` dimension.\n", "\n", @@ -72,16 +72,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that a decorator does not surround this stencil as shown before in the [basic tutorial](./01_gt4py_basics.ipynb). Instead, we'll use the `StencilFactory` to \"initiate\" the stencil." + "Note that a decorator does not surround this stencil as shown before in the [basic tutorial](./01_gt4py_basics.ipynb). Instead, we'll use the `StencilFactory` to \"initiate\" the stencil." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### **Creating a class that performs a stencil computation**\n", + "### Creating a class that performs a stencil computation\n", "\n", - "Using the `StencilFactory` object created earlier, the code will now create a class `CopyField` that takes `copy_field_stencil` and defines the computation domain from the parameters `origin` and `domain` within `__init__`. `origin` indicates the \"starting\" point of the stencil calculation, and `domain` indicates the extent of the stencil calculation in the three dimensions. Note that when creating `stencil_factory`, a 6 by 6 by 1 sized domain surrounded with a halo layer of size 1 was defined. Thus, whenever a `CopyField` object is created, it will perform calculations within the 6 by 6 by 1 domain (specified by `domain=grid_indexing.domain_compute()`), and the `origin` will start at the `[0,0,0]` location of the 6 by 6 by 1 grid (specified by `origin=grid_indexing.origin_compute()`)." + "Using the `StencilFactory` object created earlier, the code will now create a class `CopyField` that takes `copy_field_stencil` and defines the computation domain from the parameters `origin` and `domain` within `__init__`. `origin` indicates the \"starting\" point of the stencil calculation, and `domain` indicates the extent of the stencil calculation in the three dimensions. Note that when creating `stencil_factory`, a 6 by 6 by 1 sized domain surrounded with a halo layer of size 1 was defined. Thus, whenever a `CopyField` object is created, it will perform calculations within the 6 by 6 by 1 domain (specified by `domain=grid_indexing.domain_compute()`), and the `origin` will start at the `[0,0,0]` location of the 6 by 6 by 1 grid (specified by `origin=grid_indexing.origin_compute()`)." ] }, { @@ -114,9 +114,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Allocating Data in `NDSL`**\n", + "### Allocating Data in `NDSL`\n", "\n", - "The next code section will create arrays using `Quantity`. For more information about `Quantity`, see the [GT4Py Basic tutorial](./01_gt4py_basics.ipynb#Copy_Stencil_example)." + "The next code section will create arrays using `Quantity`. For more information about `Quantity`, see the [GT4Py Basic tutorial](./01_gt4py_basics.ipynb#Copy_Stencil_example)." ] }, { @@ -153,7 +153,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Calling `copy_field` stencil**\n", + "### Calling `copy_field` stencil\n", "\n", "The code will call `copy_field` to execute `copy_field_stencil` using the previously defined `Quantity` data containers and plot the result at `K = 0`." ] @@ -174,20 +174,20 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "From the plot, we see that the copy is only applied to the inner 6 by 6 area and not the entire domain. The stencil in this case only applies in this \"domain\" and not the \"halo\" region surrounding the domain." + "From the plot, we see that the copy is only applied to the inner 6 by 6 area and not the entire domain. The stencil in this case only applies in this \"domain\" and not the \"halo\" region surrounding the domain." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### **Applying a J offset**\n", + "### Applying a J offset\n", "\n", - "The next example will create a stencil that takes a `Quantity` as an input, shift the input by 1 in the `-J` direction, and write it to an output `Quantity`. This stencil is defined in `copy_field_offset_stencil`.\n", + "The next example will create a stencil that takes a `Quantity` as an input, shift the input by 1 in the `-J` direction, and write it to an output `Quantity`. This stencil is defined in `copy_field_offset_stencil`.\n", "\n", - "Note that in `copy_field_offset_stencil`, the shift in the `J` dimension is performed by referencing the `J` object from `ndsl.dsl.gt4py` for simplicity. This reference will apply the shift in `J` to the entire input domain. Another way to perform the shift without referencing the `J` object is to write `[0,-1,0]` (assuming that the variable being modified is 3-dimensional) instead of `[J-1]`.\n", + "Note that in `copy_field_offset_stencil`, the shift in the `J` dimension is performed by referencing the `J` object from `ndsl.dsl.gt4py` for simplicity. This reference will apply the shift in `J` to the entire input domain. Another way to perform the shift without referencing the `J` object is to write `[0,-1,0]` (assuming that the variable being modified is 3-dimensional) instead of `[J-1]`.\n", "\n", - "With the stencil in place, a class `CopyFieldOffset` is defined using the `StencilFactory` object and `copy_field_offset_stencil`. The class is instantiated and demonstrated to shift `qty_in` by 1 in the J-dimension and write to `qty_out`." + "With the stencil in place, a class `CopyFieldOffset` is defined using the `StencilFactory` object and `copy_field_offset_stencil`. The class is instantiated and demonstrated to shift `qty_in` by 1 in the J-dimension and write to `qty_out`." ] }, { @@ -246,7 +246,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Limits to offset : Cannot set offset outside of usable domain**\n", + "### Limits to offset : Cannot set offset outside of usable domain\n", "\n", "Note that when the copy offset by `-1` in the `j`-direction is performed, the 'halo' region at `J = 8` is copied over due to the `J` shift. This means that there are limits to the shift amount since choosing a large shift amount may result in accessing a data region that does not exist. The following example shows this by trying to perform a shift by `-2` in the `j`-direction." ] @@ -288,9 +288,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### **Example demonstrating error when writing to offset outputs**\n", + "### Example demonstrating error when writing to offset outputs\n", "\n", - "While offsets can be applied to all input `Quantity` variables in a stencil, output `Quantity` variables cannot have such offsets. When an offset is applied to an output stencil calculation, the error `GTScriptSyntaxError: Assignment to non-zero offsets is not supported.` will be displayed." + "While offsets can be applied to all input `Quantity` variables in a stencil, output `Quantity` variables cannot have such offsets. When an offset is applied to an output stencil calculation, the error `GTScriptSyntaxError: Assignment to non-zero offsets is not supported in IJ." ] }, { diff --git a/examples/NDSL/03_orchestration_basics.ipynb b/examples/NDSL/03_orchestration_basics.ipynb index bd290fb0..93f818d5 100644 --- a/examples/NDSL/03_orchestration_basics.ipynb +++ b/examples/NDSL/03_orchestration_basics.ipynb @@ -4,17 +4,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# **NDSL Orchestration Basics**\n", + "# NDSL Orchestration Basics\n", "\n", - "### **Introduction**\n", + "### Introduction\n", "\n", - "When writing code using NDSL, there will be moments where an algorithm or code pattern does not match the stencil paradigm, and shoehorning the algorithm into the paradigm increases development difficulty. For these moments, we have a capability called orchestration that enables developers to use regular Python for non-stencil algorithms alongside stencil-based code via [DaCe](https://github.com/spcl/dace). DaCe also will attempt to find optimizations before output C++ code.\n", + "When writing code using NDSL, there will be moments where an algorithm or code pattern does not match the stencil paradigm, and shoehorning the algorithm into the paradigm increases development difficulty. For these moments, we have a capability called orchestration that enables developers to use regular Python for non-stencil algorithms alongside stencil-based code via [DaCe](https://github.com/spcl/dace). DaCe also will attempt to find optimizations before output C++ code.\n", "\n", "In this example, we will explore how to orchestrate a codebase using NDSL.\n", "\n", "### **Orchestration Example**\n", "\n", - "We'll step through a simple example that will orchestrate a codebase containing stencils and Python code. First we'll import the necessary packages." + "We'll step through a simple example that will orchestrate a codebase containing stencils and Python code. First we'll import the necessary packages." ] }, { @@ -44,7 +44,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Next we'll define a simple stencil that sums the values around a point and applies a weight factor to that sum. Note that unlike [previous](./01_gt4py_basics.ipynb#Copy_Stencil_example) examples, we are not using the `@stencil` decorator since this stencil will be referenced within a `StencilFactory` function call." + "Next we'll define a simple stencil that sums the values around a point and applies a weight factor to that sum. Note that unlike [previous](./01_gt4py_basics.ipynb#Copy_Stencil_example) examples, we are not using the `@stencil` decorator since this stencil will be referenced within a `StencilFactory` function call." ] }, { @@ -68,7 +68,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We'll define an object that enables the orchestration and combines both stencils and regular Python codes. The orchestration occurs with the `orchestrate` call in the `__init__` definition. Within `__call__`, there's a combination of both stencil and regular python codes." + "We'll define an object that enables the orchestration and combines both stencils and regular Python codes. The orchestration occurs with the `orchestrate` call in the `__init__` definition. Within `__call__`, there's a combination of both stencil and regular python codes." ] }, { @@ -107,7 +107,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Next, we'll create a simple driver that defines the domain and halo size, specifies the backend (`dace:cpu` in order to use DaCe), and uses the boilerplate code to create a stencil and quantity factory objects. These objects help define the computational domain used for this particular example. After defining quantities (`in_field` and `out_field`) to hold the appropriate values and creating an object `local_sum` for our combined stencil/Python calculation, `local_sum` is called to perform the computation. In the output, we can see DaCe orchestrating the code. " + "Next, we'll create a simple driver that defines the domain and halo size, specifies the backend (`dace:cpu` in order to use DaCe), and uses the boilerplate code to create a stencil and quantity factory objects. These objects help define the computational domain used for this particular example. After defining quantities (`in_field` and `out_field`) to hold the appropriate values and creating an object `local_sum` for our combined stencil/Python calculation, `local_sum` is called to perform the computation. In the output, we can see DaCe orchestrating the code." ] }, {