def codeDG(self): code = self._code() u = self.trialFunction ubar = Coefficient(u.ufl_function_space()) penalty = self.penalty if penalty is None: penalty = 1 if isinstance(penalty, Expr): if penalty.ufl_shape == (): penalty = as_vector([penalty]) try: penalty = expand_indices( expand_derivatives(expand_compounds(penalty))) except: pass assert penalty.ufl_shape == u.ufl_shape dmPenalty = as_vector([ replace( expand_derivatives(diff(replace(penalty, {u: ubar}), ubar))[i, i], {ubar: u}) for i in range(u.ufl_shape[0]) ]) else: dmPenalty = None code.append(AccessModifier("public")) x = SpatialCoordinate(self.space.cell()) predefined = {} self.predefineCoefficients(predefined, x) spatial = Variable('const auto', 'y') predefined.update({ x: UnformattedExpression( 'auto', 'entity().geometry().global( Dune::Fem::coordinate( x ) )') }) generateMethod(code, penalty, 'RRangeType', 'penalty', args=['const Point &x', 'const DRangeType &u'], targs=['class Point', 'class DRangeType'], static=False, const=True, predefined=predefined) generateMethod(code, dmPenalty, 'RRangeType', 'linPenalty', args=['const Point &x', 'const DRangeType &u'], targs=['class Point', 'class DRangeType'], static=False, const=True, predefined=predefined) return code
def coefficient(self, idx, x): coefficient = [] for t, n in (('RangeType', 'evaluate'), ('JacobianRangeType', 'jacobian'), ('HessianRangeType', 'hessian')): result = Variable( 'typename std::tuple_element_t< ' + str(idx) + ', CoefficientFunctionSpaceTupleType >::' + t, 'result') code = [ Declaration(result), UnformattedExpression('void', 'std::get< ' + str(idx) + ' >( coefficients_ ).' + n + '( x, ' + result.name + ' )', uses=[result]), return_(result) ] coefficient += [ lambda_(capture=[this], args=['auto x'], code=code)(x) ] return coefficient
def code(self, name=None, targs=None): # self.name = "Integrands" # self.targs = ['class GridPart'] # self.gridPartType = TypeAlias("GridPartType", "GridPart") # self.ctor_args = [] # self.ctor_init = [] # self.skeleton (None is no intersecton terms are needed) # self.init (code to be added to init(Entity) method # self.vars (further class variables) # self.methods(code) if name is not None: self.name = name if targs is not None: self.targs = targs code = Struct(self.className, targs=(self.targs + ['class ' + n for n in self.coefficientTypes]), bases=self.bases) code.append(self.gridPartType) code.append(TypeAlias("GridView", "typename GridPartType::GridViewType")) if self.bindable: code.append(TypeAlias("FunctionSpaceType", "Dune::Fem::GridFunctionSpace<GridPartType,Dune::Dim<"+str(self.dimRange)+">>")) code.append(TypeAlias("EntityType", "typename GridPartType::template Codim< 0 >::EntityType")) code.append(TypeAlias("IntersectionType", "typename GridPartType::IntersectionType")) code.append(TypeAlias("GlobalCoordinateType", "typename EntityType::Geometry::GlobalCoordinate")) code.append(TypeAlias("Side","Dune::Fem::IntersectionSide")) for type, alias in zip(self._constants, self.constantTypes): code.append(TypeAlias(alias, type)) constants = ["std::shared_ptr< " + c + " >" for c in self.constantTypes] if constants: code.append(TypeAlias("ConstantTupleType", "std::tuple< " + ", ".join(constants) + " >")) code.append(TypeAlias("ConstantsRangeType", "typename std::tuple_element_t< i, ConstantTupleType >::element_type", targs=["std::size_t i"])) else: code.append(TypeAlias("ConstantTupleType", "std::tuple<>")) if self._coefficients: coefficientSpaces = [('Dune::Fem::GridFunctionSpace< GridPartType, ' + c + ' >') for c in self._coefficients] code.append(TypeAlias("CoefficientFunctionSpaceTupleType", "std::tuple< " +", ".join(coefficientSpaces) + " >")) code.append(TypeAlias('CoefficientTupleType', 'std::tuple< ' + ', '.join(self.coefficientTypes) + ' >')) code.append(TypeAlias("CoefficientFunctionSpaceType", "std::tuple_element_t< i, CoefficientFunctionSpaceTupleType >", targs=["std::size_t i"])) for s in ["RangeType", "JacobianRangeType"]: code.append(TypeAlias("Coefficient" + s, "typename CoefficientFunctionSpaceType< i >::" + s, targs=["std::size_t i"])) code.append(Declaration(Variable("bool", "gridPartValid"), initializer=UnformattedExpression("bool"," && ".join(["Dune::Fem::checkGridPartValid<GridPartType,"+ "Dune::Fem::ConstLocalFunction<"+c+">>()" for c in self.coefficientTypes])), static=True, constexpr=True)) else: code.append(TypeAlias("CoefficientTupleType", "std::tuple<>")) code.append(Declaration(Variable("bool", "gridPartValid"), initializer="true", static=True, constexpr=True)) code.append(TypeAlias('CoefficientType', 'std::tuple_element_t< i, CoefficientTupleType >', targs=['std::size_t i'])) code.append(TypeAlias('ConstantType', 'typename std::tuple_element_t< i, ConstantTupleType >::element_type', targs=['std::size_t i'])) # if self.skeleton is not None: # code.append(EnumClass('Side', ['in = 0u', 'out = 1u'], 'std::size_t')) # inside = '[ static_cast< std::size_t >( Side::in ) ]' # else: # inside = '' if not self.bindable: if self.skeleton is None: entity_ = Variable('EntityType', 'entity_') insideEntity = entity_ else: entity_ = Variable('std::array< EntityType, 2 >', 'entity_') insideEntity = entity_[UnformattedExpression('std::size_t', 'static_cast< std::size_t >( Side::in )')] outsideEntity = entity_[UnformattedExpression('std::size_t', 'static_cast< std::size_t >( Side::out )')] intersection_ = Variable('IntersectionType', 'intersection_') else: code.append(Using(self.bindableBase+'::entity')) constants_ = Variable("ConstantTupleType", "constants_") coefficientsTupleType = 'std::tuple< ' + ', '.join('Dune::Fem::ConstLocalFunction< ' + n + ' >' for n in self.coefficientTypes) + ' >' if self.skeleton is None: coefficients_ = Variable(coefficientsTupleType, 'coefficients_') else: coefficients_ = Variable('std::array< ' + coefficientsTupleType + ', 2 >', 'coefficients_') # generate code for constructor arg_param = Variable('const Dune::Fem::ParameterReader &', 'parameter') if self.bindable: args = [ Variable('const GridPartType &','gridPart'), Variable('const std::string &','name'), Variable('int','order') ] else: args = [] args += self.ctor_args + [Variable('const ' + t + ' &', n) for t, n in zip(self.coefficientTypes, self.coefficientNames)] if self.bindable: init = [self.bindableBase+'(gridPart,name,order)'] else: init = [] if self._coefficients: coeffInit = ['Dune::Fem::ConstLocalFunction< ' + n + ' >( ' + p + ' )' for n, p in zip(self.coefficientTypes, self.coefficientNames)] if self.skeleton is None: init += ["coefficients_( " + ", ".join(coeffInit) + " )"] else: init += ['coefficients_{{ ' + coefficientsTupleType + '( ' + ', '.join(coeffInit) + ' ), ' + coefficientsTupleType + '( ' + ', '.join(coeffInit) + ' ) }}'] init = self.ctor_init + init args.append(Declaration(arg_param, initializer=UnformattedExpression('const ParameterReader &', 'Dune::Fem::Parameter::container()'))) constructor = Constructor(args=args, init=init) for idx, (cppType, value) in enumerate(zip(self.constantTypes, self.constantValues)): constructor.append(assign(get(idx)(constants_), make_shared(cppType)(cppType+"(0)"))) for idx, (name, cppType) in enumerate(zip(self._parameterNames, self.constantTypes)): if name is not None: constructor.append(assign(dereference(get(idx)(constants_)), UnformattedExpression('auto', arg_param.name + '.getValue< ' + cppType + ' >( "' + name + '" )', uses=[arg_param]))) code.append(constructor) entity = Variable('const EntityType &', 'entity') intersection = Variable('const IntersectionType &', 'intersection') if self.bindable: initEntity = Method('void', 'bind', args=[entity]) initEntity.append(self.bindableBase+'::bind(entity);') uninitEntity = Method('void', 'unbind') uninitEntity.append(self.bindableBase+'::unbind();') initIntersection = Method('void', 'bind', args=[intersection, Variable('Side', 'side')]) initIntersection.append(self.bindableBase+'::bind(intersection,side);') code.append(initIntersection) else: initEntity = Method('bool', 'init', args=[entity]) initEntity.append(assign(insideEntity, entity)) uninitEntity = Method('void', 'unbind') if self.skeleton is None: for i, c in enumerate(self._coefficients): initEntity.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + ' ).bind( entity )', uses=[entity, coefficients_])) uninitEntity.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + ').unbind( )', uses=[coefficients_])) else: for i, c in enumerate(self._coefficients): initEntity.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::in ) ] ).bind( entity )', uses=[entity, coefficients_])) initEntity.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::out ) ] ).bind( entity )', uses=[entity, coefficients_])) uninitEntity.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::in ) ] ).unbind( )', uses=[coefficients_])) uninitEntity.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::out ) ] ).unbind( )', uses=[coefficients_])) initEntity.append(self.init) if not self.bindable: initEntity.append(return_(True)) code.append(initEntity) code.append(uninitEntity) if not self.bindable: initIntersection = Method('bool', 'init', args=[intersection]) initIntersection.append(assign(intersection_, intersection)) if self.skeleton is None: initIntersection.append(return_('(intersection.boundary() && init( intersection.inside() ))')) else: initIntersection.append(assign(insideEntity, UnformattedExpression('EntityType', 'intersection.inside()'))) for i, c in enumerate(self._coefficients): # initIntersection.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::in ) ] ).bind( entity_[ static_cast< std::size_t >( Side::in ) ] )', uses=[coefficients_])) initIntersection.append(UnformattedExpression('void', 'std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::in ) ] ).bind( intersection_, Side::in )', uses=[coefficients_])) initIntersection.append('if( intersection.neighbor() )') initIntersection.append('{') initIntersection.append(' entity_[ static_cast< std::size_t >( Side::out ) ] = intersection.outside();') for i, c in enumerate(self._coefficients): # initIntersection.append(UnformattedExpression('void', ' std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::out ) ] ).bind( entity_[ static_cast< std::size_t >( Side::out ) ] )', uses=[coefficients_])) initIntersection.append(UnformattedExpression('void', ' std::get< ' + str(i) + ' >( ' + coefficients_.name + '[ static_cast< std::size_t >( Side::out ) ] ).bind( intersection_, Side::out )', uses=[coefficients_])) initIntersection.append('}') initIntersection.append(return_(True)) code.append(initIntersection) ################################ self.methods(code) ################################ code.append(Method('const ConstantType< i > &', 'constant', targs=['std::size_t i'], code=return_(dereference(get('i')(constants_))), const=True)) code.append(Method('ConstantType< i > &', 'constant', targs=['std::size_t i'], code=return_(dereference(get('i')(constants_))))) for i, (t, n) in enumerate(zip(self.constantTypes, self.constantNames)): code.append(Method('const ' + t + ' &', n, code=return_(dereference(get(i)(constants_))), const=True)) code.append(Method(t + ' &', n, code=return_(dereference(get(i)(constants_))))) if not self.bindable: code.append(Method('const EntityType &', 'entity', const=True, code=return_(insideEntity))) code.append(AccessModifier('private')) if self._coefficients: for cppType, name in self._derivatives: var = Variable('typename CoefficientFunctionSpaceType< i >::' + cppType, 'result') if self.skeleton is None: method = Method(var.cppType, name + 'Coefficient', targs=['std::size_t i', 'class Point'], args=['const Point &x'], const=True) method.append(Declaration(var)) method.append(UnformattedExpression('void', 'std::get< i >( coefficients_ ).' + name + '( x, ' + var.name + ' );')) method.append(return_(var)) code.append(method) else: method = Method(var.cppType, name + 'Coefficient', targs=['std::size_t i', 'Side side', 'class Point'], args=['const Point &x'], const=True) method.append(Declaration(var)) method.append(UnformattedExpression('void', 'std::get< i >( coefficients_[ static_cast< std::size_t >( side ) ] ).' + name + '( x, ' + var.name + ' )')) method.append(return_(var)) code.append(method) method = Method(var.cppType, name + 'Coefficient', targs=['std::size_t i', 'class Point'], args=['const Point &x'], const=True) method.append(return_(UnformattedExpression(var.cppType, name + 'Coefficient< i, Side::in >( x )'))) code.append(method) if not self.bindable: code.append(Declaration(entity_), Declaration(intersection_)) code.append(Declaration(constants_), Declaration(coefficients_)) if self.vars is not None: code += self.vars return code
def facetGeometry(self): return UnformattedExpression('auto', 'intersection_.geometry()')
def facetArea(self): return UnformattedExpression('auto', 'intersection_.geometry().volume()')
def cellGeometry(self, side=None): entity = 'entity()' if side is None else 'entity_[ static_cast< std::size_t >( ' + side + ' ) ]' return UnformattedExpression('auto', entity + '.geometry()')
def facetNormal(self, x): return UnformattedExpression('GlobalCoordinateType', 'intersection_.unitOuterNormal( ' + x + '.localPosition() )')
def spatialCoordinate(self, x): return UnformattedExpression('GlobalCoordinateType', 'entity().geometry().global( Dune::Fem::coordinate( ' + x + ' ) )')
def coefficient(self, idx, x, side=None): targs = [str(idx)] if side is not None: targs.append(side) return (UnformattedExpression('typename CoefficientFunctionSpaceType< ' + str(idx) + ' >::' + t, n + 'Coefficient< ' + ', '.join(targs) + ' >( ' + x + ' )') for t, n in self._derivatives)
def constant(self, idx): return UnformattedExpression(self._constants[idx], 'constant< ' + str(idx) + ' >()')
def code(self, name=None, targs=None, ellipticBndConditions=True): if targs is None: targs = [] if name is None: name = 'Model' constants_ = Variable( 'std::tuple< ' + ', '.join('std::shared_ptr< ' + c + ' >' for c in self._constants) + ' >', 'constants_') # coefficients_ = Variable('std::tuple< ' + ', '.join(c['name'] if c['name'] is not None else 'Coefficient' + str(i) for i, c in enumerate(self._coefficients)) + ' >', 'coefficients_') coefficients_ = Variable('std::tuple< ' + ', '.join(\ 'Dune::Fem::ConstLocalFunction<' + self.cppTypeIdentifier(c['name'],"coefficient",i) + '> ' for i, c in enumerate(self._coefficients)) + ' >', 'coefficients_') entity_ = Variable('const EntityType *', 'entity_') # code = Struct(name, targs=(['class GridPart'] + ['class ' + c['name'] if c['name'] is not None else 'class Coefficient' + str(i) for i, c in enumerate(self._coefficients)] + targs)) code = Struct( name, targs=(['class GridPart'] + [ 'class ' + self.cppTypeIdentifier(c['name'], "coefficient", i) for i, c in enumerate(self._coefficients) ] + targs)) code.append(TypeAlias("GridPartType", "GridPart")) code.append( TypeAlias("EntityType", "typename GridPart::template Codim< 0 >::EntityType")) code.append( TypeAlias("IntersectionType", "typename GridPart::IntersectionType")) code.append( declareFunctionSpace("typename GridPartType::ctype", SourceWriter.cpp_fields(self.field), UnformattedExpression( "int", "GridPartType::dimensionworld"), self.dimDomain, name="DFunctionSpaceType", prefix="D", dimDomainName="dimDomain", dimRangeName="dimD")) code.append( declareFunctionSpace("typename GridPartType::ctype", SourceWriter.cpp_fields(self.field), UnformattedExpression( "int", "GridPartType::dimensionworld"), self.dimRange, name="RFunctionSpaceType", prefix="R", dimDomainName=None, dimRangeName="dimR")) code.append( Declaration(Variable("const int", "dimLocal"), initializer=UnformattedExpression( "int", "GridPartType::dimension"), static=True)) if self.hasConstants: code.append( TypeAlias("ConstantType", "typename std::tuple_element_t< i, " + constants_.cppType + " >::element_type", targs=["std::size_t i"])) code.append( Declaration(Variable("const std::size_t", "numConstants"), initializer=len(self._constants), static=True)) if self.hasCoefficients: code.append( TypeAlias('CoefficientType', 'std::tuple_element_t< i, ' + coefficients_.cppType + ' >', targs=['std::size_t i'])) # coefficientSpaces = ["Dune::Fem::FunctionSpace< DomainFieldType, " + SourceWriter.cpp_fields(c['field']) + ", dimDomain, " + str(c['dimRange']) + " >" for c in self._coefficients] coefficientSpaces = [ "typename CoefficientType<" + str(i) + ">::FunctionSpaceType" for i, c in enumerate(self._coefficients) ] code.append( TypeAlias("CoefficientFunctionSpaceTupleType", "std::tuple< " + ", ".join(coefficientSpaces) + " >")) arg_param = Variable("const Dune::Fem::ParameterReader &", "parameter") args = [ Declaration(arg_param, initializer=UnformattedExpression( 'const ParameterReader &', 'Dune::Fem::Parameter::container()')) ] init = None if self.hasCoefficients: # args = [Variable("const " + c['name'] if c['name'] is not None else "const Coefficient" + str(i) + " &", "coefficient" + str(i)) for i, c in enumerate(self._coefficients)] + args args = [ Variable( "const " + self.cppTypeIdentifier(c['name'], "coefficient", i) + " &", "coefficient" + str(i)) for i, c in enumerate(self._coefficients) ] + args init = ["coefficients_(" + ",".\ join("CoefficientType<"+str(i)+">"\ +"(coefficient" + str(i)+")" for i, c in enumerate(self._coefficients)) + " )"] constructor = Constructor(args=args, init=init) constructor.append([ assign(get(str(i))(constants_), make_shared(c)()) for i, c in enumerate(self._constants) ]) for name, idx in self._parameterNames.items(): constructor.append( assign( dereference(get(idx)(constants_)), UnformattedExpression("auto", arg_param.name + '.getValue< ' + self._constants[idx] + ' >( "' + name + '" )', uses=[arg_param]))) code.append(constructor) init = ['entity_ = &entity;'] init += [ 'std::get< ' + str(i) + ' >( ' + coefficients_.name + ').bind( entity );' for i, c in enumerate(self._coefficients) ] init = [UnformattedBlock(init)] + self.init + [return_(True)] code.append( Method('bool', 'init', args=['const EntityType &entity'], code=init, const=True)) uninit = ['entity_ = nullptr;'] uninit += [ 'std::get< ' + str(i) + ' >( ' + coefficients_.name + ').unbind( );' for i, c in enumerate(self._coefficients) ] uninit = [UnformattedBlock(uninit)] code.append(Method('void', 'unbind', code=uninit, const=True)) code.append( Method('const EntityType &', 'entity', code=return_(dereference(entity_)), const=True)) code.append( Method('std::string', 'name', const=True, code=return_( UnformattedExpression('const char *', '"' + name + '"')))) code.append( TypeAlias( "BoundaryIdProviderType", "Dune::Fem::BoundaryIdProvider< typename GridPartType::GridType >" )) code.append( Declaration(Variable("const bool", "symmetric"), initializer=self.symmetric, static=True)) code.append( Method('void', 'source', targs=['class Point'], args=[self.arg_x, self.arg_u, self.arg_du, self.arg_r], code=self.source, const=True)) code.append( Method('void', 'linSource', targs=['class Point'], args=[ self.arg_ubar, self.arg_dubar, self.arg_x, self.arg_u, self.arg_du, self.arg_r ], code=self.linSource, const=True)) code.append( Method('void', 'flux', targs=['class Point'], args=[self.arg_x, self.arg_u, self.arg_du, self.arg_dr], code=self.flux, const=True)) code.append( Method('void', 'linFlux', targs=['class Point'], args=[ self.arg_ubar, self.arg_dubar, self.arg_x, self.arg_u, self.arg_du, self.arg_dr ], code=self.linFlux, const=True)) code.append( Method('void', 'fluxDivergence', targs=['class Point'], args=[ self.arg_x, self.arg_u, self.arg_du, self.arg_d2u, self.arg_r ], code=self.fluxDivergence, const=True)) # deprecated methods code.append( Method('[[deprecated]] void', 'diffusiveFlux', targs=['class Point'], args=[self.arg_x, self.arg_u, self.arg_du, self.arg_dr], code='flux(x, u, du, result );', const=True)) code.append( Method('[[deprecated]] void', 'linDiffusiveFlux', targs=['class Point'], args=[ self.arg_ubar, self.arg_dubar, self.arg_x, self.arg_u, self.arg_du, self.arg_dr ], code='linFlux( ubar, dubar, x, u, du, result );', const=True)) # if model is femDG model, then skip alpha and Neumann/Dirichlet boundary methods if ellipticBndConditions: code.append( Method('void', 'alpha', targs=['class Point'], args=[self.arg_x, self.arg_u, self.arg_r], code=self.alpha, const=True)) code.append( Method( 'void', 'linAlpha', targs=['class Point'], args=[self.arg_ubar, self.arg_x, self.arg_u, self.arg_r], code=self.linAlpha, const=True)) code.append( Method('bool', 'hasNeumanBoundary', const=True, code=return_(self.hasNeumanBoundary))) code.append( TypeAlias("DirichletComponentType", "std::array<int," + str(self.dimRange) + ">")) code.append( Method('bool', 'hasDirichletBoundary', const=True, code=return_(self.hasDirichletBoundary))) code.append( Method('bool', 'isDirichletIntersection', args=[ self.arg_i, 'DirichletComponentType &dirichletComponent' ], code=self.isDirichletIntersection, const=True)) code.append( Method('void', 'dirichlet', targs=['class Point'], args=[self.arg_bndId, self.arg_x, self.arg_r], code=self.dirichlet, const=True)) ### end boundary conditions for elliptic operators #### if self.hasConstants: code.append( Method("const ConstantType< i > &", "constant", targs=["std::size_t i"], code=return_(dereference(get("i")(constants_))), const=True)) code.append( Method("ConstantType< i > &", "constant", targs=["std::size_t i"], code=return_(dereference(get("i")(constants_))))) if self.hasCoefficients: code.append( Method("const CoefficientType< i > &", "coefficient", targs=["std::size_t i"], code=return_(get("i")(coefficients_)), const=True)) code.append( Method("CoefficientType< i > &", "coefficient", targs=["std::size_t i"], code=return_(get("i")(coefficients_)))) for n, i in self._constantNames.items(): t = self._constants[i] code.append( Method('const ' + t + ' &', n, code=return_(dereference(get(i)(constants_))), const=True)) code.append( Method(t + ' &', n, code=return_(dereference(get(i)(constants_))))) code.append(AccessModifier("private")) code.append(Declaration(entity_, nullptr, mutable=True)) if self.hasConstants: code.append(Declaration(constants_, mutable=True)) if self.hasCoefficients: code.append(Declaration(coefficients_, mutable=True)) return code
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 _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