Пример #1
0
    def set_solver_alpha_snes2(self):
        V = self.alpha.function_space()
        denergy = derivative(self.energy, self.alpha, TestFunction(V))
        ddenergy = derivative(denergy, self.alpha, TrialFunction(V))
        self.lb = self.alpha_init  # interpolate(Constant("0."), V)
        ub = interpolate(Constant("1."), V)
        self.problem_alpha = NonlinearVariationalProblem(denergy,
                                                         self.alpha,
                                                         self.bcs_alpha,
                                                         J=ddenergy)
        self.problem_alpha.set_bounds(self.lb, ub)
        self.problem_alpha.lb = self.lb
        # set up the solver
        solver = NonlinearVariationalSolver(self.problem_alpha)

        snes_solver_parameters_bounds = {
            "nonlinear_solver": "snes",
            "snes_solver": {
                "linear_solver": "mumps",
                "maximum_iterations": 300,
                "report": True,
                "line_search": "basic",
                "method": "vinewtonrsls",
                "absolute_tolerance": 1e-5,
                "relative_tolerance": 1e-5,
                "solution_tolerance": 1e-5
            }
        }
        solver.parameters.update(snes_solver_parameters_bounds)
        #solver.solve()
        self.solver = solver
Пример #2
0
 def __init__(self, energy, u, bcs, nullspace=None):
     NonlinearProblem.__init__(self)
     self.z = u
     self.bcs = bcs
     self.nullspace = nullspace
     self.residual = derivative(energy, self.z,
                                TestFunction(self.z.function_space()))
     self.jacobian = derivative(self.residual, self.z,
                                TrialFunction(self.z.function_space()))
Пример #3
0
def tangent(problem, solution, v, w, oldmu, newmu, k, params, task, vi, hint=None):

    if k == 1:
        return (hint, 0, 0)

    info_green("Attempting tangent linearisation")
    coldmu = backend.Constant(float(oldmu))
    chgmu = backend.Constant(float(newmu)-float(oldmu))
    rho = solution.split(deepcopy=True)[0]
    Z = solution.function_space()

    (lb, ub)  = problem.bounds(Z, newmu, params)

    vi_du = None
    # FIXME: cache the symbolic calculation once, it can be expensive sometimes
    du = backend.Function(Z)
    #du = solution.copy(deepcopy=True)

    F = problem.residual(solution, v, lb, ub, coldmu, params)
    G = derivative(F, solution, du) + derivative(F, coldmu, chgmu)
    J = problem.jacobian(G, du, params, v, w)

    # FIXME: figure out if the boundary conditions depend on
    # the parameters, and set the boundary conditions on the update
    dubcs = problem.boundary_conditions(Z, newmu)
    [dubc.homogenize() for dubc in dubcs]

    # dm = problem._dm

    # FIXME: make this optional
    # teamno = 0

    # FIXME: there's probably a more elegant way to do this.
    # Or should we use one semismooth Newton step? After all
    # we already have a Newton linearisation.
    newproblem = BensonMunson(problem)
    sp = problem.solver_parameters(float(oldmu), 0, task, params)
    (success, iters, liters) = newton(G, J, du, dubcs,
                              newproblem.solver,
                              params,
                              sp,
                              None, None, problem._dm, vi_du)

    hint = [None, float(oldmu)]
    if not success:
        #do nothing
        return (hint, iters, liters)
    else:
        solution.assign(solution + du)
        infeasibility = assemble(problem.infeasibility(solution, lb, ub, newmu, params))
        info_green("Tangent linearisation success, infeasibility of guess %.5e" % (infeasibility))
        return (hint, iters, liters)
Пример #4
0
def problem():
    mesh = dolfin.UnitCubeMesh(MPI.comm_world, 10, 10, 10)
    cell = mesh.ufl_cell()

    vec_element = dolfin.VectorElement("Lagrange", cell, 1)
    # scl_element = dolfin.FiniteElement("Lagrange", cell, 1)

    Q = dolfin.FunctionSpace(mesh, vec_element)
    # Qs = dolfin.FunctionSpace(mesh, scl_element)

    # Coefficients
    v = dolfin.function.argument.TestFunction(Q)  # Test function
    du = dolfin.function.argument.TrialFunction(Q)  # Incremental displacement
    u = dolfin.Function(Q)  # Displacement from previous iteration

    B = dolfin.Constant((0.0, -0.5, 0.0), cell)  # Body force per unit volume
    T = dolfin.Constant((0.1, 0.0, 0.0),
                        cell)  # Traction force on the boundary

    # B, T = dolfin.Function(Q), dolfin.Function(Q)

    # Kinematics
    d = u.geometric_dimension()
    F = ufl.Identity(d) + grad(u)  # Deformation gradient
    C = F.T * F  # Right Cauchy-Green tensor

    # Invariants of deformation tensors
    Ic = tr(C)
    J = det(F)

    # Elasticity parameters
    E, nu = 10.0, 0.3
    mu = dolfin.Constant(E / (2 * (1 + nu)), cell)
    lmbda = dolfin.Constant(E * nu / ((1 + nu) * (1 - 2 * nu)), cell)

    # mu, lmbda = dolfin.Function(Qs), dolfin.Function(Qs)

    # Stored strain energy density (compressible neo-Hookean model)
    psi = (mu / 2) * (Ic - 3) - mu * ln(J) + (lmbda / 2) * (ln(J))**2

    # Total potential energy
    Pi = psi * dx - dot(B, u) * dx - dot(T, u) * ds

    # Compute first variation of Pi (directional derivative about u in the direction of v)
    F = ufl.derivative(Pi, u, v)

    # Compute Jacobian of F
    J = ufl.derivative(F, u, du)

    return J, F
Пример #5
0
def hyperelasticity(domain, q, p, nf=0):
    # Based on https://github.com/firedrakeproject/firedrake-bench/blob/experiments/forms/firedrake_forms.py
    V = ufl.FunctionSpace(domain, ufl.VectorElement('P', domain.ufl_cell(), q))
    P = ufl.FunctionSpace(domain, ufl.VectorElement('P', domain.ufl_cell(), p))
    v = ufl.TestFunction(V)
    du = ufl.TrialFunction(V)  # Incremental displacement
    u = ufl.Coefficient(V)     # Displacement from previous iteration
    B = ufl.Coefficient(V)     # Body force per unit mass
    # Kinematics
    I = ufl.Identity(domain.ufl_cell().topological_dimension())
    F = I + ufl.grad(u)        # Deformation gradient
    C = F.T*F                  # Right Cauchy-Green tensor
    E = (C - I)/2              # Euler-Lagrange strain tensor
    E = ufl.variable(E)
    # Material constants
    mu = ufl.Constant(domain)  # Lame's constants
    lmbda = ufl.Constant(domain)
    # Strain energy function (material model)
    psi = lmbda/2*(ufl.tr(E)**2) + mu*ufl.tr(E*E)
    S = ufl.diff(psi, E)       # Second Piola-Kirchhoff stress tensor
    PK = F*S                   # First Piola-Kirchoff stress tensor
    # Variational problem
    it = ufl.inner(PK, ufl.grad(v)) - ufl.inner(B, v)
    f = [ufl.Coefficient(P) for _ in range(nf)]
    return ufl.derivative(reduce(ufl.inner,
                                 list(map(ufl.div, f)) + [it])*ufl.dx, u, du)
Пример #6
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one with the next argument number
        from ufl.algorithms import extract_arguments
        form_arguments = extract_arguments(form)

        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        if any(arg.part() is not None for arg in form_arguments):
            cpp.dolfin_error(
                "formmanipulation.py", "compute derivative of form",
                "Cannot automatically create third argument using parts, please supply one"
            )
        part = None

        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, (list, tuple)) and all(
                isinstance(w, Function) for w in u):
            V = MixedFunctionSpace([w.function_space() for w in u])
            du = ufl.split(Argument(V, number, part))
        else:
            cpp.dolfin_error(
                "formmanipulation.py", "compute derivative of form",
                "Cannot automatically create third argument, please supply one"
            )
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #7
0
def test_assemble_derivatives():
    """This test checks the original_coefficient_positions, which may change
    under differentiation (some coefficients and constants are
    eliminated)"""
    mesh = UnitSquareMesh(MPI.COMM_WORLD, 12, 12)
    Q = dolfinx.FunctionSpace(mesh, ("Lagrange", 1))
    u = dolfinx.Function(Q)
    v = ufl.TestFunction(Q)
    du = ufl.TrialFunction(Q)
    b = dolfinx.Function(Q)
    c1 = fem.Constant(mesh, [[1.0, 0.0], [3.0, 4.0]])
    c2 = fem.Constant(mesh, 2.0)

    with b.vector.localForm() as b_local:
        b_local.set(2.0)

    # derivative eliminates 'u' and 'c1'
    L = ufl.inner(c1, c1) * v * dx + c2 * b * inner(u, v) * dx
    a = derivative(L, u, du)

    A1 = dolfinx.fem.assemble_matrix(a)
    A1.assemble()
    a = c2 * b * inner(du, v) * dx
    A2 = dolfinx.fem.assemble_matrix(a)
    A2.assemble()
    assert (A1 - A2).norm() == pytest.approx(0.0, rel=1e-12, abs=1e-12)
Пример #8
0
def split_arity(form, x, argument):
    if x not in form.coefficients():
        # No dependence on x
        return ufl.classes.Form([]), form

    form_derivative = ufl.derivative(form, x, argument=argument)
    form_derivative = ufl.algorithms.expand_derivatives(form_derivative)
    if x in form_derivative.coefficients():
        # Non-linear
        return ufl.classes.Form([]), form

    arity = len(form.arguments())
    try:
        eq_form = ufl.algorithms.expand_derivatives(
            ufl.replace(form, {x: argument}))
        A = ufl.algorithms.formtransformations.compute_form_with_arity(
            eq_form, arity + 1)
        b = ufl.algorithms.formtransformations.compute_form_with_arity(
            eq_form, arity)
    except ufl.UFLException:
        # UFL error encountered
        return ufl.classes.Form([]), form

    if not is_cached(A):
        # Non-cached higher arity form
        return ufl.classes.Form([]), form

    # Success
    return A, b
Пример #9
0
 def evaluate_adj_component(self,
                            inputs,
                            adj_inputs,
                            block_variable,
                            idx,
                            prepared=None):
     if not self.lincom:
         if isinstance(block_variable.output,
                       (AdjFloat, self.backend.Constant)):
             return adj_inputs[0].sum()
         else:
             adj_output = self.backend.Function(
                 block_variable.output.function_space())
             adj_output.assign(prepared)
             return adj_output.vector()
     else:
         # Linear combination
         expr, adj_input_func = prepared
         adj_output = self.backend.Function(
             block_variable.output.function_space())
         diff_expr = ufl.algorithms.expand_derivatives(
             ufl.derivative(expr, block_variable.saved_output,
                            adj_input_func))
         adj_output.assign(diff_expr)
         return adj_output.vector()
Пример #10
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    """Compute the derivative of a form.
    Given a form, this computes its linearization with respect to the
    provided :class:`.Function`.  The resulting form has one
    additional :class:`Argument` in the same finite element space as
    the Function.
    :arg form: a :class:`~ufl.classes.Form` to compute the derivative of.
    :arg u: a :class:`.Function` to compute the derivative with
         respect to.
    :arg du: an optional :class:`Argument` to use as the replacement
         in the new form (constructed automatically if not provided).
    :arg coefficient_derivatives: an optional :class:`dict` to
         provide the derivative of a coefficient function.
    :raises ValueError: If any of the coefficients in ``form`` were
        obtained from ``u.split()``.  UFL doesn't notice that these
        are related to ``u`` and so therefore the derivative is
        wrong (instead one should have written ``split(u)``).
    See also :func:`ufl.derivative`.
    """
    #EVENTUALLY ADD THIS CHECKING BACK IN!
    # if set(extract_coefficients(form)) & set(u.split()):
    #    raise ValueError("Taking derivative of form wrt u, but form contains coefficients from u.split()."
    #                    "\nYou probably meant to write split(u) when defining your form.")

    if du is None:
        if isinstance(u, Function):
            V = u.function_space()
            args = form.arguments()
            number = max(a.number() for a in args) if args else -1
            du = Argument(V, number + 1)
        else:
            raise RuntimeError("Can't compute derivative for form")
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #11
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one
        # with the next argument number
        form_arguments = form.arguments()

        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        if any(arg.part() is not None for arg in form_arguments):
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form",
                             "Cannot automatically create new Argument using "
                             "parts, please supply one")
        part = None

        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, (list, tuple)) and all(isinstance(w, Function) for w in u):
            cpp.dolfin_error("formmanipulation.py",
                             "take derivative of form w.r.t. a tuple of Coefficients",
                             "Take derivative w.r.t. a single Coefficient on "
                             "a mixed space instead.")
        else:
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form w.r.t. '%s'" % u,
                             "Supply Function as a Coefficient")

    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #12
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one
        # with the next argument number
        form_arguments = form.arguments()

        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        if any(arg.part() is not None for arg in form_arguments):
            raise RuntimeError(
                "Cannot automatically create new Argument using parts, please supply one"
            )
        part = None

        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, (list, tuple)) and all(
                isinstance(w, Function) for w in u):
            raise RuntimeError(
                "Take derivative w.r.t. a single Coefficient on a mixed space instead."
            )
        else:
            raise RuntimeError(
                "Computing derivative of form w.r.t. '{}'. Supply Function as a Coefficient"
                .format(u))

    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #13
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one with the next argument number
        from ufl.algorithms import extract_arguments
        form_arguments = extract_arguments(form)

        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        if any(arg.part() is not None for arg in form_arguments):
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form",
                             "Cannot automatically create third argument using parts, please supply one")
        part = None

        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u):
            V = MixedFunctionSpace([w.function_space() for w in u])
            du = ufl.split(Argument(V, number, part))
        else:
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form",
                             "Cannot automatically create third argument, please supply one")
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #14
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    """Compute the derivative of a form.

    Given a form, this computes its linearization with respect to the
    provided :class:`.Function`.  The resulting form has one
    additional :class:`Argument` in the same finite element space as
    the Function.

    :arg form: a :class:`~ufl.classes.Form` to compute the derivative of.
    :arg u: a :class:`.Function` to compute the derivative with
         respect to.
    :arg du: an optional :class:`Argument` to use as the replacement
         in the new form (constructed automatically if not provided).
    :arg coefficient_derivatives: an optional :class:`dict` to
         provide the derivative of a coefficient function.

    See also :func:`ufl.derivative`.
    """
    if du is None:
        if isinstance(u, function.Function):
            V = u.function_space()
            args = form.arguments()
            number = max(a.number() for a in args) if args else -1
            du = Argument(V, number + 1)
        else:
            raise RuntimeError("Can't compute derivative for form")
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #15
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one
        # with the next argument number
        form_arguments = form.arguments()
        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        # NOTE : Mixed-domains problems need to have arg.part() != None
        # if any(arg.part() is not None for arg in form_arguments):
        #     raise RuntimeError("Compute derivative of form, cannot automatically create new Argument using parts, please supply one")
        part = None

        if isinstance(u, Function):
            # u.part() is None except with mixed-domains
            part = u.part()
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, SpatialCoordinate):
            mesh = u.ufl_domain().ufl_cargo()
            element = u.ufl_domain().ufl_coordinate_element()
            V = FunctionSpace(mesh, element)
            du = Argument(V, number, part)
        elif isinstance(u, (list, tuple)) and all(
                isinstance(w, Function) for w in u):
            raise RuntimeError(
                "Taking derivative of form w.r.t. a tuple of Coefficients. Take derivative w.r.t. a single Coefficient on a mixed space instead."
            )
        else:
            raise RuntimeError(
                "Computing derivative of form w.r.t. '{}'. Supply Function as a Coefficient"
                .format(u))
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #16
0
def test_assemble_derivatives():
    """This test checks the original_coefficient_positions, which may change
    under differentiation (some coefficients and constants are
    eliminated)"""
    mesh = create_unit_square(MPI.COMM_WORLD, 12, 12)
    Q = FunctionSpace(mesh, ("Lagrange", 1))
    u = Function(Q)
    v = ufl.TestFunction(Q)
    du = ufl.TrialFunction(Q)
    b = Function(Q)
    c1 = Constant(mesh, np.array([[1.0, 0.0], [3.0, 4.0]], PETSc.ScalarType))
    c2 = Constant(mesh, PETSc.ScalarType(2.0))

    b.x.array[:] = 2.0

    # derivative eliminates 'u' and 'c1'
    L = ufl.inner(c1, c1) * v * dx + c2 * b * inner(u, v) * dx
    a = form(derivative(L, u, du))

    A1 = assemble_matrix(a)
    A1.assemble()
    a = form(c2 * b * inner(du, v) * dx)
    A2 = assemble_matrix(a)
    A2.assemble()
    assert (A1 - A2).norm() == pytest.approx(0.0, rel=1e-12, abs=1e-12)
Пример #17
0
def derivative(form: ufl.Form, u, du,
               coefficient_derivatives=None) -> ufl.Form:
    """Compute derivative of from about u (coefficient) in the direction
    of du (Argument)

    """
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #18
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one
        # with the next argument number
        form_arguments = form.arguments()

        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        if any(arg.part() is not None for arg in form_arguments):
            raise RuntimeError("Compute derivative of form, cannot automatically create new Argument using parts, please supply one")
        part = None

        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V, number, part)
        elif isinstance(u, SpatialCoordinate):
            mesh = u.ufl_domain().ufl_cargo()
            element = u.ufl_domain().ufl_coordinate_element()
            V = FunctionSpace(mesh, element)
            du = Argument(V, number, part)
        elif isinstance(u, (list, tuple)) and all(isinstance(w, Function) for w in u):
            raise RuntimeError("Taking derivative of form w.r.t. a tuple of Coefficients. Take derivative w.r.t. a single Coefficient on a mixed space instead.")
        else:
            raise RuntimeError("Computing derivative of form w.r.t. '{}'. Supply Function as a Coefficient".format(u))

    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #19
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    """Compute the derivative of a form.

    Given a form, this computes its linearization with respect to the
    provided :class:`.Function`.  The resulting form has one
    additional :class:`Argument` in the same finite element space as
    the Function.

    :arg form: a :class:`ufl.Form` to compute the derivative of.
    :arg u: a :class:`.Function` to compute the derivative with
         respect to.
    :arg du: an optional :class:`Argument` to use as the replacement
         in the new form (constructed automatically if not provided).
    :arg coefficient_derivatives: an optional :class:`dict` to
         provide the derivative of a coefficient function.

    See also :func:`ufl.derivative`.
    """
    if du is None:
        if isinstance(u, function.Function):
            V = u.function_space()
            args = form.arguments()
            number = max(a.number() for a in args) if args else -1
            du = Argument(V, number + 1)
        else:
            raise RuntimeError("Can't compute derivative for form")
    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #20
0
def differentiate_expr(expr, u, expand = True):
    """
    Wrapper for the UFL derivative function. This chooses an argument equal to
    Constant(1.0). Form s should be differentiated using the derivative function.
    """

    if not isinstance(expr, ufl.expr.Expr):
        raise InvalidArgumentException("expr must be an Expr")
    if isinstance(u, ufl.indexed.Indexed):
        op = u.operands()
        assert(len(op) == 2)
        if not isinstance(op[0], (dolfin.Constant, dolfin.Function)):
            raise InvalidArgumentException("Invalid Indexed")
    elif not isinstance(u, (dolfin.Constant, dolfin.Function)):
        raise InvalidArgumentException("u must be an Indexed, Constant, or Function")

    if expr is u:
        der = ufl.constantvalue.IntValue(1)
    else:
        unity = dolfin.Constant(1.0)
        der = dolfin.replace(ufl.derivative(expr, u, argument = unity), {unity:ufl.constantvalue.IntValue(1)})

        if expand:
            # Based on code from expand_derivatives1 in UFL file ad.py, (see e.g. bzr
            # 1.1.x branch revision 1484)
            cell = der.cell()
            if cell is None:
                dim = 0
            else:
                dim = der.cell().geometric_dimension()
            der = ufl.algorithms.expand_derivatives(der, dim = dim)

    return der
Пример #21
0
def differentiate_expr(expr, u, expand = True):
    """
    Wrapper for the UFL derivative function. This chooses an argument equal to
    Constant(1.0). Form s should be differentiated using the derivative function.
    """

    if not isinstance(expr, ufl.core.expr.Expr):
        raise InvalidArgumentException("expr must be an Expr")
    if isinstance(u, ufl.indexed.Indexed):
        op = u.operands()
        assert(len(op) == 2)
        if not isinstance(op[0], (dolfin.Constant, dolfin.Function)):
            raise InvalidArgumentException("Invalid Indexed")
    elif not isinstance(u, (dolfin.Constant, dolfin.Function)):
        raise InvalidArgumentException("u must be an Indexed, Constant, or Function")

    if expr is u:
        der = ufl.constantvalue.IntValue(1)
    else:
        unity = dolfin.Constant(1.0)
        der = dolfin.replace(ufl.derivative(expr, u, argument = unity), {unity:ufl.constantvalue.IntValue(1)})

        if expand:
            # Based on code from expand_derivatives1 in UFL file ad.py, (see e.g. bzr
            # 1.1.x branch revision 1484)
            cell = der.cell()
            if cell is None:
                dim = 0
            else:
                dim = der.cell().geometric_dimension()
            der = ufl.algorithms.expand_derivatives(der, dim = dim)

    return der
Пример #22
0
def test_pack_coefficients():
    """Test packing of form coefficients ahead of main assembly call"""
    mesh = create_unit_square(MPI.COMM_WORLD, 12, 15)
    V = FunctionSpace(mesh, ("Lagrange", 1))

    # Non-blocked
    u = Function(V)
    v = ufl.TestFunction(V)
    c = Constant(mesh, PETSc.ScalarType(12.0))
    F = ufl.inner(c, v) * dx - c * ufl.sqrt(u * u) * ufl.inner(u, v) * dx
    u.x.array[:] = 10.0
    _F = form(F)

    # -- Test vector
    b0 = assemble_vector(_F)
    b0.assemble()
    constants = pack_constants(_F)
    coeffs = pack_coefficients(_F)
    with b0.localForm() as _b0:
        for c in [(None, None), (None, coeffs), (constants, None), (constants, coeffs)]:
            b = assemble_vector(_F, coeffs=c)
            b.assemble()
            with b.localForm() as _b:
                assert (_b0.array_r == _b.array_r).all()

    # Change coefficients
    constants *= 5.0
    for coeff in coeffs.values():
        coeff *= 5.0
    with b0.localForm() as _b0:
        for c in [(None, coeffs), (constants, None), (constants, coeffs)]:
            b = assemble_vector(_F, coeffs=c)
            b.assemble()
            with b.localForm() as _b:
                assert (_b0 - _b).norm() > 1.0e-5

    # -- Test matrix
    du = ufl.TrialFunction(V)
    J = ufl.derivative(F, u, du)
    J = form(J)

    A0 = assemble_matrix(J)
    A0.assemble()

    constants = pack_constants(J)
    coeffs = pack_coefficients(J)
    for c in [(None, None), (None, coeffs), (constants, None), (constants, coeffs)]:
        A = assemble_matrix(J, coeffs=c)
        A.assemble()
        assert pytest.approx((A - A0).norm(), 1.0e-12) == 0.0

    # Change coefficients
    constants *= 5.0
    for coeff in coeffs.values():
        coeff *= 5.0
    for c in [(None, coeffs), (constants, None), (constants, coeffs)]:
        A = assemble_matrix(J, coeffs=c)
        A.assemble()
        assert (A - A0).norm() > 1.0e-5
Пример #23
0
def hyperelasticity_action_forms(mesh, vec_el):
    cell = mesh.ufl_cell()

    Q = dolfin.FunctionSpace(mesh, vec_el)

    # Coefficients
    v = dolfin.function.argument.TestFunction(Q)  # Test function
    du = dolfin.function.argument.TrialFunction(Q)  # Incremental displacement
    u = dolfin.Function(Q)  # Displacement from previous iteration
    u.vector().set(0.5)

    B = dolfin.Constant((0.0, -0.5, 0.0), cell)  # Body force per unit volume
    T = dolfin.Constant((0.1, 0.0, 0.0), cell)  # Traction force on the boundary

    # Kinematics
    d = u.geometric_dimension()
    F = ufl.Identity(d) + grad(u)  # Deformation gradient
    C = F.T * F  # Right Cauchy-Green tensor

    # Invariants of deformation tensors
    Ic = tr(C)
    J = det(F)

    # Elasticity parameters
    E, nu = 10.0, 0.3
    mu = dolfin.Constant(E / (2 * (1 + nu)), cell)
    lmbda = dolfin.Constant(E * nu / ((1 + nu) * (1 - 2 * nu)), cell)

    # Stored strain energy density (compressible neo-Hookean model)
    psi = (mu / 2) * (Ic - 3) - mu * ln(J) + (lmbda / 2) * (ln(J)) ** 2

    # Total potential energy
    Pi = psi * dx - dot(B, u) * dx - dot(T, u) * ds

    # Compute first variation of Pi (directional derivative about u in the direction of v)
    F = ufl.derivative(Pi, u, v)

    # Compute Jacobian of F
    J = ufl.derivative(F, u, du)

    w = dolfin.Function(Q)
    w.vector().set(1.2)

    L = ufl.action(J, w)

    return None, L, None
Пример #24
0
 def __init__(self, F, u, bc):
     V = u.function_space
     du = TrialFunction(V)
     self.L = form(F)
     self.a = form(derivative(F, u, du))
     self.bc = bc
     self._F, self._J = None, None
     self.u = u
Пример #25
0
def derivative(form, x, argument=None):
    if argument is None:
        space = derivative_space(x)
        rank = len(form.arguments())
        Argument = {0: TestFunction, 1: TrialFunction}[rank]
        argument = Argument(space)

    return ufl.derivative(form, x, argument=argument)
 def variation(self, v):
     """ Directional derivative in direction v """
     # return ufl.algorithms.expand_derivatives(ufl.derivative(self.expression, self.variable, v))
     deriv = sum([
         ufl.derivative(self.expression, var, v_)
         for (var, v_) in zip(split(self.variable), split(v))
     ])
     return ufl.algorithms.expand_derivatives(deriv)
Пример #27
0
 def __init__(self, F, u, bc):
     super().__init__()
     V = u.function_space
     du = TrialFunction(V)
     self.L = F
     self.a = derivative(F, u, du)
     self.bc = bc
     self._F, self._J = None, None
Пример #28
0
def derivative(e, u, du, u0=None):
    """Generate the functional derivative of UFL expression (or list of expressions) for the
       given function(s) u in the direction of function(s) du and at u0.

       Example (first variation): δe = dolfiny.expression.derivative(e, m, δm)

    Parameters
    ----------
    e: UFL Expr or list of UFL expressions/forms
    u: UFL Function or list of UFL functions
    du: UFL Function or list of UFL functions
    u0: UFL Function or list of UFL functions, defaults to u

    Returns
    -------
    Expression (or list of expressions) with functional derivative.

    """

    if u0 is None:
        u0 = u

    e0 = evaluate(e, u, u0)

    if isinstance(e0, list):
        de0 = []
        for e0_ in e0:
            if isinstance(u0, list) and isinstance(du, list):
                de0_ = sum(
                    ufl.derivative(e0_, v0, dv) for v0, dv in zip(u0, du))
            else:
                de0_ = ufl.derivative(e0_, u0, du)
            de0_ = ufl.algorithms.apply_algebra_lowering.apply_algebra_lowering(
                de0_)
            de0_ = ufl.algorithms.apply_derivatives.apply_derivatives(de0_)
            de0.append(de0_)
    else:
        if isinstance(u0, list) and isinstance(du, list):
            de0 = sum(ufl.derivative(e0, v0, dv) for v0, dv in zip(u0, du))
        else:
            de0 = ufl.derivative(e0, u0, du)
        de0 = ufl.algorithms.apply_algebra_lowering.apply_algebra_lowering(de0)
        de0 = ufl.algorithms.apply_derivatives.apply_derivatives(de0)

    return de0
Пример #29
0
    def __init__(self, energy, alpha, bcs, lb=None, ub=None):

        OptimisationProblem.__init__(self)
        self.energy = energy
        self.alpha = alpha
        self.V = self.alpha.function_space()
        self.denergy = derivative(self.energy, self.alpha,
                                  TestFunction(self.V))
        self.ddenergy = derivative(self.denergy, self.alpha,
                                   TrialFunction(self.V))
        if lb == None:
            lb = interpolate(Constant("0."), self.V)
        if ub == None:
            ub = interpolate(Constant("2."), self.V)
        self.lb = lb
        self.ub = ub
        self.bcs = bcs
        self.update_lb()
Пример #30
0
 def __init__(self, F, u, bc):
     V = u.function_space
     du = TrialFunction(V)
     self.L = F
     self.a = derivative(F, u, du)
     self.a_comp = dolfinx.fem.Form(self.a)
     self.bc = bc
     self._F, self._J = None, None
     self.u = u
Пример #31
0
    def evaluate_adj_component(self,
                               inputs,
                               adj_inputs,
                               block_variable,
                               idx,
                               prepared=None):
        if self.expr is None:
            if isinstance(block_variable.output, AdjFloat):
                return adj_inputs[0].sum()
            elif isinstance(block_variable.output, self.backend.Constant):
                R = block_variable.output._ad_function_space(
                    prepared.function_space().mesh())
                return self._adj_assign_constant(prepared, R)
            else:
                adj_output = self.backend.Function(
                    block_variable.output.function_space())
                adj_output.assign(prepared)
                return adj_output.vector()
        else:
            # Linear combination
            expr, adj_input_func = prepared
            adj_output = self.backend.Function(adj_input_func.function_space())
            if block_variable.saved_output.ufl_shape == adj_input_func.ufl_shape:
                diff_expr = ufl.algorithms.expand_derivatives(
                    ufl.derivative(expr, block_variable.saved_output,
                                   adj_input_func))
                adj_output.assign(diff_expr)
            else:
                # Assume current variable is scalar constant.
                # This assumption might be wrong for firedrake.
                assert isinstance(block_variable.output, self.backend.Constant)

                diff_expr = ufl.algorithms.expand_derivatives(
                    ufl.derivative(expr, block_variable.saved_output,
                                   self.backend.Constant(1.)))
                adj_output.assign(diff_expr)
                return adj_output.vector().inner(adj_input_func.vector())

            if isinstance(block_variable.output, self.backend.Constant):
                R = block_variable.output._ad_function_space(
                    adj_output.function_space().mesh())
                return self._adj_assign_constant(adj_output, R)
            else:
                return adj_output.vector()
Пример #32
0
    def __init__(self, energy, alpha, bcs, lb=None, ub=None):

        NonlinearProblem.__init__(self)
        self.energy = energy
        self.alpha = alpha
        self.V = self.alpha.function_space()
        self.denergy = derivative(self.energy, self.alpha,
                                  TestFunction(self.V))
        self.ddenergy = derivative(self.denergy, self.alpha,
                                   TrialFunction(self.V))
        if lb == None:
            lb = interpolate(Constant("0."), self.V)
        if ub == None:
            ub = interpolate(Constant("1."), self.V)
        self.lb = lb
        self.ub = ub
        self.bcs = bcs
        self.b = PETScVector()
        self.A = PETScMatrix()
Пример #33
0
def test_block(V1, V2, squaremesh_5, nest):
    mesh = squaremesh_5

    u0 = dolfinx.Function(V1, name="u0")
    u1 = dolfinx.Function(V2, name="u1")

    v0 = ufl.TestFunction(V1)
    v1 = ufl.TestFunction(V2)

    Phi = (ufl.sin(u0) - 0.5)**2 * ufl.dx(mesh) + (4.0 * u0 -
                                                   u1)**2 * ufl.dx(mesh)

    F0 = ufl.derivative(Phi, u0, v0)
    F1 = ufl.derivative(Phi, u1, v1)

    F = [F0, F1]
    u = [u0, u1]

    opts = PETSc.Options("block")

    opts.setValue('snes_type', 'newtontr')
    opts.setValue('snes_rtol', 1.0e-08)
    opts.setValue('snes_max_it', 12)

    if nest:
        opts.setValue('ksp_type', 'cg')
        opts.setValue('pc_type', 'fieldsplit')
        opts.setValue('fieldsplit_pc_type', 'lu')
        opts.setValue('ksp_rtol', 1.0e-10)
    else:
        opts.setValue('ksp_type', 'preonly')
        opts.setValue('pc_type', 'lu')
        opts.setValue('pc_factor_mat_solver_type', 'mumps')

    problem = dolfiny.snesblockproblem.SNESBlockProblem(F,
                                                        u,
                                                        nest=nest,
                                                        prefix="block")
    sol = problem.solve()

    assert problem.snes.getConvergedReason() > 0
    assert np.isclose((sol[0].vector - np.arcsin(0.5)).norm(), 0.0)
    assert np.isclose((sol[1].vector - 4.0 * np.arcsin(0.5)).norm(), 0.0)
Пример #34
0
 def __init__(self, F, u, bc):
     super().__init__()
     V = u.function_space()
     du = function.TrialFunction(V)
     self.L = F
     self.a = derivative(F, u, du)
     self.a_comp = dolfin.fem.Form(self.a)
     self.bc = bc
     self._F, self._J = None, None
     self.u = u
Пример #35
0
def derivative(form, u, du=None):
    if du is None:
        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V)
        elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u):
            V = MixedFunctionSpace([w.function_space() for w in u])
            du = ufl.split(Argument(V))
        else:
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form",
                             "Cannot automatically create third argument, please supply one")

    return ufl.derivative(form, u, du)
Пример #36
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    if du is None:
        # Get existing arguments from form and position the new one with the next argument number
        form_arguments = form.arguments()

        number = max([-1] + [arg.number() for arg in form_arguments]) + 1

        if any(arg.part() is not None for arg in form_arguments):
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form",
                             "Cannot automatically create new Argument using "
                             "parts, please supply one")
        part = None

        if isinstance(u, Function):
            V = u.function_space()
            du = Argument(V, number, part)

        elif isinstance(u, (list,tuple)) and all(isinstance(w, Function) for w in u):
            cpp.deprecation("derivative of form w.r.t. a tuple of Coefficients",
                            "1.7.0", "2.0.0",
                            "Take derivative w.r.t. a single Coefficient on "
                            "a mixed space instead.")

            # Get mesh
            mesh = u[0].function_space().mesh()
            if not all(mesh.id() == v.function_space().mesh().id() for v in u):
                cpp.dolfin_error("formmanipulation.py",
                                 "compute derivative of form",
                                 "Don't know how to compute derivative with "
                                 "respect to Coefficients on different meshes yet")

            # Build mixed element, space and argument
            element = ufl.MixedElement([v.function_space().ufl_element() for v in u])
            V = FunctionSpace(mesh, element)
            du = ufl.split(Argument(V, number, part))

        else:
            cpp.dolfin_error("formmanipulation.py",
                             "compute derivative of form w.r.t. '%s'" % u,
                             "Supply Function as a Coefficient")

    return ufl.derivative(form, u, du, coefficient_derivatives)
Пример #37
0
def derivative(form, u, du=None):
    """Compute the derivative of a form.

    Given a form, this computes its linearization with respect to the
    provided :class:`.Function`.  The resulting form has one
    additional :class:`Argument` in the same finite element space as
    the Function.

    :arg form: a :class:`ufl.Form` to compute the derivative of.
    :arg u: a :class:`.Function` to compute the derivative with
         respect to.
    :arg du: an optional :class:`Argument` to use as the replacement
         in the new form (constructed automatically if not provided).

    See also :func:`ufl.derivative`.
    """
    if du is None:
        if isinstance(u, function.Function):
            V = u.function_space()
            du = TrialFunction(V)
        else:
            raise RuntimeError("Can't compute derivative for form")
    return ufl.derivative(form, u, du)
Пример #38
0
def test_conditional_nan():
    # Test case courtesy of Marco Morandini:
    # https://github.com/firedrakeproject/tsfc/issues/183

    def crossTensor(V):
        return as_tensor([
            [0.0, V[2], -V[1]],
            [-V[2], 0.0, V[0]],
            [V[1], -V[0], 0.0]])

    def coefa(phi2):
        return conditional(le(phi2, 1.e-6),
                           phi2,
                           sin(phi2)/phi2)

    def RotDiffTensor(phi):
        PhiCross = crossTensor(phi)
        phi2 = dot(phi, phi)
        a = coefa(phi2)
        return PhiCross * a

    mesh = UnitIntervalMesh(8)
    V = VectorFunctionSpace(mesh, "CG", 1, dim=3)
    u_phi = Function(V)
    v_phi = TestFunction(V)

    Gamma = RotDiffTensor(u_phi)

    beta = dot(Gamma, grad(u_phi))
    delta_beta = ufl.derivative(beta, u_phi, v_phi)

    L = inner(delta_beta, grad(u_phi)) * dx
    result = assemble(L).dat.data

    # Check whether there are any NaNs in the result
    assert not np.isnan(result).any()
Пример #39
0
    def solve(self, problem):
        self.problem = problem
        doSave = problem.doSave
        save_this_step = False
        onlyVel = problem.saveOnlyVel
        dt = self.metadata['dt']

        nu = Constant(self.problem.nu)
        self.tc.init_watch('init', 'Initialization', True, count_to_percent=False)
        self.tc.init_watch('solve', 'Running nonlinear solver', True, count_to_percent=True)
        self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True)
        self.tc.init_watch('saveVel', 'Saved velocity', True)

        self.tc.start('init')

        mesh = self.problem.mesh

        # Define function spaces (P2-P1)
        self.V = VectorFunctionSpace(mesh, "Lagrange", 2)  # velocity
        self.Q = FunctionSpace(mesh, "Lagrange", 1)  # pressure
        self.W = MixedFunctionSpace([self.V, self.Q])
        self.PS = FunctionSpace(mesh, "Lagrange", 2)  # partial solution (must be same order as V)
        self.D = FunctionSpace(mesh, "Lagrange", 1)   # velocity divergence space

        # to assign solution in space W.sub(0) to Function(V) we need FunctionAssigner (cannot be assigned directly)
        fa = FunctionAssigner(self.V, self.W.sub(0))
        velSp = Function(self.V)

        problem.initialize(self.V, self.Q, self.PS, self.D)

        # Define unknown and test function(s) NS
        v, q = TestFunctions(self.W)
        w = Function(self.W)
        dw = TrialFunction(self.W)
        u, p = split(w)

        # Define fields
        n = FacetNormal(mesh)
        I = Identity(u.geometric_dimension())
        theta = 0.5  # Crank-Nicholson
        k = Constant(self.metadata['dt'])

        # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure
        [u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': 0.0}, {'type': 'p', 'time': 0.0}])

        if doSave:
            problem.save_vel(False, u0, 0.0)

        # boundary conditions
        bcu, bcp = problem.get_boundary_conditions(self.bc == 'outflow', self.W.sub(0), self.W.sub(1))
        # NT bcp is not used

        # Define steady part of the equation
        def T(u):
            return -p * I + 2.0 * nu * sym(grad(u))

        def F(u, v, q):
            return (inner(T(u), grad(v)) - q * div(u)) * dx + inner(grad(u) * u, v) * dx

        # Define variational forms
        F_ns = (inner((u - u0), v) / k) * dx + (1.0 - theta) * F(u0, v, q) + theta * F(u, v, q)
        J_ns = derivative(F_ns, w, dw)
        # J_ns = derivative(F_ns, w)  # did not work

        # NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns, form_compiler_parameters=ffc_options)
        NS_problem = NonlinearVariationalProblem(F_ns, w, bcu, J_ns)
        # (var. formulation, unknown, Dir. BC, jacobian, optional)
        NS_solver = NonlinearVariationalSolver(NS_problem)

        prm = NS_solver.parameters
        prm['newton_solver']['absolute_tolerance'] = 1E-08
        prm['newton_solver']['relative_tolerance'] = 1E-08
        # prm['newton_solver']['maximum_iterations'] = 45
        # prm['newton_solver']['relaxation_parameter'] = 1.0
        prm['newton_solver']['linear_solver'] = 'mumps'

        info(NS_solver.parameters, True)

        self.tc.end('init')

        # Time-stepping
        info("Running of direct method")
        ttime = self.metadata['time']
        t = dt
        step = 1
        while t < (ttime + dt/2.0):
            info("t = %f" % t)
            self.problem.update_time(t, step)
            if self.MPI_rank == 0:
                problem.write_status_file(t)

            if doSave:
                save_this_step = problem.save_this_step

            # Compute
            begin("Solving NS ....")
            try:
                self.tc.start('solve')
                NS_solver.solve()
                self.tc.end('solve')
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            end()

            # Extract solutions:
            (u, p) = w.split()
            fa.assign(velSp, u)
            # we are assigning twice (now and inside save_vel), but it works with one method save_vel for direct and
            #   projection (we could split save_vel to save one assign)

            if save_this_step:
                self.tc.start('saveVel')
                problem.save_vel(False, velSp, t)
                self.tc.end('saveVel')
            if save_this_step and not onlyVel:
                problem.save_div(False, u)
            problem.compute_err(False, u, t)
            problem.compute_div(False, u)

            # foo = Function(self.Q)
            # foo.assign(p)
            # problem.averaging_pressure(foo)
            # if save_this_step and not onlyVel:
            #     problem.save_pressure(False, foo)

            if save_this_step and not onlyVel:
                problem.save_pressure(False, p)

            # compute functionals (e. g. forces)
            problem.compute_functionals(u, p, t)

            # Move to next time step
            self.tc.start('next')
            u0.assign(velSp)
            t = round(t + dt, 6)  # round time step to 0.000001
            step += 1
            self.tc.end('next')

        info("Finished: direct method")
        problem.report()
        return 0
Пример #40
0
def derivative(form, u, du=None, coefficient_derivatives=None):
    """Compute the derivative of a form.

    Given a form, this computes its linearization with respect to the
    provided :class:`.Function`.  The resulting form has one
    additional :class:`Argument` in the same finite element space as
    the Function.

    :arg form: a :class:`~ufl.classes.Form` to compute the derivative of.
    :arg u: a :class:`.Function` to compute the derivative with
         respect to.
    :arg du: an optional :class:`Argument` to use as the replacement
         in the new form (constructed automatically if not provided).
    :arg coefficient_derivatives: an optional :class:`dict` to
         provide the derivative of a coefficient function.

    :raises ValueError: If any of the coefficients in ``form`` were
        obtained from ``u.split()``.  UFL doesn't notice that these
        are related to ``u`` and so therefore the derivative is
        wrong (instead one should have written ``split(u)``).

    See also :func:`ufl.derivative`.
    """
    # TODO: What about Constant?
    u_is_x = isinstance(u, ufl.SpatialCoordinate)
    if not u_is_x and len(u.split()) > 1 and set(extract_coefficients(form)) & set(u.split()):
        raise ValueError("Taking derivative of form wrt u, but form contains coefficients from u.split()."
                         "\nYou probably meant to write split(u) when defining your form.")

    mesh = form.ufl_domain()
    is_dX = u_is_x or u is mesh.coordinates
    args = form.arguments()

    def argument(V):
        if du is None:
            n = max(a.number() for a in args) if args else -1
            return Argument(V, n + 1)
        else:
            return du

    if is_dX:
        coords = mesh.coordinates
        u = ufl.SpatialCoordinate(mesh)
        V = coords.function_space()
        du = argument(V)
        cds = {coords: du}
        if coefficient_derivatives is not None:
            cds.update(coefficient_derivatives)
        coefficient_derivatives = cds
    elif isinstance(u, firedrake.Function):
        V = u.function_space()
        du = argument(V)
    elif isinstance(u, firedrake.Constant):
        if u.ufl_shape != ():
            raise ValueError("Real function space of vector elements not supported")
        V = firedrake.FunctionSpace(mesh, "Real", 0)
        du = argument(V)
    else:
        raise RuntimeError("Can't compute derivative for form")

    return ufl.derivative(form, u, du, coefficient_derivatives)