def estimate(self, solution): mesh = solution.function_space().mesh() # Define cell and facet residuals R_T = -(self.rhs_f + div(grad(solution))) n = FacetNormal(mesh) R_dT = dot(grad(solution), n) # Will use space of constants to localize indicator form Constants = FunctionSpace(mesh, "DG", 0) w = TestFunction(Constants) h = CellSize(mesh) # Define form for assembling error indicators form = (h ** 2 * R_T ** 2 * w * dx + avg(h) * avg(R_dT) ** 2 * 2 * avg(w) * dS) # + h * R_dT ** 2 * w * ds) # Assemble error indicators indicators = assemble(form) # Calculate error error_estimate = sqrt(sum(i for i in indicators.array())) # Take sqrt of indicators indicators = np.array([sqrt(i) for i in indicators]) # Mark cells for refinement based on maximal marking strategy largest_error = max(indicators) cell_markers = MeshFunction("bool", mesh, mesh.topology().dim()) for c in cells(mesh): cell_markers[c] = indicators[c.index()] > (self.fraction * largest_error) return error_estimate, cell_markers
def circumradius(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.is_piecewise_linear_simplex_domain(): # Don't lower for non-affine cells, instead leave it to # form compiler warning( "Only know how to compute the circumradius of an affine cell.") return o cellname = domain.ufl_cell().cellname() cellvolume = self.cell_volume(CellVolume(domain)) if cellname == "interval": r = 0.5 * cellvolume elif cellname == "triangle": J = self.jacobian(Jacobian(domain)) trev = CellEdgeVectors(domain) num_edges = 3 i, j, k = indices(3) elen = [ sqrt((J[i, j] * trev[edge, j]) * (J[i, k] * trev[edge, k])) for edge in range(num_edges) ] r = (elen[0] * elen[1] * elen[2]) / (4.0 * cellvolume) elif cellname == "tetrahedron": J = self.jacobian(Jacobian(domain)) trev = CellEdgeVectors(domain) num_edges = 6 i, j, k = indices(3) elen = [ sqrt((J[i, j] * trev[edge, j]) * (J[i, k] * trev[edge, k])) for edge in range(num_edges) ] # elen[3] = length of edge 3 # la, lb, lc = lengths of the sides of an intermediate triangle la = elen[3] * elen[2] lb = elen[4] * elen[1] lc = elen[5] * elen[0] # p = perimeter p = (la + lb + lc) # s = semiperimeter s = p / 2 # area of intermediate triangle with Herons formula triangle_area = sqrt(s * (s - la) * (s - lb) * (s - lc)) r = triangle_area / (6.0 * cellvolume) else: error("Unhandled cell type %s." % cellname) return r
def pseudo_determinant_expr(A): """Compute the pseudo-determinant of A.""" m, n = A.ufl_shape if n == 1: # Special case 1xm for simpler expression i = Index() return sqrt(A[i, 0] * A[i, 0]) elif n == 2 and m == 3: # Special case 2x3 for simpler expression c = cross_expr(A[:, 0], A[:, 1]) i = Index() return sqrt(c[i] * c[i]) else: # Generic formulation based on A.T*A return generic_pseudo_determinant_expr(A)
def _reduce_facet_edge_length(self, o, reduction_op): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if domain.ufl_cell().topological_dimension() < 3: error( "Facet edge lengths only make sense for topological dimension >= 3." ) elif not domain.ufl_coordinate_element().degree() == 1: # Don't lower bendy cells, instead leave it to form compiler warning( "Only know how to compute facet edge lengths of P1 or Q1 cell." ) return o else: # P1 tetrahedron or Q1 hexahedron edges = FacetEdgeVectors(domain) num_edges = edges.ufl_shape[0] j = Index() elen2 = [edges[e, j] * edges[e, j] for e in range(num_edges)] return sqrt(reduce(reduction_op, elen2))
def max_facet_edge_length(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.is_piecewise_linear_simplex_domain(): # Don't lower for non-affine cells, instead leave it to # form compiler warning( "Only know how to compute the max_facet_edge_length of an affine cell." ) return o cellname = domain.ufl_cell().cellname() if cellname == "triangle": return self.facet_area(FacetArea(domain)) elif cellname == "tetrahedron": J = self.jacobian(Jacobian(domain)) trev = FacetEdgeVectors(domain) num_edges = 3 i, j, k = indices(3) elen = [ sqrt((J[i, j] * trev[edge, j]) * (J[i, k] * trev[edge, k])) for edge in range(num_edges) ] return max_value(elen[0], max_value(elen[1], elen[2])) else: error("Unhandled cell type %s." % cellname)
def cell_normal(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() gdim = domain.geometric_dimension() tdim = domain.topological_dimension() if tdim == gdim - 1: # n-manifold embedded in n-1 space i = Index() J = self.jacobian(Jacobian(domain)) if tdim == 2: # Surface in 3D t0 = as_vector(J[i, 0], i) t1 = as_vector(J[i, 1], i) cell_normal = cross_expr(t0, t1) elif tdim == 1: # Line in 2D (cell normal is 'up' for a line pointing # to the 'right') cell_normal = as_vector((-J[1, 0], J[0, 0])) else: error("Cell normal not implemented for tdim %d, gdim %d" % (tdim, gdim)) # Return normalized vector, sign corrected by cell # orientation co = CellOrientation(domain) return co * cell_normal / sqrt(cell_normal[i] * cell_normal[i]) else: error("What do you want cell normal in gdim={0}, tdim={1} to be?". format(gdim, tdim))
def cell_normal(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() gdim = domain.geometric_dimension() tdim = domain.topological_dimension() if tdim == gdim - 1: # n-manifold embedded in n-1 space i = Index() J = self.jacobian(Jacobian(domain)) if tdim == 2: # Surface in 3D t0 = as_vector(J[i, 0], i) t1 = as_vector(J[i, 1], i) cell_normal = cross_expr(t0, t1) elif tdim == 1: # Line in 2D (cell normal is 'up' for a line pointing # to the 'right') cell_normal = as_vector((-J[1, 0], J[0, 0])) else: error("Cell normal not implemented for tdim %d, gdim %d" % (tdim, gdim)) # Return normalized vector, sign corrected by cell # orientation co = CellOrientation(domain) return co * cell_normal / sqrt(cell_normal[i]*cell_normal[i]) else: error("What do you want cell normal in gdim={0}, tdim={1} to be?".format(gdim, tdim))
def facet_normal(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() tdim = domain.topological_dimension() if tdim == 1: # Special-case 1D (possibly immersed), for which we say # that n is just in the direction of J. J = self.jacobian(Jacobian(domain)) # dx/dX ndir = J[:, 0] gdim = domain.geometric_dimension() if gdim == 1: nlen = abs(ndir[0]) else: i = Index() nlen = sqrt(ndir[i] * ndir[i]) rn = ReferenceNormal(domain) # +/- 1.0 here n = rn[0] * ndir / nlen r = n else: # Recall that the covariant Piola transform u -> J^(-T)*u # preserves tangential components. The normal vector is # characterised by having zero tangential component in # reference and physical space. Jinv = self.jacobian_inverse(JacobianInverse(domain)) i, j = indices(2) rn = ReferenceNormal(domain) # compute signed, unnormalised normal; note transpose ndir = as_vector(Jinv[j, i] * rn[j], i) # normalise i = Index() n = ndir / sqrt(ndir[i] * ndir[i]) r = n if r.ufl_shape != o.ufl_shape: error("Inconsistent dimensions (in=%d, out=%d)." % (o.ufl_shape[0], r.ufl_shape[0])) return r
def facet_normal(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() tdim = domain.topological_dimension() if tdim == 1: # Special-case 1D (possibly immersed), for which we say # that n is just in the direction of J. J = self.jacobian(Jacobian(domain)) # dx/dX ndir = J[:, 0] gdim = domain.geometric_dimension() if gdim == 1: nlen = abs(ndir[0]) else: i = Index() nlen = sqrt(ndir[i]*ndir[i]) rn = ReferenceNormal(domain) # +/- 1.0 here n = rn[0] * ndir / nlen r = n else: # Recall that the covariant Piola transform u -> J^(-T)*u # preserves tangential components. The normal vector is # characterised by having zero tangential component in # reference and physical space. Jinv = self.jacobian_inverse(JacobianInverse(domain)) i, j = indices(2) rn = ReferenceNormal(domain) # compute signed, unnormalised normal; note transpose ndir = as_vector(Jinv[j, i] * rn[j], i) # normalise i = Index() n = ndir / sqrt(ndir[i]*ndir[i]) r = n if r.ufl_shape != o.ufl_shape: error("Inconsistent dimensions (in=%d, out=%d)." % (o.ufl_shape[0], r.ufl_shape[0])) return r
def circumradius(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.is_piecewise_linear_simplex_domain(): error("Circumradius only makes sense for affine simplex cells") cellname = domain.ufl_cell().cellname() cellvolume = self.cell_volume(CellVolume(domain)) if cellname == "interval": # Optimization for square interval; no square root needed return 0.5 * cellvolume # Compute lengths of cell edges edges = CellEdgeVectors(domain) num_edges = edges.ufl_shape[0] j = Index() elen = [sqrt(edges[e, j] * edges[e, j]) for e in range(num_edges)] if cellname == "triangle": return (elen[0] * elen[1] * elen[2]) / (4.0 * cellvolume) elif cellname == "tetrahedron": # la, lb, lc = lengths of the sides of an intermediate triangle # NOTE: Is here some hidden numbering assumption? la = elen[3] * elen[2] lb = elen[4] * elen[1] lc = elen[5] * elen[0] # p = perimeter p = (la + lb + lc) # s = semiperimeter s = p / 2 # area of intermediate triangle with Herons formula triangle_area = sqrt(s * (s - la) * (s - lb) * (s - lc)) return triangle_area / (6.0 * cellvolume)
def circumradius(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.is_piecewise_linear_simplex_domain(): error("Circumradius only makes sense for affine simplex cells") cellname = domain.ufl_cell().cellname() cellvolume = self.cell_volume(CellVolume(domain)) if cellname == "interval": # Optimization for square interval; no square root needed return 0.5 * cellvolume # Compute lengths of cell edges edges = CellEdgeVectors(domain) num_edges = edges.ufl_shape[0] j = Index() elen = [sqrt(edges[e, j]*edges[e, j]) for e in range(num_edges)] if cellname == "triangle": return (elen[0] * elen[1] * elen[2]) / (4.0 * cellvolume) elif cellname == "tetrahedron": # la, lb, lc = lengths of the sides of an intermediate triangle # NOTE: Is here some hidden numbering assumption? la = elen[3] * elen[2] lb = elen[4] * elen[1] lc = elen[5] * elen[0] # p = perimeter p = (la + lb + lc) # s = semiperimeter s = p / 2 # area of intermediate triangle with Herons formula triangle_area = sqrt(s * (s - la) * (s - lb) * (s - lc)) return triangle_area / (6.0 * cellvolume)
def _reduce_facet_edge_length(self, o, reduction_op): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if domain.ufl_cell().topological_dimension() < 3: error("Facet edge lengths only make sense for topological dimension >= 3.") elif not domain.ufl_coordinate_element().degree() == 1: # Don't lower bendy cells, instead leave it to form compiler warning("Only know how to compute facet edge lengths of P1 or Q1 cell.") return o else: # P1 tetrahedron or Q1 hexahedron edges = FacetEdgeVectors(domain) num_edges = edges.ufl_shape[0] j = Index() elen2 = [edges[e, j]*edges[e, j] for e in range(num_edges)] return sqrt(reduce(reduction_op, elen2))
def cell_diameter(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.ufl_coordinate_element().degree() in {1, (1, 1)}: # Don't lower bendy cells, instead leave it to form compiler warning("Only know how to compute cell diameter of P1 or Q1 cell.") return o elif domain.is_piecewise_linear_simplex_domain(): # Simplices return self.max_cell_edge_length(MaxCellEdgeLength(domain)) else: # Q1 cells, maximal distance between any two vertices verts = CellVertices(domain) verts = [verts[v, ...] for v in range(verts.ufl_shape[0])] j = Index() elen2 = (real((v0 - v1)[j] * conj((v0 - v1)[j])) for v0, v1 in combinations(verts, 2)) return real(sqrt(reduce(max_value, elen2)))
def cell_diameter(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.ufl_coordinate_element().degree() == 1: # Don't lower bendy cells, instead leave it to form compiler warning("Only know how to compute cell diameter of P1 or Q1 cell.") return o elif domain.is_piecewise_linear_simplex_domain(): # Simplices return self.max_cell_edge_length(MaxCellEdgeLength(domain)) else: # Q1 cells, maximal distance between any two vertices verts = CellVertices(domain) verts = [verts[v, ...] for v in range(verts.ufl_shape[0])] j = Index() elen2 = ((v0-v1)[j]*(v0-v1)[j] for v0, v1 in combinations(verts, 2)) return sqrt(reduce(max_value, elen2))
def _reduce_cell_edge_length(self, o, reduction_op): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.ufl_coordinate_element().degree() == 1: # Don't lower bendy cells, instead leave it to form compiler warning("Only know how to compute cell edge lengths of P1 or Q1 cell.") return o elif domain.ufl_cell().cellname() == "interval": # Interval optimization, square root not needed return self.cell_volume(CellVolume(domain)) else: # Other P1 or Q1 cells edges = CellEdgeVectors(domain) num_edges = edges.ufl_shape[0] j = Index() elen2 = [edges[e, j]*edges[e, j] for e in range(num_edges)] return sqrt(reduce(reduction_op, elen2))
def _reduce_cell_edge_length(self, o, reduction_op): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() if not domain.ufl_coordinate_element().degree() == 1: # Don't lower bendy cells, instead leave it to form compiler warning("Only know how to compute cell edge lengths of P1 or Q1 cell.") return o elif domain.ufl_cell().cellname() == "interval": # Interval optimization, square root not needed return self.cell_volume(CellVolume(domain)) else: # Other P1 or Q1 cells edges = CellEdgeVectors(domain) num_edges = edges.ufl_shape[0] j = Index() elen2 = [real(edges[e, j] * conj(edges[e, j])) for e in range(num_edges)] return real(sqrt(reduce(reduction_op, elen2)))
def acos(self, f): r".. math:: \\frac{d}{dx} f(x) = \frac{d}{dx} \arccos(x) = \frac{-1}{\sqrt{1 - x^2}}" x, = f.operands() return (-1.0/sqrt(1.0 - x**2),)
def erf(self, o, a): f, fp = a o = self.reuse_if_possible(o, f) op = fp*(2.0/sqrt(pi)*exp(-f**2)) return (o, op)
def asin(self, o, a): f, fp = a o = self.reuse_if_possible(o, f) op = fp/sqrt(1.0 - f**2) return (o, op)
def erf(self, o, fp): f, = o.ufl_operands return fp * (2.0 / sqrt(pi) * exp(-f**2))
def acos(self, o, fp): f, = o.ufl_operands return -fp / sqrt(1.0 - f**2)
def asin(self, o, a): f, fp = a o = self.reuse_if_possible(o, f) op = fp / sqrt(1.0 - f**2) return (o, op)
def asin(self, o, fp): f, = o.ufl_operands return fp / sqrt(1.0 - f**2)
def erf(self, f): "d/dx erf x = 2/sqrt(pi)*exp(-x^2)" x, = f.operands() return (2.0/sqrt(pi)*exp(-x**2),)
def erf(self, o, a): f, fp = a o = self.reuse_if_possible(o, f) op = fp * (2.0 / sqrt(pi) * exp(-f**2)) return (o, op)
def generic_pseudo_determinant_expr(A): """Compute the pseudo-determinant of A: sqrt(det(A.T*A)).""" i, j, k = indices(3) ATA = as_tensor(A[k, i] * A[k, j], (i, j)) return sqrt(determinant_expr(ATA))
def asin(self, f): "d/dx asin x = 1/sqrt(1 - x^2)" x, = f.operands() return (1.0/sqrt(1.0 - x**2),)
def compute_stress(mesh: Mesh, displacement: Function) -> Function: V = FunctionSpace(mesh, 'P', 1) s = sigma(displacement) - tr(sigma(displacement)) * Identity(3) / 3 return project(sqrt(1.5 * inner(s, s)), V)