Exemplo n.º 1
0
    def __init__(self,
                 *args,
                 rayleigh_number=7.e5,
                 prandtl_number=0.0216,
                 stefan_number=0.046,
                 liquidus_temperature=0.,
                 hotwall_temperature=1.,
                 initial_temperature=-0.1546,
                 cutoff_length=0.5,
                 element_degrees=(1, 2, 2),
                 mesh_dimensions=(20, 40),
                 **kwargs):

        if "solution" not in kwargs:

            mesh = fe.RectangleMesh(nx=mesh_dimensions[0],
                                    ny=mesh_dimensions[1],
                                    Lx=cutoff_length,
                                    Ly=1.)

            element = sapphire.simulations.navier_stokes_boussinesq.element(
                cell=mesh.ufl_cell(), degrees=element_degrees)

            kwargs["solution"] = fe.Function(fe.FunctionSpace(mesh, element))

        super().__init__(*args,
                         reynolds_number=1. / prandtl_number,
                         rayleigh_number=rayleigh_number,
                         prandtl_number=prandtl_number,
                         stefan_number=stefan_number,
                         liquidus_temperature=liquidus_temperature,
                         hotwall_temperature=hotwall_temperature,
                         initial_temperature=initial_temperature,
                         **kwargs)
Exemplo n.º 2
0
 def __init__(self, *args,
         rayleigh_number = 7.e5,
         prandtl_number = 0.0216,
         stefan_number = 0.046,
         liquidus_temperature = 0.,
         hotwall_temperature = 1.,
         initial_temperature = -0.1546,
         cutoff_length = 0.5,
         taylor_hood_pressure_degree = 1,
         temperature_degree = 2,
         mesh_dimensions = (20, 40),
         **kwargs):
         
     if "solution" not in kwargs:
         
         kwargs["mesh"] = fe.RectangleMesh(
             nx = mesh_dimensions[0],
             ny = mesh_dimensions[1],
             Lx = cutoff_length,
             Ly = 1.)
     
     super().__init__(
         *args,
         reynolds_number = 1./prandtl_number,
         rayleigh_number = rayleigh_number,
         prandtl_number = prandtl_number,
         stefan_number = stefan_number,
         liquidus_temperature = liquidus_temperature,
         hotwall_temperature = hotwall_temperature,
         initial_temperature = initial_temperature,
         **kwargs)
         
Exemplo n.º 3
0
def test_diagnostic_solver_side_friction():
    model = icepack.models.IceShelf()
    opts = {"dirichlet_ids": [1], "side_wall_ids": [3, 4]}

    mesh = firedrake.RectangleMesh(32, 32, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, "CG", degree)
    Q = firedrake.FunctionSpace(mesh, "CG", degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    h = interpolate(h0 - dh * x / Lx, Q)
    A = interpolate(firedrake.Constant(icepack.rate_factor(T)), Q)

    # Choose the side wall friction coefficient so that, assuming the ice is
    # sliding at the maximum speed for the solution without friction, the
    # stress is 10 kPa.
    from icepack.constants import weertman_sliding_law as m

    τ = 0.01
    u_max = icepack.norm(u_initial, norm_type="Linfty")
    Cs = firedrake.Constant(τ * u_max**(-1 / m))

    solver = icepack.solvers.FlowSolver(model, **opts)
    fields = {
        "velocity": u_initial,
        "thickness": h,
        "fluidity": A,
        "side_friction": Cs
    }
    u = solver.diagnostic_solve(**fields)

    assert icepack.norm(u) < icepack.norm(u_initial)
Exemplo n.º 4
0
def test_diagnostic_solver_convergence():
    # Create an ice shelf model
    ice_shelf = icepack.models.IceShelf()
    opts = {'dirichlet_ids': [1], 'side_wall_ids': [3, 4], 'tol': 1e-12}

    # Solve the ice shelf model for successively higher mesh resolution
    for degree in range(1, 4):
        delta_x, error = [], []
        for N in range(16, 97 - 32 * (degree - 1), 4):
            mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
            x, y = firedrake.SpatialCoordinate(mesh)

            V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
            Q = firedrake.FunctionSpace(mesh, 'CG', degree)

            u_exact = interpolate(as_vector((exact_u(x), 0)), V)
            u_guess = interpolate(u_exact + as_vector((perturb_u(x, y), 0)), V)

            h = interpolate(h0 - dh * x / Lx, Q)
            A = interpolate(firedrake.Constant(icepack.rate_factor(T)), Q)

            u = ice_shelf.diagnostic_solve(h=h, A=A, u0=u_guess, **opts)
            error.append(norm(u_exact - u) / norm(u_exact))
            delta_x.append(Lx / N)

            print(delta_x[-1], error[-1])

        # Fit the error curve and check that the convergence rate is what we
        # expect
        log_delta_x = np.log2(np.array(delta_x))
        log_error = np.log2(np.array(error))
        slope, intercept = np.polyfit(log_delta_x, log_error, 1)

        print('log(error) ~= {:g} * log(dx) + {:g}'.format(slope, intercept))
        assert slope > degree + 0.8
Exemplo n.º 5
0
def test_hybrid_prognostic_solve():
    Lx, Ly = 20e3, 20e3
    h0, dh = 500.0, 100.0
    T = 254.15
    u_in = 100.0

    model = icepack.models.HybridModel()
    opts = {'dirichlet_ids': [1], 'side_wall_ids': [3, 4], 'tol': 1e-12}

    Nx, Ny = 32, 32
    mesh2d = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    mesh = firedrake.ExtrudedMesh(mesh2d, layers=1)

    V = firedrake.VectorFunctionSpace(mesh,
                                      dim=2,
                                      family='CG',
                                      degree=2,
                                      vfamily='GL',
                                      vdegree=1)
    Q = firedrake.FunctionSpace(mesh,
                                family='CG',
                                degree=2,
                                vfamily='DG',
                                vdegree=0)

    x, y, ζ = firedrake.SpatialCoordinate(mesh)
    height_above_flotation = 10.0
    d = -ρ_I / ρ_W * (h0 - dh) + height_above_flotation
    ρ = ρ_I - ρ_W * d**2 / (h0 - dh)**2

    Z = icepack.rate_factor(T) * (ρ * g * h0 / 4)**n
    q = 1 - (1 - (dh / h0) * (x / Lx))**(n + 1)
    ux = u_in + Z * q * Lx * (h0 / dh) / (n + 1)
    u0 = interpolate(firedrake.as_vector((ux, 0)), V)

    thickness = h0 - dh * x / Lx
    β = 1 / 2
    α = β * ρ / ρ_I * dh / Lx
    h = interpolate(h0 - dh * x / Lx, Q)
    h_inflow = h.copy(deepcopy=True)
    ds = (1 + β) * ρ / ρ_I * dh
    s = interpolate(d + h0 - dh + ds * (1 - x / Lx), Q)
    b = interpolate(s - h, Q)

    C = interpolate(α * (ρ_I * g * thickness) * ux**(-1 / m), Q)
    A = firedrake.Constant(icepack.rate_factor(T))

    final_time, dt = 1.0, 1.0 / 12
    num_timesteps = int(final_time / dt)

    u = model.diagnostic_solve(u0=u0, h=h, s=s, C=C, A=A, **opts)
    a0 = firedrake.Constant(0)
    a = interpolate((model.prognostic_solve(dt, h0=h, a=a0, u=u) - h) / dt, Q)

    for k in range(num_timesteps):
        h = model.prognostic_solve(dt, h0=h, a=a, u=u, h_inflow=h_inflow)
        s = icepack.compute_surface(h=h, b=b)
        u = model.diagnostic_solve(u0=u, h=h, s=s, C=C, A=A, **opts)

    assert icepack.norm(h, norm_type='Linfty') < np.inf
Exemplo n.º 6
0
def test_plot_mesh():
    nx, ny = 32, 32
    Lx, Ly = 1e5, 1e5
    mesh = firedrake.RectangleMesh(nx, ny, Lx, Ly)
    fig, axes = icepack.plot.subplots()
    icepack.plot.triplot(mesh, axes=axes)
    legend = axes.legend()
    assert legend is not None
Exemplo n.º 7
0
def test_diagnostic_solver():
    Nx, Ny = 32, 32
    mesh2d = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    mesh = firedrake.ExtrudedMesh(mesh2d, layers=1)
    Q = firedrake.FunctionSpace(mesh,
                                family='CG',
                                degree=2,
                                vfamily='DG',
                                vdegree=0)

    x, y, ζ = firedrake.SpatialCoordinate(mesh)
    h = firedrake.interpolate(h0 - dh * x / Lx, Q)
    s = firedrake.interpolate(d + h0 - dh + ds * (1 - x / Lx), Q)
    u_expr = firedrake.as_vector(((0.95 + 0.05 * ζ) * exact_u(x), 0))

    A = firedrake.Constant(icepack.rate_factor(254.15))
    C = firedrake.Constant(0.001)

    model = icepack.models.HybridModel()
    opts = {'dirichlet_ids': [1, 3, 4], 'tol': 1e-12}

    max_degree = 5
    Nz = 32
    xs = np.array([(Lx / 2, Ly / 2, k / Nz) for k in range(Nz + 1)])
    us = np.zeros((max_degree + 1, Nz + 1))
    for vdegree in range(max_degree, 0, -1):
        solver = icepack.solvers.FlowSolver(model, **opts)
        V = firedrake.VectorFunctionSpace(mesh,
                                          dim=2,
                                          family='CG',
                                          degree=2,
                                          vfamily='GL',
                                          vdegree=vdegree)
        u0 = firedrake.interpolate(u_expr, V)
        u = solver.diagnostic_solve(velocity=u0,
                                    thickness=h,
                                    surface=s,
                                    fluidity=A,
                                    friction=C)

        V0 = firedrake.VectorFunctionSpace(mesh,
                                           dim=2,
                                           family='CG',
                                           degree=2,
                                           vfamily='DG',
                                           vdegree=0)

        depth_avg_u = firedrake.project(u, V0)
        shear_u = firedrake.project(u - depth_avg_u, V)
        assert icepack.norm(shear_u, norm_type='Linfty') > 1e-2

        us_center = np.array(u.at(xs, tolerance=1e-6))
        us[vdegree, :] = np.sqrt(np.sum(us_center**2, 1))

        norm = np.linalg.norm(us[max_degree, :])
        error = np.linalg.norm(us[vdegree, :] - us[max_degree, :]) / norm
        print(error, flush=True)
        assert error < 1e-2
Exemplo n.º 8
0
def test_diagnostic_solver_parameterization():
    # Define a new viscosity functional, parameterized in terms of the
    # rheology `B` instead of the fluidity `A`
    from firedrake import inner, grad, sym, tr as trace, Identity, sqrt

    def M(ε, B):
        I = Identity(2)
        tr_ε = trace(ε)
        ε_e = sqrt((inner(ε, ε) + tr_ε**2) / 2)
        μ = 0.5 * B * ε_e**(1/n - 1)
        return 2 * μ * (ε + tr_ε * I)

    def ε(u):
        return sym(grad(u))

    def viscosity(**kwargs):
        u = kwargs['velocity']
        h = kwargs['thickness']
        B = kwargs['rheology']
        return n/(n + 1) * h * inner(M(ε(u), B), ε(u))

    # Make a model object with our new viscosity functional
    model = icepack.models.IceShelf(viscosity=viscosity)
    opts = {'dirichlet_ids': [1, 3, 4]}

    # Same as before
    delta_x, error = [], []
    for N in range(16, 65, 4):
        mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
        x, y = firedrake.SpatialCoordinate(mesh)

        degree = 2
        V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
        Q = firedrake.FunctionSpace(mesh, 'CG', degree)

        u_exact = interpolate(as_vector((exact_u(x), 0)), V)
        u_guess = interpolate(as_vector((exact_u(x) + perturb_u(x, y), 0)), V)
        h = interpolate(h0 - dh * x / Lx, Q)
        B = interpolate(firedrake.Constant(icepack.rate_factor(T)**(-1/n)), Q)

        solver = icepack.solvers.FlowSolver(model, **opts)
        u = solver.diagnostic_solve(
            velocity=u_guess,
            thickness=h,
            rheology=B
        )
        error.append(norm(u_exact - u) / norm(u_exact))
        delta_x.append(Lx / N)

        print(delta_x[-1], error[-1])

    log_delta_x = np.log2(np.array(delta_x))
    log_error = np.log2(np.array(error))
    slope, intercept = np.polyfit(log_delta_x, log_error, 1)

    print('log(error) ~= {:g} * log(dx) + {:g}'.format(slope, intercept))
    assert slope > degree - 0.05
Exemplo n.º 9
0
def test_order_0():
    def h_expr(x):
        return h0 - dh * x / Lx

    def s_expr(x):
        return d + h0 - dh + ds * (1 - x / Lx)

    A = firedrake.Constant(icepack.rate_factor(254.15))
    C = firedrake.Constant(0.001)
    opts = {'dirichlet_ids': [1], 'side_wall_ids': [3, 4], 'tolerance': 1e-14}

    Nx, Ny = 64, 64
    mesh2d = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    x, y = firedrake.SpatialCoordinate(mesh2d)
    Q2d = firedrake.FunctionSpace(mesh2d, family='CG', degree=2)
    V2d = firedrake.VectorFunctionSpace(mesh2d, family='CG', degree=2)
    h = firedrake.interpolate(h_expr(x), Q2d)
    s = firedrake.interpolate(s_expr(x), Q2d)
    u_expr = firedrake.as_vector((exact_u(x), 0))
    u0 = firedrake.interpolate(u_expr, V2d)

    model2d = icepack.models.IceStream()
    solver2d = icepack.solvers.FlowSolver(model2d, **opts)
    u2d = solver2d.diagnostic_solve(velocity=u0,
                                    thickness=h,
                                    surface=s,
                                    fluidity=A,
                                    friction=C)

    mesh = firedrake.ExtrudedMesh(mesh2d, layers=1)
    x, y, ζ = firedrake.SpatialCoordinate(mesh)
    Q3d = firedrake.FunctionSpace(mesh,
                                  family='CG',
                                  degree=2,
                                  vfamily='DG',
                                  vdegree=0)
    V3d = firedrake.VectorFunctionSpace(mesh,
                                        dim=2,
                                        family='CG',
                                        degree=2,
                                        vfamily='GL',
                                        vdegree=0)
    h = firedrake.interpolate(h_expr(x), Q3d)
    s = firedrake.interpolate(s_expr(x), Q3d)
    u_expr = firedrake.as_vector((exact_u(x), 0))
    u0 = firedrake.interpolate(u_expr, V3d)

    model3d = icepack.models.HybridModel()
    solver3d = icepack.solvers.FlowSolver(model3d, **opts)
    u3d = solver3d.diagnostic_solve(velocity=u0,
                                    thickness=h,
                                    surface=s,
                                    fluidity=A,
                                    friction=C)

    U2D, U3D = u2d.dat.data_ro, u3d.dat.data_ro
    assert np.linalg.norm(U3D - U2D) / np.linalg.norm(U2D) < 1e-2
Exemplo n.º 10
0
def test_max_dim():
    mesh = fd.UnitSquareMesh(100, 100)

    assert pytest.approx(max_mesh_dimension(mesh), 1.0)

    mesh = fd.RectangleMesh(10, 20, 5.0, 3.0)

    assert pytest.approx(max_mesh_dimension(mesh), 5.0)

    mesh = fd.CubeMesh(10, 10, 10, 8.0)

    assert pytest.approx(max_mesh_dimension(mesh), 8.0)
Exemplo n.º 11
0
def test_damage_transport():
    nx, ny = 32, 32
    Lx, Ly = 20e3, 20e3
    mesh = firedrake.RectangleMesh(nx, ny, Lx, Ly)
    x, y = firedrake.SpatialCoordinate(mesh)

    V = firedrake.VectorFunctionSpace(mesh, "CG", 2)
    Q = firedrake.FunctionSpace(mesh, "CG", 2)

    u0 = 100.0
    h0, dh = 500.0, 100.0
    T = 268.0

    ρ = ρ_I * (1 - ρ_I / ρ_W)
    Z = icepack.rate_factor(T) * (ρ * g * h0 / 4)**n
    q = 1 - (1 - (dh / h0) * (x / Lx))**(n + 1)
    du = Z * q * Lx * (h0 / dh) / (n + 1)

    u = interpolate(as_vector((u0 + du, 0)), V)
    h = interpolate(h0 - dh * x / Lx, Q)
    A = firedrake.Constant(icepack.rate_factor(T))

    S = firedrake.TensorFunctionSpace(mesh, "DG", 1)
    ε = firedrake.project(sym(grad(u)), S)
    M = firedrake.project(membrane_stress(strain_rate=ε, fluidity=A), S)

    degree = 1
    Δ = firedrake.FunctionSpace(mesh, "DG", degree)
    D_inflow = firedrake.Constant(0.0)
    D = firedrake.Function(Δ)

    damage_model = icepack.models.DamageTransport()
    damage_solver = icepack.solvers.DamageSolver(damage_model)

    final_time = Lx / u0
    max_speed = u.at((Lx - 1.0, Ly / 2), tolerance=1e-10)[0]
    δx = Lx / nx
    timestep = δx / max_speed / (2 * degree + 1)
    num_steps = int(final_time / timestep)
    dt = final_time / num_steps

    for step in range(num_steps):
        D = damage_solver.solve(
            dt,
            damage=D,
            velocity=u,
            strain_rate=ε,
            membrane_stress=M,
            damage_inflow=D_inflow,
        )

    Dmax = D.dat.data_ro[:].max()
    assert 0 < Dmax < 1
Exemplo n.º 12
0
def test_ice_shelf_prognostic_solver(solver_type):
    ρ = ρ_I * (1 - ρ_I / ρ_W)

    Lx, Ly = 20.0e3, 20.0e3
    h0 = 500.0
    u0 = 100.0
    T = 254.15

    model = icepack.models.IceShelf(mass_transport=solver_type())
    opts = {'dirichlet_ids': [1], 'side_wall_ids': [3, 4], 'tol': 1e-12}

    delta_x, error = [], []
    for N in range(16, 65, 4):
        delta_x.append(Lx / N)

        mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
        x, y = firedrake.SpatialCoordinate(mesh)

        degree = 2
        V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
        Q = firedrake.FunctionSpace(mesh, 'CG', degree)

        q = (n + 1) * (ρ * g * h0 * u0 / 4)**n * icepack.rate_factor(T)
        ux = (u0**(n + 1) + q * x)**(1 / (n + 1))

        h = interpolate(h0 * u0 / ux, Q)
        h_initial = h.copy(deepcopy=True)

        A = firedrake.Constant(icepack.rate_factor(T))
        a = firedrake.Constant(0)

        u_guess = interpolate(firedrake.as_vector((ux, 0)), V)
        u = model.diagnostic_solve(u0=u_guess, h=h, A=A, **opts)

        final_time, dt = 1.0, 1.0 / 12
        num_timesteps = int(final_time / dt)

        for k in range(num_timesteps):
            h = model.prognostic_solve(dt, h0=h, a=a, u=u, h_inflow=h_initial)
            u = model.diagnostic_solve(u0=u, h=h, A=A, **opts)

        error.append(norm(h - h_initial) / norm(h_initial))
        print(delta_x[-1], error[-1])

    log_delta_x = np.log2(np.array(delta_x))
    log_error = np.log2(np.array(error))
    slope, intercept = np.polyfit(log_delta_x, log_error, 1)

    print('log(error) ~= {:g} * log(dx) + {:g}'.format(slope, intercept))
    assert slope > degree - 0.05
Exemplo n.º 13
0
def test_computing_surface():
    N = 16
    mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
    degree = 2
    Q = firedrake.FunctionSpace(mesh, "CG", degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    h = interpolate(h0 - dh * x / Lx, Q)
    b0 = ρ_I / ρ_W * (dh / 2 - h0)
    b = interpolate(firedrake.Constant(b0), Q)

    s = icepack.compute_surface(thickness=h, bed=b)
    x0, y0 = Lx / 2, Ly / 2
    assert abs(s((x0, y0)) - (1 - ρ_I / ρ_W) * h((x0, y0))) < 1e-8
Exemplo n.º 14
0
def test_mass_transport_solver_convergence(solver_type):
    Lx, Ly = 1.0, 1.0
    u0 = 1.0
    h_in, dh = 1.0, 0.2

    delta_x, error = [], []
    model = icepack.models.IceShelf()
    for N in range(24, 97, 4):
        delta_x.append(Lx / N)

        mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
        x, y = firedrake.SpatialCoordinate(mesh)

        degree = 1
        V = firedrake.VectorFunctionSpace(mesh, family='CG', degree=degree)
        Q = firedrake.FunctionSpace(mesh, family='CG', degree=degree)
        solver = icepack.solvers.FlowSolver(
            model, prognostic_solver_type=solver_type
        )

        h0 = interpolate(h_in - dh * x / Lx, Q)
        a = firedrake.Function(Q)
        u = interpolate(firedrake.as_vector((u0, 0)), V)
        T = 0.5
        δx = 1.0 / N
        δt = δx / u0
        num_timesteps = int(T / δt)

        h = h0.copy(deepcopy=True)
        for step in range(num_timesteps):
            h = solver.prognostic_solve(
                δt,
                thickness=h,
                velocity=u,
                accumulation=a,
                thickness_inflow=h0
            )

        z = x - u0 * num_timesteps * δt
        h_exact = interpolate(h_in - dh/Lx * firedrake.max_value(0, z), Q)
        error.append(norm(h - h_exact) / norm(h_exact))
        print(delta_x[-1], error[-1])

    log_delta_x = np.log2(np.array(delta_x))
    log_error = np.log2(np.array(error))
    slope, intercept = np.polyfit(log_delta_x, log_error, 1)

    print('log(error) ~= {:g} * log(dx) + {:g}'.format(slope, intercept))
    assert slope > degree - 0.1
Exemplo n.º 15
0
def test_vertical_velocity():

    Lx, Ly = 20e3, 20e3
    nx, ny = 48, 48

    mesh2d = firedrake.RectangleMesh(nx, ny, Lx, Ly)
    mesh = firedrake.ExtrudedMesh(mesh2d, layers=1)
    Q = firedrake.FunctionSpace(mesh,
                                family="CG",
                                degree=2,
                                vfamily="DG",
                                vdegree=0)
    Q3D = firedrake.FunctionSpace(mesh,
                                  family="DG",
                                  degree=2,
                                  vfamily="GL",
                                  vdegree=6)
    V = firedrake.VectorFunctionSpace(mesh,
                                      dim=2,
                                      family="CG",
                                      degree=2,
                                      vfamily="GL",
                                      vdegree=5)
    # note we should call the families in the vertical velocity solver.

    x, y, ζ = firedrake.SpatialCoordinate(mesh)

    u_inflow = 1.0
    v_inflow = 2.0
    mu = 0.003
    mv = 0.001

    b = firedrake.interpolate(firedrake.Constant(0.0), Q)
    s = firedrake.interpolate(firedrake.Constant(1000.0), Q)
    h = firedrake.interpolate(s - b, Q)
    u = firedrake.interpolate(
        firedrake.as_vector((mu * x + u_inflow, mv * y + v_inflow)), V)

    m = -0.01

    def analytic_vertical_velocity(h, ζ, mu, mv, m, Q3D):
        return firedrake.interpolate(
            firedrake.Constant(m) - (firedrake.Constant(mu + mv) * h * ζ), Q3D)

    w = firedrake.interpolate(
        icepack.utilities.vertical_velocity(u, h, m=m) * h, Q3D)
    w_analytic = analytic_vertical_velocity(h, ζ, mu, mv, m, Q3D)

    assert np.mean(np.abs(w.dat.data - w_analytic.dat.data)) < 10e-9
Exemplo n.º 16
0
def basemesh(L, mx, my=-1, quadrilateral=False):
    '''Set up base mesh of intervals on [-L,L] if my<0.  For 2D base mesh
    (my>0) use triangles, or optionally quadilaterals, on [-L,L]x[-L,L].'''
    if my > 0:
        base_mesh = fd.RectangleMesh(mx,
                                     my,
                                     2.0 * L,
                                     2.0 * L,
                                     quadrilateral=quadrilateral)
        base_mesh.coordinates.dat.data[:, 0] -= L
        base_mesh.coordinates.dat.data[:, 1] -= L
    else:
        base_mesh = fd.IntervalMesh(mx, length_or_left=0.0, right=2.0 * L)
        base_mesh.coordinates.dat.data[:] -= L
    return base_mesh
Exemplo n.º 17
0
def test_diagnostic_solver_convergence(solver_type):
    # Create an ice shelf model
    model = icepack.models.IceShelf()
    opts = {
        "dirichlet_ids": [1],
        "side_wall_ids": [3, 4],
        "diagnostic_solver_type": solver_type,
    }

    # Solve the ice shelf model for successively higher mesh resolution
    for degree in range(1, 4):
        delta_x, error = [], []
        for N in range(16, 97 - 32 * (degree - 1), 4):
            mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
            x, y = firedrake.SpatialCoordinate(mesh)

            V = firedrake.VectorFunctionSpace(mesh, "CG", degree)
            Q = firedrake.FunctionSpace(mesh, "CG", degree)

            u_exact = interpolate(as_vector((exact_u(x), 0)), V)
            u_guess = interpolate(u_exact + as_vector((perturb_u(x, y), 0)), V)

            h = interpolate(h0 - dh * x / Lx, Q)
            A = interpolate(firedrake.Constant(icepack.rate_factor(T)), Q)

            solver = icepack.solvers.FlowSolver(model, **opts)
            u = solver.diagnostic_solve(
                velocity=u_guess,
                thickness=h,
                fluidity=A,
                strain_rate_min=firedrake.Constant(0.0),
            )
            error.append(norm(u_exact - u) / norm(u_exact))
            delta_x.append(Lx / N)

            print(delta_x[-1], error[-1])

        # Fit the error curve and check that the convergence rate is what we
        # expect
        log_delta_x = np.log2(np.array(delta_x))
        log_error = np.log2(np.array(error))
        slope, intercept = np.polyfit(log_delta_x, log_error, 1)

        print(f"log(error) ~= {slope:g} * log(dx) + {intercept:g}")
        assert slope > degree + 0.8
Exemplo n.º 18
0
def test_diagnostic_solver_convergence():
    model = icepack.models.IceStream()
    opts = {"dirichlet_ids": [1], "side_wall_ids": [3, 4]}

    for degree in range(1, 4):
        delta_x, error = [], []
        for N in range(16, 97 - 32 * (degree - 1), 4):
            mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
            x, y = firedrake.SpatialCoordinate(mesh)

            Q = firedrake.FunctionSpace(mesh, "CG", degree)
            V = firedrake.VectorFunctionSpace(mesh, "CG", degree)

            u_exact = interpolate(as_vector((exact_u(x), 0)), V)
            u_guess = interpolate(u_exact + as_vector((perturb_u(x, y), 0)), V)

            h = interpolate(h0 - dh * x / Lx, Q)
            s = interpolate(d + h0 - dh + ds * (1 - x / Lx), Q)
            C = interpolate(friction(x), Q)
            A = interpolate(firedrake.Constant(icepack.rate_factor(T)), Q)

            solver = icepack.solvers.FlowSolver(model, **opts)
            u = solver.diagnostic_solve(
                velocity=u_guess,
                thickness=h,
                surface=s,
                fluidity=A,
                friction=C,
                strain_rate_min=firedrake.Constant(0.0),
            )
            error.append(norm(u_exact - u) / norm(u_exact))
            delta_x.append(Lx / N)

            print(delta_x[-1], error[-1])

        log_delta_x = np.log2(np.array(delta_x))
        log_error = np.log2(np.array(error))
        slope, intercept = np.polyfit(log_delta_x, log_error, 1)

        print(f"log(error) ~= {slope:g} * log(dx) + {intercept:g}")
        assert slope > degree + 0.9
Exemplo n.º 19
0
def test_mass_transport_solver_convergence():
    Lx, Ly = 1.0, 1.0
    u0 = 1.0
    h_in, dh = 1.0, 0.2

    delta_x, error = [], []
    mass_transport = MassTransport()
    for N in range(16, 97, 4):
        delta_x.append(Lx / N)

        mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
        x, y = firedrake.SpatialCoordinate(mesh)

        degree = 1
        V = firedrake.VectorFunctionSpace(mesh, family='CG', degree=degree)
        Q = firedrake.FunctionSpace(mesh, family='CG', degree=degree)

        h = interpolate(h_in - dh * x / Lx, Q)
        a = firedrake.Function(Q)
        u = interpolate(firedrake.as_vector((u0, 0)), V)
        T = 0.5
        num_timesteps = int(0.5 * N * u0 * T / Lx)
        dt = T / num_timesteps

        for k in range(num_timesteps):
            h = mass_transport.solve(dt, h0=h, a=a, u=u)

        z = x - u0 * T
        h_exact = interpolate(h_in - dh / Lx * firedrake.max_value(0, z), Q)
        error.append(norm(h - h_exact) / norm(h_exact))

        print(delta_x[-1], error[-1])

    log_delta_x = np.log2(np.array(delta_x))
    log_error = np.log2(np.array(error))
    slope, intercept = np.polyfit(log_delta_x, log_error, 1)

    assert slope > degree - 0.05
    print(slope, intercept)
Exemplo n.º 20
0
def test_diagnostic_solver_convergence():
    ice_stream = icepack.models.IceStream()
    opts = {'dirichlet_ids': [1], 'side_wall_ids': [3, 4], 'tol': 1e-12}

    for degree in range(1, 4):
        delta_x, error = [], []
        for N in range(16, 97 - 32 * (degree - 1), 4):
            mesh = firedrake.RectangleMesh(N, N, Lx, Ly)
            x, y = firedrake.SpatialCoordinate(mesh)

            Q = firedrake.FunctionSpace(mesh, 'CG', degree)
            V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)

            u_exact = interpolate(as_vector((exact_u(x), 0)), V)
            u_guess = interpolate(u_exact + as_vector((perturb_u(x, y), 0)), V)

            h = interpolate(h0 - dh * x / Lx, Q)
            s = interpolate(d + h0 - dh + ds * (1 - x / Lx), Q)
            C = interpolate(friction(x), Q)
            A = interpolate(firedrake.Constant(icepack.rate_factor(T)), Q)

            u = ice_stream.diagnostic_solve(h=h,
                                            s=s,
                                            A=A,
                                            C=C,
                                            u0=u_guess,
                                            **opts)
            error.append(norm(u_exact - u) / norm(u_exact))
            delta_x.append(Lx / N)

            print(delta_x[-1], error[-1])

        log_delta_x = np.log2(np.array(delta_x))
        log_error = np.log2(np.array(error))
        slope, intercept = np.polyfit(log_delta_x, log_error, 1)

        print('log(error) ~= {:g} * log(dx) + {:g}'.format(slope, intercept))
        assert slope > degree + 0.9
Exemplo n.º 21
0
def test_diagnostic_solver_side_friction():
    ice_shelf = icepack.models.IceShelf()
    opts = {'dirichlet_ids': [1], 'side_wall_ids': [3, 4], 'tol': 1e-12}

    mesh = firedrake.RectangleMesh(32, 32, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
    Q = firedrake.FunctionSpace(mesh, 'CG', degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    h = interpolate(h0 - dh * x / Lx, Q)
    A = interpolate(firedrake.Constant(icepack.rate_factor(T)), Q)

    # Choose the side wall friction coefficient so that, assuming the ice is
    # sliding at the maximum speed for the solution without friction, the
    # stress is 10 kPa.
    from icepack.constants import weertman_sliding_law as m
    τ = 0.01
    u_max = icepack.norm(u_initial, norm_type='Linfty')
    Cs = firedrake.Constant(τ * u_max**(-1 / m))
    u = ice_shelf.diagnostic_solve(u0=u_initial, h=h, A=A, Cs=Cs, **opts)

    assert icepack.norm(u) < icepack.norm(u_initial)
Exemplo n.º 22
0
import os
import argparse
import firedrake
import icepack.plot

parser = argparse.ArgumentParser()
parser.add_argument('--input')
parser.add_argument('--level', type=int)
parser.add_argument('--output')

args = parser.parse_args()

Lx, Ly = 640e3, 80e3
ny = 20
nx = int(Lx / Ly) * ny
coarse_mesh = firedrake.RectangleMesh(nx, ny, Lx, Ly)
mesh_hierarchy = firedrake.MeshHierarchy(coarse_mesh, args.level)
mesh = mesh_hierarchy[args.level]

Q = firedrake.FunctionSpace(mesh, family='CG', degree=1)
V = firedrake.VectorFunctionSpace(mesh, family='CG', degree=1)

h = firedrake.Function(Q)
u = firedrake.Function(V)

input_name = os.path.splitext(args.input)[0]
with firedrake.DumbCheckpoint(input_name, mode=firedrake.FILE_READ) as chk:
    timesteps, indices = chk.get_timesteps()
    chk.set_timestep(timesteps[-1], idx=indices[-1])

    chk.load(h, name='h')
Exemplo n.º 23
0
# (at your option) any later version.
#
# The full text of the license can be found in the file LICENSE in the
# icepack source directory or at <http://www.gnu.org/licenses/>.

import numpy as np
import firedrake
from firedrake import assemble, inner, as_vector, Constant, dx, ds_t, ds_b
import icepack.models
from icepack.constants import (year, thermal_diffusivity as α,
                               melting_temperature as Tm)

# Using the same mesh and data for every test case.
Nx, Ny = 32, 32
Lx, Ly = 20e3, 20e3
mesh2d = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
mesh = firedrake.ExtrudedMesh(mesh2d, layers=1)

Q = firedrake.FunctionSpace(mesh,
                            family='CG',
                            degree=2,
                            vfamily='GL',
                            vdegree=4)
V = firedrake.VectorFunctionSpace(mesh,
                                  dim=2,
                                  family='CG',
                                  degree=2,
                                  vfamily='GL',
                                  vdegree=4)
W = firedrake.FunctionSpace(mesh,
                            family='DG',
Exemplo n.º 24
0
q0bar = (0.0, 0.0)
noflow = [TOP, BOTTOM]

# problem parameters
verbose = True
freq_res = 50
CFL = 0.25
sim_time = 50.0  # simulation time

# %%
# Process section (simulation)
# ============================

# 2) Define mesh
print('* define mesh')
mesh = fd.RectangleMesh(nx * n, ny * n, Lx, Ly, quadrilateral=quad_mesh)

if verbose:
    fd.triplot(mesh)
    plt.legend()
    plt.savefig("plots/darcy_rt.png")

# ----
# 3) Setting problem (FunctionSpace, Init.Condition, VariationalForms)
print('* setting problem')

# 3.1) # Define function space for system
if quad_mesh:
    RT = fd.FunctionSpace(mesh, "RTCF", order)
    DG = fd.FunctionSpace(mesh, "DQ", order - 1)
Exemplo n.º 25
0
tol = 1e-15
verbose = False
freq_res = 100
sim_time = 1e5  # simulation time
dtime = 3e3
cfl = 0.5

# %%
# Process section (simulation)
# -----------------------------

# 2) Define mesh
print('* define mesh')
mesh = fd.RectangleMesh(nx * refine,
                        ny * refine,
                        Lx,
                        Ly,
                        quadrilateral=quad_mesh)

if verbose:
    fd.triplot(mesh)
    plt.legend()
    plt.savefig("plots/adr_dg_mesh.png")

# 3) Setting problem (FunctionSpace, Init.Bound.Condition, VariationalForms)

# 3.1) Set Function spaces
if quad_mesh:
    DG1 = fd.FunctionSpace(mesh, "DQ", order)
    vDG1 = fd.VectorFunctionSpace(mesh, "DQ", order)
    Mh = fd.FunctionSpace(mesh, "HDiv Trace", order)
Exemplo n.º 26
0
def test_hybrid_prognostic_solve(solver_type):
    Lx, Ly = 20e3, 20e3
    h0, dh = 500.0, 100.0
    T = 254.15
    u_in = 100.0

    model = icepack.models.HybridModel()
    opts = {
        'dirichlet_ids': [1],
        'side_wall_ids': [3, 4],
        'prognostic_solver_type': solver_type
    }

    Nx, Ny = 32, 32
    mesh2d = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    mesh = firedrake.ExtrudedMesh(mesh2d, layers=1)

    V = firedrake.VectorFunctionSpace(
        mesh, 'CG', 2, vfamily='GL', vdegree=1, dim=2
    )
    Q = firedrake.FunctionSpace(mesh, 'CG', 2, vfamily='DG', vdegree=0)

    x, y, ζ = firedrake.SpatialCoordinate(mesh)
    height_above_flotation = 10.0
    d = -ρ_I / ρ_W * (h0 - dh) + height_above_flotation
    ρ = ρ_I - ρ_W * d**2 / (h0 - dh)**2

    Z = icepack.rate_factor(T) * (ρ * g * h0 / 4)**n
    q = 1 - (1 - (dh/h0) * (x/Lx))**(n + 1)
    ux = u_in + Z * q * Lx * (h0/dh) / (n + 1)
    u0 = interpolate(firedrake.as_vector((ux, 0)), V)

    thickness = h0 - dh * x / Lx
    β = 1/2
    α = β * ρ / ρ_I * dh / Lx
    h = interpolate(h0 - dh * x / Lx, Q)
    h_inflow = h.copy(deepcopy=True)
    ds = (1 + β) * ρ / ρ_I * dh
    s = interpolate(d + h0 - dh + ds * (1 - x / Lx), Q)
    b = interpolate(s - h, Q)

    C = interpolate(α * (ρ_I * g * thickness) * ux**(-1/m), Q)
    A = firedrake.Constant(icepack.rate_factor(T))

    final_time, dt = 1.0, 1.0/12
    num_timesteps = int(final_time / dt)

    solver = icepack.solvers.FlowSolver(model, **opts)
    u = solver.diagnostic_solve(
        velocity=u0, thickness=h, surface=s, fluidity=A, friction=C
    )

    a = firedrake.Function(Q)
    h_n = solver.prognostic_solve(
        dt, thickness=h, velocity=u, accumulation=a, thickness_inflow=h_inflow
    )
    a.interpolate((h_n - h) / dt)

    for k in range(num_timesteps):
        h = solver.prognostic_solve(
            dt,
            thickness=h,
            velocity=u,
            accumulation=a,
            thickness_inflow=h_inflow
        )
        s = icepack.compute_surface(thickness=h, bed=b)

        u = solver.diagnostic_solve(
            velocity=u,
            thickness=h,
            surface=s,
            fluidity=A,
            friction=C
        )

    assert icepack.norm(h, norm_type='Linfty') < np.inf
Exemplo n.º 27
0
tol = 1e-15
verbose = False
freq_res = 60
sim_time = 1e6  # simulation time
cfl = 0.125
tau_e = 1

# %%
# Process section (simulation)
# -----------------------------

# 2) Define mesh
print('* define mesh')
mesh = fd.RectangleMesh(int(nx * refine),
                        int(ny * refine),
                        Lx,
                        Ly,
                        quadrilateral=quad_mesh)

if verbose:
    fd.triplot(mesh)
    plt.legend()
    plt.savefig("plots/adr_dg_mesh.png")

# 3) Setting problem (FunctionSpace, Init.Bound.Condition, VariationalForms)

# 3.1) Set Function spaces
if quad_mesh:
    DG1 = fd.FunctionSpace(mesh, "DQ", order)
    vDG1 = fd.VectorFunctionSpace(mesh, "DQ", order)
    Mh = fd.FunctionSpace(mesh, "HDiv Trace", order)
Exemplo n.º 28
0
def test_ice_shelf_inverse(solver_type):
    import icepack
    Nx, Ny = 32, 32
    Lx, Ly = 20e3, 20e3

    u0 = 100
    h0, δh = 500, 100
    T0, δT = 254.15, 5.0
    A0 = icepack.rate_factor(T0)
    δA = icepack.rate_factor(T0 + δT) - A0

    def exact_u(x):
        ρ = ρ_I * (1 - ρ_I / ρ_W)
        Z = icepack.rate_factor(T0) * (ρ * g * h0 / 4)**n
        q = 1 - (1 - (δh / h0) * (x / Lx))**(n + 1)
        δu = Z * q * Lx * (h0 / δh) / (n + 1)
        return u0 + δu

    mesh = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
    Q = firedrake.FunctionSpace(mesh, 'CG', degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    q_initial = interpolate(firedrake.Constant(0), Q)
    h = interpolate(h0 - δh * x / Lx, Q)

    def viscosity(u, h, q):
        A = A0 * firedrake.exp(-q / n)
        return icepack.models.viscosity.viscosity_depth_averaged(u, h, A)

    ice_shelf = icepack.models.IceShelf(viscosity=viscosity)
    dirichlet_ids = [1, 3, 4]
    tol = 1e-12

    r = firedrake.sqrt((x / Lx - 1 / 2)**2 + (y / Ly - 1 / 2)**2)
    R = 1 / 4
    expr = firedrake.max_value(0, δA * (1 - (r / R)**2))
    q_true = firedrake.interpolate(-n * firedrake.ln(1 + expr / A0), Q)
    u_true = ice_shelf.diagnostic_solve(h=h,
                                        q=q_true,
                                        u0=u_initial,
                                        dirichlet_ids=dirichlet_ids,
                                        tol=tol)

    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))

    def callback(inverse_solver):
        E, R = inverse_solver.objective, inverse_solver.regularization
        misfit = firedrake.assemble(E) / area
        regularization = firedrake.assemble(R) / area
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true) / np.sqrt(area)
        print(misfit, regularization, error)

    L = 1e-4 * Lx
    problem = icepack.inverse.InverseProblem(
        model=ice_shelf,
        method=icepack.models.IceShelf.diagnostic_solve,
        objective=lambda u: 0.5 * (u - u_true)**2 * dx,
        regularization=lambda q: 0.5 * L**2 * inner(grad(q), grad(q)) * dx,
        state_name='u',
        state=u_initial,
        parameter_name='q',
        parameter=q_initial,
        model_args={
            'h': h,
            'u0': u_initial,
            'tol': tol
        },
        dirichlet_ids=dirichlet_ids)

    solver = solver_type(problem, callback)

    # Set an absolute tolerance so that we stop whenever the RMS velocity
    # errors are less than 0.1 m/yr
    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))
    atol = 0.5 * 0.01 * area
    max_iterations = 100
    iterations = solver.solve(rtol=0, atol=atol, max_iterations=max_iterations)
    print('Number of iterations: {}'.format(iterations))

    assert iterations < max_iterations
    q = solver.parameter
    assert firedrake.norm(q - q_true) / firedrake.norm(q_initial -
                                                       q_true) < 1 / 4
Exemplo n.º 29
0
def test_ice_shelf_inverse_with_noise(solver_type):
    import icepack
    Nx, Ny = 32, 32
    Lx, Ly = 20e3, 20e3

    u0 = 100
    h0, δh = 500, 100
    T0, δT = 254.15, 5.0
    A0 = icepack.rate_factor(T0)
    δA = icepack.rate_factor(T0 + δT) - A0

    def exact_u(x):
        ρ = ρ_I * (1 - ρ_I / ρ_W)
        Z = icepack.rate_factor(T0) * (ρ * g * h0 / 4)**n
        q = 1 - (1 - (δh / h0) * (x / Lx))**(n + 1)
        δu = Z * q * Lx * (h0 / δh) / (n + 1)
        return u0 + δu

    mesh = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, 'CG', degree)
    Q = firedrake.FunctionSpace(mesh, 'CG', degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    q_initial = interpolate(firedrake.Constant(0), Q)
    h = interpolate(h0 - δh * x / Lx, Q)

    def viscosity(u, h, q):
        A = A0 * firedrake.exp(-q / n)
        return icepack.models.viscosity.viscosity_depth_averaged(u, h, A)

    ice_shelf = icepack.models.IceShelf(viscosity=viscosity)
    dirichlet_ids = [1, 3, 4]
    tol = 1e-12

    r = firedrake.sqrt((x / Lx - 1 / 2)**2 + (y / Ly - 1 / 2)**2)
    R = 1 / 4
    expr = firedrake.max_value(0, δA * (1 - (r / R)**2))
    q_true = firedrake.interpolate(-n * firedrake.ln(1 + expr / A0), Q)
    u_true = ice_shelf.diagnostic_solve(h=h,
                                        q=q_true,
                                        u0=u_initial,
                                        dirichlet_ids=dirichlet_ids,
                                        tol=tol)

    # Make the noise equal to 1% of the signal
    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))
    σ = 0.001 * icepack.norm(u_true) / np.sqrt(area)
    print(σ)

    u_obs = u_true.copy(deepcopy=True)
    shape = u_obs.dat.data_ro.shape
    u_obs.dat.data[:] += σ * random.standard_normal(shape) / np.sqrt(2)

    def callback(inverse_solver):
        E, R = inverse_solver.objective, inverse_solver.regularization
        misfit = firedrake.assemble(E) / area
        regularization = firedrake.assemble(R) / area
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true) / np.sqrt(area)
        print(misfit, regularization, error, flush=True)

    L = 0.25 * Lx
    regularization = L**2 / 2 * inner(grad(q_initial), grad(q_initial)) * dx
    problem = icepack.inverse.InverseProblem(
        model=ice_shelf,
        method=icepack.models.IceShelf.diagnostic_solve,
        objective=lambda u: 0.5 * ((u - u_obs) / σ)**2 * dx,
        regularization=lambda q: 0.5 * L**2 * inner(grad(q), grad(q)) * dx,
        state_name='u',
        state=u_initial,
        parameter_name='q',
        parameter=q_initial,
        model_args={
            'h': h,
            'u0': u_initial,
            'tol': tol
        },
        dirichlet_ids=dirichlet_ids)

    solver = solver_type(problem, callback)

    max_iterations = 100
    iterations = solver.solve(rtol=1e-2, atol=0, max_iterations=max_iterations)
    print('Number of iterations: {}'.format(iterations))

    assert iterations < max_iterations
    q = solver.parameter
    assert firedrake.norm(q - q_true) / firedrake.norm(q_initial -
                                                       q_true) < 1 / 3
Exemplo n.º 30
0
def test_ice_shelf_inverse_with_noise(solver_type):
    import icepack

    Nx, Ny = 32, 32
    Lx, Ly = 20e3, 20e3

    u0 = 100
    h0, δh = 500, 100
    T0, δT = 254.15, 5.0
    A0 = icepack.rate_factor(T0)
    δA = icepack.rate_factor(T0 + δT) - A0

    def exact_u(x):
        ρ = ρ_I * (1 - ρ_I / ρ_W)
        Z = icepack.rate_factor(T0) * (ρ * g * h0 / 4)**n
        q = 1 - (1 - (δh / h0) * (x / Lx))**(n + 1)
        δu = Z * q * Lx * (h0 / δh) / (n + 1)
        return u0 + δu

    mesh = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
    degree = 2
    V = firedrake.VectorFunctionSpace(mesh, "CG", degree)
    Q = firedrake.FunctionSpace(mesh, "CG", degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    u_initial = interpolate(as_vector((exact_u(x), 0)), V)
    q_initial = interpolate(firedrake.Constant(0), Q)
    h = interpolate(h0 - δh * x / Lx, Q)

    def viscosity(**kwargs):
        u = kwargs["velocity"]
        h = kwargs["thickness"]
        q = kwargs["log_fluidity"]

        A = A0 * firedrake.exp(-q / n)
        return icepack.models.viscosity.viscosity_depth_averaged(velocity=u,
                                                                 thickness=h,
                                                                 fluidity=A)

    model = icepack.models.IceShelf(viscosity=viscosity)
    dirichlet_ids = [1, 3, 4]
    flow_solver = icepack.solvers.FlowSolver(model,
                                             dirichlet_ids=dirichlet_ids)

    r = firedrake.sqrt((x / Lx - 1 / 2)**2 + (y / Ly - 1 / 2)**2)
    R = 1 / 4
    expr = firedrake.max_value(0, δA * (1 - (r / R)**2))
    q_true = firedrake.interpolate(-n * firedrake.ln(1 + expr / A0), Q)
    u_true = flow_solver.diagnostic_solve(velocity=u_initial,
                                          thickness=h,
                                          log_fluidity=q_true)

    # Make the noise equal to 1% of the signal
    area = firedrake.assemble(firedrake.Constant(1) * dx(mesh))
    σ = 0.001 * icepack.norm(u_true) / np.sqrt(area)
    print(σ)

    u_obs = u_true.copy(deepcopy=True)
    shape = u_obs.dat.data_ro.shape
    u_obs.dat.data[:] += σ * random.standard_normal(shape) / np.sqrt(2)

    def callback(inverse_solver):
        E, R = inverse_solver.objective, inverse_solver.regularization
        misfit = firedrake.assemble(E) / area
        regularization = firedrake.assemble(R) / area
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true) / np.sqrt(area)
        print(misfit, regularization, error, flush=True)

    L = firedrake.Constant(0.25 * Lx)
    problem = icepack.inverse.InverseProblem(
        model=model,
        objective=lambda u: 0.5 * ((u - u_obs) / σ)**2 * dx,
        regularization=lambda q: 0.5 * L**2 * inner(grad(q), grad(q)) * dx,
        state_name="velocity",
        state=u_initial,
        parameter_name="log_fluidity",
        parameter=q_initial,
        solver_kwargs={"dirichlet_ids": dirichlet_ids},
        diagnostic_solve_kwargs={"thickness": h},
    )

    solver = solver_type(problem, callback)

    max_iterations = 100
    iterations = solver.solve(rtol=1e-2, atol=0, max_iterations=max_iterations)
    print(f"Number of iterations: {iterations}")

    assert iterations < max_iterations
    q = solver.parameter
    assert firedrake.norm(q - q_true) / firedrake.norm(q_initial -
                                                       q_true) < 1 / 3