Example #1
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)
Example #2
0
def test_scalar_field_norms():
    f = firedrake.Function(Q)
    f.interpolate(x * y)

    assert abs(icepack.norm(f, norm_type='L1') - 1 / 4) < tolerance
    assert abs(icepack.norm(f, norm_type='L2') - 1 / 3) < tolerance
    assert abs(icepack.norm(f, norm_type='Linfty') - 1) < tolerance
    assert abs(icepack.norm(f, norm_type='H01')**2 - 2 / 3) < tolerance
Example #3
0
def test_poisson_inverse(solver_type):
    Nx, Ny = 32, 32
    mesh = firedrake.UnitSquareMesh(Nx, Ny)
    degree = 2
    Q = firedrake.FunctionSpace(mesh, "CG", degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    q_true = interpolate(-4 * ((x - 0.5)**2 + (y - 0.5)**2), Q)
    f = interpolate(firedrake.Constant(1), Q)

    dirichlet_ids = [1, 2, 3, 4]
    model = PoissonModel()
    poisson_solver = PoissonSolver(model, dirichlet_ids=dirichlet_ids)
    u_bdry = firedrake.Function(Q)
    u_obs = poisson_solver.diagnostic_solve(u=u_bdry, q=q_true, f=f)

    q0 = firedrake.Function(Q)
    u0 = poisson_solver.diagnostic_solve(u=u_bdry, q=q0, f=f)

    def callback(inverse_solver):
        misfit = firedrake.assemble(inverse_solver.objective)
        regularization = firedrake.assemble(inverse_solver.regularization)
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true)
        print(misfit, regularization, error)

    L = firedrake.Constant(1e-4)
    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="u",
        state=u0,
        parameter_name="q",
        parameter=q0,
        solver_type=PoissonSolver,
        solver_kwargs={"dirichlet_ids": dirichlet_ids},
        diagnostic_solve_kwargs={"f": f},
    )

    solver = solver_type(problem, callback)
    assert solver.state is not None
    assert icepack.norm(solver.state) > 0
    assert icepack.norm(solver.adjoint_state) > 0
    assert icepack.norm(solver.search_direction) > 0

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

    assert iterations < max_iterations
    q = solver.parameter
    assert icepack.norm(q - q_true) < 0.25
Example #4
0
def test_poisson_inverse(solver_type):
    Nx, Ny = 32, 32
    mesh = firedrake.UnitSquareMesh(Nx, Ny)
    degree = 2
    Q = firedrake.FunctionSpace(mesh, 'CG', degree)

    x, y = firedrake.SpatialCoordinate(mesh)
    q_true = interpolate(-4 * ((x - 0.5)**2 + (y - 0.5)**2), Q)
    f = interpolate(firedrake.Constant(1), Q)

    dirichlet_ids = [1, 2, 3, 4]
    model = PoissonModel()
    u_obs = model.solve(q=q_true, f=f, dirichlet_ids=dirichlet_ids)

    q0 = interpolate(firedrake.Constant(0), Q)
    u0 = model.solve(q=q0, f=f, dirichlet_ids=dirichlet_ids)

    def callback(inverse_solver):
        misfit = firedrake.assemble(inverse_solver.objective)
        regularization = firedrake.assemble(inverse_solver.regularization)
        q = inverse_solver.parameter
        error = firedrake.norm(q - q_true)
        print(misfit, regularization, error)

    L = firedrake.Constant(1e-4)
    problem = icepack.inverse.InverseProblem(
        model=model,
        method=PoissonModel.solve,
        objective=lambda u: 0.5 * (u - u_obs)**2 * dx,
        regularization=lambda q: L**2 / 2 * inner(grad(q), grad(q)) * dx,
        state_name='u',
        state=u0,
        parameter_name='q',
        parameter=q0,
        model_args={'f': f},
        dirichlet_ids=dirichlet_ids)

    solver = solver_type(problem, callback)
    assert solver.state is not None
    assert icepack.norm(solver.state) > 0
    assert icepack.norm(solver.adjoint_state) > 0
    assert icepack.norm(solver.search_direction) > 0

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

    assert iterations < max_iterations
    q = solver.parameter
    assert icepack.norm(q - q_true) < 0.25
Example #5
0
def test_algebra():
    u = icepack.interpolate(discretization, lambda x: x[0] - x[1])
    v = icepack.interpolate(discretization, lambda x: x[0] * x[1])

    w = icepack.interpolate(discretization,
                            lambda x: x[0] - x[1] + x[0] * x[1])
    assert icepack.dist(u + v, w) / icepack.norm(w) < 1.0e-8

    w = icepack.interpolate(discretization,
                            lambda x: x[0] - x[1] - x[0] * x[1])
    assert icepack.dist(u - v, w) / icepack.norm(w) < 1.0e-8

    w = icepack.interpolate(discretization, lambda x: 2 * x[0] * x[1])
    assert icepack.dist(2.0 * v, w) / icepack.norm(w) < 1.0e-8

    assert abs(icepack.inner_product(u, v)) < 1.0e-8
Example #6
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
Example #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
Example #8
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)
Example #9
0
def streamplot(u, **kwargs):
    r"""Draw streamlines of a vector field"""
    if u.ufl_shape != (2, ):
        raise ValueError('Stream plots only defined for 2D vector fields!')

    u = _project_to_2d(u)
    axes = kwargs.pop('axes', plt.gca())
    cmap = kwargs.pop('cmap', matplotlib.cm.viridis)

    mesh = u.ufl_domain()
    coordinates = _get_coordinates(mesh)
    precision = kwargs.pop('precision', _mesh_hmin(coordinates))
    density = kwargs.pop('density', 2 * _mesh_hmin(coordinates))
    max_num_points = kwargs.pop('max_num_points', np.inf)
    coords = coordinates.dat.data_ro
    max_speed = icepack.norm(u, norm_type='Linfty')

    tree = scipy.spatial.KDTree(coords)
    indices = set(range(len(coords)))

    trajectories = []
    line_colors = []
    while indices:
        x0 = coords[indices.pop(), :]
        try:
            s = streamline(u, x0, precision, max_num_points)
            for y in s:
                for index in tree.query_ball_point(y, density):
                    indices.discard(index)

            points = s.reshape(-1, 1, 2)
            trajectories.extend(np.hstack([points[:-1], points[1:]]))

            speeds = np.sqrt(np.sum(
                np.asarray(u.at(s, tolerance=1e-10))**2, 1))
            colors = speeds / max_speed
            line_colors.extend(cmap(colors[:-1]))

        except ValueError:
            pass

    line_collection = LineCollection(trajectories,
                                     colors=np.array(line_colors))
    axes.add_collection(line_collection)
    axes.autoscale_view()

    norm = matplotlib.colors.Normalize(vmin=0, vmax=max_speed)
    return StreamplotSet(lines=line_collection, cmap=cmap, norm=norm)
Example #10
0
def norm(v):
    return icepack.norm(v, norm_type="L2")
Example #11
0
def test_vector_field_norms():
    u = firedrake.Function(V)
    u.interpolate(firedrake.as_vector((x**2 - y**2, 2 * x * y)))

    assert abs(icepack.norm(u, norm_type='Linfty') - 2) < tolerance
Example #12
0
icepack.plot.plot_mesh(ax, mesh)
plt.show(fig)

discretization = icepack.make_discretization(mesh, 1)

v = icepack.interpolate(discretization, vx_obs, vy_obs)
h = icepack.interpolate(discretization, h_obs)

# Make a dumb guess for the ice temperature. In "real life", you would want to
# use an inverse method that would tune the temperature to fit observations.
theta = icepack.interpolate(discretization, lambda x: 253.0)

# Solve for the ice velocity, assuming this guess for the temperature.
dirichlet_boundary_ids = {2, 3, 4, 5}
ice_shelf = icepack.IceShelf(dirichlet_boundary_ids)
u = ice_shelf.solve(h, theta, v)

print("Misfit between computed and observed velocities: {}".format(
    icepack.dist(u, v) / icepack.norm(v)))

fig, axes = plt.subplots(ncols=2, sharey=True)
for ax in axes:
    ax.set_aspect('equal')
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
ctr_u = icepack.plot.plot_field(axes[0], u)
ctr_v = icepack.plot.plot_field(axes[1], v)
fig.colorbar(ctr_v, ax=axes[1], fraction=0.046, pad=0.04)
fig.tight_layout()
plt.show(fig)
Example #13
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
Example #14
0
def test_diagnostic_solver(dim):
    Nx, Ny, Nz = 32, 32, 32
    if dim == "xz":
        opts = {"dirichlet_ids": [1], "tol": 1e-12}
        mesh_x = firedrake.IntervalMesh(Nx, Lx)
        mesh = firedrake.ExtrudedMesh(mesh_x, layers=1)
        x, ζ = firedrake.SpatialCoordinate(mesh)
        u_expr = (0.95 + 0.05 * ζ) * exact_u(x)
        xs = np.array([(Lx / 2, k / Nz) for k in range(Nz + 1)])
    elif dim == "xyz":
        opts = {"dirichlet_ids": [1, 3, 4], "tol": 1e-12}
        mesh_x = firedrake.RectangleMesh(Nx, Ny, Lx, Ly)
        mesh = firedrake.ExtrudedMesh(mesh_x, layers=1)
        x, y, ζ = firedrake.SpatialCoordinate(mesh)
        u_expr = firedrake.as_vector(((0.95 + 0.05 * ζ) * exact_u(x), 0))
        xs = np.array([(Lx / 2, Ly / 2, k / Nz) for k in range(Nz + 1)])

    Q = firedrake.FunctionSpace(mesh, "CG", 2, vfamily="DG", vdegree=0)

    h = firedrake.interpolate(h0 - dh * x / Lx, Q)
    s = firedrake.interpolate(d + h0 - dh + ds * (1 - x / Lx), Q)

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

    model = icepack.models.HybridModel()

    max_degree = 5
    us = np.zeros((max_degree + 1, Nz + 1))
    for vdegree in range(max_degree, 0, -1):
        solver = icepack.solvers.FlowSolver(model, **opts)
        if dim == "xz":
            V = firedrake.FunctionSpace(mesh,
                                        "CG",
                                        2,
                                        vfamily="DG",
                                        vdegree=vdegree)
            V0 = firedrake.FunctionSpace(mesh,
                                         "CG",
                                         2,
                                         vfamily="DG",
                                         vdegree=0)
        elif dim == "xyz":
            V = firedrake.VectorFunctionSpace(mesh,
                                              "CG",
                                              2,
                                              vfamily="DG",
                                              vdegree=vdegree,
                                              dim=2)
            V0 = firedrake.VectorFunctionSpace(mesh,
                                               "CG",
                                               2,
                                               vfamily="DG",
                                               vdegree=0,
                                               dim=2)

        u0 = firedrake.interpolate(u_expr, V)
        u = solver.diagnostic_solve(velocity=u0,
                                    thickness=h,
                                    surface=s,
                                    fluidity=A,
                                    friction=C)

        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))
        if dim == "xz":
            us[vdegree, :] = us_center
        elif dim == "xyz":
            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
theta = icepack.interpolate(discretization, lambda x: 253.0)

dirichlet_boundary_ids = {2, 3, 4, 5}
ice_shelf = icepack.IceShelf(dirichlet_boundary_ids)
u0 = ice_shelf.solve(h0, theta, v)

# And this should be familiar from example 2.
dt = min(1.0, icepack.compute_timestep(0.5, u0))

# Make a steady-state accumulation rate field.
a0 = icepack.interpolate(discretization, lambda x: 0.0)
a0 = (ice_shelf.solve(dt, h0, a0, u0, h0) - h0) / dt

# Really hacky way to compute the average of a field.
one = icepack.interpolate(discretization, lambda x: 1.0)
a_avg = icepack.inner_product(a0, one) / icepack.norm(one)**2

# Make things even simpler by replacing the accumulation with its average.
a = icepack.interpolate(discretization, lambda x: a_avg)

h, u = h0, u0

# Pick a final time and compute the number of timesteps
T = 50.0
N = int(T / dt)
for k in range(N):
    fig, axes = plt.subplots(ncols=2)
    for ax in axes:
        ax.set_aspect('equal')
    ctr_h = icepack.plot.plot_field(axes[0], h)
    ctr_u = icepack.plot.plot_field(axes[1], u)
Example #16
0
def norm(v):
    return icepack.norm(v, norm_type='L2')
Example #17
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
theta = icepack.interpolate(discretization, lambda x: 253.0)

dirichlet_boundary_ids = {2, 3, 4, 5}
ice_shelf = icepack.IceShelf(dirichlet_boundary_ids);
u0 = ice_shelf.solve(h0, theta, v)

# And this should be familiar from example 2.
dt = min(1.0, icepack.compute_timestep(0.5, u0))

# Make a steady-state accumulation rate field.
a0 = icepack.interpolate(discretization, lambda x: 0.0)
a0 = (ice_shelf.solve(dt, h0, a0, u0, h0) - h0) / dt

# Really hacky way to compute the average of a field.
one = icepack.interpolate(discretization, lambda x: 1.0)
a_avg = icepack.inner_product(a0, one) / icepack.norm(one)**2

# Make things even simpler by replacing the accumulation with its average.
a = icepack.interpolate(discretization, lambda x: a_avg)

h, u = h0, u0

# Pick a final time and compute the number of timesteps
T = 50.0
N = int(T / dt)
for k in range(N):
    fig, axes = plt.subplots(ncols=2)
    for ax in axes:
        ax.set_aspect('equal')
    ctr_h = icepack.plot.plot_field(axes[0], h)
    ctr_u = icepack.plot.plot_field(axes[1], u)
Example #19
0
def test_ice_stream_prognostic_solve():
    Lx, Ly = 20e3, 20e3
    h0, dh = 500.0, 100.0
    T = 254.15
    u0 = 100.0

    model = icepack.models.IceStream()
    opts = {"dirichlet_ids": [1], "side_wall_ids": [3, 4]}

    N = 32
    mesh = firedrake.RectangleMesh(N, N, Lx, Ly)

    V = firedrake.VectorFunctionSpace(mesh, "CG", 2)
    Q = firedrake.FunctionSpace(mesh, "CG", 2)
    solver = icepack.solvers.FlowSolver(model, **opts)

    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 = u0 + 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 = Constant(icepack.rate_factor(T))

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

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

    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,
            strain_rate_min=Constant(0.0),
        )

    assert icepack.norm(h, norm_type="Linfty") < np.inf
plt.show(fig)

discretization = icepack.make_discretization(mesh, 1)

v = icepack.interpolate(discretization, vx_obs, vy_obs)
h = icepack.interpolate(discretization, h_obs)

# Make a dumb guess for the ice temperature. In "real life", you would want to
# use an inverse method that would tune the temperature to fit observations.
theta = icepack.interpolate(discretization, lambda x: 253.0)

# Solve for the ice velocity, assuming this guess for the temperature.
dirichlet_boundary_ids = {2, 3, 4, 5}
ice_shelf = icepack.IceShelf(dirichlet_boundary_ids)
u = ice_shelf.solve(h, theta, v)

print("Misfit between computed and observed velocities: {}"
      .format(icepack.dist(u, v) / icepack.norm(v)))

fig, axes = plt.subplots(ncols=2, sharey=True)
for ax in axes:
    ax.set_aspect('equal')
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
ctr_u = icepack.plot.plot_field(axes[0], u)
ctr_v = icepack.plot.plot_field(axes[1], v)
fig.colorbar(ctr_v, ax=axes[1], fraction=0.046, pad=0.04)
fig.tight_layout()
plt.show(fig)

Example #21
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