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
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
def _getitem(self, component): # Treat component consistently as tuple below if not isinstance(component, tuple): component = (component, ) shape = self.ufl_shape # Analyse slices (:) and Ellipsis (...) all_indices, slice_indices, repeated_indices = create_slice_indices( component, shape, self.ufl_free_indices) # Check that we have the right number of indices for a tensor with # this shape if len(shape) != len(all_indices): error( "Invalid number of indices {0} for expression of rank {1}.".format( len(all_indices), len(shape))) # Special case for simplifying foo[...] => foo, foo[:] => foo or # similar if len(slice_indices) == len(all_indices): return self # Special case for simplifying as_tensor(ai,(i,))[i] => ai if isinstance(self, ComponentTensor): if all_indices == self.indices().indices(): return self.ufl_operands[0] # Apply all indices to index self, yielding a scalar valued # expression mi = MultiIndex(all_indices) a = Indexed(self, mi) # TODO: I think applying as_tensor after index sums results in # cleaner expression graphs. # If the Ellipsis or any slices were found, wrap as tensor valued # with the slice indices created at the top here if slice_indices: a = as_tensor(a, slice_indices) # If any repeated indices were found, apply implicit summation # over those for i in repeated_indices: mi = MultiIndex((i, )) a = IndexSum(a, mi) # Check for zero (last so we can get indices etc from a, could # possibly be done faster by checking early instead) if isinstance(self, Zero): shape = a.ufl_shape fi = a.ufl_free_indices fid = a.ufl_index_dimensions a = Zero(shape, fi, fid) return a
def as_tensor(expressions, indices=None): """UFL operator: Make a tensor valued expression. This works in two different ways, by using indices or lists. 1) Returns :math:`A` such that :math:`A` [*indices*] = *expressions*. If *indices* are provided, *expressions* must be a scalar valued expression with all the provided indices among its free indices. This operator will then map each of these indices to a tensor axis, thereby making a tensor valued expression from a scalar valued expression with free indices. 2) Returns :math:`A` such that :math:`A[k,...]` = *expressions*[k]. If no indices are provided, *expressions* must be a list or tuple of expressions. The expressions can also consist of recursively nested lists to build higher rank tensors. """ if indices is None: # Allow as_tensor(as_tensor(A)) and as_vector(as_vector(v)) in user code if isinstance(expressions, Expr): return expressions # Support numpy array, but avoid importing numpy if not needed if not isinstance(expressions, (list, tuple)): expressions = from_numpy_to_lists(expressions) # Sanity check if not isinstance(expressions, (list, tuple)): error("Expecting nested list or tuple.") # Recursive conversion from nested lists to nested ListTensor # objects return _as_list_tensor(expressions) else: # Make sure we have a tuple of indices if isinstance(indices, list): indices = tuple(indices) elif not isinstance(indices, tuple): indices = (indices, ) # Special case for as_tensor(expr, ii) with ii = () if indices == (): return expressions indices = MultiIndex(indices) # Special case for simplification as_tensor(A[ii], ii) -> A if isinstance(expressions, Indexed): A, ii = expressions.ufl_operands if indices.indices() == ii.indices(): return A # Make a tensor from given scalar expression with free indices return ComponentTensor(expressions, indices)
def __init__(self, gc, i): self.scalar = True component = (i, ) shape = gc.ufl_shape all_indices, _, _ = create_slice_indices(component, shape, gc.ufl_free_indices) mi = MultiIndex(all_indices) Indexed.__init__(self, gc, mi) if gc.gf.scalar: assert i == 0 self.__impl__ = gc.gf self.gf = gc else: self.__impl__ = gc.gf[i] self.gf = None
def multi_index(self, o): new_indices = tuple(self.index(i) for i in o.indices()) return MultiIndex(new_indices)
def _mult(a, b): # Discover repeated indices, which results in index sums afi = a.ufl_free_indices bfi = b.ufl_free_indices afid = a.ufl_index_dimensions bfid = b.ufl_index_dimensions fi, fid, ri, rid = merge_overlapping_indices(afi, afid, bfi, bfid) # Pick out valid non-scalar products here (dot products): # - matrix-matrix (A*B, M*grad(u)) => A . B # - matrix-vector (A*v) => A . v s1, s2 = a.ufl_shape, b.ufl_shape r1, r2 = len(s1), len(s2) if r1 == 0 and r2 == 0: # Create scalar product p = Product(a, b) ti = () elif r1 == 0 or r2 == 0: # Scalar - tensor product if r2 == 0: a, b = b, a # Check for zero, simplifying early if possible if isinstance(a, Zero) or isinstance(b, Zero): shape = s1 or s2 return Zero(shape, fi, fid) # Repeated indices are allowed, like in: # v[i]*M[i,:] # Apply product to scalar components ti = indices(len(b.ufl_shape)) p = Product(a, b[ti]) elif r1 == 2 and r2 in (1, 2): # Matrix-matrix or matrix-vector if ri: error("Not expecting repeated indices in non-scalar product.") # Check for zero, simplifying early if possible if isinstance(a, Zero) or isinstance(b, Zero): shape = s1[:-1] + s2[1:] return Zero(shape, fi, fid) # Return dot product in index notation ai = indices(len(a.ufl_shape) - 1) bi = indices(len(b.ufl_shape) - 1) k = indices(1) p = a[ai + k] * b[k + bi] ti = ai + bi else: error("Invalid ranks {0} and {1} in product.".format(r1, r2)) # TODO: I think applying as_tensor after index sums results in # cleaner expression graphs. # Wrap as tensor again if ti: p = as_tensor(p, ti) # If any repeated indices were found, apply implicit summation # over those for i in ri: mi = MultiIndex((Index(count=i), )) p = IndexSum(p, mi) return p
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
def multi_index(self, x): comp = self._multi_index_values(x) return MultiIndex(tuple(FixedIndex(i) for i in comp))
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