Esempio n. 1
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
Esempio n. 2
0
def energy_norm(form, coefficient=None):
    """UFL form operator:
    Given a bilinear form *a* and a coefficient *f*,
    return the functional :math:`a(f,f)`."""
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_energy_norm(form, coefficient)
Esempio n. 3
0
def block_replace_zero(block_form, index, block_function_space):
    assert len(index) in (1, 2)
    if len(index) == 2:
        I = index[0]  # noqa
        J = index[1]
        assert (isinstance(
            block_form[I][J], Form
        )  # this function is always called after flattening, so it cannot be an array or list
                or (isinstance(block_form[I][J],
                               (float, int)) and block_form[I][J] in zeros))
        if block_form[I][J] in zeros:
            block_form_IJ = block_form[I][J]
        elif has_exact_type(block_form[I][J], CoefficientDerivative):
            block_form_IJ = expand_derivatives(block_form[I][J])
        else:
            block_form_IJ = block_form[I][J]
        if block_form_IJ in zeros or block_form_IJ.empty():
            block_form_IJ = _get_zero_form(block_function_space, (I, J))
        else:
            assert not block_form_IJ.empty()
        return block_form_IJ
    else:
        I = index[0]  # noqa
        assert (isinstance(
            block_form[I], Form
        )  # this function is always called after flattening, so it cannot be an array or list
                or (isinstance(block_form[I],
                               (float, int)) and block_form[I] in zeros))
        block_form_I = block_form[I]
        if block_form_I in zeros:
            block_form_I = _get_zero_form(block_function_space, (I, ))
        else:
            assert not block_form_I.empty()
        return block_form_I
Esempio n. 4
0
def energy_norm(form, coefficient=None):
    """UFL form operator:
    Given a bilinear form *a* and a coefficient *f*,
    return the functional :math:`a(f,f)`."""
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_energy_norm(form, coefficient)
Esempio n. 5
0
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
Esempio n. 6
0
 def __init__(self, block_form, block_function_space, form_compiler_parameters=None):
     # Store UFL form
     self._block_form = block_form
     # Store block function space
     assert len(block_function_space) == 2
     self._block_function_space = block_function_space
     # Replace UFL form by Dolfin form before passing it to the constructor
     # (note that we assume that block_form has been already preprocessed,
     #  so we can assume that nested blocks have been unrolled and zero
     #  placeholders have been replaced by zero forms)
     N = len(block_form)
     M = len(block_form[0])
     assert all([len(block_form_I) == M for block_form_I in block_form])
     replaced_block_form = empty((N, M), dtype=object)
     for I in range(N):
         for J in range(M):
             if isinstance(block_form[I, J], Form) and has_exact_type(block_form[I, J], CoefficientDerivative):
                 block_form[I, J] = expand_derivatives(block_form[I, J])
             replaced_block_form[I, J] = block_replace_zero(block_form, (I, J), block_function_space)
             assert isinstance(replaced_block_form[I, J], Form) or _is_zero(replaced_block_form[I, J])
             if isinstance(replaced_block_form[I, J], Form):
                 replaced_block_form[I, J] = _create_dolfin_form(
                     form=replaced_block_form[I, J],
                     form_compiler_parameters=form_compiler_parameters
                 )
             elif _is_zero(replaced_block_form[I, J]):
                 assert isinstance(replaced_block_form[I, J], cpp_Form)
             else:
                 raise TypeError("Invalid form")
     BlockForm2_Base.__init__(self, replaced_block_form.tolist(), [block_function_space_.cpp_object() for block_function_space_ in block_function_space])
     # Store sizes for shape method
     self.N = N
     self.M = M
    def __init__(self, form):
        # Preprocess form
        form = expand_derivatives(form)
        form = remove_complex_nodes(
            form)  # TODO support forms in the complex field
        # Extract spaces from forms
        len_spaces = len(form.arguments())
        assert len_spaces in (0, 1, 2)
        if len_spaces is 2:
            spaces = (form_argument_space(form,
                                          0), form_argument_space(form, 1))
        elif len_spaces is 1:
            spaces = (form_argument_space(form, 0), )
        elif len_spaces is 0:
            spaces = ()
        else:
            raise ValueError("Invalid arguments")
        # Create empty snapshot
        if len_spaces in (1, 2):

            def assemble_empty_snapshot():
                empty_snapshot = assemble(form, keep_diagonal=True)
                empty_snapshot.zero()
                empty_snapshot.generator = self
                return empty_snapshot
        elif len_spaces is 0:

            def assemble_empty_snapshot():
                return 0.
        else:
            raise ValueError("Invalid arguments")
        # Call Parent
        ParametrizedTensorFactory_Base.__init__(self, form, spaces,
                                                assemble_empty_snapshot)
Esempio n. 8
0
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
Esempio n. 9
0
def replace(e, mapping):
    """Replace subexpressions in expression.

    @param e:
        An Expr or Form.
    @param mapping:
        A dict with from:to replacements to perform.
    """
    mapping2 = dict((k, as_ufl(v)) for (k, v) in mapping.items())

    # Workaround for problem with delayed derivative evaluation
    # The problem is that J = derivative(f(g, h), g) does not evaluate immediately
    # So if we subsequently do replace(J, {g: h}) we end up with an expression:
    # derivative(f(h, h), h)
    # rather than what were were probably thinking of:
    # replace(derivative(f(g, h), g), {g: h})
    #
    # To fix this would require one to expand derivatives early (which
    # is not attractive), or make replace lazy too.
    if has_exact_type(e, CoefficientDerivative):
        # Hack to avoid circular dependencies
        from ufl.algorithms.ad import expand_derivatives
        e = expand_derivatives(e)

    return map_integrand_dags(MyReplacer(mapping2), e)
Esempio n. 10
0
 def __init__(self, form, strict=False):
     AbstractSeparatedParametrizedForm.__init__(self, form)
     form = expand_derivatives(form)
     form = expand_sum_product(form)
     form = rewrite_quotients(form)
     form = remove_complex_nodes(
         form)  # TODO support forms in the complex field
     self._form = form
     self._coefficients = list()  # of list of ParametrizedExpression
     self._placeholders = list()  # of list of Constants
     self._placeholder_names = list()  # of list of string
     self._form_with_placeholders = list()  # of forms
     self._form_unchanged = list()  # of forms
     # Internal usage
     self._NaN = float("NaN")
     # Strict mode when
     # * checking candidates to be added to coefficients which contain both parametrized and non parametrized leaves.
     # * checking for coefficients that are solution
     # If False (default)
     # * coefficient splitting is prevented, because separating the non parametrized part would result in more
     #   than one coefficient, and the candidate is accepted as the coefficient which contain both parametrized and non parametrized leaves.
     # * solutions are considered as parametrized
     # If True
     # * coefficient is split in order to assure that all coefficients only contains parametrized terms, at the expense of
     #   a larger number of coefficients
     # * solutions and geometric quantities (except normals) are prevented for being collected in coefficients
     self._strict = strict
Esempio n. 11
0
def StokesTest(N, butcher_tableau, stage_type="deriv", splitting=AI):
    mesh = UnitSquareMesh(N, N)

    Ve = VectorElement("CG", mesh.ufl_cell(), 2)
    Pe = FiniteElement("CG", mesh.ufl_cell(), 1)
    Ze = MixedElement([Ve, Pe])
    Z = FunctionSpace(mesh, Ze)

    t = Constant(0.0)
    dt = Constant(1.0/N)
    (x, y) = SpatialCoordinate(mesh)

    uexact = as_vector([x*t + y**2, -y*t+t*(x**2)])
    pexact = Constant(0, domain=mesh)

    u_rhs = expand_derivatives(diff(uexact, t)) - div(grad(uexact)) + grad(pexact)
    p_rhs = -div(uexact)

    z = Function(Z)
    test_z = TestFunction(Z)
    (u, p) = split(z)
    (v, q) = split(test_z)
    F = (inner(Dt(u), v)*dx
         + inner(grad(u), grad(v))*dx
         - inner(p, div(v))*dx
         - inner(q, div(u))*dx
         - inner(u_rhs, v)*dx
         - inner(p_rhs, q)*dx)

    bcs = [DirichletBC(Z.sub(0), uexact, "on_boundary")]
    nsp = [(1, VectorSpaceBasis(constant=True))]

    u, p = z.split()
    u.interpolate(uexact)

    lu = {"mat_type": "aij",
          "snes_type": "newtonls",
          "snes_linesearch_type": "l2",
          "snes_linesearch_monitor": None,
          "snes_monitor": None,
          "snes_rtol": 1e-8,
          "snes_atol": 1e-8,
          "snes_force_iteration": 1,
          "ksp_type": "preonly",
          "pc_type": "lu",
          "pc_factor_mat_solver_type": "mumps"}

    stepper = TimeStepper(F, butcher_tableau, t, dt, z,
                          stage_type=stage_type,
                          bcs=bcs, solver_parameters=lu, nullspace=nsp)

    while (float(t) < 1.0):
        if (float(t) + float(dt) > 1.0):
            dt.assign(1.0 - float(t))
        stepper.advance()
        t.assign(float(t) + float(dt))

    (u, p) = z.split()
    return errornorm(uexact, u) + errornorm(pexact, p)
Esempio n. 12
0
def action(form, coefficient=None):
    """UFL form operator:
    Given a bilinear form, return a linear form
    with an additional coefficient, representing the
    action of the form on the coefficient. This can be
    used for matrix-free methods."""
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_action(form, coefficient)
Esempio n. 13
0
def action(form, coefficient=None):
    """UFL form operator:
    Given a bilinear form, return a linear form
    with an additional coefficient, representing the
    action of the form on the coefficient. This can be
    used for matrix-free methods."""
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_action(form, coefficient)
Esempio n. 14
0
    def __compute_shape_derivative(self):
        """Computes the shape derivative.

		Returns
		-------
		None

		Notes
		-----
		This only works properly if differential operators only
		act on state and adjoint variables, else the results are incorrect.
		A corresponding warning whenever this could be the case is issued.
		"""

        # Shape derivative of Lagrangian w/o regularization and pull-backs
        self.shape_derivative = fenics.derivative(
            self.lagrangian.lagrangian_form,
            fenics.SpatialCoordinate(self.mesh), self.test_vector_field)

        # Add pull-backs
        if self.use_pull_back:
            self.state_adjoint_ids = [coeff.id() for coeff in self.states] + [
                coeff.id() for coeff in self.adjoints
            ]

            self.material_derivative_coeffs = []
            for coeff in self.lagrangian.lagrangian_form.coefficients():
                if coeff.id() in self.state_adjoint_ids:
                    pass
                else:
                    if not (coeff.ufl_element().family() == 'Real'):
                        self.material_derivative_coeffs.append(coeff)

            if len(self.material_derivative_coeffs) > 0:
                warning(
                    'Shape derivative might be wrong, if differential operators act on variables other than states and adjoints. \n'
                    'You can check for correctness of the shape derivative with cashocs.verification.shape_gradient_test\n'
                )

            for coeff in self.material_derivative_coeffs:
                # temp_space = fenics.FunctionSpace(self.mesh, coeff.ufl_element())
                # placeholder = fenics.Function(temp_space)
                # temp_form = fenics.derivative(self.lagrangian.lagrangian_form, coeff, placeholder)
                # material_derivative = replace(temp_form, {placeholder : fenics.dot(fenics.grad(coeff), self.test_vector_field)})

                material_derivative = fenics.derivative(
                    self.lagrangian.lagrangian_form, coeff,
                    fenics.dot(fenics.grad(coeff), self.test_vector_field))
                material_derivative = expand_derivatives(material_derivative)

                self.shape_derivative += material_derivative

        # Add regularization
        self.shape_derivative += self.regularization.compute_shape_derivative()
Esempio n. 15
0
def ad_algorithm(expr):
    # alt = 1
    # alt = 4
    # alt = 6
    alt = 0
    if alt == 0:
        return expand_derivatives(expr)
    elif alt == 1:
        return expand_derivatives(expr,
                                  apply_expand_compounds_before=True,
                                  apply_expand_compounds_after=False,
                                  use_alternative_wrapper_algorithm=True)
    elif alt == 2:
        return expand_derivatives(expr,
                                  apply_expand_compounds_before=False,
                                  apply_expand_compounds_after=True,
                                  use_alternative_wrapper_algorithm=False)
    elif alt == 3:
        return expand_derivatives(expr,
                                  apply_expand_compounds_before=False,
                                  apply_expand_compounds_after=False,
                                  use_alternative_wrapper_algorithm=False)
    elif alt == 4:
        return expand_derivatives(expr,
                                  apply_expand_compounds_before=False,
                                  apply_expand_compounds_after=False,
                                  use_alternative_wrapper_algorithm=True)
    elif alt == 5:
        return expand_derivatives(expr,
                                  apply_expand_compounds_before=False,
                                  apply_expand_compounds_after=False,
                                  use_alternative_wrapper_algorithm=False)
Esempio n. 16
0
def ad_algorithm(expr):
    # alt = 1
    # alt = 4
    # alt = 6
    alt = 0
    if alt == 0:
        return expand_derivatives(expr)
    elif alt == 1:
        return expand_derivatives(expr,
            apply_expand_compounds_before=True,
            apply_expand_compounds_after=False,
            use_alternative_wrapper_algorithm=True)
    elif alt == 2:
        return expand_derivatives(expr,
            apply_expand_compounds_before=False,
            apply_expand_compounds_after=True,
            use_alternative_wrapper_algorithm=False)
    elif alt == 3:
        return expand_derivatives(expr,
            apply_expand_compounds_before=False,
            apply_expand_compounds_after=False,
            use_alternative_wrapper_algorithm=False)
    elif alt == 4:
        return expand_derivatives(expr,
            apply_expand_compounds_before=False,
            apply_expand_compounds_after=False,
            use_alternative_wrapper_algorithm=True)
    elif alt == 5:
        return expand_derivatives(expr,
            apply_expand_compounds_before=False,
            apply_expand_compounds_after=False,
            use_alternative_wrapper_algorithm=False)
Esempio n. 17
0
def rhs(form):
    """UFL form operator:
    Given a combined bilinear and linear form,
    extract the right hand side (negated linear form part).

    Example::

        a = u*v*dx + f*v*dx
        L = rhs(a) -> -f*v*dx
    """
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_rhs(form)
Esempio n. 18
0
def lhs(form):
    """UFL form operator:
    Given a combined bilinear and linear form,
    extract the left hand side (bilinear form part).

    Example::

        a = u*v*dx + f*v*dx
        a = lhs(a) -> u*v*dx
    """
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_lhs(form)
Esempio n. 19
0
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)
Esempio n. 20
0
def rhs(form):
    """UFL form operator:
    Given a combined bilinear and linear form,
    extract the right hand side (negated linear form part).

    Example::

        a = u*v*dx + f*v*dx
        L = rhs(a) -> -f*v*dx
    """
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_rhs(form)
Esempio n. 21
0
def _eval(self, coord, mapping=None, component=()):
    # Evaluate expression at this particular coordinate, with provided
    # values for other terminals in mapping

    # Evaluate derivatives first
    from ufl.algorithms import expand_derivatives
    f = expand_derivatives(self)

    # Evaluate recursively
    if mapping is None:
        mapping = {}
    index_values = StackDict()
    return f.evaluate(coord, mapping, component, index_values)
Esempio n. 22
0
def _eval(self, coord, mapping=None, component=()):
    # Evaluate expression at this particular coordinate, with provided
    # values for other terminals in mapping

    # Evaluate derivatives first
    from ufl.algorithms import expand_derivatives
    f = expand_derivatives(self)

    # Evaluate recursively
    if mapping is None:
        mapping = {}
    index_values = StackDict()
    return f.evaluate(coord, mapping, component, index_values)
def adjoint(form, reordered_arguments=None):
    """UFL form operator:
    Given a combined bilinear form, compute the adjoint form by
    changing the ordering (count) of the test and trial functions.

    By default, new Argument objects will be created with
    opposite ordering. However, if the adjoint form is to
    be added to other forms later, their arguments must match.
    In that case, the user must provide a tuple reordered_arguments=(u2,v2).
    """
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_adjoint(form, reordered_arguments)
Esempio n. 24
0
def adjoint(form, reordered_arguments=None):
    """UFL form operator:
    Given a combined bilinear form, compute the adjoint form by
    changing the ordering (count) of the test and trial functions.

    By default, new ``Argument`` objects will be created with
    opposite ordering. However, if the adjoint form is to
    be added to other forms later, their arguments must match.
    In that case, the user must provide a tuple *reordered_arguments*=(u2,v2).
    """
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_adjoint(form, reordered_arguments)
Esempio n. 25
0
def lhs(form):
    """UFL form operator:
    Given a combined bilinear and linear form,
    extract the left hand side (bilinear form part).

    Example::

        a = u*v*dx + f*v*dx
        a = lhs(a) -> u*v*dx
    """
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_lhs(form)
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
Esempio n. 27
0
def heat(n, deg, time_stages, stage_type="deriv", splitting=IA):
    N = 2**n
    msh = UnitIntervalMesh(N)

    params = {
        "snes_type": "ksponly",
        "ksp_type": "preonly",
        "mat_type": "aij",
        "pc_type": "lu"
    }

    V = FunctionSpace(msh, "CG", deg)
    x, = SpatialCoordinate(msh)

    t = Constant(0.0)
    dt = Constant(2.0 / N)

    uexact = exp(-t) * sin(pi * x)
    rhs = expand_derivatives(diff(uexact, t)) - div(grad(uexact))

    butcher_tableau = GaussLegendre(time_stages)

    u = project(uexact, V)

    v = TestFunction(V)

    F = (inner(Dt(u), v) * dx + inner(grad(u), grad(v)) * dx -
         inner(rhs, v) * dx)

    bc = DirichletBC(V, Constant(0), "on_boundary")

    stepper = TimeStepper(F,
                          butcher_tableau,
                          t,
                          dt,
                          u,
                          bcs=bc,
                          solver_parameters=params,
                          stage_type=stage_type,
                          splitting=splitting)

    while (float(t) < 1.0):
        if (float(t) + float(dt) > 1.0):
            dt.assign(1.0 - float(t))
        stepper.advance()
        t.assign(float(t) + float(dt))

    return errornorm(uexact, u) / norm(uexact)
Esempio n. 28
0
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 _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
Esempio n. 30
0
    def __init__(self, form):
        # Preprocess form
        form = expand_derivatives(form)
        # Extract spaces from forms
        len_spaces = len(form.arguments())
        assert len_spaces in (1, 2)
        if len_spaces == 2:
            spaces = (form_argument_space(form,
                                          0), form_argument_space(form, 1))
        elif len_spaces == 1:
            spaces = (form_argument_space(form, 0), )
        # Create empty snapshot
        def assemble_empty_snapshot():
            empty_snapshot = assemble(form, keep_diagonal=True)
            empty_snapshot.zero()
            empty_snapshot.generator = self
            return empty_snapshot

        # Call Parent
        ParametrizedTensorFactory_Base.__init__(self, form, spaces,
                                                assemble_empty_snapshot)
def _eval(self, coord, mapping=None, component=()):
    # Evaluate expression at this particular coordinate,
    # with provided values for other terminals in mapping

    # Try to infer dimension from given x argument
    if coord is None:
        cell = self.cell()
        dim = None if cell is None else cell.geometric_dimension()
    elif isinstance(coord, (tuple, list)):
        dim = len(coord)
    else:  # No type checking here, assuming a scalar x value...
        dim = 1

    # Evaluate derivatives first
    from ufl.algorithms import expand_derivatives
    f = expand_derivatives(self, dim)

    # Evaluate recursively
    if mapping is None:
        mapping = {}
    index_values = StackDict()
    return f.evaluate(coord, mapping, component, index_values)
Esempio n. 32
0
def functional(form):  # TODO: Does this make sense for anything other than testing?
    "UFL form operator: Extract the functional part of form."
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_functional(form)
Esempio n. 33
0
def getForm(F, butch, t, dt, u0, bcs=None):
    """Given a time-dependent variational form and a
    :class:`ButcherTableau`, produce UFL for the s-stage RK method.

    :arg F: UFL form for the semidiscrete ODE/DAE
    :arg butch: the :class:`ButcherTableau` for the RK method being used to
         advance in time.
    :arg t: a :class:`Constant` referring to the current time level.
         Any explicit time-dependence in F is included
    :arg dt: a :class:`Constant` referring to the size of the current
         time step.
    :arg u0: a :class:`Function` referring to the state of
         the PDE system at time `t`
    :arg bcs: optionally, a :class:`DirichletBC` object (or iterable thereof)
         containing (possible time-dependent) boundary conditions imposed
         on the system.

    On output, we return a tuple consisting of four parts:

       - Fnew, the :class:`Form`
       - k, the :class:`firedrake.Function` holding all the stages.
         It lives in a :class:`firedrake.FunctionSpace` corresponding to the
         s-way tensor product of the space on which the semidiscrete
         form lives.
       - `bcnew`, a list of :class:`firedrake.DirichletBC` objects to be posed
         on the stages,
       - `gblah`, a list of pairs of the form (f, expr), where f is
         a :class:`firedrake.Function` and expr is a :class:`ufl.Expr`.
         at each time step, each expr needs to be re-interpolated/projected
         onto the corresponding f in order for Firedrake to pick up that
         time-dependent boundary conditions need to be re-applied.
"""

    v = F.arguments()[0]
    V = v.function_space()
    assert V == u0.function_space()

    A = numpy.array([[Constant(aa) for aa in arow] for arow in butch.A])
    c = numpy.array([Constant(ci) for ci in butch.c])

    num_stages = len(c)
    num_fields = len(V)

    Vbig = numpy.prod([V for i in range(num_stages)])
    # Silence a warning about transfer managers when we
    # coarsen coefficients in V
    push_parent(V.dm, Vbig.dm)
    vnew = TestFunction(Vbig)
    k = Function(Vbig)
    if len(V) == 1:
        u0bits = [u0]
        vbits = [v]
        if num_stages == 1:
            vbigbits = [vnew]
            kbits = [k]
        else:
            vbigbits = split(vnew)
            kbits = split(k)
    else:
        u0bits = split(u0)
        vbits = split(v)
        vbigbits = split(vnew)
        kbits = split(k)

    kbits_np = numpy.zeros((num_stages, num_fields), dtype="object")

    for i in range(num_stages):
        for j in range(num_fields):
            kbits_np[i, j] = kbits[i * num_fields + j]

    Ak = A @ kbits_np

    Fnew = Zero()

    for i in range(num_stages):
        repl = {t: t + c[i] * dt}
        for j, (ubit, vbit, kbit) in enumerate(zip(u0bits, vbits, kbits)):
            repl[ubit] = ubit + dt * Ak[i, j]
            repl[vbit] = vbigbits[num_fields * i + j]
            repl[TimeDerivative(ubit)] = kbits_np[i, j]
            if (len(ubit.ufl_shape) == 1):
                for kk, kbitbit in enumerate(kbits_np[i, j]):
                    repl[TimeDerivative(ubit[kk])] = kbitbit
                    repl[ubit[kk]] = repl[ubit][kk]
                    repl[vbit[kk]] = repl[vbit][kk]
        Fnew += replace(F, repl)

    bcnew = []
    gblah = []

    if bcs is None:
        bcs = []
    for bc in bcs:
        if isinstance(bc.domain_args[0], str):
            boundary = bc.domain_args[0]
        else:
            boundary = ()
            try:
                for j in bc.sub_domain:
                    boundary += j
            except TypeError:
                boundary = (bc.sub_domain, )
        gfoo = expand_derivatives(diff(bc._original_arg, t))
        if len(V) == 1:
            for i in range(num_stages):
                gcur = replace(gfoo, {t: t + c[i] * dt})
                try:
                    gdat = interpolate(gcur, V)
                except NotImplementedError:
                    gdat = project(gcur, V)
                gblah.append((gdat, gcur))
                bcnew.append(DirichletBC(Vbig[i], gdat, boundary))
        else:
            sub = bc.function_space_index()
            for i in range(num_stages):
                gcur = replace(gfoo, {t: t + butch.c[i] * dt})
                try:
                    gdat = interpolate(gcur, V.sub(sub))
                except NotImplementedError:
                    gdat = project(gcur, V)
                gblah.append((gdat, gcur))
                bcnew.append(
                    DirichletBC(Vbig[sub + num_fields * i], gdat, boundary))

    return Fnew, k, bcnew, gblah
Esempio n. 34
0
def safe_action(x, y):
    x = expand_derivatives(x)
    if x.integrals() == ():
        return x # form is empty, return anyway
    else:
        return ufl_action(x, y)
Esempio n. 35
0
 def bc2gcur(bc, i):
     gorig = bc._original_arg
     gfoo = expand_derivatives(diff(gorig, t))
     return replace(gfoo, {t: t + c[i] * dt}) + u0_mult[i] * gorig
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
Esempio n. 38
0
def functional(form):  # TODO: Does this make sense for anything other than testing?
    "UFL form operator: Extract the functional part of form."
    form = as_form(form)
    form = expand_derivatives(form)
    return compute_form_functional(form)
Esempio n. 39
0
def safe_action(x, y):
    x = expand_derivatives(x)
    if x.integrals() == ():
        return x  # form is empty, return anyway
    else:
        return ufl_action(x, y)
Esempio n. 40
0
def testCoefficient():
    coord_elem = VectorElement("P", triangle, 1, dim=3)
    mesh = Mesh(coord_elem)
    V = FunctionSpace(mesh, FiniteElement("P", triangle, 1))
    v = Coefficient(V)
    assert round(expand_derivatives(diff(v, v)) - 1.0, 7) == 0
Esempio n. 41
0
def testCoefficient():
    v = Constant(triangle)
    assert round(expand_derivatives(diff(v, v))-1.0, 7) == 0