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)
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
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
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
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
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
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
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)
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)
def norm(v): return icepack.norm(v, norm_type="L2")
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
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)
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
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)
def norm(v): return icepack.norm(v, norm_type='L2')
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)
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)
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