Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Devito.jl version for cfd/01_convection example #53

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

laughingrice
Copy link

In relation to issue #51 - Is there any way to define boundary conditions?
Implemented a Devito.jl version for the first example from the cfd example set under Devito

@samtkaplan
Copy link
Member

samtkaplan commented Jan 10, 2022

thanks @laughingrice. Looks great! Just a few suggestions:

  1. In the exposition, you refer to u.data[0] and u.data[1], but in the subsequent code, you use constructs such as data(u)[:,:,1]. I think the code is correct, and the explanation needs to be changed.

  2. In the exposition, you refer to u.dt, u.dxl and u.dyl, but in the code you use dxl(u) and dyl(u). Again, I believe that the code has the correct "julian" syntax.

  3. [No action needed for this PR] In the code, you have ...subdomain=grid.o.interior. Instead we should want ...subdomain=interior(grid). At the moment, I don't think Devito.jl has the interior(grid) method, so this will have to stay as is until we add it. I guess the same is true for solve and nsimplify.

  4. I believe that we can write ccode(op) rather than PyCall.builtin.print(op.o.ccode).

side-note: I guess after we merge this we will want to combine the demo and examples folders.

@deckerla
Copy link
Member

@laughingrice I believe with the last couple PRs we have Devito.jl wrappers for interior, solve and nsimplify.

We are excited and delighted by your contributions to this project! Please let us know if they expose any other functionality that we should add to Devito.jl

Copy link
Member

@deckerla deckerla left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great example! I think the suggested changes will work with your script if you rebase your branch off the newest PR.

"#### Devito implementation\n",
"Now we want to re-create the above example via a Devito operator. To do this, we can start by defining our computational grid and creating a function `u` as a symbolic `devito.TimeFunction`. The core thing to note here is that this is one of Devito's symbolic functions, which have a dual role in the creation of finite difference solvers:\n",
"* They behave symbolically like `sympy.Function` objects, so that we can construct derivatives and use them in symbolic expressions, thus inheriting all the power of automated symbolic manipulation that SymPy provides.\n",
"* They act as containers for user data by providing a `.data` property, accessed via the `Devito.data` function that wraps automatically allocated memory space in a neat Julia array.\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"* They act as containers for user data by providing a `.data` property, accessed via the `Devito.data` function that wraps automatically allocated memory space in a neat Julia array.\n",
"* They act as containers for user data by providing a `data` property, accessed via the `Devito.data` function that wraps automatically allocated memory space in a neat Julia array.\n",

"source": [
"# Specify the `interior` flag so that the stencil is only\n",
"# applied to the interior of the domain.\n",
"eq = Eq(dt(u) + c * dxl(u) + c * dyl(u), subdomain=grid.o.interior)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"eq = Eq(dt(u) + c * dxl(u) + c * dyl(u), subdomain=grid.o.interior)"
"eq = Eq(dt(u) + c * dxl(u) + c * dyl(u), subdomain=interior(grid))"

"# nsimplify: 1.0*x = x\n",
"# pprint(nsimplify(stencil))\n",
"\n",
"Devito.devito.sympy.nsimplify(stencil)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Devito.devito.sympy.nsimplify(stencil)"
"stencil = nsimplify(stencil)"

"metadata": {},
"outputs": [],
"source": [
"PyCall.builtin.print(op.o.ccode)"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"PyCall.builtin.print(op.o.ccode)"
"print(ccode(op))"

"metadata": {},
"outputs": [],
"source": [
"# from devito import solve\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"# from devito import solve\n",

"* They behave symbolically like `sympy.Function` objects, so that we can construct derivatives and use them in symbolic expressions, thus inheriting all the power of automated symbolic manipulation that SymPy provides.\n",
"* They act as containers for user data by providing a `.data` property, accessed via the `Devito.data` function that wraps automatically allocated memory space in a neat Julia array.\n",
"\n",
"The particular `TimeFunction` type that we will declare our variable $u$ as in this case is aware of the fact that we will want to implement a timestepping algorithm with it. So the object `u` will declare two buffers of shape `(nx, ny)` for us, as defined by the `Grid` object, and present them as `u.data[0]` and `u.data[1]`. Let's fill the initial buffer with some data and look at it:"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"The particular `TimeFunction` type that we will declare our variable $u$ as in this case is aware of the fact that we will want to implement a timestepping algorithm with it. So the object `u` will declare two buffers of shape `(nx, ny)` for us, as defined by the `Grid` object, and present them as `u.data[0]` and `u.data[1]`. Let's fill the initial buffer with some data and look at it:"
"The particular `TimeFunction` type that we will declare our variable $u$ as in this case is aware of the fact that we will want to implement a timestepping algorithm with it. So the object `u` will declare two buffers of shape `(nx, ny)` for us, as defined by the `Grid` object, and present them as `data(u)[1]` and `data(u)[2]`. Let's fill the initial buffer with some data and look at it:"

"cell_type": "markdown",
"metadata": {},
"source": [
"Nice. Now we can look at deriving our 3-point stencil using the symbolic capabilities given to our function $u$ by SymPy. For this we will first construct our derivative terms in space and time. For the forward derivative in time we can easily use Devito's shorthand notation `u.dt` to denote the first derivative in time and `u.dxl` and `u.dyl` to denote the space derivatives. Note that the `l` means were using the \"left\" or backward difference here to adhere to the discretization used in the original tutorials.\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Nice. Now we can look at deriving our 3-point stencil using the symbolic capabilities given to our function $u$ by SymPy. For this we will first construct our derivative terms in space and time. For the forward derivative in time we can easily use Devito's shorthand notation `u.dt` to denote the first derivative in time and `u.dxl` and `u.dyl` to denote the space derivatives. Note that the `l` means were using the \"left\" or backward difference here to adhere to the discretization used in the original tutorials.\n",
"Nice. Now we can look at deriving our 3-point stencil using the symbolic capabilities given to our function $u$ by SymPy. For this we will first construct our derivative terms in space and time. For the forward derivative in time we can easily use Devito's shorthand notation `dt(u)` to denote the first derivative in time and `dxl(u)` and `dyl(u)` to denote the space derivatives. Note that the `l` means were using the \"left\" or backward difference here to adhere to the discretization used in the original tutorials.\n",

"# from devito import solve\n",
"# from sympy import nsimplify, pprint\n",
"\n",
"stencil = Devito.devito.solve(eq, forward(u))\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"stencil = Devito.devito.solve(eq, forward(u))\n",
"stencil = solve(eq, forward(u))\n",

"\n",
"# Create an operator that updates the forward stencil point\n",
"# Note that the subs parameter is required for this to work\n",
"op = Operator(Eq(forward(u), stencil, subdomain=grid.o.interior); subs=spacing_map(grid))\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"op = Operator(Eq(forward(u), stencil, subdomain=grid.o.interior); subs=spacing_map(grid))\n",
"op = Operator(Eq(forward(u), stencil, subdomain=interior(grid)); subs=spacing_map(grid))\n",

"Now, despite getting a correct looking result, there is still one problem with the above operator: It doesn't set any boundary conditions as part of the time loop. We also note that the operator includes a time loop, but at this point Devito doesn't actually provide any language constructs to explicitly define different types of boundary conditions (Devito is probably still a kind of prototype at this point). Luckily though, Devito provides a backdoor for us to insert custom expression in the so-called \"indexed\" or \"low-level\" API that allow us to encode the Dirichlet boundary condition of the original example.\n",
"\n",
"#### The \"indexed\" or low-level API\n",
"The `TimeFunction` field we created earlier behaves symbolically like a `sympy.Function` object with the appropriate indices, eg. `u(t, x, y)`. If we take a simple first-order derivative of that we have a term that includes the spacing variable `h`, which Devito uses as the default for encoding $dx$ or $dy$. For example, `u.dx` simply expands to `-u(t, x, y)/h + u(t, x + h, y)/h`.\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"The `TimeFunction` field we created earlier behaves symbolically like a `sympy.Function` object with the appropriate indices, eg. `u(t, x, y)`. If we take a simple first-order derivative of that we have a term that includes the spacing variable `h`, which Devito uses as the default for encoding $dx$ or $dy$. For example, `u.dx` simply expands to `-u(t, x, y)/h + u(t, x + h, y)/h`.\n",
"The `TimeFunction` field we created earlier behaves symbolically like a `sympy.Function` object with the appropriate indices, eg. `u(t, x, y)`. If we take a simple first-order derivative of that we have a term that includes the spacing variable `h`, which Devito uses as the default for encoding $dx$ or $dy$. For example, `dx(u)` simply expands to `-u(t, x, y)/h + u(t, x + h, y)/h`.\n",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants