def value_size(obj: ufl.Coefficient) -> Union[List[int], int]: if DOLFIN_VERSION_MAJOR >= 2018: value_shape = obj.value_shape() if len(value_shape) == 0: return 1 return [0] return obj.value_size()
def __init__(self, space, name='x'): with PETSc.Log.Stage(name + '_init'): Coefficient.__init__(self, space) self._name = name self.space = space with PETSc.Log.Event('create_global'): self._vector = self.space.get_composite_da().createGlobalVec() self._vector.set(0.0) self._activevector = self._vector with PETSc.Log.Event('create_local'): #create local vectors- one for EACH component on each PATCH self._lvectors = [] for si in xrange(self.space.nspaces): for ci in xrange(self.space.get_space(si).ncomp): for bi in xrange(self.space.get_space(si).npatches): self._lvectors.append( self.space.get_space(si).get_da( ci, bi).createLocalVector()) if self.space.nspaces > 1: self._split = tuple( SplitFunction(self.space.get_space(i), name="%s[%d]" % (self.name(), i), gvec=self._vector, si=i, parentspace=self.space) for i in range(self.space.nspaces)) else: self._split = (self, )
def count_flops(n): mesh = Mesh(VectorElement('CG', interval, 1)) tfs = FunctionSpace(mesh, TensorElement('DG', interval, 1, shape=(n, n))) vfs = FunctionSpace(mesh, VectorElement('DG', interval, 1, dim=n)) ensemble_f = Coefficient(vfs) ensemble2_f = Coefficient(vfs) phi = TestFunction(tfs) i, j = indices(2) nc = 42 # magic number L = ((IndexSum( IndexSum( Product(nc * phi[i, j], Product(ensemble_f[i], ensemble_f[i])), MultiIndex((i, ))), MultiIndex((j, ))) * dx) + (IndexSum( IndexSum( Product(nc * phi[i, j], Product( ensemble2_f[j], ensemble2_f[j])), MultiIndex( (i, ))), MultiIndex((j, ))) * dx) - (IndexSum( IndexSum( 2 * nc * Product(phi[i, j], Product(ensemble_f[i], ensemble2_f[j])), MultiIndex((i, ))), MultiIndex((j, ))) * dx)) kernel, = compile_form(L, parameters=dict(mode='spectral')) return EstimateFlops().visit(kernel.ast)
def test_expr(): from ufl import triangle, FiniteElement, TestFunction, TrialFunction, Coefficient element = FiniteElement("CG", triangle, 1) v = TestFunction(element) u = TrialFunction(element) f = Coefficient(element) g = Coefficient(element) expr = (f + g) * u.dx(0) * (g - 1) * v return expr
def test_only_first_order(V): u = Coefficient(V) v = TestFunction(V) c = Coefficient(V) F = (inner(c, c) * inner(Dt(Dt(u)), v) + inner(grad(u), grad(v)) + inner(c, v) + inner(Dt(u), v)) * dx with pytest.raises(ValueError): check_integrals(F.integrals(), expect_time_derivative=True)
def set_coefficients(self, integral_data, form_data): """Prepare the coefficients of the form. :arg integral_data: UFL integral data :arg form_data: UFL form data """ coefficients = [] coefficient_numbers = [] # enabled_coefficients is a boolean array that indicates which # of reduced_coefficients the integral requires. for i in range(len(integral_data.enabled_coefficients)): if integral_data.enabled_coefficients[i]: coefficient = form_data.reduced_coefficients[i] if type(coefficient.ufl_element()) == ufl_MixedElement: split = [ Coefficient( FunctionSpace(coefficient.ufl_domain(), element)) for element in coefficient.ufl_element().sub_elements() ] coefficients.extend(split) self.coefficient_split[coefficient] = split else: coefficients.append(coefficient) # This is which coefficient in the original form the # current coefficient is. # Consider f*v*dx + g*v*ds, the full form contains two # coefficients, but each integral only requires one. coefficient_numbers.append( form_data.original_coefficient_positions[i]) for i, coefficient in enumerate(coefficients): self.coefficient_args.append( self._coefficient(coefficient, "w_%d" % i)) self.kernel.coefficient_numbers = tuple(coefficient_numbers)
def test_pre_and_post_traversal(): element = FiniteElement("CG", "triangle", 1) v = TestFunction(element) f = Coefficient(element) g = Coefficient(element) p1 = f * v p2 = g * v s = p1 + p2 # NB! These traversal algorithms are intended to guarantee only # parent before child and vice versa, not this particular # ordering: assert list(pre_traversal(s)) == [s, p2, g, v, p1, f, v] assert list(post_traversal(s)) == [g, v, p2, f, v, p1, s] assert list(unique_pre_traversal(s)) == [s, p2, g, v, p1, f] assert list(unique_post_traversal(s)) == [v, f, p1, g, p2, s]
def set_cell_sizes(self, domain): """Setup a fake coefficient for "cell sizes". :arg domain: The domain of the integral. This is required for scaling of derivative basis functions on physically mapped elements (Argyris, Bell, etc...). We need a measure of the mesh size around each vertex (hence this lives in P1). Should the domain have topological dimension 0 this does nothing. """ if domain.ufl_cell().topological_dimension() > 0: # Can't create P1 since only P0 is a valid finite element if # topological_dimension is 0 and the concept of "cell size" # is not useful for a vertex. f = Coefficient( FunctionSpace(domain, FiniteElement("P", domain.ufl_cell(), 1))) funarg, expression = prepare_coefficient( f, "cell_sizes", self.scalar_type, interior_facet=self.interior_facet) self.cell_sizes_arg = funarg self._cell_sizes = expression
def test_physically_mapped_facet(): mesh = Mesh(VectorElement("P", triangle, 1)) # set up variational problem U = FiniteElement("Morley", mesh.ufl_cell(), 2) V = FiniteElement("P", mesh.ufl_cell(), 1) R = FiniteElement("P", mesh.ufl_cell(), 1) Vv = VectorElement(BrokenElement(V)) Qhat = VectorElement(BrokenElement(V[facet])) Vhat = VectorElement(V[facet]) Z = FunctionSpace(mesh, MixedElement(U, Vv, Qhat, Vhat, R)) z = Coefficient(Z) u, d, qhat, dhat, lam = split(z) s = FacetNormal(mesh) trans = as_matrix([[1, 0], [0, 1]]) mat = trans*grad(grad(u))*trans + outer(d, d) * u J = (u**2*dx + u**3*dx + u**4*dx + inner(mat, mat)*dx + inner(grad(d), grad(d))*dx + dot(s, d)**2*ds) L_match = inner(qhat, dhat - d) L = J + inner(lam, inner(d, d)-1)*dx + (L_match('+') + L_match('-'))*dS + L_match*ds compile_form(L)
def set_coefficients(self, integral_data, form_data): """Prepare the coefficients of the form. :arg integral_data: UFL integral data :arg form_data: UFL form data """ name = "w" self.coefficient_args = [ coffee.Decl(SCALAR_TYPE, coffee.Symbol(name), pointers=[("const",), ()], qualifiers=["const"]) ] # enabled_coefficients is a boolean array that indicates which # of reduced_coefficients the integral requires. for n in range(len(integral_data.enabled_coefficients)): if not integral_data.enabled_coefficients[n]: continue coeff = form_data.reduced_coefficients[n] if type(coeff.ufl_element()) == ufl_MixedElement: coeffs = [Coefficient(FunctionSpace(coeff.ufl_domain(), element)) for element in coeff.ufl_element().sub_elements()] self.coefficient_split[coeff] = coeffs else: coeffs = [coeff] expressions = prepare_coefficients(coeffs, n, name, self.interior_facet) self.coefficient_map.update(zip(coeffs, expressions))
def test_can_split_mixed(W): u = Coefficient(W) v = TestFunction(W) c = Coefficient(W) F = (inner(c, c) * inner(Dt(u), v) + inner(grad(u), grad(v)) + inner(c, v) + inner(Dt(u), v)) * dx split = extract_terms(F) expect_t = (inner(c, c) * inner(Dt(u), v) + inner(Dt(u), v)) * dx expect_no_t = inner(grad(u), grad(v)) * dx + inner(c, v) * dx assert sig(expect_t) == sig(split.time) assert sig(expect_no_t) == sig(split.remainder)
def test_expecting_time_derivative(V): u = Coefficient(V) v = TestFunction(V) c = Coefficient(V) F = (inner(grad(u), grad(v)) + inner(c, v)) * dx with pytest.raises(ValueError): check_integrals(F.integrals(), expect_time_derivative=True) check_integrals(F.integrals(), expect_time_derivative=False) F += inner(Dt(u), v) * dx with pytest.raises(ValueError): check_integrals(F.integrals(), expect_time_derivative=False)
def set_coordinates(self, domain): """Prepare the coordinate field. :arg domain: :class:`ufl.Domain` """ # Create a fake coordinate coefficient for a domain. f = Coefficient(FunctionSpace(domain, domain.ufl_coordinate_element())) self.domain_coordinate[domain] = f self.coordinates_arg = self._coefficient(f, "coords")
def test_Dt_linear(V, typ): u = Coefficient(V) v = TestFunction(V) c = Coefficient(V) F = (inner(grad(u), grad(v)) + inner(c, v) + inner(Dt(u), v)) * dx if typ == "mul": F += inner(Dt(u), c) * inner(Dt(u), v) * dx elif typ == "div": F += inner(Dt(u), v) / Dt(u)[0] * dx elif typ == "sin": F += inner(sin(Dt(u)[0]), v[0]) * dx with pytest.raises(ValueError): check_integrals(F.integrals(), expect_time_derivative=True)
def HodgeLaplaceGradCurl(element, felement): tau, v = TestFunctions(element) sigma, u = TrialFunctions(element) f = Coefficient(felement) a = (inner(tau, sigma) - inner(grad(tau), u) + inner(v, grad(sigma)) + inner(curl(v), curl(u))) * dx L = inner(v, f) * dx return a, L
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_can_split_mixed_split(W): u = Coefficient(W) from ufl import split as splt u0, u1 = splt(u) v = TestFunction(W) v0, v1 = splt(v) c = Coefficient(W) F = (inner(c, c) * inner(Dt(u0), v0) + inner(grad(u), grad(v)) + inner(c, v) + inner(Dt(u), v)) * dx split = extract_terms(F) expect_t = (inner(c, c) * inner(Dt(u0), v0) + inner(Dt(u), v)) * dx expect_no_t = inner(grad(u), grad(v)) * dx + inner(c, v) * dx assert sig(expect_t) == sig(split.time) assert sig(expect_no_t) == sig(split.remainder)
def set_cell_sizes(self, domain): """Setup a fake coefficient for "cell sizes". :arg domain: The domain of the integral. This is required for scaling of derivative basis functions on physically mapped elements (Argyris, Bell, etc...). We need a measure of the mesh size around each vertex (hence this lives in P1). """ f = Coefficient(FunctionSpace(domain, FiniteElement("P", domain.ufl_cell(), 1))) funarg, expression = prepare_coefficient(f, "cell_sizes", self.scalar_type, interior_facet=self.interior_facet) self.cell_sizes_arg = funarg self._cell_sizes = expression
def initialize_data(self): """ Extract required objects for defining error control forms. This will be stored, reused and in particular named. """ # Developer's note: The UFL-FFC-DOLFIN--PyDOLFIN toolchain for # error control is quite fine-tuned. In particular, the order # of coefficients in forms is (and almost must be) used for # their assignment. This means that the order in which these # coefficients are defined matters and should be considered # fixed. from ufl import FiniteElement, Coefficient from ufl.algorithms.elementtransformations import tear, increase_order # Primal trial element space self._V = self.u.element() # Primal test space == Dual trial space Vhat = self.weak_residual.arguments()[0].element() # Discontinuous version of primal trial element space self._dV = tear(self._V) # Extract domain and geometric dimension domain, = self._V.domains() gdim = domain.geometric_dimension() # Coefficient representing improved dual E = increase_order(Vhat) self._Ez_h = Coefficient(E) self.ec_names[id(self._Ez_h)] = "__improved_dual" # Coefficient representing cell bubble function B = FiniteElement("B", domain, gdim + 1) self._b_T = Coefficient(B) self.ec_names[id(self._b_T)] = "__cell_bubble" # Coefficient representing strong cell residual self._R_T = Coefficient(self._dV) self.ec_names[id(self._R_T)] = "__cell_residual" # Coefficient representing cell cone function C = FiniteElement("DG", domain, gdim) self._b_e = Coefficient(C) self.ec_names[id(self._b_e)] = "__cell_cone" # Coefficient representing strong facet residual self._R_dT = Coefficient(self._dV) self.ec_names[id(self._R_dT)] = "__facet_residual" # Define discrete dual on primal test space self._z_h = Coefficient(Vhat) self.ec_names[id(self._z_h)] = "__discrete_dual_solution" # Piecewise constants for assembling indicators self._DG0 = FiniteElement("DG", domain, 0)
def test_remove_complex_nodes(self): cell = triangle element = FiniteElement("Lagrange", cell, 1) u = TrialFunction(element) v = TestFunction(element) f = Coefficient(element) a = conj(v) b = real(u) c = imag(f) d = conj(real(v))*imag(conj(u)) assert remove_complex_nodes(a) == v assert remove_complex_nodes(b) == u with pytest.raises(ufl.log.UFLException): remove_complex_nodes(c) with pytest.raises(ufl.log.UFLException): remove_complex_nodes(d)
def test_delta_elimination(mode): # Code sample courtesy of Marco Morandini: # https://github.com/firedrakeproject/tsfc/issues/182 scheme = "default" degree = 3 element_lambda = FiniteElement("Quadrature", tetrahedron, degree, quad_scheme=scheme) element_eps_p = VectorElement("Quadrature", tetrahedron, degree, dim=6, quad_scheme=scheme) element_chi_lambda = MixedElement(element_eps_p, element_lambda) chi_lambda = Coefficient(element_chi_lambda) delta_chi_lambda = TestFunction(element_chi_lambda) L = inner(delta_chi_lambda, chi_lambda) * dx(degree=degree, scheme=scheme) kernel, = compile_form(L, parameters={'mode': mode})
# # UFL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # UFL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with UFL. If not, see <http://www.gnu.org/licenses/>. # # Modified by Martin Sandve Alnæs, 2009 # # Last changed: 2009-03-02 # # The bilinear form a(v, u) and linear form L(v) for Poisson's equation. from ufl import (Coefficient, FiniteElement, TestFunction, TrialFunction, dx, grad, inner, triangle) element = FiniteElement("Lagrange", triangle, 1) u = TrialFunction(element) v = TestFunction(element) f = Coefficient(element) a = inner(grad(v), grad(u)) * dx(degree=1) L = v * f * dx(degree=2)
def prepare_input_arguments(forms, object_names, reserved_objects): """ Extract required input arguments to UFLErrorControlGenerator. *Arguments* forms (tuple) Three (linear case) or two (nonlinear case) forms specifying the primal problem and the goal object_names (dict) Map from object ids to object names reserved_names (dict) Map from reserved object names to object ids *Returns* tuple (of length 3) containing Form or tuple A single linear form or a tuple of a bilinear and a linear form Form A linear form or a functional for the goal functional Coefficient The coefficient considered as the unknown """ # Check that we get a tuple of forms expecting_tuple_msg = "Expecting tuple of forms, got %s" % str(forms) assert(isinstance(forms, (list, tuple))), expecting_tuple_msg def __is_nonlinear(forms): return len(forms) == 2 def __is_linear(forms): return len(forms) == 3 # Extract Coefficient labelled as 'unknown' u = reserved_objects.get("unknown", None) if __is_nonlinear(forms): (F, M) = forms # Check that unknown is defined assert (u), "Can't extract 'unknown'. The Coefficient representing the unknown must be labelled by 'unknown' for nonlinear problems." # Check that forms have the expected rank assert(len(F.arguments()) == 1) assert(len(M.arguments()) == 0) # Return primal, goal and unknown return (F, M, u) elif __is_linear(forms): # Throw error if unknown is given, don't quite know what to do # with this case yet if u: error("'unknown' defined: not implemented for linear problems") (a, L, M) = forms # Check that forms have the expected rank arguments = a.arguments() assert(len(arguments) == 2) assert(len(L.arguments()) == 1) assert(len(M.arguments()) == 1) # Standard case: create default Coefficient in trial space and # label it __discrete_primal_solution V = arguments[1].element() u = Coefficient(V) object_names[id(u)] = "__discrete_primal_solution" return ((a, L), M, u) else: error("Wrong input tuple length: got %s, expected 2 or 3-tuple" % str(forms))
# # Implemented by imitation of # http://code.google.com/p/debiosee/wiki/DemosOptiocFlowHornSchunck # but not tested so this could contain errors! # from ufl import (Coefficient, Constant, FiniteElement, VectorElement, derivative, dot, dx, grad, inner, triangle) # Finite element spaces for scalar and vector fields cell = triangle S = FiniteElement("CG", cell, 1) V = VectorElement("CG", cell, 1) # Optical flow function u = Coefficient(V) # Previous image brightness I0 = Coefficient(S) # Current image brightness I1 = Coefficient(S) # Regularization parameter lamda = Constant(cell) # Coefficiental to minimize M = (dot(u, grad(I1)) + (I1 - I0))**2 * dx\ + lamda * inner(grad(u), grad(u)) * dx # Derived linear system L = derivative(M, u)
coord_element = VectorElement("Lagrange", triangle, 1) mesh = Mesh(coord_element) # Function Space element = FiniteElement("Lagrange", triangle, 2) V = FunctionSpace(mesh, element) # Trial and test functions u = TrialFunction(V) v = TestFunction(V) # Define a constant RHS f = Constant(V) # Define the bilinear and linear forms according to the # variational formulation of the equations:: a = inner(grad(u), grad(v)) * dx L = inner(f, v) * dx # Define linear form representing the action of the form "a" on # the coefficient "ui" ui = Coefficient(V) M = action(a, ui) # Define form to compute the L2 norm of the error usol = Coefficient(V) uexact = Coefficient(V) E = inner(usol - uexact, usol - uexact) * dx forms = [M, L, E]
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with UFL. If not, see <http://www.gnu.org/licenses/>. # # Modified by Martin Sandve Alnes, 2009 # # Last changed: 2009-01-12 # # The bilinear form a(v, u) and linear form L(v) for # a mixed formulation of Poisson's equation with BDM # (Brezzi-Douglas-Marini) elements. # from ufl import (Coefficient, FiniteElement, TestFunctions, TrialFunctions, div, dot, dx, triangle) cell = triangle BDM1 = FiniteElement("Brezzi-Douglas-Marini", cell, 1) DG0 = FiniteElement("Discontinuous Lagrange", cell, 0) element = BDM1 * DG0 (tau, w) = TestFunctions(element) (sigma, u) = TrialFunctions(element) f = Coefficient(DG0) a = (dot(tau, sigma) - div(tau) * u + w * div(sigma)) * dx L = w * f * dx
# Copyright (C) 2005-2007 Anders Logg # # This file is part of UFL. # # UFL is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # UFL is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with UFL. If not, see <http://www.gnu.org/licenses/>. # # The bilinear form a(v, u) and linear form L(v) for # tensor-weighted Poisson's equation. from ufl import (Coefficient, FiniteElement, TensorElement, TestFunction, TrialFunction, dx, grad, inner, triangle) P1 = FiniteElement("Lagrange", triangle, 1) P0 = TensorElement("Discontinuous Lagrange", triangle, 0, shape=(2, 2)) v = TestFunction(P1) u = TrialFunction(P1) C = Coefficient(P0) a = inner(grad(v), C * grad(u)) * dx
# but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with UFL. If not, see <http://www.gnu.org/licenses/>. # # First added: 2008-03-31 # Last changed: 2008-03-31 # # The linearised bilinear form a(u,v) and linear form L(v) for # the nonlinear equation - div (1+u) grad u = f (non-linear Poisson) from ufl import (Coefficient, FiniteElement, TestFunction, TrialFunction, VectorElement, dot, dx, grad, i, triangle) element = FiniteElement("Lagrange", triangle, 2) QE = FiniteElement("Quadrature", triangle, 2, quad_scheme="default") sig = VectorElement("Quadrature", triangle, 1, quad_scheme="default") v = TestFunction(element) u = TrialFunction(element) u0 = Coefficient(element) C = Coefficient(QE) sig0 = Coefficient(sig) f = Coefficient(element) a = v.dx(i) * C * u.dx(i) * dx( metadata={"quadrature_degree": 2}) + v.dx(i) * 2 * u0 * u * u0.dx(i) * dx L = v * f * dx - dot(grad(v), sig0) * dx(metadata={"quadrature_degree": 1})
def compileUFL(form, patch, *args, **kwargs): if isinstance(form, Equation): form = form.lhs - form.rhs if not isinstance(form, Form): raise Exception("ufl.Form expected.") if len(form.arguments()) < 2: raise Exception("ConservationLaw model requires form with at least two arguments.") phi_, u_ = form.arguments() if phi_.ufl_function_space().scalar: phi = TestFunction(phi_.ufl_function_space().toVectorSpace()) form = replace(form,{phi_:phi[0]}) else: phi = phi_ if u_.ufl_function_space().scalar: u = TrialFunction(u_.ufl_function_space().toVectorSpace()) form = replace(form,{u_:u[0]}) else: u = u_ _, coeff_ = extract_arguments_and_coefficients(form) coeff_ = set(coeff_) # added for dirichlet treatment same as conservationlaw model dirichletBCs = [arg for arg in args if isinstance(arg, DirichletBC)] # remove the dirichletBCs arg = [arg for arg in args if not isinstance(arg, DirichletBC)] for dBC in dirichletBCs: _, coeff__ = extract_arguments_and_coefficients(dBC.ufl_value) coeff_ |= set(coeff__) if patch is not None: for a in patch: try: _, coeff__ = extract_arguments_and_coefficients(a) coeff_ |= set(coeff__) except: pass # a might be a float/int and not a ufl expression coeff = {c : c.toVectorCoefficient()[0] for c in coeff_ if len(c.ufl_shape) == 0 and not c.is_cellwise_constant()} form = replace(form,coeff) for bc in dirichletBCs: bc.ufl_value = replace(bc.ufl_value, coeff) if patch is not None: patch = [a if not isinstance(a, Expr) else replace(a,coeff) for a in patch] phi = form.arguments()[0] dimRange = phi.ufl_shape[0] u = form.arguments()[1] du = Grad(u) d2u = Grad(du) ubar = Coefficient(u.ufl_function_space()) dubar = Grad(ubar) d2ubar = Grad(dubar) dimDomain = u.ufl_shape[0] x = SpatialCoordinate(form.ufl_cell()) try: field = u.ufl_function_space().field except AttributeError: field = "double" # if exact solution is passed in subtract a(u,.) from the form if "exact" in kwargs: b = replace(form, {u: as_vector(kwargs["exact"])} ) form = form - b dform = apply_derivatives(derivative(action(form, ubar), ubar, u)) source, flux, boundarySource = splitUFLForm(form) linSource, linFlux, linBoundarySource = splitUFLForm(dform) fluxDivergence, _, _ = splitUFLForm(inner(source.as_ufl() - div(flux.as_ufl()), phi) * dx(0)) # split linNVSource off linSource # linSources = splitUFL2(u, du, d2u, linSource) # linNVSource = linSources[2] # linSource = linSources[0] + linSources[1] if patch is not None: model = ConservationLawModel(dimDomain, dimRange, u, modelSignature(form,*patch,*args)) else: model = ConservationLawModel(dimDomain, dimRange, u, modelSignature(form,None,*args)) model._replaceCoeff = coeff model.hasNeumanBoundary = not boundarySource.is_zero() #expandform = expand_indices(expand_derivatives(expand_compounds(equation.lhs))) #if expandform == adjoint(expandform): # model.symmetric = 'true' model.field = field dirichletBCs = [arg for arg in args if isinstance(arg, DirichletBC)] # deprecated # if "dirichlet" in kwargs: # dirichletBCs += [DirichletBC(u.ufl_function_space(), as_vector(value), bndId) for bndId, value in kwargs["dirichlet"].items()] uflCoefficients = set(form.coefficients()) for bc in dirichletBCs: _, c = extract_arguments_and_coefficients(bc.ufl_value) uflCoefficients |= set(c) if patch is not None: for a in patch: if isinstance(a, Expr): _, c = extract_arguments_and_coefficients(a) uflCoefficients |= set(c) constants = dict() coefficients = dict() for coefficient in uflCoefficients: try: name = getattr(coefficient, "name") except AttributeError: name = str(coefficient) if coefficient.is_cellwise_constant(): try: parameter = getattr(coefficient, "parameter") except AttributeError: parameter = None if len(coefficient.ufl_shape) == 0: constants[coefficient] = model.addConstant('double', name=name, parameter=parameter) elif len(coefficient.ufl_shape) == 1: constants[coefficient] = model.addConstant('Dune::FieldVector< double, ' + str(coefficient.ufl_shape[0]) + ' >', name=name, parameter=parameter) else: Exception('Currently, only scalars and vectors are supported as constants') else: shape = coefficient.ufl_shape[0] try: coefficients[coefficient] = model.addCoefficient( shape, coefficient.cppTypeName, name=name, field=coefficient.ufl_function_space().field) except AttributeError: coefficients[coefficient] = model.addCoefficient( shape, coefficient.cppTypeName, name=name) model.coefficients = coefficients model.constants = constants tempVars = kwargs.get("tempVars", True) predefined = {u: model.arg_u, du: model.arg_du, d2u: model.arg_d2u} predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )') model.predefineCoefficients(predefined,'x') model.source = generateCode(predefined, source, tempVars=tempVars) model.flux = generateCode(predefined, flux, tempVars=tempVars) predefined.update({ubar: model.arg_ubar, dubar: model.arg_dubar, d2ubar: model.arg_d2ubar}) model.linSource = generateCode(predefined, linSource, tempVars=tempVars) model.linFlux = generateCode(predefined, linFlux, tempVars=tempVars) # model.linNVSource = generateCode({u: arg, du: darg, d2u: d2arg, ubar: argbar, dubar: dargbar, d2ubar: d2argbar}, linNVSource, model.coefficients, tempVars) predefined = {u: model.arg_u} predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )') model.predefineCoefficients(predefined,'x') model.alpha = generateCode(predefined, boundarySource, tempVars=tempVars) predefined.update({ubar: model.arg_ubar}) model.linAlpha = generateCode(predefined, linBoundarySource, tempVars=tempVars) predefined = {u: model.arg_u, du: model.arg_du, d2u: model.arg_d2u} predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )') model.predefineCoefficients(predefined,'x') model.fluxDivergence = generateCode(predefined, fluxDivergence, tempVars=tempVars) if dirichletBCs: model.hasDirichletBoundary = True predefined = {} predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )') model.predefineCoefficients(predefined,'x') maxId = 0 codeDomains = [] bySubDomain = dict() neuman = [] for bc in dirichletBCs: if bc.subDomain in bySubDomain: raise Exception('Multiply defined Dirichlet boundary for subdomain ' + str(bc.subDomain)) if not isinstance(bc.functionSpace, (FunctionSpace, FiniteElementBase)): raise Exception('Function space must either be a ufl.FunctionSpace or a ufl.FiniteElement') if isinstance(bc.functionSpace, FunctionSpace) and (bc.functionSpace != u.ufl_function_space()): raise Exception('Space of trial function and dirichlet boundary function must be the same - note that boundary conditions on subspaces are not available, yet') if isinstance(bc.functionSpace, FiniteElementBase) and (bc.functionSpace != u.ufl_element()): raise Exception('Cannot handle boundary conditions on subspaces, yet') if isinstance(bc.value, list): neuman = [i for i, x in enumerate(bc.value) if x == None] else: neuman = [] value = ExprTensor(u.ufl_shape) for key in value.keys(): value[key] = Indexed(bc.ufl_value, MultiIndex(tuple(FixedIndex(k) for k in key))) if isinstance(bc.subDomain,int): bySubDomain[bc.subDomain] = value,neuman maxId = max(maxId, bc.subDomain) else: domain = ExprTensor(()) for key in domain.keys(): domain[key] = Indexed(bc.subDomain, MultiIndex(tuple(FixedIndex(k) for k in key))) codeDomains.append( (value,neuman,domain) ) defaultCode = [] defaultCode.append(Declaration(Variable('int', 'domainId'))) defaultCode.append(Declaration(Variable('auto', 'tmp0'), initializer=UnformattedExpression('auto','intersection.geometry().center()'))) for i,v in enumerate(codeDomains): block = Block() defaultCode.append( generateDirichletDomainCode(predefined, v[2], tempVars=tempVars)) defaultCode.append('if (domainId)') block = UnformattedBlock() block.append('std::fill( dirichletComponent.begin(), dirichletComponent.end(), ' + str(maxId+i+1) + ' );') if len(v[1])>0: [block.append('dirichletComponent[' + str(c) + '] = 0;') for c in v[1]] block.append('return true;') defaultCode.append(block) defaultCode.append(return_(False)) bndId = Variable('const int', 'bndId') getBndId = UnformattedExpression('int', 'BoundaryIdProviderType::boundaryId( ' + model.arg_i.name + ' )') switch = SwitchStatement(bndId, default=defaultCode) for i,v in bySubDomain.items(): code = [] if len(v[1])>0: [code.append('dirichletComponent[' + str(c) + '] = 0;') for c in v[1]] code.append(return_(True)) switch.append(i, code) model.isDirichletIntersection = [Declaration(bndId, initializer=getBndId), UnformattedBlock('std::fill( dirichletComponent.begin(), dirichletComponent.end(), ' + bndId.name + ' );'), switch ] switch = SwitchStatement(model.arg_bndId, default=assign(model.arg_r, construct("RRangeType", 0))) for i, v in bySubDomain.items(): switch.append(i, generateDirichletCode(predefined, v[0], tempVars=tempVars)) for i,v in enumerate(codeDomains): switch.append(i+maxId+1, generateDirichletCode(predefined, v[0], tempVars=tempVars)) model.dirichlet = [switch] return model
def form(cell, degree): m = Mesh(VectorElement('CG', cell, 1)) V = FunctionSpace(m, VectorElement('CG', cell, degree)) f = Coefficient(V) return div(f) * dx