def get_aspect_ratios2d(mesh, python=False): """ Computes the aspect ratio of each cell in a 2D triangular mesh :arg mesh: the input mesh to do computations on :kwarg python: compute the measure using Python? :rtype: firedrake.function.Function aspect_ratios with aspect ratio data """ P0 = firedrake.FunctionSpace(mesh, "DG", 0) if python: P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0) J = firedrake.interpolate(ufl.Jacobian(mesh), P0_ten) edge1 = ufl.as_vector([J[0, 0], J[1, 0]]) edge2 = ufl.as_vector([J[0, 1], J[1, 1]]) edge3 = edge1 - edge2 a = ufl.sqrt(ufl.dot(edge1, edge1)) b = ufl.sqrt(ufl.dot(edge2, edge2)) c = ufl.sqrt(ufl.dot(edge3, edge3)) aspect_ratios = firedrake.interpolate( a * b * c / ((a + b - c) * (b + c - a) * (c + a - b)), P0 ) else: coords = mesh.coordinates aspect_ratios = firedrake.Function(P0) op2.par_loop( get_pyop2_kernel("get_aspect_ratio", 2), mesh.cell_set, aspect_ratios.dat(op2.WRITE, aspect_ratios.cell_node_map()), coords.dat(op2.READ, coords.cell_node_map()), ) return aspect_ratios
def solve_something(mesh): V = fd.FunctionSpace(mesh, "CG", 1) u = fd.Function(V) v = fd.TestFunction(V) x, y = fd.SpatialCoordinate(mesh) # f = fd.sin(x) * fd.sin(y) + x**2 + y**2 # uex = x**4 * y**4 uex = fd.sin(x) * fd.sin(y) #*(x*y)**3 # def source(xs, ys): # return 1/((x-xs)**2+(y-ys)**2 + 0.1) # uex = source(0, 0) uex = uex - fd.assemble(uex * fd.dx) / fd.assemble(1 * fd.dx(domain=mesh)) # f = fd.conditional(fd.ge(abs(x)-abs(y), 0), 1, 0) from firedrake import inner, grad, dx, ds, div, sym eps = fd.Constant(0.0) f = uex - div(grad(uex)) + eps * div(grad(div(grad(uex)))) n = fd.FacetNormal(mesh) g = inner(grad(uex), n) g1 = inner(grad(div(grad(uex))), n) g2 = div(grad(uex)) # F = 0.1 * inner(u, v) * dx + inner(grad(u), grad(v)) * dx + inner(grad(grad(u)), grad(grad(v))) * dx - f * v * dx - g * v * ds F = inner(u, v) * dx + inner(grad(u), grad(v)) * dx - f * v * dx - g * v * ds F += eps * inner(div(grad(u)), div(grad(v))) * dx F += eps * g1 * v * ds F -= eps * g2 * inner(grad(v), n) * ds # f = -div(grad(uex)) # F = inner(grad(u), grad(v)) * dx - f * v * dx # bc = fd.DirichletBC(V, uex, "on_boundary") bc = None fd.solve(F == 0, u, bcs=bc, solver_parameters={ "ksp_type": "cg", "ksp_atol": 1e-13, "ksp_rtol": 1e-13, "ksp_dtol": 1e-13, "ksp_stol": 1e-13, "pc_type": "jacobi", "pc_factor_mat_solver_type": "mumps", "snes_type": "ksponly", "ksp_converged_reason": None }) print("||u-uex|| =", fd.norm(u - uex)) print("||grad(u-uex)|| =", fd.norm(grad(u - uex))) print("||grad(grad(u-uex))|| =", fd.norm(grad(grad(u - uex)))) err = fd.Function( fd.TensorFunctionSpace(mesh, "DG", V.ufl_element().degree() - 2)).interpolate( grad(grad(u - uex))) # err = fd.Function(fd.FunctionSpace(mesh, "DG", V.ufl_element().degree())).interpolate(u-uex) fd.File(outdir + "sln.pvd").write(u) fd.File(outdir + "err.pvd").write(err)
def TensorFunctionSpaceHierarchy(mesh_hierarchy, *args, **kwargs): from firedrake.logging import warning, RED warning( RED % "TensorFunctionSpaceHierarchy is obsolete. Just build a FunctionSpace on the relevant mesh" ) return tuple( firedrake.TensorFunctionSpace(mesh, *args, **kwargs) for mesh in mesh_hierarchy)
def __init__(self, mesh, permittivity_dict, k0L, **kvargs): super().__init__(mesh, k0L, **kvargs) self.II = fd.as_matrix(((1, 0), (0, 1))) self.permittivity = fd.Function( fd.TensorFunctionSpace(self.mesh, "DG", 0)) for (subd_id, epsilon_tensor) in permittivity_dict.items(): epsilon = fd.as_matrix(epsilon_tensor) self.permittivity.interpolate( epsilon, self.mesh.measure_set("cell", subd_id))
def stresses(mesh, icemodel, u): Q1 = fd.FunctionSpace(mesh, 'Q', 1) TQ1 = fd.TensorFunctionSpace(mesh, 'Q', 1) Du = fd.Function(TQ1).interpolate(0.5 * (fd.grad(u) + fd.grad(u).T)) Du2 = fd.Function(Q1).interpolate(0.5 * fd.inner(Du, Du) + icemodel.eps * icemodel.Dtyp**2.0) nu = fd.Function(Q1).interpolate(0.5 * Bn * Du2**(-1.0 / n)) nu.rename('effective viscosity') tau = fd.Function(TQ1).interpolate(2.0 * nu * Du) tau.rename('tau') return tau, nu
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, c, bound, *args, **kwargs): super().__init__(*args, **kwargs) self.c = c self.T = self.Q.T r_mesh = self.T.ufl_domain() self.lam_space = fd.TensorFunctionSpace(r_mesh, "DG", 0) self.scalar_space = fd.FunctionSpace(r_mesh, "DG", 0) self.nuclear_norm = fd.Function(self.scalar_space) self.viol = fd.Function(self.scalar_space) self.lam = fd.Function(self.lam_space) self.gradS = fd.Function(self.lam_space) self.lam_c_grad_S = fd.Function(self.lam_space) self.argmin = fd.Function(self.lam_space) self.bound = fd.Function(self.scalar_space).interpolate(bound) self.iden = fd.Function(self.V_r) self.iden.interpolate(fd.SpatialCoordinate(r_mesh)) self.S = self.T.copy(deepcopy=True) self.dim = r_mesh.topological_dimension()
def test_metric_math(dim): """ Check that the metric exponential and metric logarithm are indeed inverses. """ mesh = uniform_mesh(dim, 1) P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0) I = ufl.Identity(dim) M = firedrake.interpolate(2 * I, P0_ten) logM = metric_logarithm(M) expected = firedrake.interpolate(np.log(2) * I, P0_ten) assert np.allclose(logM.dat.data, expected.dat.data) M_ = metric_exponential(logM) assert np.allclose(M.dat.data, M_.dat.data) expM = metric_exponential(M) expected = firedrake.interpolate(np.exp(2) * I, P0_ten) assert np.allclose(expM.dat.data, expected.dat.data) M_ = metric_logarithm(expM) assert np.allclose(M.dat.data, M_.dat.data)
def get_scaled_jacobians2d(mesh, python=False): """ Computes the scaled Jacobian of each cell in a 2D triangular mesh :arg mesh: the input mesh to do computations on :kwarg python: compute the measure using Python? :rtype: firedrake.function.Function scaled_jacobians with scaled jacobian data. """ P0 = firedrake.FunctionSpace(mesh, "DG", 0) if python: P0_ten = firedrake.TensorFunctionSpace(mesh, "DG", 0) J = firedrake.interpolate(ufl.Jacobian(mesh), P0_ten) edge1 = ufl.as_vector([J[0, 0], J[1, 0]]) edge2 = ufl.as_vector([J[0, 1], J[1, 1]]) edge3 = edge1 - edge2 a = ufl.sqrt(ufl.dot(edge1, edge1)) b = ufl.sqrt(ufl.dot(edge2, edge2)) c = ufl.sqrt(ufl.dot(edge3, edge3)) detJ = ufl.JacobianDeterminant(mesh) jacobian_sign = ufl.sign(detJ) max_product = ufl.Max( ufl.Max(ufl.Max(a * b, a * c), ufl.Max(b * c, b * a)), ufl.Max(c * a, c * b) ) scaled_jacobians = firedrake.interpolate(detJ / max_product * jacobian_sign, P0) else: coords = mesh.coordinates scaled_jacobians = firedrake.Function(P0) op2.par_loop( get_pyop2_kernel("get_scaled_jacobian", 2), mesh.cell_set, scaled_jacobians.dat(op2.WRITE, scaled_jacobians.cell_node_map()), coords.dat(op2.READ, coords.cell_node_map()), ) return scaled_jacobians
def initialize(self, pc): _, P = pc.getOperators() assert P.type == "python" context = P.getPythonContext() (self.J, self.bcs) = (context.a, context.row_bcs) test, trial = self.J.arguments() if test.function_space() != trial.function_space(): raise NotImplementedError("test and trial spaces must be the same") Pk = test.function_space() element = Pk.ufl_element() shape = element.value_shape() mesh = Pk.ufl_domain() if len(shape) == 0: P1 = firedrake.FunctionSpace(mesh, "CG", 1) elif len(shape) == 2: P1 = firedrake.VectorFunctionSpace(mesh, "CG", 1, dim=shape[0]) else: P1 = firedrake.TensorFunctionSpace(mesh, "CG", 1, shape=shape, symmetry=element.symmetry()) # TODO: A smarter low-order operator would also interpolate # any coefficients to the coarse space. mapper = ArgumentReplacer({ test: firedrake.TestFunction(P1), trial: firedrake.TrialFunction(P1) }) self.lo_J = map_integrands.map_integrand_dags(mapper, self.J) lo_bcs = [] for bc in self.bcs: # Don't actually need the value, since it's only used for # killing parts of the restriction matrix. lo_bcs.append( firedrake.DirichletBC(P1, firedrake.zero(P1.shape), bc.sub_domain, method=bc.method)) self.lo_bcs = tuple(lo_bcs) mat_type = PETSc.Options().getString( pc.getOptionsPrefix() + "lo_mat_type", firedrake.parameters["default_matrix_type"]) self.lo_op = firedrake.assemble(self.lo_J, bcs=self.lo_bcs, mat_type=mat_type) self.lo_op.force_evaluation() A, P = pc.getOperators() nearnullsp = P.getNearNullSpace() if nearnullsp.handle != 0: # Actually have a near nullspace tmp = firedrake.Function(Pk) low = firedrake.Function(P1) vecs = [] for vec in nearnullsp.getVecs(): with tmp.dat.vec as v: vec.copy(v) low.interpolate(tmp) with low.dat.vec_ro as v: vecs.append(v.copy()) nullsp = PETSc.NullSpace().create(vectors=vecs, comm=pc.comm) self.lo_op.petscmat.setNearNullSpace(nullsp) lo = PETSc.PC().create(comm=pc.comm) lo.incrementTabLevel(1, parent=pc) lo.setOperators(self.lo_op.petscmat, self.lo_op.petscmat) lo.setOptionsPrefix(pc.getOptionsPrefix() + "lo_") lo.setFromOptions() self.lo = lo self.restriction = restriction_matrix(Pk, P1, self.bcs, self.lo_bcs) self.work = self.lo_op.petscmat.createVecs() if len(self.bcs) > 0: bc_nodes = numpy.unique( numpy.concatenate([bc.nodes for bc in self.bcs])) bc_nodes = bc_nodes[bc_nodes < Pk.dof_dset.size] bc_iset = PETSc.IS().createBlock(numpy.prod(shape), bc_nodes, comm=PETSc.COMM_SELF) self.bc_indices = bc_iset.getIndices() bc_iset.destroy() else: self.bc_indices = numpy.empty(0, dtype=numpy.int32)
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) # Others function space V = fd.VectorFunctionSpace(mesh, "DQ", order - 1) T = fd.TensorFunctionSpace(mesh, "DQ", order - 1) else: RT = fd.FunctionSpace(mesh, "RT", order) DG = fd.FunctionSpace(mesh, "DG", order - 1) # Others function space V = fd.VectorFunctionSpace(mesh, "DG", order - 1) T = fd.TensorFunctionSpace(mesh, "DG", order - 1) W = RT * DG # test and trial functions on the subspaces of the mixed function spaces as # follows: :: u, p = fd.TrialFunctions(W) v, q = fd.TestFunctions(W)
def clement_interpolant(source, target_space=None, boundary_tag=None): r""" Compute the Clement interpolant of a :math:`\mathbb P0` source field, i.e. take the volume average over neighbouring cells at each vertex. :arg source: the :math:`\mathbb P0` source field :kwarg target_space: the :math:`\mathbb P1` space to interpolate into :boundary_tag: optional boundary tag to compute the Clement interpolant over. """ V = source.function_space() assert V.ufl_element().family() == "Discontinuous Lagrange" assert V.ufl_element().degree() == 0 rank = len(V.ufl_element().value_shape()) mesh = V.mesh() dim = mesh.topological_dimension() P1 = firedrake.FunctionSpace(mesh, "CG", 1) dX = ufl.dx if boundary_tag is None else ufl.ds(boundary_tag) if target_space is None: if rank == 0: target_space = P1 elif rank == 1: target_space = firedrake.VectorFunctionSpace(mesh, "CG", 1) elif rank == 2: target_space = firedrake.TensorFunctionSpace(mesh, "CG", 1) else: raise ValueError(f"Rank-{rank} tensors are not supported.") else: assert target_space.ufl_element().family() == "Lagrange" assert target_space.ufl_element().degree() == 1 target = firedrake.Function(target_space) # Compute the patch volume at each vertex if boundary_tag is None: P0 = firedrake.FunctionSpace(mesh, "DG", 0) dx = ufl.dx(domain=mesh) volume = firedrake.assemble(firedrake.TestFunction(P0) * dx) else: volume = get_facet_areas(mesh) patch_volume = firedrake.Function(P1) kernel = "for (int i=0; i < p.dofs; i++) p[i] += v[0];" keys = { "v": (volume, op2.READ), "p": (patch_volume, op2.INC), } firedrake.par_loop(kernel, dX, keys) # Volume average keys = { "s": (source, op2.READ), "v": (volume, op2.READ), "t": (target, op2.INC), } if rank == 0: firedrake.par_loop( """ for (int i=0; i < t.dofs; i++) { t[i] += s[0]*v[0]; } """, dX, keys, ) elif rank == 1: firedrake.par_loop( """ int d = %d; for (int i=0; i < t.dofs; i++) { for (int j=0; j < d; j++) { t[i*d + j] += s[j]*v[0]; } } """ % dim, dX, keys, ) elif rank == 2: firedrake.par_loop( """ int d = %d; int Nd = d*d; for (int i=0; i < t.dofs; i++) { for (int j=0; j < d; j++) { for (int k=0; k < d; k++) { t[i*Nd + j*d + k] += s[j*d + k]*v[0]; } } } """ % dim, dX, keys, ) else: raise ValueError(f"Rank-{rank} tensors are not supported.") target.interpolate(target / patch_volume) if boundary_tag is not None: target.dat.data_with_halos[:] = np.nan_to_num(target.dat.data_with_halos) return target
parser = argparse.ArgumentParser() parser.add_argument('--mesh') parser.add_argument('--input') parser.add_argument('--output') parser.add_argument('--damage', action='store_true') parser.add_argument('--final-time', type=float) parser.add_argument('--num-steps', type=int) args = parser.parse_args() # Load the mesh and create some function spaces mesh = firedrake.Mesh(args.mesh) Q = firedrake.FunctionSpace(mesh, family='CG', degree=2) V = firedrake.VectorFunctionSpace(mesh, family='CG', degree=2) Δ = firedrake.FunctionSpace(mesh, family='DG', degree=1) S = firedrake.TensorFunctionSpace(mesh, family='DG', degree=1) # Load the initial data from an HDF5 file if available if args.input: h0 = firedrake.Function(Q) u0 = firedrake.Function(V) input_name = os.path.splitext(args.input)[0] with firedrake.DumbCheckpoint(input_name, mode=firedrake.FILE_READ) as chk: chk.load(h0, name='h') chk.load(u0, name='u') # Otherwise, create some synthetic initial data symbolically else: import numpy as np from numpy import pi as π