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)
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)
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_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
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_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
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_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
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
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)
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
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
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
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
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
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
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
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
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)
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
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)
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')
# (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',
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)
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)
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
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)
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
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
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