# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # This notebook demos the FVM laplacian

# Compute the Laplacian using combinations of the differential operators encountered so far

# +
from dusk.script import *


@stencil
def laplacian_fvm(
    u: Field[Edge], 
    v: Field[Edge], 
    nx: Field[Edge], 
    ny: Field[Edge],
    uv_div: Field[Cell],
    uv_curl: Field[Vertex],
    grad_of_curl: Field[Edge],
    grad_of_div: Field[Edge],
    uv_nabla2: Field[Edge],
    L: Field[Edge],
    dualL: Field[Edge],
    A: Field[Cell],
    dualA: Field[Vertex],
    tangent_orientation: Field[Edge],
    edge_orientation_vertex: Field[Vertex > Edge],
    edge_orientation_cell: Field[Cell > Edge],
) -> None:

    with levels_upward as k:

        # compute curl (on vertices)
        uv_curl = sum_over(Vertex > Edge, (u*nx + v*ny) * dualL * edge_orientation_vertex) / dualA

        # compute divergence (on cells)
        uv_div = sum_over(Cell > Edge, (u*nx + v*ny) * L * edge_orientation_cell) / A

        # first term of of nabla2 (gradient of curl)
        grad_of_curl = sum_over(Edge > Vertex, uv_curl, weights=[-1., 1, ])*tangent_orientation/L

        # second term of of nabla2 (gradient of divergence)
        grad_of_div = sum_over(Edge > Cell, uv_div, weights=[-1., 1, ])/dualL        

        # finalize nabla2 (difference between the two gradients)
        uv_nabla2 = grad_of_div - grad_of_curl



# -

# Then we can use dusk's Python API to convert the stencils to SIR. This API can also invoke dawn to compile SIR to C++:

from dusk.transpile import callables_to_pyast, pyast_to_sir, sir_to_json
with open("laplacian_fvm.sir", "w+") as f:
    sir = pyast_to_sir(callables_to_pyast([laplacian_fvm]))
    f.write(sir_to_json(sir))
# !dawn-opt laplacian_fvm.sir | dawn-codegen -b naive-ico -o laplacian_fvm_cxx-naive.cpp

# The generated C++ code also requires a driver which is already setup for this demo. With the driver code we can generate an executable `runner`:

# !make

# The runner is going to execute the Laplacian stencil. The divergence and curl are intermediary results this time around, and checked automatically. There is no need for you to specify anything, just execute the runner to see which quantities you got right!

# !./runner 

# Besides ensuring the error norms L1, L2 and L infinity are small (they should all be well below 0.1), you can also have a look at the test function and its Laplacian by executing `checker.py laplacian`. You are free to also look at the `divergence` or `curl` computed above, by using `checker.py divergence` and `checker.py curl`. However, those are the same as the ones computed in the last exercise. You will notice that the **error for the Laplacian is a lot worse** than for the other differentials. We will address this in the next exercise. 

# %run checker.py laplacian

StarcoderdataJupyterScriptsDedupFiltered