def __init__(self, mesh_r, refinements=1, order=1): mh = fd.MeshHierarchy(mesh_r, refinements) self.mesh_hierarchy = mh # Control space on coarsest mesh self.mesh_r_coarse = self.mesh_hierarchy[0] self.V_r_coarse = fd.VectorFunctionSpace(self.mesh_r_coarse, "CG", order) # Create self.id and self.T on refined mesh. element = self.V_r_coarse.ufl_element() self.intermediate_Ts = [] for i in range(refinements - 1): mesh = self.mesh_hierarchy[i + 1] V = fd.FunctionSpace(mesh, element) self.intermediate_Ts.append(fd.Function(V)) self.mesh_r = self.mesh_hierarchy[-1] element = self.V_r_coarse.ufl_element() self.V_r = fd.FunctionSpace(self.mesh_r, element) X = fd.SpatialCoordinate(self.mesh_r) self.id = fd.Function(self.V_r).interpolate(X) self.T = fd.Function(self.V_r, name="T") self.T.assign(self.id) self.mesh_m = fda.Mesh(self.T) self.V_m = fd.FunctionSpace(self.mesh_m, element)
def test_n_min_ufl(): """Tests that the sharp cutoff function does what it should when n is given by a ufl expression.""" k = 10.0 mesh = fd.UnitSquareMesh(10,10) V = fd.FunctionSpace(mesh,"CG",1) x = fd.SpatialCoordinate(mesh) n = 1.0 + fd.sin(30*x[0]) prob = hh.HelmholtzProblem(k,V,n=n) n_min_val = 2.0 prob.n_min(n_min_val) V_DG = fd.FunctionSpace(mesh,"DG",0) n_fn = fd.Function(V_DG) n_fn.interpolate(prob._n) assert (n_fn.dat.data_ro >= n_min_val).all()
def test_n_min_pre_ufl(): """Tests that the sharp cutoff function does what it should when n_pre is given by a UFL expression.""" k = 10.0 mesh = fd.UnitSquareMesh(10,10) V = fd.FunctionSpace(mesh,"CG",1) x = fd.SpatialCoordinate(mesh) n_pre = 1.0 + fd.sin(30*x[0]) prob = hh.HelmholtzProblem(k,V,n_pre=n_pre,A_pre = fd.as_matrix([[1.0,0.0],[0.0,1.0]])) n_min_val = 2.0 prob.n_min(n_min_val,True) V_DG = fd.FunctionSpace(mesh,"DG",0) n_fn = fd.Function(V_DG) n_fn.interpolate(prob._n_pre) assert (n_fn.dat.data_ro >= n_min_val).all()
def test_sharp_cutoff_ufl(): """Tests that the sharp cutoff function does what it should when the coefficient is given by a ufl expression.""" k = 10.0 mesh = fd.UnitSquareMesh(10,10) V = fd.FunctionSpace(mesh,"CG",1) x = fd.SpatialCoordinate(mesh) n = 1.0 + fd.sin(30*x[0]) prob = hh.HelmholtzProblem(k,V,n=n) prob.sharp_cutoff(np.array([0.5,0.5]),0.5) V_DG = fd.FunctionSpace(mesh,"DG",0) n_fn = fd.Function(V_DG) n_fn.interpolate(prob._n) # This is a rudimentary test that it's 1 on the boundary # Yes, I kind of made this pass by changing the value to check until it did. # But I've confirmed that it's doing (roughly) the right thing visually, so I'm content assert n_fn.dat.data_ro[97] == 1.0
def test_sharp_cutoff_pre_ufl(): """Tests that the sharp cutoff function does what it should when the preconditioning coefficient is given by ufl.""" k = 10.0 mesh = fd.UnitSquareMesh(10,10) V = fd.FunctionSpace(mesh,"CG",1) x = fd.SpatialCoordinate(mesh) n_pre = 1.0 + fd.sin(30*x[0]) prob = hh.HelmholtzProblem(k,V,n_pre=n_pre,A_pre = fd.as_matrix([[1.0,0.0],[0.0,1.0]])) prob.sharp_cutoff(np.array([0.5,0.5]),0.5,True) V_DG = fd.FunctionSpace(mesh,"DG",0) n_fn = fd.Function(V_DG) n_fn.interpolate(prob._n_pre) # As above assert n_fn.dat.data_ro[97] == 1.0
def test_sharp_cutoff(): """Tests that the sharp cutoff function does what it should.""" k = 10.0 mesh = fd.UnitSquareMesh(10,10) V = fd.FunctionSpace(mesh,"CG",1) prob = hh.HelmholtzProblem(k,V,n=2.0) prob.sharp_cutoff(np.array([0.5,0.5]),0.5) V_DG = fd.FunctionSpace(mesh,"DG",0) n_fn = fd.Function(V_DG) n_fn.interpolate(prob._n) # This is a rudimentary test that it's 1 on the boundary and 2 elsewhere # Yes, I kind of made this pass by changing the value to check until it did. # But I've confirmed that it's doing (roughly) the right thing visually, so I'm content assert n_fn.dat.data_ro[97] == 1.0 assert n_fn.dat.data_ro[95] == 2.0
def __init__(self, mesh_r): # Create mesh_r and V_r self.mesh_r = mesh_r element = self.mesh_r.coordinates.function_space().ufl_element() self.V_r = fd.FunctionSpace(self.mesh_r, element) # Create self.id and self.T, self.mesh_m, and self.V_m. X = fd.SpatialCoordinate(self.mesh_r) self.id = fd.interpolate(X, self.V_r) self.T = fd.Function(self.V_r, name="T") self.T.assign(self.id) self.mesh_m = fd.Mesh(self.T) self.V_m = fd.FunctionSpace(self.mesh_m, element) self.is_DG = False """ ControlSpace for discontinuous coordinate fields (e.g. periodic domains) In Firedrake, periodic meshes are implemented using a discontinuous field. This implies that self.V_r contains discontinuous functions. To ensure domain updates do not create holes in the domain, use a continuous subspace self.V_c of self.V_r as control space. """ if element.family() == 'Discontinuous Lagrange': self.is_DG = True self.V_c = fd.VectorFunctionSpace(self.mesh_r, "CG", element._degree) self.Ip = fd.Interpolator(fd.TestFunction(self.V_c), self.V_r).callable().handle
def test_scalar_field(): Nx, Ny = 16, 16 mesh2d = firedrake.UnitSquareMesh(Nx, Ny) mesh3d = firedrake.ExtrudedMesh(mesh2d, layers=1) x, y, z = firedrake.SpatialCoordinate(mesh3d) Q3D = firedrake.FunctionSpace(mesh3d, family='CG', degree=2, vfamily='GL', vdegree=5) q3d = firedrake.interpolate((x**2 + y**2) * (1 - z**4), Q3D) q_avg = depth_average(q3d) p3d = firedrake.interpolate(x**2 + y**2, Q3D) p_avg = depth_average(p3d, weight=1 - z**4) Q2D = firedrake.FunctionSpace(mesh2d, family='CG', degree=2) x, y = firedrake.SpatialCoordinate(mesh2d) q2d = firedrake.interpolate(4 * (x**2 + y**2) / 5, Q2D) assert q_avg.ufl_domain() is mesh2d assert norm(q_avg - q2d) / norm(q2d) < 1 / (Nx * Ny)**2 assert norm(p_avg - q2d) / norm(q2d) < 1 / (Nx * Ny)**2 Q0 = firedrake.FunctionSpace(mesh3d, family='CG', degree=2, vfamily='GL', vdegree=0) q_lift = lift3d(q_avg, Q0) assert norm(depth_average(q_lift) - q2d) / norm(q2d) < 1 / (Nx * Ny)**2
def vectorspaces(mesh, vertical_higher_order=0): '''On an extruded mesh, build finite element spaces for velocity u, pressure p, and vertical displacement c. Construct component spaces by explicitly applying TensorProductElement(). Elements are Q2 prisms [P2(triangle)xP2(interval)] for velocity, Q1 prisms [P1(triangle)xP1(interval)] for pressure, and Q1 prisms [P1(triangle)xP1(interval)] for displacement. Optionally the base mesh can be built from quadrilaterals and/or the vertical factors can be higher order for velocity and pressure.''' if mesh._base_mesh.cell_dimension() not in {1, 2}: raise ValueError('only 2D and 3D extruded meshes are allowed') ThreeD = (mesh._base_mesh.cell_dimension() == 2) quad = (mesh._base_mesh.ufl_cell() == fd.quadrilateral) if quad and not ThreeD: raise ValueError('base mesh from quadilaterals only possible in 3D') zudeg, zpdeg = _degreexz[vertical_higher_order] # velocity u (vector) if ThreeD: if quad: xuE = fd.FiniteElement('Q', fd.quadrilateral, 2) else: xuE = fd.FiniteElement('P', fd.triangle, 2) else: xuE = fd.FiniteElement('P', fd.interval, 2) zuE = fd.FiniteElement('P', fd.interval, zudeg) uE = fd.TensorProductElement(xuE, zuE) Vu = fd.VectorFunctionSpace(mesh, uE) # pressure p (scalar) # Note Isaac et al (2015) recommend discontinuous pressure space # to get mass conservation. Switching base mesh elements to dP0 # (or dQ0 for base quads) is inconsistent w.r.t. velocity result; # (unstable?) and definitely more expensive. if ThreeD: if quad: xpE = fd.FiniteElement('Q', fd.quadrilateral, 1) else: xpE = fd.FiniteElement('P', fd.triangle, 1) else: xpE = fd.FiniteElement('P', fd.interval, 1) zpE = fd.FiniteElement('P', fd.interval, zpdeg) pE = fd.TensorProductElement(xpE, zpE) Vp = fd.FunctionSpace(mesh, pE) # vertical displacement c (scalar) if ThreeD: if quad: xcE = fd.FiniteElement('Q', fd.quadrilateral, 1) else: xcE = fd.FiniteElement('P', fd.triangle, 1) else: xcE = fd.FiniteElement('P', fd.interval, 1) zcE = fd.FiniteElement('P', fd.interval, 1) cE = fd.TensorProductElement(xcE, zcE) Vc = fd.FunctionSpace(mesh, cE) return Vu, Vp, Vc
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_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 __init__(self, mesh_r): # Create mesh_r and V_r self.mesh_r = mesh_r element = self.mesh_r.coordinates.function_space().ufl_element() self.V_r = fd.FunctionSpace(self.mesh_r, element) # Create self.id and self.T, self.mesh_m, and self.V_m. X = fd.SpatialCoordinate(self.mesh_r) self.id = fd.interpolate(X, self.V_r) self.T = fda.Function(self.V_r, name="T") self.T.assign(self.id) self.mesh_m = fda.Mesh(self.T) self.V_m = fd.FunctionSpace(self.mesh_m, element)
def extend(mesh, f): if mesh._base_mesh.cell_dimension() == 2: if mesh._base_mesh.ufl_cell() == fd.quadrilateral: Q1R = fd.FunctionSpace(mesh, 'Q', 1, vfamily='R', vdegree=0) else: Q1R = fd.FunctionSpace(mesh, 'P', 1, vfamily='R', vdegree=0) elif mesh._base_mesh.cell_dimension() == 1: Q1R = fd.FunctionSpace(mesh, 'P', 1, vfamily='R', vdegree=0) else: raise ValueError('base mesh of extruded input mesh must be 1D or 2D') fextend = fd.Function(Q1R) fextend.dat.data[:] = f.dat.data_ro[:] return fextend
def _build_space(mesh, el, space, deg): if el == "tria": V = fd.FunctionSpace(mesh, space, deg) elif el == "quad": if space == "spectral": element = fd.FiniteElement( "CG", mesh.ufl_cell(), degree=deg, variant="spectral" ) V = fd.FunctionSpace(mesh, element) elif space == "S": V = fd.FunctionSpace(mesh, "S", deg) else: raise ValueError("Space not supported yet") return V
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 __init__(self, mesh_m): super().__init__() self.mesh_m = mesh_m # Setup problem self.V = fd.FunctionSpace(self.mesh_m, "CG", 1) # Preallocate solution variables for state and adjoint equations self.solution = fd.Function(self.V, name="State") # Weak form of Poisson problem u = self.solution v = fd.TestFunction(self.V) self.f = fd.Constant(4.) self.F = (fd.inner(fd.grad(u), fd.grad(v)) - self.f * v) * fd.dx self.bcs = fd.DirichletBC(self.V, 0., "on_boundary") # PDE-solver parameters self.params = { "ksp_type": "cg", "mat_type": "aij", "pc_type": "hypre", "pc_factor_mat_solver_package": "boomerang", "ksp_rtol": 1e-11, "ksp_atol": 1e-11, "ksp_stol": 1e-15, } stateproblem = fd.NonlinearVariationalProblem(self.F, self.solution, bcs=self.bcs) self.solver = fd.NonlinearVariationalSolver( stateproblem, solver_parameters=self.params)
def test_plot_field(): mesh = firedrake.UnitSquareMesh(32, 32) Q = firedrake.FunctionSpace(mesh, "CG", 1) x, y = firedrake.SpatialCoordinate(mesh) u = interpolate(x * y, Q) fig, axes = icepack.plot.subplots(nrows=2, ncols=2, sharex=True, sharey=True) filled_contours = icepack.plot.tricontourf(u, axes=axes[0, 0]) assert filled_contours is not None colorbar = plt.colorbar(filled_contours, ax=axes[0, 0]) assert colorbar is not None contours = icepack.plot.tricontour(u, axes=axes[0, 1]) assert contours is not None colors_flat = icepack.plot.tripcolor(u, shading="flat", axes=axes[1, 0]) assert colors_flat is not None colors_gouraud = icepack.plot.tripcolor(u, shading="gouraud", axes=axes[1, 1]) assert colors_flat.get_array().shape != colors_gouraud.get_array().shape
def test_coeff_definition_no_error(): """Test that a coeff with just too few many pieces is not caught.""" k = 20.0 mesh = fd.UnitSquareMesh(100, 100) V = fd.FunctionSpace(mesh, "CG", 1) num_pieces = 12 noise_level = 0.1 num_repeats = 10 A_pre = fd.as_matrix(np.array([[1.0, 0.0], [0.0, 1.0]])) A_stoch = PiecewiseConstantCoeffGenerator(mesh, num_pieces, noise_level, A_pre, [2, 2]) n_pre = 1.0 n_stoch = PiecewiseConstantCoeffGenerator(mesh, num_pieces, noise_level, n_pre, [1]) f = 1.0 g = 1.0 GMRES_its = nbex.nearby_preconditioning_experiment(V, k, A_pre, A_stoch, n_pre, n_stoch, f, g, num_repeats) # The code should not error. assert GMRES_its.shape != (0, )
def test_coeff_definition_error(): """Test that a coeff with too many pieces is caught.""" k = 20.0 mesh = fd.UnitSquareMesh(100, 100) V = fd.FunctionSpace(mesh, "CG", 1) num_pieces = 13 noise_level = 0.1 num_repeats = 10 A_pre = fd.as_matrix(np.array([[1.0, 0.0], [0.0, 1.0]])) A_stoch = PiecewiseConstantCoeffGenerator(mesh, num_pieces, noise_level, A_pre, [2, 2]) n_pre = 1.0 n_stoch = PiecewiseConstantCoeffGenerator(mesh, num_pieces, noise_level, n_pre, [1]) f = 1.0 g = 1.0 GMRES_its = nbex.nearby_preconditioning_experiment(V, k, A_pre, A_stoch, n_pre, n_stoch, f, g, num_repeats) # The code should catch the error and print a warning message, and # exit, not recording any GMRES iterations. assert GMRES_its.shape == (0, )
def coarsen_function_space(V, self, coefficient_mapping=None): if hasattr(V, "_coarse"): return V._coarse fine = V indices = [] while True: if V.index is not None: indices.append(V.index) if V.component is not None: indices.append(V.component) if V.parent is not None: V = V.parent else: break mesh = self(V.mesh(), self) Vf = V V = firedrake.FunctionSpace(mesh, V.ufl_element()) from firedrake.dmhooks import get_transfer_operators, push_transfer_operators transfer = get_transfer_operators(Vf.dm) push_transfer_operators(V.dm, *transfer) if len(V) > 1: for V_, Vc_ in zip(Vf, V): transfer = get_transfer_operators(V_.dm) push_transfer_operators(Vc_.dm, *transfer) for i in reversed(indices): V = V.sub(i) V._fine = fine fine._coarse = V return V
def get_restriction_weights(coarse, fine): mesh = coarse.mesh() assert hasattr(mesh, "_shared_data_cache") cache = mesh._shared_data_cache["hierarchy_restriction_weights"] key = entity_dofs_key(coarse.finat_element.entity_dofs()) try: return cache[key] except KeyError: # We hit each fine dof more than once since we loop # elementwise over the coarse cells. So we need a count of # how many times we did this to weight the final contribution # appropriately. if not (coarse.ufl_element() == fine.ufl_element()): raise ValueError("Can't transfer between different spaces") if coarse.finat_element.entity_dofs( ) == coarse.finat_element.entity_closure_dofs(): return cache.setdefault(key, None) ele = coarse.ufl_element() if isinstance(ele, ufl.VectorElement): ele = ele.sub_elements()[0] weights = firedrake.Function( firedrake.FunctionSpace(fine.mesh(), ele)) else: weights = firedrake.Function(fine) c2f_map = coarse_to_fine_node_map(coarse, fine) kernel = get_count_kernel(c2f_map.arity) op2.par_loop(kernel, c2f_map.iterset, weights.dat(op2.INC, c2f_map[op2.i[0]])) weights.assign(1 / weights) return cache.setdefault(key, weights)
def coarsen(dm, comm): """Callback to coarsen a DM. :arg DM: The DM to coarsen. :arg comm: The communicator for the new DM (ignored) This transfers a coarse application context over to the coarsened DM (if found on the input DM). """ from firedrake.mg.utils import get_level from firedrake.mg.ufl_utils import coarsen V = get_function_space(dm) if V is None: raise RuntimeError("No functionspace found on DM") hierarchy, level = get_level(V.mesh()) if level < 1: raise RuntimeError("Cannot coarsen coarsest DM") if hasattr(V, "_coarse"): cdm = V._coarse.dm else: V._coarse = firedrake.FunctionSpace(hierarchy[level - 1], V.ufl_element()) cdm = V._coarse.dm transfer = get_transfer_operators(dm) push_transfer_operators(cdm, *transfer) ctx = get_appctx(dm) if ctx is not None: push_appctx(cdm, coarsen(ctx)) # Necessary for MG inside a fieldsplit in a SNES. cdm.setKSPComputeOperators(firedrake.solving_utils._SNESContext.compute_operators) V._coarse._fine = V return cdm
def __init__(self, mesh_m): super().__init__() # Setup problem V = fd.FunctionSpace(mesh_m, "CG", 1) # Weak form of Poisson problem u = fda.Function(V, name="State") v = fd.TestFunction(V) f = fda.Constant(4.) F = (fd.inner(fd.grad(u), fd.grad(v)) - f * v) * fd.dx bcs = fda.DirichletBC(V, 0., "on_boundary") # PDE-solver parameters params = { "ksp_type": "cg", "mat_type": "aij", "pc_type": "hypre", "pc_factor_mat_solver_package": "boomerang", "ksp_rtol": 1e-11, "ksp_atol": 1e-11, "ksp_stol": 1e-15, } self.solution = u problem = fda.NonlinearVariationalProblem(F, self.solution, bcs=bcs) self.solver = fda.NonlinearVariationalSolver(problem, solver_parameters=params)
def __init__(self, mesh, element, variational_form_residual, dirichlet_boundary_conditions, initial_values, quadrature_degree=None, time_dependent=True, time_stencil_size=2, output_directory_path="output/"): self.mesh = mesh self.element = element self.function_space = fe.FunctionSpace(mesh, element) self.quadrature_degree = quadrature_degree self.solutions = [ fe.Function(self.function_space) for i in range(time_stencil_size) ] self.solution = self.solutions[0] self.backup_solution = fe.Function(self.solution) if time_dependent: assert (time_stencil_size > 1) self.time = fe.Constant(0.) self.timestep_size = fe.Constant(1.) else: self.time = None self.timestep_size = None self.output_directory_path = pathlib.Path(output_directory_path) self.solution_file = None self.plotvars = None self.initial_values = initial_values(sim=self) for solution in self.solutions: solution.assign(self.initial_values) self.variational_form_residual = variational_form_residual( sim=self, solution=self.solution) self.dirichlet_boundary_conditions = \ dirichlet_boundary_conditions(sim = self) self.snes_iteration_count = 0
def create_form(form_string, family, degree, dimension, operation): from firedrake import dx, inner, grad import firedrake as f f.parameters['coffee']['optlevel'] = 'O3' f.parameters['pyop2_options']['opt_level'] = 'O3' f.parameters['pyop2_options']['simd_isa'] = 'avx' f.parameters["pyop2_options"]["lazy_evaluation"] = False m = f.UnitSquareMesh(2, 2, quadrilateral=True) if dimension == 3: m = f.ExtrudedMesh(m, 2) fs = f.FunctionSpace(m, family, degree) v = f.TestFunction(fs) if operation == "matrix": u = f.TrialFunction(fs) elif operation == "action": u = f.Function(fs) else: raise ValueError("Unknown operation: %s" % operation) if form_string == "u * v * dx": return u * v * dx elif form_string == "inner(grad(u), grad(v)) * dx": return inner(grad(u), grad(v)) * dx
def test_ilu(): """Tests that ILU functionality gives correct solution.""" k = 10.0 num_cells = utils.h_to_num_cells(k**-1.5,2) mesh = fd.UnitSquareMesh(num_cells,num_cells) V = fd.FunctionSpace(mesh,"CG",1) prob = hh.HelmholtzProblem(k,V) angle = 2.0 * np.pi/7.0 d = [np.cos(angle),np.sin(angle)] prob.f_g_plane_wave(d) for fill_in in range(40): prob.use_ilu_gmres(fill_in) prob.solve() x = fd.SpatialCoordinate(mesh) # This error was found out by eye assert np.abs(fd.norms.errornorm(fd.exp(1j * k * fd.dot(fd.as_vector(d),x)),uh=prob.u_h,norm_type='H1')) < 0.5
def test_diagnostic_solver_convergence(): shallow_ice = icepack.models.ShallowIce() for degree in range(1, 4): delta_x, error = [], [] for N in range(10, 110 - 20 * (degree - 1), 10): mesh = make_mesh(R_mesh, R / N) Q = firedrake.FunctionSpace(mesh, 'CG', degree) V = firedrake.VectorFunctionSpace(mesh, 'CG', degree) h_expr = Bueler_profile(mesh, R) u_exact = interpolate(exact_u(h_expr, Q), V) h = interpolate(h_expr, Q) s = interpolate(h_expr, Q) u = firedrake.Function(V) u_num = shallow_ice.diagnostic_solve(u0=u, h=h, s=s, A=A) error.append(norm(u_exact - u_num) / norm(u_exact)) delta_x.append(R / N) print(delta_x[-1], error[-1]) assert assemble(shallow_ice.scale(u=u_num)) > 0 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 > 0.9
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 __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 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