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

Using a mixed Function as a control #1856

Open
jwallwork23 opened this issue Oct 2, 2020 · 0 comments
Open

Using a mixed Function as a control #1856

jwallwork23 opened this issue Oct 2, 2020 · 0 comments

Comments

@jwallwork23
Copy link
Contributor

I'm trying to invert for an initial condition using firedrake-adjoint and have noticed that an error arises if the control is a from mixed function space.

Consider the Thetis 2d shallow water demo. If the control is the initial tuple then the ReducedFunctional built on the square L2 norm of the final solution tuple gives inconsistent output. If the control is the initial elevation component then everything is okay.

control = Control(q_init)

Unrolling the tape,   J = 2.94130152e+07
Rerunning the solver, J = 3.04229596e+07

vs
uv_init, elev_init = q_init.split(); control = Control(elev_init)

Unrolling the tape,   J = 3.04229596e+07
Rerunning the solver, J = 3.04229596e+07

See below for code. This issue may be related to #1843.

from thetis import *
from firedrake_adjoint import *
import numpy as np

# Mesh
lx = 40e3
ly = 2e3
nx = 25
ny = 2
mesh2d = RectangleMesh(nx, ny, lx, ly)

# Bathymetry
P1_2d = FunctionSpace(mesh2d, 'CG', 1)
bathymetry_2d = Function(P1_2d, name='Bathymetry')
depth = 20.0
bathymetry_2d.assign(depth)

# Timestepping
t_end = 0.25 * 3600
t_export = 100.0

# Initial condition
V = VectorFunctionSpace(mesh2d, 'DG', 1)*FunctionSpace(mesh2d, 'CG', 2)
q_init = Function(V)
uv_init, elev_init = q_init.split()
xy = SpatialCoordinate(mesh2d)
gauss_width = 4000.
gauss_ampl = 2.0
gauss_expr = gauss_ampl * exp(-((xy[0]-lx/2)/gauss_width)**2)
elev_init.interpolate(gauss_expr)

def my_reduced_functional(init):
    """
    Given an initial surface, run the forward model and
    evaluate some functional of the final solution tuple.
    """
    solver_obj = solver2d.FlowSolver2d(mesh2d, bathymetry_2d)
    options = solver_obj.options
    options.element_family = 'dg-cg'
    options.simulation_export_time = t_export
    options.simulation_end_time = t_end
    options.timestepper_type = 'CrankNicolson'
    options.timestep = 50.0
    u_init, eta_init = init.split()
    solver_obj.assign_initial_conditions(uv=u_init, elev=eta_init)
    solver_obj.iterate()
    q = solver_obj.fields.solution_2d
    return assemble(inner(q, q)*dx)

# Choose a control, write to tape
control = Control(elev_init)  # NOTE: does not work if elev_init replaced with q_init
J = my_reduced_functional(q_init)
print("Initially, J = {:.8e}".format(J))
stop_annotating()
Jhat = ReducedFunctional(J, control)  # Create a ReducedFunctional object

# Change the initial condition and check for consistency
elev_init.assign(-elev_init)
J_unrolled = Jhat(elev_init)  # NOTE: does not work if elev_init replaced with q_init
J_rerun = my_reduced_functional(q_init)
print("Unrolling the tape,   J = {:.8e}".format(J_unrolled))
print("Rerunning the solver, J = {:.8e}".format(J_rerun))
assert np.isclose(J_unrolled, J_rerun)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants