예제 #1
0
    def indexed(self, o, Ap,
                ii):  # TODO: (Partially) duplicated in generic rules
        # Reuse if untouched
        if Ap is o.ufl_operands[0]:
            return o

        # Untangle as_tensor(C[kk], jj)[ii] -> C[ll] to simplify
        # resulting expression
        if isinstance(Ap, ComponentTensor):
            B, jj = Ap.ufl_operands
            if isinstance(B, Indexed):
                C, kk = B.ufl_operands

                kk = list(kk)
                if all(j in kk for j in jj):
                    Cind = list(kk)
                    for i, j in zip(ii, jj):
                        Cind[kk.index(j)] = i
                    return Indexed(C, MultiIndex(tuple(Cind)))

        # Otherwise a more generic approach
        r = len(Ap.ufl_shape) - len(ii)
        if r:
            kk = indices(r)
            op = Indexed(Ap, MultiIndex(ii.indices() + kk))
            op = as_tensor(op, kk)
        else:
            op = Indexed(Ap, ii)
        return op
예제 #2
0
    def indexed(self, o, Ap,
                ii):  # TODO: (Partially) duplicated in nesting rules
        # Propagate zeros
        if isinstance(Ap, Zero):
            return self.independent_operator(o)

        # Untangle as_tensor(C[kk], jj)[ii] -> C[ll] to simplify
        # resulting expression
        if isinstance(Ap, ComponentTensor):
            B, jj = Ap.ufl_operands
            if isinstance(B, Indexed):
                C, kk = B.ufl_operands
                kk = list(kk)
                if all(j in kk for j in jj):
                    rep = dict(zip(jj, ii))
                    Cind = [rep.get(k, k) for k in kk]
                    expr = Indexed(C, MultiIndex(tuple(Cind)))
                    assert expr.ufl_free_indices == o.ufl_free_indices
                    assert expr.ufl_shape == o.ufl_shape
                    return expr

        # Otherwise a more generic approach
        r = len(Ap.ufl_shape) - len(ii)
        if r:
            kk = indices(r)
            op = Indexed(Ap, MultiIndex(ii.indices() + kk))
            op = as_tensor(op, kk)
        else:
            op = Indexed(Ap, ii)
        return op
예제 #3
0
def test_index_simplification_reference_grad(self):
    mesh = Mesh(VectorElement("P", quadrilateral, 1))
    i, = indices(1)
    A = as_tensor(Indexed(Jacobian(mesh), MultiIndex((i, i))), (i,))
    expr = apply_derivatives(apply_geometry_lowering(
        apply_algebra_lowering(A[0])))
    assert expr == ReferenceGrad(SpatialCoordinate(mesh))[0, 0]
    assert expr.ufl_free_indices == ()
    assert expr.ufl_shape == ()
예제 #4
0
    def indexed(self, o, expr, multiindex):
        indices = list(multiindex)
        while indices and isinstance(expr, ListTensor) and isinstance(indices[0], FixedIndex):
            index = indices.pop(0)
            expr = expr.ufl_operands[int(index)]

        if indices:
            return Indexed(expr, MultiIndex(tuple(indices)))
        else:
            return expr
예제 #5
0
def test_index_simplification_handles_repeated_indices(self):
    mesh = Mesh(VectorElement("P", quadrilateral, 1))
    V = FunctionSpace(mesh, TensorElement("DQ", quadrilateral, 0))
    K = JacobianInverse(mesh)
    G = outer(Identity(2), Identity(2))
    i, j, k, l, m, n = indices(6)
    A = as_tensor(K[m, i] * K[n, j] * G[i, j, k, l], (m, n, k, l))
    i, j = indices(2)
    # Can't use A[i, i, j, j] because UFL automagically index-sums
    # repeated indices in the __getitem__ call.
    Adiag = Indexed(A, MultiIndex((i, i, j, j)))
    A = as_tensor(Adiag, (i, j))
    v = TestFunction(V)
    f = inner(A, v)*dx
    fd = compute_form_data(f, do_apply_geometry_lowering=True)
    integral, = fd.preprocessed_form.integrals()
    assert integral.integrand().ufl_free_indices == ()
예제 #6
0
def apply_mapping(expression, mapping, domain):
    """
    This applies the appropriate transformation to the
    given expression for interpolation to a specific
    element, according to the manner in which it maps
    from the reference cell.

    The following is borrowed from the UFC documentation:

    Let g be a field defined on a physical domain T with physical
    coordinates x. Let T_0 be a reference domain with coordinates
    X. Assume that F: T_0 -> T such that

      x = F(X)

    Let J be the Jacobian of F, i.e J = dx/dX and let K denote the
    inverse of the Jacobian K = J^{-1}. Then we (currently) have the
    following four types of mappings:

    'affine' mapping for g:

      G(X) = g(x)

    For vector fields g:

    'contravariant piola' mapping for g:

      G(X) = det(J) K g(x)   i.e  G_i(X) = det(J) K_ij g_j(x)

    'covariant piola' mapping for g:

      G(X) = J^T g(x)          i.e  G_i(X) = J^T_ij g(x) = J_ji g_j(x)

    'double covariant piola' mapping for g:

      G(X) = J^T g(x) J     i.e. G_il(X) = J_ji g_jk(x) J_kl

    'double contravariant piola' mapping for g:

      G(X) = det(J)^2 K g(x) K^T  i.e. G_il(X)=(detJ)^2 K_ij g_jk K_lk

    If 'contravariant piola' or 'covariant piola' are applied to a
    matrix-valued function, the appropriate mappings are applied row-by-row.

    :arg expression: UFL expression
    :arg mapping: a string indicating the mapping to apply
    """

    mesh = expression.ufl_domain()
    if mesh is None:
        mesh = domain
    if domain is not None and mesh != domain:
        raise NotImplementedError("Multiple domains not supported")
    rank = len(expression.ufl_shape)
    if mapping == "affine":
        return expression
    elif mapping == "covariant piola":
        J = Jacobian(mesh)
        *i, j, k = indices(len(expression.ufl_shape) + 1)
        expression = Indexed(expression, MultiIndex((*i, k)))
        return as_tensor(J.T[j, k] * expression, (*i, j))
    elif mapping == "contravariant piola":
        K = JacobianInverse(mesh)
        detJ = JacobianDeterminant(mesh)
        *i, j, k = indices(len(expression.ufl_shape) + 1)
        expression = Indexed(expression, MultiIndex((*i, k)))
        return as_tensor(detJ * K[j, k] * expression, (*i, j))
    elif mapping == "double covariant piola" and rank == 2:
        J = Jacobian(mesh)
        return J.T * expression * J
    elif mapping == "double contravariant piola" and rank == 2:
        K = JacobianInverse(mesh)
        detJ = JacobianDeterminant(mesh)
        return (detJ)**2 * K * expression * K.T
    else:
        raise NotImplementedError("Don't know how to handle mapping type %s for expression of rank %d" % (mapping, rank))
예제 #7
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
예제 #8
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
예제 #9
0
    def _mapped(self, t):
        # Check that we have a valid input object
        if not isinstance(t, Terminal):
            error("Expecting a Terminal.")

        # Get modifiers accumulated by previous handler calls
        ngrads = self._ngrads
        restricted = self._restricted
        avg = self._avg
        if avg != "":
            error("Averaging not implemented.")  # FIXME

        # These are the global (g) and reference (r) values
        if isinstance(t, FormArgument):
            g = t
            r = ReferenceValue(g)
        elif isinstance(t, GeometricQuantity):
            g = t
            r = g
        else:
            error("Unexpected type {0}.".format(type(t).__name__))

        # Some geometry mapping objects we may need multiple times below
        domain = t.ufl_domain()
        J = Jacobian(domain)
        detJ = JacobianDeterminant(domain)
        K = JacobianInverse(domain)

        # Restrict geometry objects if applicable
        if restricted:
            J = J(restricted)
            detJ = detJ(restricted)
            K = K(restricted)

        # Create Hdiv mapping from possibly restricted geometry objects
        Mdiv = (1.0 / detJ) * J

        # Get component indices of global and reference terminal objects
        gtsh = g.ufl_shape
        # rtsh = r.ufl_shape
        gtcomponents = compute_indices(gtsh)
        # rtcomponents = compute_indices(rtsh)

        # Create core modified terminal, with eventual
        # layers of grad applied directly to the terminal,
        # then eventual restriction applied last
        for i in range(ngrads):
            g = Grad(g)
            r = ReferenceGrad(r)
        if restricted:
            g = g(restricted)
            r = r(restricted)

        # Get component indices of global and reference objects with
        # grads applied
        gsh = g.ufl_shape
        # rsh = r.ufl_shape
        # gcomponents = compute_indices(gsh)
        # rcomponents = compute_indices(rsh)

        # Get derivative component indices
        dsh = gsh[len(gtsh):]
        dcomponents = compute_indices(dsh)

        # Create nested array to hold expressions for global
        # components mapped from reference values
        def ndarray(shape):
            if len(shape) == 0:
                return [None]
            elif len(shape) == 1:
                return [None] * shape[-1]
            else:
                return [ndarray(shape[1:]) for i in range(shape[0])]
        global_components = ndarray(gsh)

        # Compute mapping from reference values for each global component
        for gtc in gtcomponents:

            if isinstance(t, FormArgument):

                # Find basic subelement and element-local component
                # ec, element, eoffset = t.ufl_element().extract_component2(gtc) # FIXME: Translate this correctly
                eoffset = 0
                ec, element = t.ufl_element().extract_reference_component(gtc)

                # Select mapping M from element, pick row emapping =
                # M[ec,:], or emapping = [] if no mapping
                if isinstance(element, MixedElement):
                    error("Expecting a basic element here.")
                mapping = element.mapping()
                if mapping == "contravariant Piola":  # S == HDiv:
                    # Handle HDiv elements with contravariant piola
                    # mapping contravariant_hdiv_mapping = (1/det J) *
                    # J * PullbackOf(o)
                    ec, = ec
                    emapping = Mdiv[ec, :]
                elif mapping == "covariant Piola":  # S == HCurl:
                    # Handle HCurl elements with covariant piola mapping
                    # covariant_hcurl_mapping = JinvT * PullbackOf(o)
                    ec, = ec
                    emapping = K[:, ec]  # Column of K is row of K.T
                elif mapping == "identity":
                    emapping = None
                else:
                    error("Unknown mapping {0}".format(mapping))

            elif isinstance(t, GeometricQuantity):
                eoffset = 0
                emapping = None

            else:
                error("Unexpected type {0}.".format(type(t).__name__))

            # Create indices
            # if rtsh:
            #     i = Index()
            if len(dsh) != ngrads:
                error("Mismatch between derivative shape and ngrads.")
            if ngrads:
                ii = indices(ngrads)
            else:
                ii = ()

            # Apply mapping row to reference object
            if emapping:  # Mapped, always nonscalar terminal Not
                # using IndexSum for the mapping row dot product to
                # keep it simple, because we don't have a slice type
                emapped_ops = [emapping[s] * Indexed(r, MultiIndex((FixedIndex(eoffset + s),) + ii))
                               for s in range(len(emapping))]
                emapped = sum(emapped_ops[1:], emapped_ops[0])
            elif gtc:  # Nonscalar terminal, unmapped
                emapped = Indexed(r, MultiIndex((FixedIndex(eoffset),) + ii))
            elif ngrads:  # Scalar terminal, unmapped, with derivatives
                emapped = Indexed(r, MultiIndex(ii))
            else:  # Scalar terminal, unmapped, no derivatives
                emapped = r

            for di in dcomponents:
                # Multiply derivative mapping rows, parameterized by
                # free column indices
                dmapping = as_ufl(1)
                for j in range(ngrads):
                    dmapping *= K[ii[j], di[j]]  # Row of K is column of JinvT

                # Compute mapping from reference values for this
                # particular global component
                global_value = dmapping * emapped

                # Apply index sums
                # if rtsh:
                #     global_value = IndexSum(global_value, MultiIndex((i,)))
                # for j in range(ngrads): # Applied implicitly in the dmapping * emapped above
                #     global_value = IndexSum(global_value, MultiIndex((ii[j],)))

                # This is the component index into the full object
                # with grads applied
                gc = gtc + di

                # Insert in nested list
                comp = global_components
                for i in gc[:-1]:
                    comp = comp[i]
                comp[0 if gc == () else gc[-1]] = global_value

        # Wrap nested list in as_tensor unless we have a scalar
        # expression
        if gsh:
            tensor = as_tensor(global_components)
        else:
            tensor, = global_components
        return tensor