Example #1
0
    def __init__(self, module, F, M, u):
        """
        *Arguments*

            module (Python module)
               The module to use for specific form manipulations
               (typically ufl or dolfin)

            F (tuple or Form)
               tuple of (bilinear, linear) forms or linear form

            M (Form)
               functional or linear form

            u (Coefficient)
              The coefficient considered as the unknown.
        """
        # Store module
        self.module = module

        # Store solution Coefficient/Function
        self.u = u

        # Extract the lhs (bilinear form), rhs (linear form), goal
        # (functional), weak residual (linear form)
        linear_case = (isinstance(F, (tuple, list)) and len(F) == 2)
        if linear_case:
            self.lhs, self.rhs = F
            try:
                self.goal = action(M, u)
            except:
                self.goal = M  # Allow functionals as input as well
            self.weak_residual = self.rhs - action(self.lhs, u)
        else:
            self.lhs = self.module.derivative(F, u)
            self.rhs = F
            self.goal = M
            self.weak_residual = -F

        # At least check that final forms have correct rank
        assert (len(self.lhs.arguments()) == 2)
        assert (len(self.rhs.arguments()) == 1)
        assert (len(self.goal.arguments()) == 0)
        assert (len(self.weak_residual.arguments()) == 1)

        # Get the domain, assuming there's only one
        assert (len(self.weak_residual.domains()) == 1)
        self.domain, = self.weak_residual.domains()

        # Store map from identifiers to names for forms and generated
        # coefficients
        self.ec_names = {}

        # Use predefined names for the forms in the primal problem
        self.ec_names[id(self.lhs)] = "lhs"
        self.ec_names[id(self.rhs)] = "rhs"
        self.ec_names[id(self.goal)] = "goal"

        # Initialize other required data
        self.initialize_data()
Example #2
0
    def __init__(self, module, F, M, u):
        """
        *Arguments*

            module (Python module)
               The module to use for specific form manipulations
               (typically ufl or dolfin)

            F (tuple or Form)
               tuple of (bilinear, linear) forms or linear form

            M (Form)
               functional or linear form

            u (Coefficient)
              The coefficient considered as the unknown.
        """
        # Store module
        self.module = module

        # Store solution Coefficient/Function
        self.u = u

        # Extract the lhs (bilinear form), rhs (linear form), goal
        # (functional), weak residual (linear form)
        linear_case = (isinstance(F, (tuple, list)) and len(F) == 2)
        if linear_case:
            self.lhs, self.rhs = F
            try:
                self.goal = action(M, u)
            except Exception:
                self.goal = M    # Allow functionals as input as well
            self.weak_residual = self.rhs - action(self.lhs, u)
        else:
            self.lhs = self.module.derivative(F, u)
            self.rhs = F
            self.goal = M
            self.weak_residual = - F

        # At least check that final forms have correct rank
        assert(len(self.lhs.arguments()) == 2)
        assert(len(self.rhs.arguments()) == 1)
        assert(len(self.goal.arguments()) == 0)
        assert(len(self.weak_residual.arguments()) == 1)

        # Get the domain
        self.domain = self.weak_residual.ufl_domain()

        # Store map from identifiers to names for forms and generated
        # coefficients
        self.ec_names = {}

        # Use predefined names for the forms in the primal problem
        self.ec_names[id(self.lhs)] = "lhs"
        self.ec_names[id(self.rhs)] = "rhs"
        self.ec_names[id(self.goal)] = "goal"

        # Initialize other required data
        self.initialize_data()
Example #3
0
    def subtract_adjoint_derivative_actions(self, adj_x, nl_deps, dep_Bs):
        for dep_index, dep_B in dep_Bs.items():
            if dep_index not in self._adjoint_dF_cache:
                dep = self.dependencies()[dep_index]
                dF = derivative(self._F, dep)
                dF = ufl.algorithms.expand_derivatives(dF)
                dF = eliminate_zeros(dF)
                if dF.empty():
                    dF = None
                else:
                    dF = adjoint(dF)
                self._adjoint_dF_cache[dep_index] = dF
            dF = self._adjoint_dF_cache[dep_index]

            if dF is not None:
                if dep_index not in self._adjoint_action_cache:
                    if self._cache_rhs_assembly \
                            and isinstance(adj_x, backend_Function) \
                            and is_cached(dF):
                        # Cached matrix action
                        self._adjoint_action_cache[dep_index] = CacheRef()
                    elif self._defer_adjoint_assembly:
                        # Cached form, deferred assembly
                        self._adjoint_action_cache[dep_index] = None
                    else:
                        # Cached form, immediate assembly
                        self._adjoint_action_cache[dep_index] = unbound_form(
                            ufl.action(dF, coefficient=adj_x),
                            list(self.nonlinear_dependencies()) + [adj_x])
                cache = self._adjoint_action_cache[dep_index]

                if cache is None:
                    # Cached form, deferred assembly
                    replace_map = dict(zip(self.nonlinear_dependencies(),
                                       nl_deps))
                    dep_B.sub(ufl.action(ufl.replace(dF, replace_map),
                                         coefficient=adj_x))
                elif isinstance(cache, CacheRef):
                    # Cached matrix action
                    mat_bc = cache()
                    if mat_bc is None:
                        replace_map = dict(zip(self.nonlinear_dependencies(),
                                               nl_deps))
                        self._adjoint_action_cache[dep_index], (mat, _) = \
                            assembly_cache().assemble(
                                dF,
                                form_compiler_parameters=self._form_compiler_parameters,  # noqa: E501
                                replace_map=replace_map)
                    else:
                        mat, _ = mat_bc
                    dep_B.sub(matrix_multiply(mat, function_vector(adj_x)))
                else:
                    # Cached form, immediate assembly
                    assert isinstance(cache, ufl.classes.Form)
                    bind_form(cache, list(nl_deps) + [adj_x])
                    dep_B.sub(assemble(
                        cache,
                        form_compiler_parameters=self._form_compiler_parameters))  # noqa: E501
                    unbind_form(cache)
Example #4
0
    def __init__(self, form, target, source, rowbcs, colbcs):
        self._twoform = form
        self._rowbcs = rowbcs
        self._target = target
        self._source = source
        self._colbcs = colbcs

        self._x = Function(target, name='internalx')
        self._y = Function(source, name='internaly')

        self._form = ufl.action(form, self._x)
        self._formT = ufl.action(adjoint(form), self._y)
        self._assembled = False

        if len(rowbcs) > 0:
            self._xbcs = Function(target)
        if len(colbcs) > 0:
            self._ybcs = Function(source)

        idx_kernels = compile_form(self._form)
        self.local_assembly_idx = []
        self.local_assembly_kernels = []
        for idx, kernels in idx_kernels:
            self.local_assembly_idx.append(idx)
            self.local_assembly_kernels.append(kernels)

        idx_kernels = compile_form(self._formT)
        self.Tlocal_assembly_idx = []
        self.Tlocal_assembly_kernels = []
        for idx, kernels in idx_kernels:
            self.Tlocal_assembly_idx.append(idx)
            self.Tlocal_assembly_kernels.append(kernels)

        # create matrix
        mlist = []
        nlist = []
        for si1 in range(target.nspaces):
            tspace = target.get_space(si1)
            for ci1 in range(tspace.ncomp):
                m = tspace.get_localndofs(ci1)
                mlist.append(m)
        for si2 in range(source.nspaces):
            sspace = source.get_space(si2)
            for ci2 in range(sspace.ncomp):
                n = sspace.get_localndofs(ci2)
                nlist.append(n)

        M = np.sum(np.array(mlist, dtype=np.int32))
        N = np.sum(np.array(nlist, dtype=np.int32))
        self.petscmat = PETSc.Mat()
        self.petscmat.create(PETSc.COMM_WORLD)
        self.petscmat.setSizes(((M, None), (N, None)))
        self.petscmat.setType('python')
        self.petscmat.setPythonContext(self)
        self.petscmat.setUp()
        self.petscmat.assemblyBegin()
        self.petscmat.assemblyEnd()
Example #5
0
def _assemble_system(A_form,
                     b_form=None,
                     bcs=[],
                     form_compiler_parameters={},
                     *args,
                     **kwargs):
    if isinstance(bcs, backend_DirichletBC):
        bcs = (bcs, )
    if b_form is None:
        bind_forms(A_form)
    else:
        bind_forms(A_form, b_form)

    A = _assemble(A_form,
                  bcs=bcs,
                  form_compiler_parameters=form_compiler_parameters,
                  *args,
                  **kwargs)

    if len(bcs) > 0:
        F = backend_Function(A_form.arguments()[0].function_space())
        for bc in bcs:
            bc.apply(F)

        if b_form is None:
            b = _assemble(-ufl.action(A_form, F),
                          bcs=bcs,
                          form_compiler_parameters=form_compiler_parameters,
                          *args,
                          **kwargs)

            with b.dat.vec_ro as b_v:
                if b_v.norm(norm_type=PETSc.NormType.NORM_INFINITY) == 0.0:
                    b = None
        else:
            b = _assemble(b_form - ufl.action(A_form, F),
                          bcs=bcs,
                          form_compiler_parameters=form_compiler_parameters,
                          *args,
                          **kwargs)
    else:
        if b_form is None:
            b = None
        else:
            b = _assemble(b_form,
                          form_compiler_parameters=form_compiler_parameters,
                          *args,
                          **kwargs)

    A._tlm_adjoint__lift_bcs = False

    if b_form is None:
        unbind_forms(A_form)
    else:
        unbind_forms(A_form, b_form)
    return A, b
Example #6
0
    def __init__(self, a, row_bcs=[], col_bcs=[], fc_params=None, appctx=None):
        self.a = a
        self.aT = a.T if isinstance(self.a, slate.TensorBase) else adjoint(a)
        self.fc_params = fc_params
        self.appctx = appctx

        self.row_bcs = row_bcs
        self.col_bcs = col_bcs

        # create functions from test and trial space to help
        # with 1-form assembly
        test_space, trial_space = [
            a.arguments()[i].function_space() for i in (0, 1)
        ]
        from firedrake import function

        self._y = function.Function(test_space)
        self._x = function.Function(trial_space)

        # These are temporary storage for holding the BC
        # values during matvec application.  _xbc is for
        # the action and ._ybc is for transpose.
        if len(self.row_bcs) > 0:
            self._xbc = function.Function(trial_space)
        if len(self.col_bcs) > 0:
            self._ybc = function.Function(test_space)

        # Get size information from template vecs on test and trial spaces
        trial_vec = trial_space.dof_dset.layout_vec
        test_vec = test_space.dof_dset.layout_vec
        self.col_sizes = trial_vec.getSizes()
        self.row_sizes = test_vec.getSizes()

        self.block_size = (test_vec.getBlockSize(), trial_vec.getBlockSize())

        if isinstance(self.a, slate.TensorBase):
            self.action = self.a * slate.AssembledVector(self._x)
            self.actionT = self.aT * slate.AssembledVector(self._y)
        else:
            self.action = action(self.a, self._x)
            self.actionT = action(self.aT, self._y)

        from firedrake.assemble import create_assembly_callable
        self._assemble_action = create_assembly_callable(
            self.action,
            tensor=self._y,
            form_compiler_parameters=self.fc_params)

        self._assemble_actionT = create_assembly_callable(
            self.actionT,
            tensor=self._x,
            form_compiler_parameters=self.fc_params)
Example #7
0
    def __init__(self, a, L, u, bcs=None, aP=None,
                 form_compiler_parameters=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to ``False``.
        """
        # In the linear case, the Jacobian is the equation LHS.
        J = a
        # Jacobian is checked in superclass, but let's check L here.
        if not isinstance(L, ufl.Form):
            raise TypeError("Provided RHS is a '%s', not a Form" % type(L).__name__)
        if len(L.arguments()) != 1:
            raise ValueError("Provided RHS is not a linear form")

        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J, aP,
                                                       form_compiler_parameters=form_compiler_parameters)
        self._constant_jacobian = constant_jacobian
Example #8
0
def laplace_coeff_action_forms(mesh, el, coeff_el):
    Q = dolfin.function.functionspace.FunctionSpace(mesh, el)

    u = dolfin.function.argument.TrialFunction(Q)
    v = dolfin.function.argument.TestFunction(Q)

    """
    def boundary(x):
        return np.sum(np.logical_or(x < DOLFIN_EPS, x > 1.0 - DOLFIN_EPS), axis=1) > 0
    """

    # u_bc = dolfin.function.constant.Constant(50.0)
    # bc = dolfin.fem.dirichletbc.DirichletBC(Q, u_bc, boundary)

    c = dolfin.function.expression.Expression("3.14*x[0]", element=coeff_el)
    f = dolfin.function.expression.Expression("0.4*x[1]*x[2]", element=el)

    a = inner(c * grad(u), grad(v)) * dx
    L = f * v * dx

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

    L = ufl.action(a, w)

    return None, L, None
Example #9
0
def test_mass_action(form, cell, order):
    degrees = numpy.arange(4, 10)
    flops = [
        count_flops(action(form(cell, int(degree)))) for degree in degrees
    ]
    rates = numpy.diff(numpy.log(flops)) / numpy.diff(numpy.log(degrees + 1))
    assert (rates < order).all()
Example #10
0
    def __init__(self, a, L, u, bcs=None, aP=None,
                 form_compiler_parameters=None,
                 nest=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param nest: indicate if matrices on mixed spaces should be
               built as monolithic operators (suitable for direct
               solves), or as nested blocks (suitable for fieldsplit
               preconditioning).  If not provided, uses the default
               given by :data:`parameters["matnest"]`.
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to :data:`False`.
        """

        # In the linear case, the Jacobian is the equation LHS.
        J = a
        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J, aP,
                                                       form_compiler_parameters=form_compiler_parameters, nest=nest)
        self._constant_jacobian = constant_jacobian
    def __init__(self, a, L, u, bcs=None, aP=None,
                 form_compiler_parameters=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to ``False``.
        """
        # In the linear case, the Jacobian is the equation LHS.
        J = a
        # Jacobian is checked in superclass, but let's check L here.
        if not isinstance(L, ufl.Form):
            raise TypeError("Provided RHS is a '%s', not a Form" % type(L).__name__)
        if len(L.arguments()) != 1:
            raise ValueError("Provided RHS is not a linear form")

        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J, aP,
                                                       form_compiler_parameters=form_compiler_parameters)
        self._constant_jacobian = constant_jacobian
Example #12
0
 def error_estimate(self):
     """
     Generate and return functional defining error estimate
     """
     # Error estimate defined as r(Ez_h):
     eta_h = action(self.weak_residual, self._Ez_h)
     return eta_h
def verify_assembly(J, rhs, J_mat, b, bcs, form_compiler_parameters,
                    linear_solver_parameters, J_tolerance, b_tolerance):
    if J_mat is not None and not np.isposinf(J_tolerance):
        J_mat_debug = backend_assemble(
            J, bcs=bcs, **assemble_arguments(2,
                                             form_compiler_parameters,
                                             linear_solver_parameters))
        assert J_mat.petscmat.assembled
        J_error = J_mat.petscmat.copy()
        J_error.axpy(-1.0, J_mat_debug.petscmat)
        assert J_error.assembled
        assert J_error.norm(norm_type=PETSc.NormType.NORM_INFINITY) \
            <= J_tolerance * J_mat.petscmat.norm(norm_type=PETSc.NormType.NORM_INFINITY)  # noqa: E501

    if b is not None and not np.isposinf(b_tolerance):
        F = backend_Function(rhs.arguments()[0].function_space())
        for bc in bcs:
            bc.apply(F)
        b_debug = backend_assemble(
            rhs - ufl.action(J, F), bcs=bcs,
            form_compiler_parameters=form_compiler_parameters)
        b_error = b.copy(deepcopy=True)
        with b_error.dat.vec as b_error_v, b_debug.dat.vec_ro as b_debug_v:
            b_error_v.axpy(-1.0, b_debug_v)
        with b_error.dat.vec_ro as b_error_v, b.dat.vec_ro as b_v:
            assert b_error_v.norm(norm_type=PETSc.NormType.NORM_INFINITY) \
                <= b_tolerance * b_v.norm(norm_type=PETSc.NormType.NORM_INFINITY)  # noqa: E501
Example #14
0
    def __init__(self, a, L, u, bcs=None, aP=None,
                 form_compiler_parameters=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to :data:`False`.
        """

        # In the linear case, the Jacobian is the equation LHS.
        J = a
        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J, aP,
                                                       form_compiler_parameters=form_compiler_parameters)
        self._constant_jacobian = constant_jacobian
Example #15
0
    def adjoint_derivative_action(self, nl_deps, dep_index, adj_x):
        # Derived from EquationSolver.derivative_action (see dolfin-adjoint
        # reference below). Code first added 2017-12-07.
        # Re-written 2018-01-28
        # Updated to adjoint only form 2018-01-29

        eq_deps = self.dependencies()
        if dep_index < 0 or dep_index >= len(eq_deps):
            raise EquationException("dep_index out of bounds")
        elif dep_index == 0:
            return adj_x

        dep = eq_deps[dep_index]
        dF = derivative(self._rhs, dep)
        dF = ufl.algorithms.expand_derivatives(dF)
        dF = eliminate_zeros(dF)
        if dF.empty():
            return None

        dF = ufl.replace(dF, dict(zip(self.nonlinear_dependencies(), nl_deps)))
        if self._rank == 0:
            dF = assemble(
                dF, form_compiler_parameters=self._form_compiler_parameters)
            return (-real_function_value(adj_x), dF)
        else:
            assert self._rank == 1
            dF = assemble(
                ufl.action(adjoint(dF), adj_x),
                form_compiler_parameters=self._form_compiler_parameters)
            return (-1.0, dF)
Example #16
0
    def adjoint_derivative_action(self, nl_deps, dep_index, adj_x):
        # Derived from EquationSolver.derivative_action (see dolfin-adjoint
        # reference below). Code first added 2017-12-07.
        # Re-written 2018-01-28
        # Updated to adjoint only form 2018-01-29

        eq_deps = self.dependencies()
        if dep_index < 0 or dep_index >= len(eq_deps):
            raise EquationException("dep_index out of bounds")
        elif dep_index == 0:
            return adj_x

        dep = eq_deps[dep_index]
        dF = derivative(self._rhs, dep)
        dF = ufl.algorithms.expand_derivatives(dF)
        dF = eliminate_zeros(dF)
        if dF.empty():
            return None

        dF = self._nonlinear_replace(dF, nl_deps)
        if self._rank == 0:
            dF = ufl.Form([integral.reconstruct(integrand=ufl.conj(integral.integrand()))  # noqa: E501
                           for integral in dF.integrals()])  # dF = adjoint(dF)
            dF = assemble(
                dF, form_compiler_parameters=self._form_compiler_parameters)
            return (-function_scalar_value(adj_x), dF)
        else:
            assert self._rank == 1
            dF = assemble(
                ufl.action(adjoint(dF), coefficient=adj_x),
                form_compiler_parameters=self._form_compiler_parameters)
            return (-1.0, dF)
Example #17
0
 def error_estimate(self):
     """
     Generate and return functional defining error estimate
     """
     # Error estimate defined as r(Ez_h):
     eta_h = action(self.weak_residual, self._Ez_h)
     return eta_h
Example #18
0
    def __init__(self, a, L, u, bcs=None, aP=None,
                 form_compiler_parameters=None,
                 nest=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param nest: indicate if matrices on mixed spaces should be
               built as monolithic operators (suitable for direct
               solves), or as nested blocks (suitable for fieldsplit
               preconditioning).  If not provided, uses the default
               given by :data:`parameters["matnest"]`.
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to :data:`False`.
        """

        # In the linear case, the Jacobian is the equation LHS.
        J = a
        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J, aP,
                                                       form_compiler_parameters=form_compiler_parameters, nest=nest)
        self._constant_jacobian = constant_jacobian
Example #19
0
def test_rhs(cell, order):
    degrees = list(range(3, 8))
    if cell == TensorProductCell(triangle, interval):
        degrees = list(range(3, 6))
    flops = [count_flops(action(helmholtz(cell, degree)))
             for degree in degrees]
    rates = numpy.diff(numpy.log(flops)) / numpy.diff(numpy.log(degrees))
    assert (rates < order).all()
Example #20
0
    def __init__(self, a, row_bcs=[], col_bcs=[],
                 fc_params=None, appctx=None):
        self.a = a
        self.aT = adjoint(a)
        self.fc_params = fc_params
        self.appctx = appctx

        self.row_bcs = row_bcs
        self.col_bcs = col_bcs

        # create functions from test and trial space to help
        # with 1-form assembly
        test_space, trial_space = [
            a.arguments()[i].function_space() for i in (0, 1)
        ]
        from firedrake import function

        self._y = function.Function(test_space)
        self._x = function.Function(trial_space)

        # These are temporary storage for holding the BC
        # values during matvec application.  _xbc is for
        # the action and ._ybc is for transpose.
        if len(self.row_bcs) > 0:
            self._xbc = function.Function(trial_space)
        if len(self.col_bcs) > 0:
            self._ybc = function.Function(test_space)

        # Get size information from template vecs on test and trial spaces
        trial_vec = trial_space.dof_dset.layout_vec
        test_vec = test_space.dof_dset.layout_vec
        self.col_sizes = trial_vec.getSizes()
        self.row_sizes = test_vec.getSizes()

        self.block_size = (test_vec.getBlockSize(), trial_vec.getBlockSize())

        self.action = action(self.a, self._x)
        self.actionT = action(self.aT, self._y)

        from firedrake.assemble import create_assembly_callable
        self._assemble_action = create_assembly_callable(self.action, tensor=self._y,
                                                         form_compiler_parameters=self.fc_params)

        self._assemble_actionT = create_assembly_callable(self.actionT, tensor=self._x,
                                                          form_compiler_parameters=self.fc_params)
Example #21
0
def test_vector_laplace_action(cell, order):
    degrees = numpy.arange(3, 8)
    if cell == TensorProductCell(triangle, interval):
        degrees = numpy.arange(3, 6)
    flops = [[count_flops(action(form))
              for form in split_vector_laplace(cell, int(degree))]
             for degree in degrees]
    rates = numpy.diff(numpy.log(flops).T) / numpy.diff(numpy.log(degrees))
    assert (rates < order).all()
Example #22
0
def vjp_solve_eval_impl(
    g: np.array,
    fenics_solution: fenics.Function,
    fenics_residual: ufl.Form,
    fenics_inputs: List[FenicsVariable],
    bcs: List[fenics.DirichletBC],
) -> Tuple[np.array]:
    """Computes the gradients of the output with respect to the inputs."""
    # Convert tangent covector (adjoint) to a FEniCS variable
    adj_value = numpy_to_fenics(g, fenics_solution)
    adj_value = adj_value.vector()

    F = fenics_residual
    u = fenics_solution
    V = u.function_space()
    dFdu = fenics.derivative(F, u)
    adFdu = ufl.adjoint(
        dFdu, reordered_arguments=ufl.algorithms.extract_arguments(dFdu)
    )

    u_adj = fenics.Function(V)
    adj_F = ufl.action(adFdu, u_adj)
    adj_F = ufl.replace(adj_F, {u_adj: fenics.TrialFunction(V)})
    adj_F_assembled = fenics.assemble(adj_F)

    if len(bcs) != 0:
        for bc in bcs:
            bc.homogenize()
        hbcs = bcs

        for bc in hbcs:
            bc.apply(adj_F_assembled)
            bc.apply(adj_value)

    fenics.solve(adj_F_assembled, u_adj.vector(), adj_value)

    fenics_grads = []
    for fenics_input in fenics_inputs:
        if isinstance(fenics_input, fenics.Function):
            V = fenics_input.function_space()
        dFdm = fenics.derivative(F, fenics_input, fenics.TrialFunction(V))
        adFdm = fenics.adjoint(dFdm)
        result = fenics.assemble(-adFdm * u_adj)
        if isinstance(fenics_input, fenics.Constant):
            fenics_grad = fenics.Constant(result.sum())
        else:  # fenics.Function
            fenics_grad = fenics.Function(V, result)
        fenics_grads.append(fenics_grad)

    # Convert FEniCS gradients to jax array representation
    jax_grads = (
        None if fg is None else np.asarray(fenics_to_numpy(fg)) for fg in fenics_grads
    )

    jax_grad_tuple = tuple(jax_grads)

    return jax_grad_tuple
Example #23
0
 def _rhs(self):
     from firedrake.assemble import create_assembly_callable
     u = function.Function(self.trial_space)
     b = function.Function(self.test_space)
     if isinstance(self.A.a, slate.TensorBase):
         expr = -self.A.a * slate.AssembledVector(u)
     else:
         expr = -ufl.action(self.A.a, u)
     return u, create_assembly_callable(expr, tensor=b), b
Example #24
0
    def _Abcs(self):
        """A function storing the action of the operator on a zero Function
        satisfying the BCs.

        Used in the presence of BCs.
        """
        b = function.Function(self._W)
        for bc in self.A.bcs:
            bc.apply(b)
        return assemble._assemble(ufl.action(self.A.a, b))
def _Matrix_mul(self, other):
    return_value = backend_Matrix._tlm_adjoint__orig___mul__(self, other)
    if hasattr(self, "_tlm_adjoint__form") \
       and hasattr(other, "_tlm_adjoint__function") \
       and len(self._tlm_adjoint__bcs) == 0:
        return_value._tlm_adjoint__form = ufl.action(
            self._tlm_adjoint__form, coefficient=other._tlm_adjoint__function)
        return_value._tlm_adjoint__bcs = []
        return_value._tlm_adjoint__form_compiler_parameters \
            = self._tlm_adjoint__form_compiler_parameters
    return return_value
Example #26
0
    def _Abcs(self):
        """A function storing the action of the operator on a zero Function
        satisfying the BCs.

        Used in the presence of BCs.
        """
        b = function.Function(self._W)
        for bc in self.A.bcs:
            bc.apply(b)
        from firedrake.assemble import _assemble
        return _assemble(ufl.action(self.A.a, b))
Example #27
0
def forward(x):
    u = fn.TrialFunction(V)
    w = fn.TestFunction(V)
    sigma = lmbda * tr(sym(grad(u))) * Identity(2) + 2 * G * sym(
        grad(u))  # Stress
    R = simp(x) * inner(sigma, grad(w)) * dx - dot(b, w) * dx
    a, L = ufl.lhs(R), ufl.rhs(R)
    u = fn.Function(V)
    F = L - ufl.action(a, u)
    fn.solve(a == L, u, bcs)
    return u, F, bcs
Example #28
0
def action(form, coefficient):
    """Compute the action of a form on a coefficient.

    :arg form: A UFL form, or a Slate tensor.
    :arg coefficient: The :class:`~.Function` to act on.
    :returns: a symbolic expression for the action.
    """
    if isinstance(form, firedrake.slate.TensorBase):
        if form.rank == 0:
            raise ValueError("Can't take action of rank-0 tensor")
        return form * firedrake.AssembledVector(coefficient)
    else:
        return ufl.action(form, coefficient)
Example #29
0
 def _form_action(self, u):
     """Assemble the form action of this :class:`Matrix`' bilinear form
     onto the :class:`Function` ``u``.
     .. note::
         This is the form **without** any boundary conditions."""
     if not hasattr(self, '_a_action'):
         self._a_action = ufl.action(self._a, u)
     if hasattr(self, '_a_action_coeff'):
         self._a_action = ufl.replace(self._a_action, {self._a_action_coeff: u})
     self._a_action_coeff = u
     # Since we assemble the cached form, the kernels will already have
     # been compiled and stashed on the form the second time round
     return assemble._assemble(self._a_action)
Example #30
0
def action(form, coefficient):
    """Compute the action of a form on a coefficient.

    :arg form: A UFL form, or a Slate tensor.
    :arg coefficient: The :class:`~.Function` to act on.
    :returns: a symbolic expression for the action.
    """
    if isinstance(form, firedrake.slate.TensorBase):
        if form.rank == 0:
            raise ValueError("Can't take action of rank-0 tensor")
        return form * firedrake.AssembledVector(coefficient)
    else:
        return ufl.action(form, coefficient)
Example #31
0
    def _Abcs(self):
        """A function storing the action of the operator on a zero Function
        satisfying the BCs.

        Used in the presence of BCs.
        """
        b = function.Function(self._W)
        for bc in self.A.bcs:
            bc.apply(b)
        from firedrake.assemble import _assemble
        if isinstance(self.A.a, slate.TensorBase):
            return _assemble(self.A.a * b)
        else:
            return _assemble(ufl.action(self.A.a, b))
Example #32
0
    def _Abcs(self):
        """A function storing the action of the operator on a zero Function
        satisfying the BCs.

        Used in the presence of BCs.
        """
        b = function.Function(self._W)
        for bc in self.A.bcs:
            bc.apply(b)
        from firedrake.assemble import _assemble
        if isinstance(self.A.a, slate.TensorBase):
            return _assemble(self.A.a * slate.AssembledVector(b))
        else:
            return _assemble(ufl.action(self.A.a, b))
Example #33
0
    def __init__(self,
                 a,
                 L,
                 u,
                 bcs=None,
                 aP=None,
                 form_compiler_parameters=None,
                 nest=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param nest: indicate if matrices on mixed spaces should be
               built as monolithic operators (suitable for direct
               solves), or as nested blocks (suitable for fieldsplit
               preconditioning).  If not provided, uses the default
               given by ``parameters["matnest"]``.
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to ``False``.
        """
        # In the linear case, the Jacobian is the equation LHS.
        J = a
        # Jacobian is checked in superclass, but let's check L here.
        if not isinstance(L, ufl.Form):
            raise TypeError("Provided RHS is a '%s', not a Form" %
                            type(L).__name__)
        if len(L.arguments()) != 1:
            raise ValueError("Provided RHS is not a linear form")

        F = ufl.action(J, u) - L

        super(LinearVariationalProblem,
              self).__init__(F,
                             u,
                             bcs,
                             J,
                             aP,
                             form_compiler_parameters=form_compiler_parameters,
                             nest=nest)
        self._constant_jacobian = constant_jacobian
Example #34
0
 def _form_action(self, u):
     """Assemble the form action of this :class:`Matrix`' bilinear form
     onto the :class:`Function` ``u``.
     .. note::
         This is the form **without** any boundary conditions."""
     if not hasattr(self, '_a_action'):
         self._a_action = ufl.action(self._a, u)
     if hasattr(self, '_a_action_coeff'):
         self._a_action = ufl.replace(self._a_action,
                                      {self._a_action_coeff: u})
     self._a_action_coeff = u
     # Since we assemble the cached form, the kernels will already have
     # been compiled and stashed on the form the second time round
     from firedrake.assemble import _assemble
     return _assemble(self._a_action)
Example #35
0
    def __init__(self, a, L, u, bcs=None,
                 form_compiler_parameters=None):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        """

        # In the linear case, the Jacobian is the equation LHS.
        J = a
        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J,
                                                       form_compiler_parameters)
Example #36
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
Example #37
0
def jvp_solve_eval(
    fenics_function: Callable,
    fenics_templates: Iterable[FenicsVariable],
    primals: Tuple[np.array],
    tangents: Tuple[np.array],
) -> Tuple[np.array]:
    """Computes the tangent linear model
    """

    (
        numpy_output_primal,
        fenics_solution_primal,
        residual_form,
        fenics_primals,
        bcs,
    ) = solve_eval(fenics_function, fenics_templates, *primals)

    # Now tangent evaluation!
    F = residual_form
    u = fenics_solution_primal
    V = u.function_space()

    if len(bcs) != 0:
        for bc in bcs:
            bc.homogenize()
    hbcs = bcs

    fenics_tangents = convert_all_to_fenics(fenics_primals, *tangents)
    fenics_output_tangents = []
    for fp, ft in zip(fenics_primals, fenics_tangents):
        dFdu = fenics.derivative(F, u)
        dFdm = fenics.derivative(F, fp, ft)
        u_tlm = fenics.Function(V)
        tlm_F = ufl.action(dFdu, u_tlm) + dFdm
        tlm_F = ufl.replace(tlm_F, {u_tlm: fenics.TrialFunction(V)})
        fenics.solve(ufl.lhs(tlm_F) == ufl.rhs(tlm_F), u_tlm, bcs=hbcs)
        fenics_output_tangents.append(u_tlm)

    jax_output_tangents = (fenics_to_numpy(ft)
                           for ft in fenics_output_tangents)
    jax_output_tangent = sum(jax_output_tangents)

    return numpy_output_primal, jax_output_tangent
Example #38
0
    def __init__(self, a, L, u, bcs=None, aP=None,
                 form_compiler_parameters=None,
                 nest=None,
                 constant_jacobian=True):
        """
        :param a: the bilinear form
        :param L: the linear form
        :param u: the :class:`.Function` to solve for
        :param bcs: the boundary conditions (optional)
        :param aP: an optional operator to assemble to precondition
                 the system (if not provided a preconditioner may be
                 computed from ``a``)
        :param dict form_compiler_parameters: parameters to pass to the form
            compiler (optional)
        :param nest: indicate if matrices on mixed spaces should be
               built as monolithic operators (suitable for direct
               solves), or as nested blocks (suitable for fieldsplit
               preconditioning).  If not provided, uses the default
               given by ``parameters["matnest"]``.
        :param constant_jacobian: (optional) flag indicating that the
                 Jacobian is constant (i.e. does not depend on
                 varying fields).  If your Jacobian can change, set
                 this flag to ``False``.
        """
        # In the linear case, the Jacobian is the equation LHS.
        J = a
        # Jacobian is checked in superclass, but let's check L here.
        if not isinstance(L, ufl.Form):
            raise TypeError("Provided RHS is a '%s', not a Form" % type(L).__name__)
        if len(L.arguments()) != 1:
            raise ValueError("Provided RHS is not a linear form")

        F = ufl.action(J, u) - L

        super(LinearVariationalProblem, self).__init__(F, u, bcs, J, aP,
                                                       form_compiler_parameters=form_compiler_parameters, nest=nest)
        self._constant_jacobian = constant_jacobian
Example #39
0
#
# Author: Martin Sandve Alnes
# Date: 2008-10-30
#
from ufl import (Coefficient, FiniteElement, action, adjoint, derivative, dx,
                 grad, inner, triangle)

element = FiniteElement("Lagrange", triangle, 1)

w = Coefficient(element)

# H1 semi-norm
f = inner(grad(w), grad(w)) / 2 * dx
# grad(w) : grad(v)
b = derivative(f, w)
# stiffness matrix, grad(u) : grad(v)
a = derivative(b, w)

# adjoint, grad(v) : grad(u)
astar = adjoint(a)
# action of adjoint, grad(v) : grad(w)
astaraction = action(astar)

forms = [f, b, a, astar, astaraction]
Example #40
0
    def __init__(self, eq, x, bcs=[], J=None, form_compiler_parameters={},
                 solver_parameters={}, adjoint_solver_parameters=None,
                 tlm_solver_parameters=None, initial_guess=None,
                 cache_jacobian=None, cache_adjoint_jacobian=None,
                 cache_tlm_jacobian=None, cache_rhs_assembly=None,
                 match_quadrature=None, defer_adjoint_assembly=None):
        if isinstance(bcs, backend_DirichletBC):
            bcs = (bcs,)
        else:
            bcs = tuple(bcs)
        if cache_jacobian is None:
            if not parameters["tlm_adjoint"]["EquationSolver"]["enable_jacobian_caching"]:  # noqa: E501
                cache_jacobian = False
        if cache_rhs_assembly is None:
            cache_rhs_assembly = parameters["tlm_adjoint"]["EquationSolver"]["cache_rhs_assembly"]  # noqa: E501
        if match_quadrature is None:
            match_quadrature = parameters["tlm_adjoint"]["EquationSolver"]["match_quadrature"]  # noqa: E501
        if defer_adjoint_assembly is None:
            defer_adjoint_assembly = parameters["tlm_adjoint"]["EquationSolver"]["defer_adjoint_assembly"]  # noqa: E501
        if match_quadrature and defer_adjoint_assembly:
            raise EquationException("Cannot both match quadrature and defer adjoint assembly")  # noqa: E501

        lhs, rhs = eq.lhs, eq.rhs
        del eq
        lhs = ufl.classes.Form(lhs.integrals())
        linear = isinstance(rhs, ufl.classes.Form)
        if linear:
            rhs = ufl.classes.Form(rhs.integrals())
        if J is not None:
            J = ufl.classes.Form(J.integrals())

        if linear:
            if x in lhs.coefficients() or x in rhs.coefficients():
                raise EquationException("Invalid non-linear dependency")
            F = ufl.action(lhs, coefficient=x) + form_neg(rhs)
            nl_solve_J = None
            J = lhs
        else:
            F = lhs
            if rhs != 0:
                raise EquationException("Invalid right-hand-side")
            nl_solve_J = J
            J = derivative(F, x)
            J = ufl.algorithms.expand_derivatives(J)

        deps, nl_deps = extract_dependencies(F)

        if nl_solve_J is not None:
            for dep in nl_solve_J.coefficients():
                if is_function(dep):
                    dep_id = function_id(dep)
                    if dep_id not in deps:
                        deps[dep_id] = dep

        if initial_guess is not None:
            warnings.warn("'initial_guess' argument is deprecated",
                          DeprecationWarning, stacklevel=2)
            if initial_guess == x:
                initial_guess = None
            else:
                initial_guess_id = function_id(initial_guess)
                if initial_guess_id not in deps:
                    deps[initial_guess_id] = initial_guess

        deps = list(deps.values())
        if x in deps:
            deps.remove(x)
        deps.insert(0, x)
        nl_deps = tuple(nl_deps.values())

        hbcs = tuple(homogenized_bc(bc) for bc in bcs)

        if cache_jacobian is None:
            cache_jacobian = is_cached(J) and bcs_is_cached(bcs)
        if cache_adjoint_jacobian is None:
            cache_adjoint_jacobian = cache_jacobian
        if cache_tlm_jacobian is None:
            cache_tlm_jacobian = cache_jacobian

        if nl_solve_J is None:
            (solver_parameters, linear_solver_parameters,
             ic, J_ic) = process_solver_parameters(solver_parameters, linear)
        else:
            (solver_parameters, _,
             ic, _) = process_solver_parameters(solver_parameters, linear)
            (_, linear_solver_parameters,
             _, J_ic) = process_solver_parameters(solver_parameters, linear)

        if adjoint_solver_parameters is None:
            adjoint_solver_parameters = process_adjoint_solver_parameters(linear_solver_parameters)  # noqa: E501
            adj_ic = J_ic
        else:
            (_, adjoint_solver_parameters,
             adj_ic, _) = process_solver_parameters(adjoint_solver_parameters, linear=True)  # noqa: E501

        if tlm_solver_parameters is not None:
            (_, tlm_solver_parameters,
             _, _) = process_solver_parameters(tlm_solver_parameters, linear=True)  # noqa: E501

        form_compiler_parameters_ = copy_parameters_dict(parameters["form_compiler"])  # noqa: E501
        update_parameters_dict(form_compiler_parameters_,
                               form_compiler_parameters)
        form_compiler_parameters = form_compiler_parameters_
        if match_quadrature:
            update_parameters_dict(
                form_compiler_parameters,
                form_form_compiler_parameters(F, form_compiler_parameters))

        super().__init__(x, deps, nl_deps=nl_deps,
                         ic=initial_guess is None and ic,
                         adj_ic=adj_ic)
        self._F = F
        self._lhs, self._rhs = lhs, rhs
        self._bcs = bcs
        self._hbcs = hbcs
        self._J = J
        self._nl_solve_J = nl_solve_J
        self._form_compiler_parameters = form_compiler_parameters
        self._solver_parameters = solver_parameters
        self._linear_solver_parameters = linear_solver_parameters
        self._adjoint_solver_parameters = adjoint_solver_parameters
        self._tlm_solver_parameters = tlm_solver_parameters
        if initial_guess is None:
            self._initial_guess_index = None
        else:
            self._initial_guess_index = deps.index(initial_guess)
        self._linear = linear

        self._cache_jacobian = cache_jacobian
        self._cache_adjoint_jacobian = cache_adjoint_jacobian
        self._cache_tlm_jacobian = cache_tlm_jacobian
        self._cache_rhs_assembly = cache_rhs_assembly
        self._defer_adjoint_assembly = defer_adjoint_assembly

        self._forward_eq = None
        self._forward_J_solver = CacheRef()
        self._forward_b_pa = None

        self._adjoint_dF_cache = {}
        self._adjoint_action_cache = {}

        self._adjoint_J_solver = CacheRef()
        self._adjoint_J = None
Example #41
0
def _compileUFL(integrands, form, *args, tempVars=True):
    if isinstance(form, Equation):
        form = form.lhs - form.rhs
    if not isinstance(form, Form):
        raise ValueError("ufl.Form or ufl.Equation expected.")

    # added for dirichlet treatment same as conservationlaw model
    dirichletBCs = [arg for arg in args if isinstance(arg, DirichletBC)]

    uflExpr = [form] + [bc.ufl_value for bc in dirichletBCs]
    if len(form.arguments()) < 2:
        raise ValueError(
            "Integrands model requires form with at least two arguments.")

    x = SpatialCoordinate(form.ufl_cell())
    n = FacetNormal(form.ufl_cell())

    cellVolume = CellVolume(form.ufl_cell())
    maxCellEdgeLength = MaxCellEdgeLength(form.ufl_cell())
    minCellEdgeLength = MinCellEdgeLength(form.ufl_cell())

    facetArea = FacetArea(form.ufl_cell())
    maxFacetEdgeLength = MaxFacetEdgeLength(form.ufl_cell())
    minFacetEdgeLength = MinFacetEdgeLength(form.ufl_cell())

    phi, u = form.arguments()
    ubar = Coefficient(u.ufl_function_space())

    derivatives = gatherDerivatives(form, [phi, u])

    derivatives_phi = derivatives[0]
    derivatives_u = derivatives[1]
    derivatives_ubar = map_expr_dags(Replacer({u: ubar}), derivatives_u)

    try:
        integrands.field = u.ufl_function_space().field
    except AttributeError:
        pass

    integrals = splitForm(form, [phi])

    dform = apply_derivatives(derivative(action(form, ubar), ubar, u))
    linearizedIntegrals = splitForm(dform, [phi, u])

    if not set(
            integrals.keys()) <= {'cell', 'exterior_facet', 'interior_facet'}:
        raise Exception('unknown integral encountered in ' +
                        str(set(integrals.keys())) + '.')

    if 'cell' in integrals.keys():
        arg = Variable(integrands.domainValueTuple, 'u')

        predefined = {
            derivatives_u[i]: arg[i]
            for i in range(len(derivatives_u))
        }
        predefined[x] = integrands.spatialCoordinate('x')
        predefined[cellVolume] = integrands.cellVolume()
        predefined[maxCellEdgeLength] = maxEdgeLength(
            integrands.cellGeometry())
        predefined[minCellEdgeLength] = minEdgeLength(
            integrands.cellGeometry())
        integrands.predefineCoefficients(predefined, False)
        integrands.interior = generateUnaryCode(predefined,
                                                derivatives_phi,
                                                integrals['cell'],
                                                tempVars=tempVars)

        predefined = {
            derivatives_ubar[i]: arg[i]
            for i in range(len(derivatives_u))
        }
        predefined[x] = integrands.spatialCoordinate('x')
        predefined[cellVolume] = integrands.cellVolume()
        predefined[maxCellEdgeLength] = maxEdgeLength(
            integrands.cellGeometry())
        predefined[minCellEdgeLength] = minEdgeLength(
            integrands.cellGeometry())
        integrands.predefineCoefficients(predefined, False)
        integrands.linearizedInterior = generateUnaryLinearizedCode(
            predefined,
            derivatives_phi,
            derivatives_u,
            linearizedIntegrals.get('cell'),
            tempVars=tempVars)

    if 'exterior_facet' in integrals.keys():
        arg = Variable(integrands.domainValueTuple, 'u')

        predefined = {
            derivatives_u[i]: arg[i]
            for i in range(len(derivatives_u))
        }
        predefined[x] = integrands.spatialCoordinate('x')
        predefined[n] = integrands.facetNormal('x')
        predefined[cellVolume] = integrands.cellVolume()
        predefined[maxCellEdgeLength] = maxEdgeLength(
            integrands.cellGeometry())
        predefined[minCellEdgeLength] = minEdgeLength(
            integrands.cellGeometry())
        predefined[facetArea] = integrands.facetArea()
        predefined[maxFacetEdgeLength] = maxEdgeLength(
            integrands.facetGeometry())
        predefined[minFacetEdgeLength] = minEdgeLength(
            integrands.facetGeometry())
        integrands.predefineCoefficients(predefined, False)
        integrands.boundary = generateUnaryCode(predefined,
                                                derivatives_phi,
                                                integrals['exterior_facet'],
                                                tempVars=tempVars)

        predefined = {
            derivatives_ubar[i]: arg[i]
            for i in range(len(derivatives_u))
        }
        predefined[x] = integrands.spatialCoordinate('x')
        predefined[n] = integrands.facetNormal('x')
        predefined[cellVolume] = integrands.cellVolume()
        predefined[maxCellEdgeLength] = maxEdgeLength(
            integrands.cellGeometry())
        predefined[minCellEdgeLength] = minEdgeLength(
            integrands.cellGeometry())
        predefined[facetArea] = integrands.facetArea()
        predefined[maxFacetEdgeLength] = maxEdgeLength(
            integrands.facetGeometry())
        predefined[minFacetEdgeLength] = minEdgeLength(
            integrands.facetGeometry())
        integrands.predefineCoefficients(predefined, False)
        integrands.linearizedBoundary = generateUnaryLinearizedCode(
            predefined,
            derivatives_phi,
            derivatives_u,
            linearizedIntegrals.get('exterior_facet'),
            tempVars=tempVars)

    if 'interior_facet' in integrals.keys():
        argIn = Variable(integrands.domainValueTuple, 'uIn')
        argOut = Variable(integrands.domainValueTuple, 'uOut')

        predefined = {
            derivatives_u[i](s): arg[i]
            for i in range(len(derivatives_u))
            for s, arg in (('+', argIn), ('-', argOut))
        }
        predefined[x] = integrands.spatialCoordinate('xIn')
        predefined[n('+')] = integrands.facetNormal('xIn')
        predefined[cellVolume('+')] = integrands.cellVolume('Side::in')
        predefined[cellVolume('-')] = integrands.cellVolume('Side::out')
        predefined[maxCellEdgeLength('+')] = maxEdgeLength(
            integrands.cellGeometry('Side::in'))
        predefined[maxCellEdgeLength('-')] = maxEdgeLength(
            integrands.cellGeometry('Side::out'))
        predefined[minCellEdgeLength('+')] = minEdgeLength(
            integrands.cellGeometry('Side::in'))
        predefined[minCellEdgeLength('-')] = minEdgeLength(
            integrands.cellGeometry('Side::out'))
        predefined[facetArea] = integrands.facetArea()
        predefined[maxFacetEdgeLength] = maxEdgeLength(
            integrands.facetGeometry())
        predefined[minFacetEdgeLength] = minEdgeLength(
            integrands.facetGeometry())
        integrands.predefineCoefficients(predefined, True)
        integrands.skeleton = generateBinaryCode(predefined,
                                                 derivatives_phi,
                                                 integrals['interior_facet'],
                                                 tempVars=tempVars)

        predefined = {
            derivatives_ubar[i](s): arg[i]
            for i in range(len(derivatives_u))
            for s, arg in (('+', argIn), ('-', argOut))
        }
        predefined[x] = integrands.spatialCoordinate('xIn')
        predefined[n('+')] = integrands.facetNormal('xIn')
        predefined[cellVolume('+')] = integrands.cellVolume('Side::in')
        predefined[cellVolume('-')] = integrands.cellVolume('Side::out')
        predefined[maxCellEdgeLength('+')] = maxEdgeLength(
            integrands.cellGeometry('Side::in'))
        predefined[maxCellEdgeLength('-')] = maxEdgeLength(
            integrands.cellGeometry('Side::out'))
        predefined[minCellEdgeLength('+')] = minEdgeLength(
            integrands.cellGeometry('Side::in'))
        predefined[minCellEdgeLength('-')] = minEdgeLength(
            integrands.cellGeometry('Side::out'))
        predefined[facetArea] = integrands.facetArea()
        predefined[maxFacetEdgeLength] = maxEdgeLength(
            integrands.facetGeometry())
        predefined[minFacetEdgeLength] = minEdgeLength(
            integrands.facetGeometry())
        integrands.predefineCoefficients(predefined, True)
        integrands.linearizedSkeleton = generateBinaryLinearizedCode(
            predefined,
            derivatives_phi,
            derivatives_u,
            linearizedIntegrals.get('interior_facet'),
            tempVars=tempVars)

    if dirichletBCs:
        integrands.hasDirichletBoundary = True

        predefined = {}
        # predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + integrands.arg_x.name + ' ) )')
        predefined[x] = UnformattedExpression(
            'auto', 'intersection.geometry().center( )')
        integrands.predefineCoefficients(predefined, False)

        maxId = 0
        codeDomains = []
        bySubDomain = dict()
        neuman = []
        wholeDomain = None
        for bc in dirichletBCs:
            if bc.subDomain in bySubDomain:
                raise Exception(
                    'Multiply defined Dirichlet boundary for subdomain ' +
                    str(bc.subDomain))
            if not isinstance(bc.functionSpace,
                              (FunctionSpace, FiniteElementBase)):
                raise Exception(
                    'Function space must either be a ufl.FunctionSpace or a ufl.FiniteElement'
                )
            if isinstance(bc.functionSpace, FunctionSpace) and (
                    bc.functionSpace != u.ufl_function_space()):
                raise Exception(
                    'Space of trial function and dirichlet boundary function must be the same - note that boundary conditions on subspaces are not available, yet'
                )
            if isinstance(bc.functionSpace, FiniteElementBase) and (
                    bc.functionSpace != u.ufl_element()):
                raise Exception(
                    'Cannot handle boundary conditions on subspaces, yet')

            if isinstance(bc.value, list):
                neuman = [i for i, x in enumerate(bc.value) if x == None]
            else:
                neuman = []

            value = ExprTensor(u.ufl_shape)
            for key in value.keys():
                value[key] = Indexed(
                    bc.ufl_value,
                    MultiIndex(tuple(FixedIndex(k) for k in key)))
            if bc.subDomain is None:
                wholeDomain = value, neuman
            elif isinstance(bc.subDomain, int):
                bySubDomain[bc.subDomain] = value, neuman
                maxId = max(maxId, bc.subDomain)
            else:
                domain = ExprTensor(())
                for key in domain.keys():
                    domain[key] = Indexed(
                        bc.subDomain,
                        MultiIndex(tuple(FixedIndex(k) for k in key)))
                codeDomains.append((value, neuman, domain))
        defaultCode = []
        if len(codeDomains) > 0:
            defaultCode.append(Declaration(Variable('int', 'domainId')))
        # defaultCode.append(Declaration(Variable('auto', 'x'),
        #     initializer=UnformattedExpression('auto','intersection.geometry().center()')))
        for i, v in enumerate(codeDomains):
            block = Block()
            block.append(
                generateDirichletDomainCode(predefined,
                                            v[2],
                                            tempVars=tempVars))
            block.append('if (domainId)')
            ifBlock = UnformattedBlock()
            ifBlock.append(
                'std::fill( dirichletComponent.begin(), dirichletComponent.end(), '
                + str(maxId + i + 2) + ' );')
            if len(v[1]) > 0:
                [
                    ifBlock.append('dirichletComponent[' + str(c) + '] = 0;')
                    for c in v[1]
                ]
            ifBlock.append('return true;')
            block.append(ifBlock)
            defaultCode.append(block)
        if wholeDomain is not None:
            block = UnformattedBlock()
            block.append(
                'std::fill( dirichletComponent.begin(), dirichletComponent.end(), '
                + str(maxId + 1) + ' );')
            if len(wholeDomain[1]) > 0:
                [
                    block.append('dirichletComponent[' + str(c) + '] = 0;')
                    for c in wholeDomain[1]
                ]
            block.append('return true;')
            defaultCode.append(block)
        defaultCode.append(return_(False))

        bndId = Variable('const int', 'bndId')
        getBndId = UnformattedExpression(
            'int', 'BoundaryIdProviderType::boundaryId( ' +
            integrands.arg_i.name + ' )')
        # getBndId = UnformattedExpression('int', 'boundaryIdGetter_.boundaryId( ' + integrands.arg_i.name + ' )')
        switch = SwitchStatement(bndId, default=defaultCode)
        for i, v in bySubDomain.items():
            code = []
            if len(v[1]) > 0:
                [
                    code.append('dirichletComponent[' + str(c) + '] = 0;')
                    for c in v[1]
                ]
            code.append(return_(True))
            switch.append(i, code)
        integrands.isDirichletIntersection = [
            Declaration(bndId, initializer=getBndId),
            UnformattedBlock(
                'std::fill( dirichletComponent.begin(), dirichletComponent.end(), '
                + bndId.name + ' );'), switch
        ]

        predefined[x] = UnformattedExpression(
            'auto', 'entity().geometry().global( Dune::Fem::coordinate( ' +
            integrands.arg_x.name + ' ) )')
        if wholeDomain is None:
            defaultCode = assign(integrands.arg_r, construct("RRangeType", 0))
        else:
            defaultCode = generateDirichletCode(predefined,
                                                wholeDomain[0],
                                                tempVars=tempVars)
        switch = SwitchStatement(integrands.arg_bndId, default=defaultCode)
        for i, v in bySubDomain.items():
            switch.append(
                i, generateDirichletCode(predefined, v[0], tempVars=tempVars))
        for i, v in enumerate(codeDomains):
            switch.append(
                i + maxId + 2,
                generateDirichletCode(predefined, v[0], tempVars=tempVars))
        integrands.dirichlet = [switch]

    return integrands
Example #42
0
def _action(A, x):
    A = ufl.algorithms.expand_derivatives(A)
    if A.integrals() != ():  # form is not empty:
        return ufl.action(A, x)
    else:
        return A  # form is empty, doesn't matter
Example #43
0
coord_element = VectorElement("Lagrange", triangle, 1)
mesh = Mesh(coord_element)

# Function Space
element = FiniteElement("Lagrange", triangle, 2)
V = FunctionSpace(mesh, element)

# Trial and test functions
u = TrialFunction(V)
v = TestFunction(V)

# Define a constant RHS
f = Constant(V)

# Define the bilinear and linear forms according to the
# variational formulation of the equations::
a = inner(grad(u), grad(v)) * dx
L = inner(f, v) * dx

# Define linear form representing the action of the form "a" on
# the coefficient "ui"
ui = Coefficient(V)
M = action(a, ui)

# Define form to compute the L2 norm of the error
usol = Coefficient(V)
uexact = Coefficient(V)
E = inner(usol - uexact, usol - uexact) * dx

forms = [M, L, E]
Example #44
0
def compileUFL(form, patch, *args, **kwargs):
    if isinstance(form, Equation):
        form = form.lhs - form.rhs
    if not isinstance(form, Form):
        raise Exception("ufl.Form expected.")
    if len(form.arguments()) < 2:
        raise Exception("ConservationLaw model requires form with at least two arguments.")

    phi_, u_ = form.arguments()

    if phi_.ufl_function_space().scalar:
        phi = TestFunction(phi_.ufl_function_space().toVectorSpace())
        form = replace(form,{phi_:phi[0]})
    else:
        phi = phi_
    if u_.ufl_function_space().scalar:
        u = TrialFunction(u_.ufl_function_space().toVectorSpace())
        form = replace(form,{u_:u[0]})
    else:
        u = u_
    _, coeff_ = extract_arguments_and_coefficients(form)
    coeff_ = set(coeff_)

    # added for dirichlet treatment same as conservationlaw model
    dirichletBCs = [arg for arg in args if isinstance(arg, DirichletBC)]
    # remove the dirichletBCs
    arg = [arg for arg in args if not isinstance(arg, DirichletBC)]
    for dBC in dirichletBCs:
        _, coeff__ = extract_arguments_and_coefficients(dBC.ufl_value)
        coeff_ |= set(coeff__)
    if patch is not None:
        for a in patch:
            try:
                _, coeff__ = extract_arguments_and_coefficients(a)
                coeff_ |= set(coeff__)
            except:
                pass # a might be a float/int and not a ufl expression

    coeff = {c : c.toVectorCoefficient()[0] for c in coeff_ if len(c.ufl_shape) == 0 and not c.is_cellwise_constant()}
    form = replace(form,coeff)
    for bc in dirichletBCs:
        bc.ufl_value = replace(bc.ufl_value, coeff)
    if patch is not None:
        patch = [a if not isinstance(a, Expr) else replace(a,coeff) for a in patch]

    phi = form.arguments()[0]
    dimRange = phi.ufl_shape[0]

    u = form.arguments()[1]
    du = Grad(u)
    d2u = Grad(du)
    ubar = Coefficient(u.ufl_function_space())
    dubar = Grad(ubar)
    d2ubar = Grad(dubar)
    dimDomain = u.ufl_shape[0]

    x = SpatialCoordinate(form.ufl_cell())

    try:
        field = u.ufl_function_space().field
    except AttributeError:
        field = "double"

    # if exact solution is passed in subtract a(u,.) from the form
    if "exact" in kwargs:
        b = replace(form, {u: as_vector(kwargs["exact"])} )
        form = form - b

    dform = apply_derivatives(derivative(action(form, ubar), ubar, u))

    source, flux, boundarySource = splitUFLForm(form)
    linSource, linFlux, linBoundarySource = splitUFLForm(dform)
    fluxDivergence, _, _ = splitUFLForm(inner(source.as_ufl() - div(flux.as_ufl()), phi) * dx(0))

    # split linNVSource off linSource
    # linSources = splitUFL2(u, du, d2u, linSource)
    # linNVSource = linSources[2]
    # linSource = linSources[0] + linSources[1]

    if patch is not None:
        model = ConservationLawModel(dimDomain, dimRange, u, modelSignature(form,*patch,*args))
    else:
        model = ConservationLawModel(dimDomain, dimRange, u, modelSignature(form,None,*args))
    model._replaceCoeff = coeff

    model.hasNeumanBoundary = not boundarySource.is_zero()

    #expandform = expand_indices(expand_derivatives(expand_compounds(equation.lhs)))
    #if expandform == adjoint(expandform):
    #    model.symmetric = 'true'
    model.field = field

    dirichletBCs = [arg for arg in args if isinstance(arg, DirichletBC)]
    # deprecated
    # if "dirichlet" in kwargs:
    #     dirichletBCs += [DirichletBC(u.ufl_function_space(), as_vector(value), bndId) for bndId, value in kwargs["dirichlet"].items()]

    uflCoefficients = set(form.coefficients())
    for bc in dirichletBCs:
        _, c = extract_arguments_and_coefficients(bc.ufl_value)
        uflCoefficients |= set(c)
    if patch is not None:
        for a in patch:
            if isinstance(a, Expr):
                _, c = extract_arguments_and_coefficients(a)
                uflCoefficients |= set(c)

    constants = dict()
    coefficients = dict()

    for coefficient in uflCoefficients:
        try:
            name = getattr(coefficient, "name")
        except AttributeError:
            name = str(coefficient)
        if coefficient.is_cellwise_constant():
            try:
                parameter = getattr(coefficient, "parameter")
            except AttributeError:
                parameter = None
            if len(coefficient.ufl_shape) == 0:
                constants[coefficient] = model.addConstant('double', name=name, parameter=parameter)
            elif len(coefficient.ufl_shape) == 1:
                constants[coefficient] = model.addConstant('Dune::FieldVector< double, ' + str(coefficient.ufl_shape[0]) + ' >', name=name, parameter=parameter)
            else:
                Exception('Currently, only scalars and vectors are supported as constants')
        else:
            shape = coefficient.ufl_shape[0]
            try:
                coefficients[coefficient] = model.addCoefficient(
                        shape,
                        coefficient.cppTypeName,
                        name=name,
                        field=coefficient.ufl_function_space().field)
            except AttributeError:
                coefficients[coefficient] = model.addCoefficient(
                        shape,
                        coefficient.cppTypeName,
                        name=name)

    model.coefficients = coefficients
    model.constants = constants

    tempVars = kwargs.get("tempVars", True)

    predefined = {u: model.arg_u, du: model.arg_du, d2u: model.arg_d2u}
    predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )')
    model.predefineCoefficients(predefined,'x')
    model.source = generateCode(predefined, source, tempVars=tempVars)
    model.flux = generateCode(predefined, flux, tempVars=tempVars)
    predefined.update({ubar: model.arg_ubar, dubar: model.arg_dubar, d2ubar: model.arg_d2ubar})
    model.linSource = generateCode(predefined, linSource, tempVars=tempVars)
    model.linFlux = generateCode(predefined, linFlux, tempVars=tempVars)

    # model.linNVSource = generateCode({u: arg, du: darg, d2u: d2arg, ubar: argbar, dubar: dargbar, d2ubar: d2argbar}, linNVSource, model.coefficients, tempVars)

    predefined = {u: model.arg_u}
    predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )')
    model.predefineCoefficients(predefined,'x')
    model.alpha = generateCode(predefined, boundarySource, tempVars=tempVars)
    predefined.update({ubar: model.arg_ubar})
    model.linAlpha = generateCode(predefined, linBoundarySource, tempVars=tempVars)

    predefined = {u: model.arg_u, du: model.arg_du, d2u: model.arg_d2u}
    predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )')
    model.predefineCoefficients(predefined,'x')
    model.fluxDivergence = generateCode(predefined, fluxDivergence, tempVars=tempVars)

    if dirichletBCs:
        model.hasDirichletBoundary = True

        predefined = {}
        predefined[x] = UnformattedExpression('auto', 'entity().geometry().global( Dune::Fem::coordinate( ' + model.arg_x.name + ' ) )')
        model.predefineCoefficients(predefined,'x')

        maxId = 0
        codeDomains = []
        bySubDomain = dict()
        neuman = []
        for bc in dirichletBCs:
            if bc.subDomain in bySubDomain:
                raise Exception('Multiply defined Dirichlet boundary for subdomain ' + str(bc.subDomain))
            if not isinstance(bc.functionSpace, (FunctionSpace, FiniteElementBase)):
                raise Exception('Function space must either be a ufl.FunctionSpace or a ufl.FiniteElement')
            if isinstance(bc.functionSpace, FunctionSpace) and (bc.functionSpace != u.ufl_function_space()):
                raise Exception('Space of trial function and dirichlet boundary function must be the same - note that boundary conditions on subspaces are not available, yet')
            if isinstance(bc.functionSpace, FiniteElementBase) and (bc.functionSpace != u.ufl_element()):
                raise Exception('Cannot handle boundary conditions on subspaces, yet')

            if isinstance(bc.value, list):
                neuman = [i for i, x in enumerate(bc.value) if x == None]
            else:
                neuman = []

            value = ExprTensor(u.ufl_shape)
            for key in value.keys():
                value[key] = Indexed(bc.ufl_value, MultiIndex(tuple(FixedIndex(k) for k in key)))
            if isinstance(bc.subDomain,int):
                bySubDomain[bc.subDomain] = value,neuman
                maxId = max(maxId, bc.subDomain)
            else:
                domain = ExprTensor(())
                for key in domain.keys():
                    domain[key] = Indexed(bc.subDomain, MultiIndex(tuple(FixedIndex(k) for k in key)))
                codeDomains.append( (value,neuman,domain) )
        defaultCode = []
        defaultCode.append(Declaration(Variable('int', 'domainId')))
        defaultCode.append(Declaration(Variable('auto', 'tmp0'),
            initializer=UnformattedExpression('auto','intersection.geometry().center()')))
        for i,v in enumerate(codeDomains):
            block = Block()
            defaultCode.append(
                    generateDirichletDomainCode(predefined, v[2], tempVars=tempVars))
            defaultCode.append('if (domainId)')
            block = UnformattedBlock()
            block.append('std::fill( dirichletComponent.begin(), dirichletComponent.end(), ' + str(maxId+i+1) + ' );')
            if len(v[1])>0:
                [block.append('dirichletComponent[' + str(c) + '] = 0;') for c in v[1]]
            block.append('return true;')
            defaultCode.append(block)
        defaultCode.append(return_(False))

        bndId = Variable('const int', 'bndId')
        getBndId = UnformattedExpression('int', 'BoundaryIdProviderType::boundaryId( ' + model.arg_i.name + ' )')
        switch = SwitchStatement(bndId, default=defaultCode)
        for i,v in bySubDomain.items():
            code = []
            if len(v[1])>0:
                [code.append('dirichletComponent[' + str(c) + '] = 0;') for c in v[1]]
            code.append(return_(True))
            switch.append(i, code)
        model.isDirichletIntersection = [Declaration(bndId, initializer=getBndId),
                                         UnformattedBlock('std::fill( dirichletComponent.begin(), dirichletComponent.end(), ' + bndId.name + ' );'),
                                         switch
                                        ]

        switch = SwitchStatement(model.arg_bndId, default=assign(model.arg_r, construct("RRangeType", 0)))
        for i, v in bySubDomain.items():
            switch.append(i, generateDirichletCode(predefined, v[0], tempVars=tempVars))
        for i,v in enumerate(codeDomains):
            switch.append(i+maxId+1, generateDirichletCode(predefined, v[0], tempVars=tempVars))
        model.dirichlet = [switch]

    return model
Example #45
0
def test_mass_action(form, cell, order):
    degrees = numpy.arange(4, 10)
    flops = [count_flops(action(form(cell, int(degree)))) for degree in degrees]
    rates = numpy.diff(numpy.log(flops)) / numpy.diff(numpy.log(degrees + 1))
    assert (rates < order).all()