def expression_replace(expression, replacements): replaced_expression = replace(expression, replacements) replaced_expression_domains = extract_domains(replaced_expression) assert len(replaced_expression_domains) in (0, 1) expression_domains = extract_domains(expression) assert len(expression_domains) in (0, 1) assert len(expression_domains) == len(replaced_expression_domains) if len(expression_domains) == 1: assert replaced_expression_domains[0] is not expression_domains[0] return replaced_expression
def _generate_space(expression: Operator): # Extract mesh from expression (from dolfin/fem/projection.py, _extract_function_space function) meshes = set( [ufl_domain.ufl_cargo() for ufl_domain in extract_domains(expression)]) for t in traverse_unique_terminals( expression): # from ufl/domain.py, extract_domains if hasattr(t, "_mesh"): meshes.add(t._mesh) assert len(meshes) == 1 mesh = meshes.pop() # The EIM algorithm will evaluate the expression at vertices. However, since the Operator expression may # contain e.g. a gradient of a solution defined in a C^0 space, we resort to DG1 spaces. shape = expression.ufl_shape assert len(shape) in (0, 1, 2) if len(shape) == 0: space = FunctionSpace(mesh, "Discontinuous Lagrange", 1) elif len(shape) == 1: space = VectorFunctionSpace(mesh, "Discontinuous Lagrange", 1, dim=shape[0]) elif len(shape) == 2: space = TensorFunctionSpace(mesh, "Discontinuous Lagrange", 1, shape=shape) else: raise ValueError( "Invalid expression in ParametrizedExpressionFactory.__init__().") return space
def form_replace(form, replacements, replacement_type="nodes"): assert replacement_type in ("nodes", "measures") if replacement_type == "nodes": replaced_form = replace(form, replacements) for (integral, replaced_integral) in zip(form.integrals(), replaced_form.integrals()): replaced_integral_domains = extract_domains(replaced_integral.integrand()) assert len(replaced_integral_domains) == 1 integral_domains = extract_domains(integral.integrand()) assert len(integral_domains) == 1 assert replaced_integral_domains[0] is not integral_domains[0] return replaced_form elif replacement_type == "measures": replaced_form = 0 for integral in form.integrals(): measure = replacements[integral.integrand(), integral.integral_type(), integral.subdomain_id()] replaced_form += integral.integrand() * measure return replaced_form else: raise ValueError("Invalid replacement type")
def jump(v, n=None): "UFL operator: Take the jump of *v* across a facet." v = as_ufl(v) is_constant = len(extract_domains(v)) > 0 if is_constant: if n is None: return v('+') - v('-') r = len(v.ufl_shape) if r == 0: return v('+') * n('+') + v('-') * n('-') else: return dot(v('+'), n('+')) + dot(v('-'), n('-')) else: warning("Returning zero from jump of expression without a domain. This may be erroneous if a dolfin.Expression is involved.") # FIXME: Is this right? If v has no domain, it doesn't depend # on anything spatially variable or any form arguments, and # thus the jump is zero. In other words, I'm assuming that "v # has no geometric domains" is equivalent with "v is a spatial # constant". Update: This is NOT true for # jump(Expression("x[0]")) from dolfin. return Zero(v.ufl_shape, v.ufl_free_indices, v.ufl_index_dimensions)
def __rmul__(self, integrand): """Multiply a scalar expression with measure to construct a form with a single integral. This is to implement the notation form = integrand * self Integration properties are taken from this Measure object. """ # Avoid circular imports from ufl.integral import Integral from ufl.form import Form # Allow python literals: 1*dx and 1.0*dx if isinstance(integrand, (int, float)): integrand = as_ufl(integrand) # Let other types implement multiplication with Measure if # they want to (to support the dolfin-adjoint TimeMeasure) if not isinstance(integrand, Expr): return NotImplemented # Allow only scalar integrands if not is_true_ufl_scalar(integrand): error("Can only integrate scalar expressions. The integrand is a " "tensor expression with value shape %s and free indices with labels %s." % (integrand.ufl_shape, integrand.ufl_free_indices)) # If we have a tuple of domain ids, delegate composition to # Integral.__add__: subdomain_id = self.subdomain_id() if isinstance(subdomain_id, tuple): return sum(integrand*self.reconstruct(subdomain_id=d) for d in subdomain_id) # Check that we have an integer subdomain or a string # ("everywhere" or "otherwise", any more?) if not isinstance(subdomain_id, (str, numbers.Integral,)): error("Expecting integer or string domain id.") # If we don't have an integration domain, try to find one in # integrand domain = self.ufl_domain() if domain is None: domains = extract_domains(integrand) if len(domains) == 1: domain, = domains elif len(domains) == 0: error("This integral is missing an integration domain.") else: error("Multiple domains found, making the choice of integration domain ambiguous.") # Otherwise create and return a one-integral form integral = Integral(integrand=integrand, integral_type=self.integral_type(), domain=domain, subdomain_id=subdomain_id, metadata=self.metadata(), subdomain_data=self.subdomain_data()) return Form([integral])
def ufl_domains( self): # TODO: Deprecate this and use extract_domains(expr) "Return all domains this expression is defined on." from ufl.domain import extract_domains return extract_domains(self)
def ufl_domains(self): # TODO: Deprecate this and use extract_domains(expr) "Return all domains this expression is defined on." from ufl.domain import extract_domains return extract_domains(self)