Ejemplo n.º 1
0
def _dx(self, *ii):
    "Return the partial derivative with respect to spatial variable number *ii*."
    d = self
    # Unwrap ii to allow .dx(i,j) and .dx((i,j))
    if len(ii) == 1 and isinstance(ii[0], tuple):
        ii = ii[0]
    # Apply all derivatives
    for i in ii:
        d = Grad(d)

    # Take all components, applying repeated index sums in the [] operation
    return d.__getitem__((Ellipsis,) + ii)
Ejemplo n.º 2
0
def _dx(self, *ii):
    "Return the partial derivative with respect to spatial variable number *ii*."
    d = self
    # Unwrap ii to allow .dx(i,j) and .dx((i,j))
    if len(ii) == 1 and isinstance(ii[0], tuple):
        ii = ii[0]
    # Apply all derivatives
    for i in ii:
        d = Grad(d)

    # Take all components, applying repeated index sums in the [] operation
    return d.__getitem__((Ellipsis, ) + ii)
Ejemplo n.º 3
0
def splitUFLForm(form):
    phi = form.arguments()[0]
    dphi = Grad(phi)

    source = ExprTensor(phi.ufl_shape)
    flux = ExprTensor(dphi.ufl_shape)
    boundarySource = ExprTensor(phi.ufl_shape)

    form = expand_indices(expand_derivatives(expand_compounds(form)))
    for integral in form.integrals():
        if integral.integral_type() == 'cell':
            fluxExprs = splitMultiLinearExpr(integral.integrand(), [phi])
            for op in fluxExprs:
                if op[0] == phi:
                    source = source + fluxExprs[op]
                elif op[0] == dphi:
                    flux = flux + fluxExprs[op]
                else:
                    raise Exception('Invalid derivative encountered in bulk integral: ' + str(op[0]))
        elif integral.integral_type() == 'exterior_facet':
            fluxExprs = splitMultiLinearExpr(integral.integrand(), [phi])
            for op in fluxExprs:
                if op[0] == phi:
                    boundarySource = boundarySource + fluxExprs[op]
                else:
                    raise Exception('Invalid derivative encountered in boundary integral: ' + str(op[0]))
        else:
            raise NotImplementedError('Integrals of type ' + integral.integral_type() + ' are not supported.')

    return source, flux, boundarySource
Ejemplo n.º 4
0
 def predefineCoefficients(self, predefined, x):
     for coefficient, idx in self.coefficients.items():
         for derivative in self.coefficient(idx, x):
             predefined[coefficient] = derivative
             coefficient = Grad(coefficient)
     predefined.update(
         {c: self.constant(i)
          for c, i in self.constants.items()})
Ejemplo n.º 5
0
def _dx(self, *ii):
    "Return the partial derivative with respect to spatial variable number i."
    d = self
    # Apply all derivatives
    for i in ii:
        d = Grad(d)
    # Take all components, applying repeated index sums in the [] operation
    return d[..., ii]
Ejemplo n.º 6
0
 def _predefineCoefficients(self, predefined, x, side=None):
     for idx, coefficient in enumerate(self.coefficientList):
         for derivative in self.coefficient(idx, x, side=side):
             if side is None:
                 predefined[coefficient] = derivative
             elif side == 'Side::in':
                 predefined[coefficient('+')] = derivative
             elif side == 'Side::out':
                 predefined[coefficient('-')] = derivative
             coefficient = Grad(coefficient)
Ejemplo n.º 7
0
 def apply_grads(f):
     if not isinstance(f, FormArgument):
         print ',' * 60
         print f
         print o
         print g
         print ',' * 60
         error("What?")
     for i in range(ngrads):
         f = Grad(f)
     return f
Ejemplo n.º 8
0
def generateMethodBody(cppType, expr, returnResult, default, predefined):
    if expr is not None and not expr == [None]:
        try:
            dimR = expr.ufl_shape[0]
        except:
            if isinstance(expr,list) or isinstance(expr,tuple):
                expr = as_vector(expr)
            else:
                expr = as_vector([expr])
            dimR = expr.ufl_shape[0]

        _, coeff = extract_arguments_and_coefficients(expr)
        coeff = {c : c.toVectorCoefficient()[0] for c in coeff if len(c.ufl_shape) == 0 and not c.is_cellwise_constant()}
        expr = replace(expr, coeff)

        t = ExprTensor(expr.ufl_shape) # , exprTensorApply(lambda u: u, expr.ufl_shape, expr))
        expression = [expr[i] for i in t.keys()]
        u = extract_arguments_and_coefficients(expr)[0]
        if u != []:
            u = u[0]
            du = Grad(u)
            d2u = Grad(du)
            arg_u = Variable("const RangeType &", "u")
            arg_du = Variable("const JacobianRangeType &", "du")
            arg_d2u = Variable("const HessianRangeType &", "d2u")
            predefined.update( {u: arg_u, du: arg_du, d2u: arg_d2u} )
        code, results = generateCode(predefined, expression, tempVars=False)
        result = Variable(cppType, 'result')
        if cppType == 'double':
            code = code + [assign(result, results[0])]
        else:
            code = code + [assign(result[i], r) for i, r in zip(t.keys(), results)]
        if returnResult:
            code = [Declaration(result)] + code + [return_(result)]
    else:
        result = Variable(cppType, 'result')
        code = [assign(result, construct(cppType,default) )]
        if returnResult:
            code = [Declaration(result)] + code + [return_(result)]
    return code
Ejemplo n.º 9
0
    def grad(self, o):
        "Represent grad(grad(f)) as Grad(Grad(f))."

        # TODO: Not sure how to detect that gradient of f is cellwise constant.
        #       Can we trust element degrees?
        #if o.is_cellwise_constant():
        #    return self.terminal(o)
        # TODO: Maybe we can ask "f.has_derivatives_of_order(n)" to check
        #       if we should make a zero here?

        f, = o.operands()
        ufl_assert(isinstance(f, (Grad, Terminal)),
                   "Expecting derivatives of child to be already expanded.")
        return (o, Grad(o))
Ejemplo n.º 10
0
def grad(f):
    """UFL operator: Take the gradient of f.

    This operator follows the grad convention where

      grad(s)[i] = s.dx(j)

      grad(v)[i,j] = v[i].dx(j)

      grad(T)[:,i] = T[:].dx(i)

    for scalar expressions s, vector expressions v,
    and arbitrary rank tensor expressions T.
    """
    f = as_ufl(f)
    return Grad(f)
Ejemplo n.º 11
0
    def __init__(self, name, uflExpr, virtualize, dimRange=None, predefined=None):
        self.className = name
        self.targs = ['class GridPart']
        if dimRange is not None:
            self.bindable = True
            self.dimRange = dimRange
            self.bindableBase = 'Dune::Fem::BindableGridFunctionWithSpace<GridPart,Dune::Dim<'+str(self.dimRange)+'>>'
            self.bases = ['public '+self.bindableBase]
            self.includeFiles = ['dune/fem/function/localfunction/bindable.hh']
        else:
            self.bindable = False
            self.bases = []
            self.includeFiles = []
        self.includeFiles += ['dune/fem/common/intersectionside.hh']
        self.gridPartType = TypeAlias("GridPartType", "GridPart")
        self.ctor_args = []
        self.ctor_init = []
        self.skeleton = None
        self.init = None
        self.vars = None

        uflExpr = [e for e in uflExpr if e is not None]
        coefficients = set()
        for expr in uflExpr:
            try:
                coefficients |= set(expr.coefficients())
            except:
                _, cc = extract_arguments_and_coefficients(expr)
                coefficients |= set(cc)
        extracedAll = False
        while not extracedAll:
            extracedAll = True
            for c in coefficients:
                try:
                    predef = c.predefined
                except AttributeError:
                    continue
                for expr in predef.values():
                    _, cc = extract_arguments_and_coefficients(expr)
                    cc = set(cc)
                    if not cc.issubset(coefficients):
                       coefficients |= cc
                       extracedAll = False
                if not extracedAll:
                    break

        self.constantList = sorted((c for c in coefficients if c.is_cellwise_constant()), key=lambda c: c.count())
        self.coefficientList = sorted((c for c in coefficients if not c.is_cellwise_constant()), key=lambda c: c.count())

        constants=[fieldVectorType(c,useScalar=True) for c in self.constantList]
        coefficients=(fieldVectorType(c) for c in self.coefficientList)
        constantNames=[getattr(c, 'name', None) for c in self.constantList]
        constantShapes=[getattr(c, 'ufl_shape', None) for c in self.constantList]
        coefficientNames=[getattr(c, 'name', None) for c in self.coefficientList]
        parameterNames=[getattr(c, 'parameter', None) for c in self.constantList]

        if not len(set(constantNames)) == len(constantNames):
            raise AttributeError("two constants have the same name which will lead to failure during code generation:"+','.join(c for c in constantNames))

        # this part modifies duplicate names in coefficient - slow version
        # can be improved
        coefficientNames_ = coefficientNames
        coefficientNames = []
        for c in coefficientNames_:
            if c is not None:
                while c in coefficientNames:
                    c = c+"A"
            coefficientNames.append(c)

        self._constants = [] if constants is None else list(constants)
        self._coefficients = [] if coefficients is None else list(coefficients)

        self._constantShapes = [None,] * len(self._constants) if constantShapes is None else list(constantShapes)
        self._constantNames  = [None,] * len(self._constants) if constantNames is None else list(constantNames)
        self._constantNames  = ['constant' + str(i) if n is None else n for i, n in enumerate(self._constantNames)]
        if len(self._constantNames) != len(self._constants):
            raise ValueError("Length of constantNames must match length of constants")
        invalidConstants = [n for n in self._constantNames if n is not None and re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', n) is None]
        if invalidConstants:
            raise ValueError('Constant names are not valid C++ identifiers:' + ', '.join(invalidConstants) + '.')
        self._constantValues = [ None if not hasattr(c,"value") else c.value for c in self.constantList ]

        self._coefficientNames = [None,] * len(self._coefficients) if coefficientNames is None else list(coefficientNames)
        self._coefficientNames = ['coefficient' + str(i) if n is None else n for i, n in enumerate(self._coefficientNames)]
        if len(self._coefficientNames) != len(self._coefficients):
            raise ValueError("Length of coefficientNames must match length of coefficients")
        invalidCoefficients = [n for n in self._coefficientNames if n is not None and re.match('^[a-zA-Z_][a-zA-Z0-9_]*$', n) is None]
        if invalidCoefficients:
            raise ValueError('Coefficient names are not valid C++ identifiers:' + ', '.join(invalidCoefficients) + '.')

        self._parameterNames = [None,] * len(self._constants) if parameterNames is None else list(parameterNames)
        if len(self._parameterNames) != len(self._constants):
            raise ValueError("Length of parameterNames must match length of constants")
        self._derivatives = [('RangeType', 'evaluate'), ('JacobianRangeType', 'jacobian'), ('HessianRangeType', 'hessian')]
        if self._coefficients:
            if virtualize:
                self.coefficientCppTypes = \
                    ['Dune::FemPy::VirtualizedGridFunction< ' +\
                     gridPartType(c) + ', ' + fieldVectorType(c) + ' >' \
                        if not c.cppTypeName.startswith("Dune::Python::SimpleGridFunction") \
                        else c.cppTypeName \
                    for c in self.coefficientList]
                # VirtualizedGF need GridParts but they have to be the same for all coefficients
                # Do we want this to work in some way? Then we can add
                # includes here - but '.bind(entity)' will fail.
                # for c in self.coefficientList:
                #     self.includeFiles += c.grid.cppIncludes
            else:
                self.coefficientCppTypes = [c.cppTypeName for c in self.coefficientList]
        else:
            self.coefficientCppTypes = []

        # need to replace possible grid functions in values of predefined
        # import pdb; pdb.set_trace()
        self.predefined = {} if predefined is None else predefined
        for idx, coefficient in enumerate(self.coefficientList):
            try:
                self.predefined.update( coefficient.predefined )
            except AttributeError:
                pass
        for idx, coefficient in enumerate(self.coefficientList):
            for derivative in self.coefficient(idx, 'x', side=None):
                for k,v in self.predefined.items():
                    if coefficient == v:
                        self.predefined[k] = derivative
                coefficient = Grad(coefficient)
Ejemplo n.º 12
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
Ejemplo n.º 13
0
 def form_argument(self, o):
     "Represent grad(f) as Grad(f)."
     # Collapse gradient of cellwise function to zero
     if o.is_cellwise_constant():
         return self.terminal(o)
     return (o, Grad(o))