Source code for ffc.uflacs.backends.ffc.symbols

# -*- coding: utf-8 -*-
# Copyright (C) 2011-2017 Martin Sandve Alnæs
#
# This file is part of UFLACS.
#
# UFLACS is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# UFLACS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with UFLACS. If not, see <http://www.gnu.org/licenses/>

"""FFC/UFC specific symbol naming."""

from ffc.log import error


# TODO: Get restriction postfix from somewhere central
[docs]def ufc_restriction_postfix(restriction): if restriction == "+": res = "_0" elif restriction == "-": res = "_1" else: res = ""
return res
[docs]def format_mt_name(basename, mt): "Format variable name for modified terminal." access = str(basename) # Add averaged state to name if mt.averaged: avg = "_a{0}".format(mt.averaged) access += avg # Format restriction res = ufc_restriction_postfix(mt.restriction).replace("_", "_r") access += res # Format local derivatives assert not mt.global_derivatives if mt.local_derivatives: der = "_d{0}".format(''.join(map(str, mt.local_derivatives))) access += der # Add domain number domain_number = mt.terminal.ufl_domain()._ufl_id if domain_number >= 0: domain = "_m{0}".format(domain_number) access += domain # Add flattened component to name if mt.component: comp = "_c{0}".format(mt.flat_component) access += comp
return access
[docs]class FFCBackendSymbols(object): """FFC specific symbol definitions. Provides non-ufl symbols.""" def __init__(self, language, coefficient_numbering): self.L = language self.S = self.L.Symbol self.coefficient_numbering = coefficient_numbering # Used for padding variable names based on restriction self.restriction_postfix = { r: ufc_restriction_postfix(r) for r in ("+", "-", None) } # TODO: Make this configurable for easy experimentation with dolfin! # Coordinate dofs for each component are interleaved? Must match dolfin. # True = XYZXYZXYZXYZ, False = XXXXYYYYZZZZ self.interleaved_components = True
[docs] def element_tensor(self): "Symbol for the element tensor itself."
return self.S("A")
[docs] def entity(self, entitytype, restriction): "Entity index for lookup in element tables." if entitytype == "cell": # Mixed-dimensional cells integrals # are handled as exterior boundary facet # integrals on each contrib cell # (default value : 0) return self.S("local_facet") elif entitytype == "facet": return self.S("facet" + ufc_restriction_postfix(restriction)) elif entitytype == "vertex": return self.S("vertex") else:
error("Unknown entitytype {}".format(entitytype))
[docs] def cell_orientation_argument(self, restriction): "Cell orientation argument in ufc. Not same as cell orientation in generated code."
return self.S("cell_orientation" + ufc_restriction_postfix(restriction))
[docs] def cell_orientation_internal(self, restriction): "Internal value for cell orientation in generated code."
return self.S("co" + ufc_restriction_postfix(restriction))
[docs] def argument_loop_index(self, iarg): "Loop index for argument #iarg." indices = ["i", "j", "k", "l"]
return self.S(indices[iarg])
[docs] def coefficient_dof_sum_index(self): """Index for loops over coefficient dofs, assumed to never be used in two nested loops."""
return self.S("ic")
[docs] def quadrature_loop_index(self): """Reusing a single index name for all quadrature loops, assumed not to be nested."""
return self.S("iq")
[docs] def num_custom_quadrature_points(self): "Number of quadrature points, argument to custom integrals."
return self.S("num_quadrature_points")
[docs] def custom_quadrature_weights(self): "Quadrature weights including cell measure scaling, argument to custom integrals."
return self.S("quadrature_weights")
[docs] def custom_quadrature_points(self): "Physical quadrature points, argument to custom integrals."
return self.S("quadrature_points")
[docs] def custom_weights_table(self): "Table for chunk of custom quadrature weights (including cell measure scaling)."
return self.S("weights_chunk")
[docs] def custom_points_table(self): "Table for chunk of custom quadrature points (physical coordinates)."
return self.S("points_chunk")
[docs] def weights_table(self, num_points): "Table of quadrature weights."
return self.S("weights%d" % (num_points,))
[docs] def points_table(self, num_points): "Table of quadrature points (points on the reference integration entity)."
return self.S("points%d" % (num_points,))
[docs] def x_component(self, mt): "Physical coordinate component."
return self.S(format_mt_name("x", mt))
[docs] def X_component(self, mt): "Reference coordinate component."
return self.S(format_mt_name("X", mt))
[docs] def J_component(self, mt): "Jacobian component." # FIXME: Add domain number!
return self.S(format_mt_name("J", mt))
[docs] def domain_dof_access(self, dof, component, gdim, num_scalar_dofs, restriction): # FIXME: Add domain number or offset! vc = self.S("coordinate_dofs" + ufc_restriction_postfix(restriction)) if self.interleaved_components: return vc[gdim*dof + component] else:
return vc[num_scalar_dofs*component + dof]
[docs] def domain_dofs_access(self, gdim, num_scalar_dofs, restriction): # FIXME: Add domain number or offset! return [self.domain_dof_access(dof, component, gdim, num_scalar_dofs, restriction) for component in range(gdim)
for dof in range(num_scalar_dofs)]
[docs] def coefficient_dof_access(self, coefficient, dof_number): # TODO: Add domain number? c = self.coefficient_numbering[coefficient] w = self.S("w")
return w[c, dof_number]
[docs] def coefficient_value(self, mt): "Symbol for variable holding value or derivative component of coefficient." c = self.coefficient_numbering[mt.terminal]
return self.S(format_mt_name("w%d" % (c,), mt))
[docs] def element_table(self, tabledata, entitytype, restriction): if tabledata.is_uniform: entity = 0 else: entity = self.entity(entitytype, restriction) if tabledata.is_piecewise: iq = 0 else: iq = self.quadrature_loop_index() # Return direct access to element table
return self.S(tabledata.name)[entity][iq]