/usr/lib/python2.7/dist-packages/ffc/mixedelement.py is in python-ffc 1.6.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | # Copyright (C) 2005-2010 Anders Logg
#
# This file is part of FFC.
#
# FFC 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.
#
# FFC 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 FFC. If not, see <http://www.gnu.org/licenses/>.
#
# Modified by Garth N. Wells, 2006-2009
# Modified by Marie E. Rognes, 2007-2010
# Modified by Kristian B. Oelgaard, 2010
# Modified by Lizao Li, 2015
#
# Last changed: 2015-04-25
# Python modules
import numpy
# FFC modules
from ffc.log import error
# UFL utils
from ufl.utils.sequences import product
class MixedElement:
"Create a FFC mixed element from a list of FFC/FIAT elements."
def __init__(self, elements):
self._elements = elements
self._entity_dofs = _combine_entity_dofs(self._elements)
def elements(self):
return self._elements
def space_dimension(self):
return sum(e.space_dimension() for e in self._elements)
def value_shape(self):
# Values of Tensor elements are flattened in MixedElements
num_comps = lambda x: numpy.prod(x) if x else 1
return (sum(num_comps(e.value_shape()) or 1 for e in self._elements),)
def entity_dofs(self):
return self._entity_dofs
def mapping(self):
return [m for e in self._elements for m in e.mapping()]
def dual_basis(self):
return [L for e in self._elements for L in e.dual_basis()]
def num_components(self):
return sum(_num_components(e) for e in self._elements)
def tabulate(self, order, points):
"""
Tabulate values on mixed element by appropriately reordering
the tabulated values for the nested elements.
The table of values is organized as follows:
D^a v_i[j](x_k) = table[a][i][j][k]
where a is a multi-index (tuple) representing the derivative.
For example, a = (1, 1) represents d/dx d/dy.
"""
# Special case: only one element
# NOTE: KBO: Why do we need this special case? (FFC Bug #798578)
# When calling tabulate() on a MixedElement one should be able to
# rely on getting data back which is ordered like a mixed element
# irrespective of the number of elements?
# if len(self._elements) == 1:
# return self._elements[0].tabulate(order, points)
# Zeros for insertion into mixed table
table_shape = (self.space_dimension(), self.num_components(), len(points))
# Iterate over elements and fill in non-zero values
irange = (0, 0)
crange = (0, 0)
mixed_table = {}
for element in self._elements:
# Tabulate element
table = element.tabulate(order, points)
# Compute range for insertion into mixed table
irange = (irange[1], irange[1] + element.space_dimension())
crange = (crange[1], crange[1] + _num_components(element))
# Insert table into mixed table
for dtuple in table.keys():
# Insert zeros if necessary (should only happen first time)
if not dtuple in mixed_table:
# NOTE: It is super important to create a new numpy.zeros
# instance to avoid manipulating a numpy reference in case
# it is created outside the loop.
mixed_table[dtuple] = numpy.zeros(table_shape)
# Insert non-zero values
if (crange[1] - crange[0]) > 1:
mixed_table[dtuple][irange[0]:irange[1], crange[0]:crange[1]] = numpy.reshape(table[dtuple], (irange[1] - irange[0], crange[1] - crange[0], len(points)))
else:
mixed_table[dtuple][irange[0]:irange[1], crange[0]] = table[dtuple]
return mixed_table
#--- Utility functions ---
def _combine_entity_dofs(elements):
"""
Combine the entity_dofs from a list of elements into a combined
entity_dof containing the information for all the elements.
"""
# Return {} if no elements
if not elements:
return {}
# Initialize entity_dofs dictionary
entity_dofs = dict((key, {}) for key in elements[0].entity_dofs())
for dim in elements[0].entity_dofs():
for entity in elements[0].entity_dofs()[dim]:
entity_dofs[dim][entity] = []
offset = 0
# Insert dofs from each element into the mixed entity_dof.
for e in elements:
dofs = e.entity_dofs()
for dim in dofs:
for entity in dofs[dim]:
# Must take offset into account
shifted_dofs = [v + offset for v in dofs[dim][entity]]
# Insert dofs from this element into the entity_dofs
entity_dofs[dim][entity] += shifted_dofs
# Adjust offset
offset += e.space_dimension()
return entity_dofs
def _num_components(element):
"Compute number of components for element."
return product(element.value_shape())
|