Source code for ffc.uflacs.backends.ufc.dofmap

# -*- coding: utf-8 -*-
# Copyright (C) 2009-2016 Anders Logg and 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/>.

# Note: Most of the code in this file is a direct translation from the old implementation in FFC


from ffc.uflacs.backends.ufc.generator import ufc_generator
from ffc.uflacs.backends.ufc.utils import generate_return_new_switch


[docs]class ufc_dofmap(ufc_generator): def __init__(self): ufc_generator.__init__(self, "dofmap")
[docs] def topological_dimension(self, L, ir): "Default implementation of returning topological dimension fetched from ir." tdim = ir["topological_dimension"] return L.Return(L.LiteralInt(tdim))
[docs] def needs_mesh_entities(self, L, ir): d = L.Symbol("d") nme = ir["needs_mesh_entities"] cases = [(L.LiteralInt(dim), L.Return(L.LiteralBool(need))) for dim, need in enumerate(nme)] default = L.Return(L.LiteralBool(False)) return L.Switch(d, cases, default=default, autoscope=False, autobreak=False)
[docs] def global_dimension(self, L, ir): # A list of num dofs per entity num_entity_dofs, num_global_dofs = ir["global_dimension"] # Input array entities = L.Symbol("num_global_entities") # Accumulate number of dofs per entity times given number of entities in mesh dimension = sum(L.LiteralInt(num)*entities[dim] for dim, num in enumerate(num_entity_dofs) if num > 0) # Add global dofs if any if num_global_dofs: dimension = dimension + L.LiteralInt(num_global_dofs) return L.Return(dimension)
[docs] def num_element_dofs(self, L, ir): value = ir["num_element_dofs"] return L.Return(L.LiteralInt(value))
[docs] def num_facet_dofs(self, L, ir): value = ir["num_facet_dofs"] return L.Return(L.LiteralInt(value))
[docs] def num_entity_dofs(self, L, ir): d = L.Symbol("d") values = ir["num_entity_dofs"] cases = [(i, L.Return(L.LiteralInt(value))) for i, value in enumerate(values)] default = L.Return(L.LiteralInt(0)) return L.Switch(d, cases, default=default)
[docs] def num_entity_closure_dofs(self, L, ir): d = L.Symbol("d") values = ir["num_entity_closure_dofs"] cases = [(i, L.Return(L.LiteralInt(value))) for i, value in enumerate(values)] default = L.Return(L.LiteralInt(0)) return L.Switch(d, cases, default=default)
[docs] def tabulate_dofs(self, L, ir): # Input arguments entity_indices = L.Symbol("entity_indices") num_mesh_entities = L.Symbol("num_global_entities") # Output arguments dofs_variable = L.Symbol("dofs") ir = ir["tabulate_dofs"] if ir is None: # What is this supposed to mean? return L.Assign(dofs_variable[0], 0) # Extract representation #(dofs_per_element, num_dofs_per_element, need_offset, fakes) = ir # names from original ffc code (subelement_dofs, num_dofs_per_subelement, need_offset, is_subelement_real) = ir #len(is_subelement_real) == len(subelement_dofs) == len(num_dofs_per_subelement) == number of combined (flattened) subelements? #is_subelement_real[subelement_number] is bool, is subelement Real? #num_dofs_per_subelement[subelement_number] is int, number of dofs for each (flattened) subelement #subelement_dofs[subelement_number] is list of entity_dofs for each (flattened) subelement #len(entity_dofs) == tdim+1 #len(entity_dofs[cell_entity_dim]) == "num_cell_entities[dim]" (i.e. 3 vertices, 3 edges, 1 face for triangle) #len(entity_dofs[cell_entity_dim][entity_index[dim][k]]) == number of dofs for this entity #num = entity_dofs[dim] #entity_dofs =? entity_dofs[d][i][:] # dofs on entity (d,i) # Collect code pieces in list code = [] # Declare offset if needed if need_offset: offset = L.Symbol("offset") code.append(L.VariableDecl("std::size_t", offset, value=0)) else: offset = 0 # Generate code for each element subelement_offset = 0 for (subelement_index, entity_dofs) in enumerate(subelement_dofs): # Handle is_subelement_real (Space of reals) if is_subelement_real[subelement_index]: assert num_dofs_per_subelement[subelement_index] == 1 code.append(L.Assign(dofs_variable[subelement_offset], offset)) if need_offset: code.append(L.AssignAdd(offset, 1)) subelement_offset += 1 continue # Generate code for each degree of freedom for each dimension for (cell_entity_dim, dofs_on_cell_entity) in enumerate(entity_dofs): num_dofs_per_mesh_entity = len(dofs_on_cell_entity[0]) assert all(num_dofs_per_mesh_entity == len(dofs) for dofs in dofs_on_cell_entity) # Ignore if no dofs for this dimension if num_dofs_per_mesh_entity == 0: continue # For each cell entity of this dimension for (cell_entity_index, dofs) in enumerate(dofs_on_cell_entity): # dofs is a list of the local dofs that live on this cell entity # find offset for this particular mesh entity entity_offset = len(dofs) * entity_indices[cell_entity_dim, cell_entity_index] for (j, dof) in enumerate(dofs): # dof is the local dof index on the subelement # j is the local index of dof among the dofs on this particular cell/mesh entity local_dof_index = subelement_offset + dof global_dof_index = offset + entity_offset + j code.append(L.Assign(dofs_variable[local_dof_index], global_dof_index)) # Update offset corresponding to mesh entity: if need_offset: code.append(L.AssignAdd(offset, num_dofs_per_mesh_entity * num_mesh_entities[cell_entity_dim])) subelement_offset += num_dofs_per_subelement[subelement_index] return L.StatementList(code)
[docs] def tabulate_facet_dofs(self, L, ir): all_facet_dofs = ir["tabulate_facet_dofs"] # Input arguments facet = L.Symbol("facet") dofs = L.Symbol("dofs") # For each facet, copy all_facet_dofs[facet][:] into output argument array dofs[:] cases = [] for facet, single_facet_dofs in enumerate(all_facet_dofs): assigns = L.StatementList([L.Assign(dofs[i], dof) for (i, dof) in enumerate(single_facet_dofs)]) cases.append((facet, assigns)) return L.Switch(facet, cases, autoscope=False)
[docs] def tabulate_entity_dofs(self, L, ir): entity_dofs, num_dofs_per_entity = ir["tabulate_entity_dofs"] # Output argument array dofs = L.Symbol("dofs") # Input arguments d = L.Symbol("d") i = L.Symbol("i") # TODO: Removed check for (d <= tdim + 1) tdim = len(num_dofs_per_entity) - 1 # Generate cases for each dimension: all_cases = [] for dim in range(tdim + 1): # Ignore if no entities for this dimension if num_dofs_per_entity[dim] == 0: continue # Generate cases for each mesh entity cases = [] for entity in range(len(entity_dofs[dim])): casebody = [] for (j, dof) in enumerate(entity_dofs[dim][entity]): casebody += [L.Assign(dofs[j], dof)] cases.append((entity, L.StatementList(casebody))) # Generate inner switch # TODO: Removed check for (i <= num_entities-1) inner_switch = L.Switch(i, cases, autoscope=False) all_cases.append((dim, inner_switch)) return L.Switch(d, all_cases, autoscope=False)
[docs] def tabulate_entity_closure_dofs(self, L, ir): # Extract variables from ir entity_closure_dofs, entity_dofs, num_dofs_per_entity = \ ir["tabulate_entity_closure_dofs"] # Output argument array dofs = L.Symbol("dofs") # Input arguments d = L.Symbol("d") i = L.Symbol("i") # TODO: Removed check for (d <= tdim + 1) tdim = len(num_dofs_per_entity) - 1 # Generate cases for each dimension: all_cases = [] for dim in range(tdim + 1): num_entities = len(entity_dofs[dim]) # Generate cases for each mesh entity cases = [] for entity in range(num_entities): casebody = [] for (j, dof) in enumerate(entity_closure_dofs[(dim, entity)]): casebody += [L.Assign(dofs[j], dof)] cases.append((entity, L.StatementList(casebody))) # Generate inner switch # TODO: Removed check for (i <= num_entities-1) inner_switch = L.Switch(i, cases, autoscope=False) all_cases.append((dim, inner_switch)) return L.Switch(d, all_cases, autoscope=False)
[docs] def num_sub_dofmaps(self, L, ir): value = ir["num_sub_dofmaps"] return L.Return(L.LiteralInt(value))
[docs] def create_sub_dofmap(self, L, ir): i = L.Symbol("i") classnames = ir["create_sub_dofmap"] return generate_return_new_switch(L, i, classnames, factory=ir["jit"])