def splitUFLForm(form): phi = form.arguments()[0] dphi = Grad(phi) source = ExprTensor(phi.ufl_shape) flux = ExprTensor(dphi.ufl_shape) boundarySource = ExprTensor(phi.ufl_shape) form = expand_indices(expand_derivatives(expand_compounds(form))) for integral in form.integrals(): if integral.integral_type() == 'cell': fluxExprs = splitMultiLinearExpr(integral.integrand(), [phi]) for op in fluxExprs: if op[0] == phi: source = source + fluxExprs[op] elif op[0] == dphi: flux = flux + fluxExprs[op] else: raise Exception('Invalid derivative encountered in bulk integral: ' + str(op[0])) elif integral.integral_type() == 'exterior_facet': fluxExprs = splitMultiLinearExpr(integral.integrand(), [phi]) for op in fluxExprs: if op[0] == phi: boundarySource = boundarySource + fluxExprs[op] else: raise Exception('Invalid derivative encountered in boundary integral: ' + str(op[0])) else: raise NotImplementedError('Integrals of type ' + integral.integral_type() + ' are not supported.') return source, flux, boundarySource
def is_zero_ufl_expression(expr, return_val=False): """ Is the given expression always identically zero or not Returns a boolean by default, but will return the actual evaluated expression value if return_val=True This function is somewhat brittle. If the ufl library changes how forms are processed (additional steps or other complexity is added) then this function must be extended to be able to break the expressions down into the smallest possible parts. """ # Reduce the complexity of the expression as much as possible expr = expand_derivatives(expr) expr = expand_compounds(expr) expr = expand_indices(expr) expr = IndexSimplificator().visit(expr) # Perform the zero-form estimation val = EstimateZeroForms().visit(expr) val = int(val) # val > 0 if the form is (likely) non-Zero and 0 if it is # provably identically Zero() if return_val: return val else: return val == 0
def codeDG(self): code = self._code() u = self.trialFunction ubar = Coefficient(u.ufl_function_space()) penalty = self.penalty if penalty is None: penalty = 1 if isinstance(penalty, Expr): if penalty.ufl_shape == (): penalty = as_vector([penalty]) try: penalty = expand_indices( expand_derivatives(expand_compounds(penalty))) except: pass assert penalty.ufl_shape == u.ufl_shape dmPenalty = as_vector([ replace( expand_derivatives(diff(replace(penalty, {u: ubar}), ubar))[i, i], {ubar: u}) for i in range(u.ufl_shape[0]) ]) else: dmPenalty = None code.append(AccessModifier("public")) x = SpatialCoordinate(self.space.cell()) predefined = {} self.predefineCoefficients(predefined, x) spatial = Variable('const auto', 'y') predefined.update({ x: UnformattedExpression( 'auto', 'entity().geometry().global( Dune::Fem::coordinate( x ) )') }) generateMethod(code, penalty, 'RRangeType', 'penalty', args=['const Point &x', 'const DRangeType &u'], targs=['class Point', 'class DRangeType'], static=False, const=True, predefined=predefined) generateMethod(code, dmPenalty, 'RRangeType', 'linPenalty', args=['const Point &x', 'const DRangeType &u'], targs=['class Point', 'class DRangeType'], static=False, const=True, predefined=predefined) return code
def test_mixed_tensor_symmetries(): from ufl.algorithms import expand_indices, expand_compounds S = FiniteElement('CG', triangle, 1) V = VectorElement('CG', triangle, 1) T = TensorElement('CG', triangle, 1, symmetry=True) # M has dimension 4+1, symmetries are 2->1 M = T * S P = Coefficient(M) M = inner(P, P) * dx M2 = expand_indices(expand_compounds(M)) assert '[1]' in str(M2) assert '[2]' not in str(M2) # M has dimension 2+(1+4), symmetries are 5->4 M = V * (S * T) P = Coefficient(M) M = inner(P, P) * dx M2 = expand_indices(expand_compounds(M)) assert '[4]' in str(M2) assert '[5]' not in str(M2)