# Debugging¶

## Visualising the system¶

It is sometimes useful when debugging a problem to see dolfin-adjoint’s
interpretation of your forward system, and the other models it derives
from that. The `visualise`

function
visualises the system as a graph using TensorFlow. To do this add

```
tape = get_working_tape()
tape.visualise()
```

This will create a log directory with TensorFlow event files. We can then run TensorBoard, which comes bundled with TensorFlow, and point it to this log directory:

```
tensorboard --logdir=log
```

By default the log directory is a directory `log`

in the
current working directory. This can be changed by specifying a
directory in the `logdir`

keyword argument to
`visualise`

.

Finally, we can open http://localhost:6006/ in a web browser to view the graph. To demonstrate, let us use a simplified version of our old Burgers’ equation example:

```
from dolfin import *
from fenics_adjoint import *
n = 30
mesh = UnitSquareMesh(n, n)
V = VectorFunctionSpace(mesh, "CG", 2)
u = project(Expression(("sin(2*pi*x[0])", "cos(2*pi*x[1])"), degree=2), V)
u_next = Function(V)
v = TestFunction(V)
nu = Constant(0.0001)
timestep = Constant(0.01)
F = (inner((u_next - u)/timestep, v)
+ inner(grad(u_next)*u_next, v)
+ nu*inner(grad(u_next), grad(v)))*dx
bc = DirichletBC(V, (0.0, 0.0), "on_boundary")
solve(F == 0, u_next, bc)
tape = get_working_tape()
tape.visualise()
```

Here we solve the equation for only one timestep.

Download the code to find graph.

Running TensorBoard and opening http://localhost:6006/ in our web browser shows us the following graph:

Each node corresponds to an elementary operation, and we see that the structure is what we should expect: two functions, two constants and a set of boundary conditions go into an equation and we get one function out. To increase readability further we can add names to the functions:

```
from dolfin import *
from fenics_adjoint import *
n = 30
mesh = UnitSquareMesh(n, n)
V = VectorFunctionSpace(mesh, "CG", 2)
u = project(Expression(("sin(2*pi*x[0])", "cos(2*pi*x[1])"), degree=2), V)
u_next = Function(V, name="u_next")
v = TestFunction(V)
nu = Constant(0.0001, name="nu")
timestep = Constant(0.01, name="dt")
F = (inner((u_next - u)/timestep, v)
+ inner(grad(u_next)*u_next, v)
+ nu*inner(grad(u_next), grad(v)))*dx
bc = DirichletBC(V, (0.0, 0.0), "on_boundary")
solve(F == 0, u_next, bc)
tape = get_working_tape()
tape.visualise()
```

The resulting graph is the following:

Here we have expanded some of the nodes by double-clicking on them. We
see that it is indeed `u_next`

that is found by the equation
solve.

Download the code to find the graph with names.

If we have a time loop, the graph can easily become large and difficult
to read. The `name_scope`

factory
function can be used to make this easier. To demonstrate this, we add a
time loop to our example above:

```
from dolfin import *
from fenics_adjoint import *
n = 30
mesh = UnitSquareMesh(n, n)
V = VectorFunctionSpace(mesh, "CG", 2)
u = project(Expression(("sin(2*pi*x[0])", "cos(2*pi*x[1])"), degree=2), V)
u_next = Function(V, name="u_next")
v = TestFunction(V)
nu = Constant(0.0001, name="nu")
timestep = Constant(0.01, name="dt")
F = (inner((u_next - u)/timestep, v)
+ inner(grad(u_next)*u_next, v)
+ nu*inner(grad(u_next), grad(v)))*dx
bc = DirichletBC(V, (0.0, 0.0), "on_boundary")
tape = get_working_tape()
t = 0.0
end = 0.05
while (t <= end):
with tape.name_scope("Timestep"):
solve(F == 0, u_next, bc)
u.assign(u_next)
t += float(timestep)
tape.visualise()
```

Here, we should note the line after we enter the `while`

loop. In this line we use a `with`

statement together with
`name_scope`

and a name for the
scope. This will ensure that all nodes corresponding to one time step
will be added to its own scope. After the time loop, we call
`visualise`

and get the following
graph:

We can then expand the scopes as we like. Here we have expanded the first time step:

Download the code to find the graph with name scopes.

In the next section we discuss parallelisation.