~ubuntu-branches/ubuntu/trusty/ffc/trusty

« back to all changes in this revision

Viewing changes to ffc/fem/dofmap.py

  • Committer: Bazaar Package Importer
  • Author(s): Johannes Ring
  • Date: 2010-02-03 20:22:35 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20100203202235-fe8d0kajuvgy2sqn
Tags: 0.9.0-1
* New upstream release.
* debian/control: Bump Standards-Version (no changes needed).
* Update debian/copyright and debian/copyright_hints.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
__author__ = "Anders Logg (logg@simula.no)"
2
 
__date__ = "2007-01-24 -- 2008-05-08"
3
 
__copyright__ = "Copyright (C) 2007-2008 Anders Logg"
4
 
__license__  = "GNU GPL version 3 or any later version"
5
 
 
6
 
# Modified by Marie E. Rognes (meg@math.uio.no), 2007
7
 
# Modified by Kristian Oelgaard, 2007
8
 
 
9
 
# FFC common modules
10
 
from ffc.common.utils import *
11
 
from ffc.common.log import error
12
 
 
13
 
# FFC fem modules
14
 
from finiteelement import *
15
 
from quadratureelement import *
16
 
from mixedelement import *
17
 
 
18
 
class DofMap:
19
 
    """A DofMap represents a description of the degrees of a freedom
20
 
    of a finite element space, from which the mapping from local to
21
 
    global degrees of freedom can be computed."""
22
 
 
23
 
    def __init__(self, element):
24
 
        "Create dof map from given finite element"
25
 
 
26
 
        # Get entity dofs and dof representation from element
27
 
        entity_dofs = element.entity_dofs()
28
 
 
29
 
        # Generate dof map data
30
 
        self.__signature           = "FFC dof map for " + element.signature()
31
 
        self.__local_dimension     = element.space_dimension()
32
 
        self.__geometric_dimension = element.geometric_dimension()
33
 
        self.__entity_dofs         = entity_dofs
34
 
        self.__num_dofs_per_dim    = self.__compute_num_dofs_per_dim(entity_dofs)
35
 
        self.__num_facet_dofs      = self.__compute_num_facet_dofs(entity_dofs, element.cell_shape())
36
 
        self.__dof_entities        = self.__compute_dof_entities(entity_dofs)
37
 
        self.__incidence           = self.__compute_incidence(element.cell_shape())
38
 
        self.__dof_maps            = self.__compute_dof_maps(element)
39
 
        self.__element             = element
40
 
 
41
 
    def signature(self):
42
 
        "Return a string identifying the dof map"
43
 
        return self.__signature
44
 
 
45
 
    def local_dimension(self):
46
 
        "Return the dimension of the local finite element function space"
47
 
        return self.__local_dimension
48
 
 
49
 
    def geometric_dimension(self):
50
 
        "Return the geometric dimension of the finite element domain"
51
 
        return self.__geometric_dimension
52
 
 
53
 
    def entity_dofs(self):
54
 
        """Return a dictionary mapping the mesh entities of the
55
 
        reference cell to the degrees of freedom associated with the
56
 
        entity"""
57
 
        return self.__entity_dofs
58
 
 
59
 
    def num_facet_dofs(self):
60
 
        "Return the number of dofs on each cell facet"
61
 
        return self.__num_facet_dofs
62
 
 
63
 
    def get_num_of_points(self):
64
 
        "Return the number of points associated with each dof"
65
 
        return [len(dof.points) for dof in self.dual_basis()]
66
 
 
67
 
    def get_max_num_of_points(self):
68
 
        "Return the maximal number of points associated with the dofs"
69
 
        return max(self.get_num_of_points())
70
 
       
71
 
    def dof_coordinates(self):
72
 
        "Return the coordinates associated with each dof"
73
 
        # FIXME meg: Now returns the first coordinate associated with
74
 
        # each dof... for the sake of the codegeneration for
75
 
        # tabulate_coordinates!
76
 
        return [dof.points[0] for dof in self.dual_basis()]
77
 
 
78
 
    def num_dofs_per_dim(self, sub_dof_map=None):
79
 
        "Return the number of dofs associated with each topological dimension for sub dof map or total"
80
 
        if sub_dof_map == None:
81
 
            D = max(self.__entity_dofs[0])
82
 
            num_dofs_per_dim = (D + 1)*[0]
83
 
            for sub_num_dofs_per_dim in self.__num_dofs_per_dim:
84
 
                for dim in sub_num_dofs_per_dim:
85
 
                    num_dofs_per_dim[dim] += sub_num_dofs_per_dim[dim]
86
 
            return num_dofs_per_dim
87
 
        else:
88
 
            return self.__num_dofs_per_dim[sub_dof_map]
89
 
 
90
 
    def dof_entities(self):
91
 
        "Return a list of which entities are associated with each dof"
92
 
        return self.__dof_entities
93
 
 
94
 
    def incidence(self):
95
 
        "Return a dictionary of which entities are incident with which"
96
 
        return self.__incidence
97
 
 
98
 
    def num_sub_dof_maps(self):
99
 
        "Return the number of sub dof maps"
100
 
        return len(self.__dof_maps)
101
 
 
102
 
    def sub_dof_map(self, i):
103
 
        "Return sub dof map i"
104
 
        if len(self.__dof_maps) > 0:
105
 
            return self.__dof_maps[i]
106
 
        else:
107
 
            return None
108
 
 
109
 
    def element(self):
110
 
        "Return the finite element associated with the dof map"
111
 
        return self.__element
112
 
 
113
 
    def dual_basis(self):
114
 
        """Return the representation of the dual basis for the element
115
 
        associated with the DofMap"""
116
 
        return self.element().dual_basis()
117
 
 
118
 
    def __compute_num_dofs_per_dim(self, entity_dofs):
119
 
        "Compute the number of dofs associated with each topological dimension"
120
 
        num_dofs_per_dim = []
121
 
        for sub_entity_dofs in entity_dofs:
122
 
            sub_num_dofs_per_dim = {}
123
 
            for dim in sub_entity_dofs:
124
 
                num_dofs = [len(sub_entity_dofs[dim][entity]) for entity in sub_entity_dofs[dim]]
125
 
                if dim in sub_num_dofs_per_dim:
126
 
                    sub_num_dofs_per_dim[dim] += pick_first(num_dofs)
127
 
                else:
128
 
                    sub_num_dofs_per_dim[dim] = pick_first(num_dofs)
129
 
            num_dofs_per_dim += [sub_num_dofs_per_dim]
130
 
        return num_dofs_per_dim
131
 
 
132
 
    def __compute_num_facet_dofs(self, entity_dofs, cell_shape):
133
 
        "Compute the number of dofs on each cell facet"
134
 
 
135
 
        # Number of entites of each dimension incident with a facet
136
 
        num_facet_entities = {LINE: [1, 0], TRIANGLE: [2, 1, 0], TETRAHEDRON: [3, 3, 1, 0]}
137
 
 
138
 
        # Get total number of dofs per dimension
139
 
        num_dofs_per_dim = self.num_dofs_per_dim()
140
 
 
141
 
        # Count the total
142
 
        num_facet_dofs = 0
143
 
        for dim in range(len(num_dofs_per_dim)):
144
 
            num_facet_dofs += num_facet_entities[cell_shape][dim]*num_dofs_per_dim[dim]
145
 
 
146
 
        return num_facet_dofs
147
 
        
148
 
    def __compute_dof_entities(self, entity_dofs):
149
 
        "Compute the entities associated with each dof"
150
 
        dof_entities = {}
151
 
        offset = 0
152
 
        for sub_entity_dofs in entity_dofs:
153
 
            for dim in sub_entity_dofs:
154
 
                for entity in sub_entity_dofs[dim]:
155
 
                    for dof in sub_entity_dofs[dim][entity]:
156
 
                        dof_entities[offset + dof] = (dim, entity)
157
 
            offset = max(dof_entities) + 1
158
 
        return dof_entities
159
 
 
160
 
    def __compute_incidence(self, cell_shape):
161
 
        "Compute which entities are incident with which"
162
 
 
163
 
        # Set topological dimension of simplex
164
 
        if cell_shape == LINE:
165
 
            D = 1
166
 
        elif cell_shape == TRIANGLE:
167
 
            D = 2
168
 
        elif cell_shape == TETRAHEDRON:
169
 
            D = 3
170
 
        else:
171
 
            error("Cannot handle cell shape: " + str(cell_shape))
172
 
 
173
 
        # Compute the incident vertices for each entity
174
 
        sub_simplices = []
175
 
        for dim in range(D + 1):
176
 
            sub_simplices += [self.__compute_sub_simplices(D, dim)]
177
 
 
178
 
        # Check which entities are incident, d0 --> d1 for d0 >= d1
179
 
        incidence = {}
180
 
        for d0 in range(0, D + 1):
181
 
            for i0 in range(len(sub_simplices[d0])):
182
 
                for d1 in range(d0 + 1):
183
 
                    for i1 in range(len(sub_simplices[d1])):
184
 
                        if min([v in sub_simplices[d0][i0] for v in sub_simplices[d1][i1]]) == True:
185
 
                            incidence[((d0, i0), (d1, i1))] = True
186
 
                        else:
187
 
                            incidence[((d0, i0), (d1, i1))] = False
188
 
 
189
 
        return incidence
190
 
 
191
 
    def __compute_dof_maps(self, element):
192
 
        "Compute recursively nested dof maps"
193
 
        if isinstance(element, FiniteElement):
194
 
            return [self]
195
 
        return [DofMap(element.sub_element(i)) for i in range(element.num_sub_elements())]
196
 
 
197
 
    def __compute_sub_simplices(self, D, d):
198
 
        "Compute vertices for all sub simplices of dimension d (code taken from Exterior)"
199
 
 
200
 
        # Number of vertices
201
 
        num_vertices = D + 1
202
 
 
203
 
        # Special cases: d = 0 and d = D
204
 
        if d == 0:
205
 
            return [[i] for i in range(num_vertices)]
206
 
        elif d == D:
207
 
            return [range(num_vertices)]
208
 
 
209
 
        # Compute all permutations of num_vertices - (d + 1)
210
 
        permutations = compute_permutations(num_vertices - d - 1, num_vertices)
211
 
 
212
 
        # Iterate over sub simplices
213
 
        sub_simplices = []
214
 
        for i in range(len(permutations)):
215
 
 
216
 
            # Pick tuple i among permutations (non-incident vertices)
217
 
            remove = permutations[i]
218
 
 
219
 
            # Remove vertices, keeping d + 1 vertices
220
 
            vertices = [v for v in range(num_vertices) if not v in remove]
221
 
            sub_simplices += [vertices]
222
 
 
223
 
        return sub_simplices
224
 
 
225
 
    def __is_vector_lagrange(self, element):
226
 
        "Check if element is vector Lagrange element"
227
 
        if not element.family() == "Mixed":
228
 
            return False
229
 
        families = [element.sub_element(i).family() for i in range(element.num_sub_elements())]
230
 
        dimensions = [element.sub_element(i).space_dimension() for i in range(element.num_sub_elements())]
231
 
        return families[:-1] == families[1:] and \
232
 
               dimensions[:-1] == dimensions[1:]  and \
233
 
               families[0] in ["Lagrange", "Discontinuous Lagrange"]
234
 
        
235
 
    def __repr__(self):
236
 
        "Pretty print"
237
 
        return self.signature()