def test_segregated_derivative_of_convection(self): cell = tetrahedron V = FiniteElement("CG", cell, 1) W = VectorElement("CG", cell, 1) u = Coefficient(W) v = Coefficient(W) du = TrialFunction(V) dv = TestFunction(V) L = dot(dot(u, nabla_grad(u)), v) Lv = {} Lvu = {} for i in range(cell.geometric_dimension()): Lv[i] = derivative(L, v[i], dv) for j in range(cell.geometric_dimension()): Lvu[i, j] = derivative(Lv[i], u[j], du) for i in range(cell.geometric_dimension()): for j in range(cell.geometric_dimension()): form = Lvu[i, j]*dx fd = compute_form_data(form) pf = fd.preprocessed_form a = expand_indices(pf) # print (i,j), str(a) k = Index() for i in range(cell.geometric_dimension()): for j in range(cell.geometric_dimension()): actual = Lvu[i, j] expected = du*u[i].dx(j)*dv + u[k]*du.dx(k)*dv assertEqualBySampling(actual, expected)
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 generateCode(predefined, expressions, coefficients=None, tempVars=True): expressions = [applyRestrictions(expand_indices(apply_derivatives(apply_algebra_lowering(expr)))) for expr in expressions] generator = CodeGenerator(predefined, coefficients, tempVars) results = map_expr_dags(generator, expressions) l = list(generator.using) l.sort() return l + generator.code, results
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_expand_indices(): element = FiniteElement("Lagrange", triangle, 2) v = TestFunction(element) u = TrialFunction(element) def evaluate(form): return form.cell_integral()[0].integrand()((), {v: 3, u: 5}) # TODO: How to define values of derivatives? a = div(grad(v)) * u * dx # a1 = evaluate(a) a = expand_derivatives(a) # a2 = evaluate(a) a = expand_indices(a)
def cppcode(form,*args): import ufl.algorithms as alg # expand_derivatives calls expand_compounds for us g = form # g = alg.expand_compounds(g) g = alg.expand_derivatives(g) g = alg.expand_indices(g) s = g.__str__() for var in args: s = s.replace(var.__str__(), var.expression().cppcode) return s
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)
def test_expand_indices(): element = FiniteElement("Lagrange", triangle, 2) v = TestFunction(element) u = TrialFunction(element) def evaluate(form): return form.cell_integral()[0].integrand()((), { v: 3, u: 5 }) # TODO: How to define values of derivatives? a = div(grad(v)) * u * dx # a1 = evaluate(a) a = expand_derivatives(a) # a2 = evaluate(a) a = expand_indices(a)
def splitForm(form, arguments=None): if arguments is None: arguments = form.arguments() form = applyRestrictions(form) form = expand_indices(apply_derivatives(apply_algebra_lowering(form))) form = applyRestrictions(form) integrals = {} for integral in form.integrals(): right = splitMultiLinearExpr(integral.integrand(), arguments) left = integrals.get(integral.integral_type()) if left is not None: right = sumTensorMaps(left, right) integrals[integral.integral_type()] = right return integrals
def expr2latex(expr, variables=None): "This is a test specific function for formatting ufl to LaTeX." # Preprocessing expression before applying formatting. In a # compiler, one should probably assume that these have been # applied and use ExprFormatter directly. expr_data = preprocess_expression(expr) expr = expand_indices(expr_data.preprocessed_expr) # This formatter is a multifunction with single operator # formatting rules for generic LaTeX formatting latex_formatter = LatexFormatter() # This final formatter implements a generic framework handling # indices etc etc. variables = variables or {} expr_formatter = ExprFormatter(latex_formatter, variables) code = expr_formatter.visit(expr) return code
def _find_linear_terms(rhs_exprs, u): """Help function that takes a list of rhs expressions and return a list of bools determining what component, rhs_exprs[i], is linear wrt u[i]. """ uu = [Constant(1.0) for _ in rhs_exprs] if len(rhs_exprs) > 1: repl = {u: ufl.as_vector(uu)} else: repl = {u: uu[0]} linear_terms = [] for i, ui in enumerate(uu): comp_i_s = expand_indices(ufl.replace(rhs_exprs[i], repl)) linear_terms.append(ui in extract_coefficients(comp_i_s) and ui not in extract_coefficients( expand_derivatives(ufl.diff(comp_i_s, ui)))) return linear_terms
def process_form(F): global msize, mtime printmem() print "size of form", asizeof(F) print_expr_size(F.cell_integrals()[0].integrand()) t1 = time.time() print 'starting preprocess' Ffd = F.compute_form_data() t2 = time.time() print 'preprocess took %d s' % (t2 - t1) print "size of form data (in MB)", asizeof(Ffd) / float(1024**2) print_expr_size(Ffd.preprocessed_form.cell_integrals()[0].integrand()) printmem() printmem() t1 = time.time() print 'starting expand_indices' eiF = expand_indices(Ffd.preprocessed_form) t2 = time.time() print 'expand_indices took %d s' % (t2 - t1) #print "REPR LEN", len(repr(eiF)) msize = asizeof(eiF) / float(1024**2) mtime = t2 - t1 print "size of expanded form (in MB)", msize print_expr_size(eiF.cell_integrals()[0].integrand()) printmem() t1 = time.time() print 'starting graph building' FG = Graph(eiF.cell_integrals()[0].integrand()) t2 = time.time() print 'graph building took %d s' % (t2 - t1) print "size of graph (in MB)", asizeof(FG) / float(1024**2) printmem() return eiF
def process_form(F): global msize, mtime printmem() print "size of form", asizeof(F) print_expr_size(F.cell_integrals()[0].integrand()) t1 = time.time() print 'starting preprocess' Ffd = F.compute_form_data() t2 = time.time() print 'preprocess took %d s' % (t2-t1) print "size of form data (in MB)", asizeof(Ffd)/float(1024**2) print_expr_size(Ffd.preprocessed_form.cell_integrals()[0].integrand()) printmem() printmem() t1 = time.time() print 'starting expand_indices' eiF = expand_indices(Ffd.preprocessed_form) t2 = time.time() print 'expand_indices took %d s' % (t2-t1) #print "REPR LEN", len(repr(eiF)) msize = asizeof(eiF)/float(1024**2) mtime = t2-t1 print "size of expanded form (in MB)", msize print_expr_size(eiF.cell_integrals()[0].integrand()) printmem() t1 = time.time() print 'starting graph building' FG = Graph(eiF.cell_integrals()[0].integrand()) t2 = time.time() print 'graph building took %d s' % (t2-t1) print "size of graph (in MB)", asizeof(FG)/float(1024**2) printmem() return eiF
def expr2cpp(expr, variables=None): "This is a test specific function for formatting ufl to C++." # Preprocessing expression before applying formatting. # In a compiler, one should probably assume that these # have been applied and use ExprFormatter directly. expr_data = preprocess_expression(expr) # Applying expand_indices instead of going through # compiler algorithm to get scalar valued expressions # that can be directlly formatted into C++ expr = expand_indices(expr_data.preprocessed_expr) # This formatter is a multifunction implementing target # specific C++ formatting rules cpp_formatter = ToyCppLanguageFormatter(dh, ir) # This final formatter implements a generic framework handling indices etc etc. expr_formatter = ExprFormatter(cpp_formatter, variables or {}) # Finally perform the formatting code = expr_formatter.visit(expr) return code
def _rush_larsen_scheme_generator_adm(rhs_form, solution, time, order, generalized, perturbation): """Generates a list of forms and solutions for the adjoint linearisation of the Rush-Larsen scheme *Arguments* rhs_form (ufl.Form) A UFL form representing the rhs for a time differentiated equation solution (_Function_) The prognostic variable time (_Constant_) A Constant holding the time at the start of the time step order (int) The order of the scheme generalized (bool) If True generate a generalized Rush Larsen scheme, linearizing all components. perturbation (Function) The vector on which we compute the adjoint action. """ DX = _check_form(rhs_form) if DX != ufl.dP: raise TypeError("Expected a form with a Pointintegral.") # Create time step dt = Constant(0.1) # Get test function # arguments = rhs_form.arguments() # coefficients = rhs_form.coefficients() # Get time dependent expressions time_dep_expressions = _time_dependent_expressions(rhs_form, time) # Extract rhs expressions from form rhs_integrand = rhs_form.integrals()[0].integrand() rhs_exprs, v = extract_tested_expressions(rhs_integrand) vector_rhs = len(v.ufl_shape) > 0 and v.ufl_shape[0] > 1 system_size = v.ufl_shape[0] if vector_rhs else 1 # Fix for indexing of v for scalar expressions v = v if vector_rhs else [v] # Extract linear terms if not using generalized Rush Larsen if not generalized: linear_terms = _find_linear_terms(rhs_exprs, solution) else: linear_terms = [True for _ in range(system_size)] # Wrap the rhs expressions into a ufl vector type rhs_exprs = ufl.as_vector([rhs_exprs[i] for i in range(system_size)]) rhs_jac = ufl.diff(rhs_exprs, solution) # Takes time! if vector_rhs: diff_rhs_exprs = [expand_indices(expand_derivatives(rhs_jac[ind, ind])) for ind in range(system_size)] soln = solution else: diff_rhs_exprs = [expand_indices(expand_derivatives(rhs_jac[0]))] solution = [solution] soln = solution[0] ufl_stage_forms = [] dolfin_stage_forms = [] dt_stage_offsets = [] trial = TrialFunction(soln.function_space()) # Stage solutions (3 per order rhs, linearized, and final step) # If 2nd order the final step for 1 step is a stage if order == 1: stage_solutions = [] # Fetch the original step rl_ufl_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, system_size, solution, None, dt, time, 1.0, 0.0, v, DX, time_dep_expressions) # If this is commented out, we don't get NaNs. Yhy is # solution a list of length zero anyway? rl_ufl_form = safe_action(safe_adjoint(derivative(rl_ufl_form, soln, trial)), perturbation) elif order == 2: # Stage solution for order 2 fn_space = soln.function_space() stage_solutions = [Function(fn_space, name="y_1/2"), Function(fn_space, name="y_1"), Function(fn_space, name="y_bar_1/2")] y_half_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, system_size, solution, None, dt, time, 0.5, 0.0, v, DX, time_dep_expressions) y_one_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, system_size, solution, stage_solutions[0], dt, time, 1.0, 0.5, v, DX, time_dep_expressions) y_bar_half_form = safe_action(safe_adjoint(derivative(y_one_form, stage_solutions[0], trial)), perturbation) rl_ufl_form = safe_action(safe_adjoint(derivative(y_one_form, soln, trial)), perturbation) + \ safe_action(safe_adjoint(derivative(y_half_form, soln, trial)), stage_solutions[2]) ufl_stage_forms.append([y_half_form]) ufl_stage_forms.append([y_one_form]) ufl_stage_forms.append([y_bar_half_form]) dolfin_stage_forms.append([Form(y_half_form)]) dolfin_stage_forms.append([Form(y_one_form)]) dolfin_stage_forms.append([Form(y_bar_half_form)]) # Get last stage form last_stage = Form(rl_ufl_form) human_form = "%srush larsen %s" % ("generalized " if generalized else "", str(order)) return rhs_form, linear_terms, ufl_stage_forms, dolfin_stage_forms, last_stage, \ stage_solutions, dt, dt_stage_offsets, human_form, perturbation
def _rush_larsen_scheme_generator(rhs_form, solution, time, order, generalized): """Generates a list of forms and solutions for a given Butcher tableau *Arguments* rhs_form (ufl.Form) A UFL form representing the rhs for a time differentiated equation solution (_Function_) The prognostic variable time (_Constant_) A Constant holding the time at the start of the time step order (int) The order of the scheme generalized (bool) If True generate a generalized Rush Larsen scheme, linearizing all components. """ DX = _check_form(rhs_form) if DX != ufl.dP: raise TypeError("Expected a form with a Pointintegral.") # Create time step dt = Constant(0.1) # Get test function # arguments = rhs_form.arguments() # coefficients = rhs_form.coefficients() # Get time dependent expressions time_dep_expressions = _time_dependent_expressions(rhs_form, time) # Extract rhs expressions from form rhs_integrand = rhs_form.integrals()[0].integrand() rhs_exprs, v = extract_tested_expressions(rhs_integrand) vector_rhs = len(v.ufl_shape) > 0 and v.ufl_shape[0] > 1 system_size = v.ufl_shape[0] if vector_rhs else 1 # Fix for indexing of v for scalar expressions v = v if vector_rhs else [v] # Extract linear terms if not using generalized Rush Larsen if not generalized: linear_terms = _find_linear_terms(rhs_exprs, solution) else: linear_terms = [True for _ in range(system_size)] # Wrap the rhs expressions into a ufl vector type rhs_exprs = ufl.as_vector([rhs_exprs[i] for i in range(system_size)]) rhs_jac = ufl.diff(rhs_exprs, solution) # Takes time! if vector_rhs: diff_rhs_exprs = [expand_indices(expand_derivatives(rhs_jac[ind, ind])) for ind in range(system_size)] else: diff_rhs_exprs = [expand_indices(expand_derivatives(rhs_jac[0]))] solution = [solution] ufl_stage_forms = [] dolfin_stage_forms = [] dt_stage_offsets = [] # Stage solutions (3 per order rhs, linearized, and final step) # If 2nd order the final step for 1 step is a stage if order == 1: stage_solutions = [] rl_ufl_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, system_size, solution, None, dt, time, 1.0, 0.0, v, DX, time_dep_expressions) elif order == 2: # Stage solution for order 2 if vector_rhs: stage_solutions = [Function(solution.function_space(), name="y_1/2")] else: stage_solutions = [Function(solution[0].function_space(), name="y_1/2")] stage_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, system_size, solution, None, dt, time, 0.5, 0.0, v, DX, time_dep_expressions) rl_ufl_form = _rush_larsen_step(rhs_exprs, diff_rhs_exprs, linear_terms, system_size, solution, stage_solutions[0], dt, time, 1.0, 0.5, v, DX, time_dep_expressions) ufl_stage_forms.append([stage_form]) dolfin_stage_forms.append([Form(stage_form)]) # Get last stage form last_stage = Form(rl_ufl_form) human_form = "%srush larsen %s" % ("generalized " if generalized else "", str(order)) return rhs_form, linear_terms, ufl_stage_forms, dolfin_stage_forms, last_stage, \ stage_solutions, dt, dt_stage_offsets, human_form, None