What can be expected from replay?

Asked by Marie Rognes

A couple of questions/issues and a general question:

1. The below code snippet gives 0 equations registered in the .html output -- I would expect at least 1. Also, the replay reports success, this seems disturbing.

2. If commenting in the vector modification in "Issue 2", at least 1 equation is registered (though we would expect 2) but replay still reports success although we are modifying the vector directly. I'm pretty surprised by this...

(I'm on dolfin and dolfin-adjoint from today.)

I'm generally using replay as a first step to check that the solve is annotated correctly. But perhaps this is a little hopeful... I guess that if I deliberately turn off annotation, then I cannot expect replay to complain. Also, same if I make modifications that does not actually modify the results (setting vector values that are 0 to 0). But, in general, what can I expect replay to complain about?

from dolfin import *
from dolfin_adjoint import *

mesh = UnitIntervalMesh(2)
V = FunctionSpace(mesh, "CG", 1)
w = Function(V)

u = TrialFunction(V)
v = TestFunction(V)

f = Constant(1.0)

# Issue 1: This doesn't seem to register?
w = project(f, V)

## Issue 2: Success when modifying the vector?
#solve(u*v*dx == v*dx, w)
#w.vector()[1] = 0.0
#print w.vector().array()

adj_html("forward.html", "forward")

success = replay_dolfin(tol=0.0, stop=True)
print "success = ", success

Question information

Language:
English Edit question
Status:
Solved
For:
dolfin-adjoint Edit question
Assignee:
No assignee Edit question
Solved by:
Marie Rognes
Solved:
Last query:
Last reply:
Revision history for this message
Patrick Farrell (pefarrell) said :
#1

Hi Marie,

Issue #1: The logic for when projects and interpolates should be annotated is a little complicated, because I wanted it to "do the right thing" in as many cases as possible. In particular, if you're projecting a Constant, it doesn't annotate it (dolfin_adjoint/projection.py:22), because likely you don't want it to. The fact that f is constant 1 everywhere will be noted the first time f is used in a solve.

Issue #2: When that solve happens, it does two things: annotates the solve, and records the value of the solved-for variable. That all happens inside that call to solve(). The replay will replay the tape, and then compare its solution to the solution *obtained at the point of that solve()*. The fact that you've changed w afterwards is of no consequence to the successful replay of that solve call, because w is never used again (it's a redundant branch in the computational graph).

Now, when would the replay help you? Change the commented out code to

solve(u*v*dx == v*dx, w)
w.vector()[1] = 0.0
solve(u*v*dx == w*v*dx, w)

Here, d-a only sees the two solve() calls, but you've changed w in some non-observable way in between. That means that when d-a replays the second solve, it will use the unmodified value of w, rather than the modified one, and so there will be a difference between the recorded value and the replayed value:

Solving linear system of size 3 x 3 (PETSc Krylov solver).
Solving linear variational problem.
Solving linear variational problem.
Comparing w_2:0:1:Forward against previously recorded value: norm of the difference is 5.773503e-01 (> tolerance of 0.000000e+00)
success = False

Does that help?

Cheerio,

Patrick

Revision history for this message
Marie Rognes (meg-simula) said :
#2

Hi Patrick,

Thanks for the explanation! Issue 2 is now very much clearer

However, if I replace the constant f with f = Expression("sin(pi*x[0])", degree=2) in the first issue, still no equations are recorded. Moreover, if I try to force annotation of either case (with annotate=True), still nothing seems to be recorded. I find this unexpected.

Revision history for this message
Marie Rognes (meg-simula) said :
#3

Looking at the code, why this happens is of course obvious. However, I find those "don't have any possibility what so ever of annotating projections of constants/expression" confusing. Anyhow, at least now the explanation is recorded here for all of eternity ;-)

Revision history for this message
Patrick Farrell (pefarrell) said :
#4

I suppose I have to err between missing important project()s and recording redundant ones. If you're project()ing a known constant or expression, you're probably just initialising your fields -- those initial conditions will be recorded when that function appears in a solve(). If you're projecting a function that was previously solved for, on the other hand, it's probably part of the main chain of computation from parameters to functional, and so it should be recorded. Occasionally it isn't actually part of the main chain, and you have to annotate=False it or suffer a small performance penalty (cf. Gabriel's question a few days ago).

But I'm open to changing the logic, if you can generate a compelling test case that shows that a different default behaviour would be better (by better I mean "minimises the expected amount of manually adding annotate=True|False flags").

Revision history for this message
Marie Rognes (meg-simula) said :
#5

I'm now spending some time debugging something is not working correctly by trying to reduce my solver to something minimal. The number of things that are not annotated even though I say "annotate = True" (projections of Constants/Expressions, assignment of things that have not been seen before(?!)) is not helping...

Would it be an idea that the default is annotate=None and if annotate=None, modify annotate to True/False depending on heuristics, but accept True/False if the user actually says True/False?