/usr/lib/python2.7/dist-packages/ufl/domain.py is in python-ufl 1.6.0-1.
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | "Types for representing a geometric domain."
# Copyright (C) 2008-2014 Martin Sandve Alnes
#
# This file is part of UFL.
#
# UFL 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.
#
# UFL 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 UFL. If not, see <http://www.gnu.org/licenses/>.
#
# Modified by Anders Logg, 2009.
# Modified by Kristian B. Oelgaard, 2009
# Modified by Marie E. Rognes 2012
from collections import defaultdict
from six import iteritems
from ufl.corealg.traversal import traverse_unique_terminals
from ufl.log import warning, error, deprecate
from ufl.assertions import ufl_assert
from ufl.common import istr, EmptyDict
from ufl.core.terminal import Terminal
from ufl.protocols import id_or_none
from ufl.cell import as_cell, affine_cells, Cell, ProductCell
class Domain(object):
"""Symbolic representation of a geometrical domain.
Used in the definition of geometric terminal expressions,
finite element spaces, and integration measures.
Takes a single positional argument which is either the
cell of the underlying mesh
D = Domain(triangle)
or the coordinate field which is a vector valued Coefficient.
P2 = VectorElement("CG", D, 2)
x = Coefficient(P2)
E = Domain(x)
With the cell variant of the constructor, an optional
label can be passed to distinguish two domains from each
other.
Da = Domain(cell, label="a")
Db = Domain(cell, label="b")
an optional data argument can also be passed, for integration
with problem solver environments (e.g. dolfin), this is typically
the underlying mesh.
Da = Domain(cell, label="a", data=mesha)
Db = Domain(cell, label="b", data=meshb)
"""
__slots__ = (
"_geometric_dimension",
"_topological_dimension",
"_cell",
"_coordinates",
"_label",
"_data",
)
def __init__(self, *args, **kwargs):
# Parse positional argument, either a Cell or a Coefficient
ufl_assert(len(args) == 1, "Only one positional argument accepted. See Domain docstring.")
arg, = args
# To avoid circular dependencies...
from ufl.coefficient import Coefficient
if isinstance(arg, Cell):
# Allow keyword arguments for label or data
self._coordinates = None
self._cell = arg
self._label = kwargs.pop("label", None)
self._data = kwargs.pop("data", None)
elif isinstance(arg, Coefficient):
# Disallow additional label and data, get from underlying 'flat domain'
self._coordinates = arg
flat_domain = arg.domain()
self._cell = flat_domain.cell()
self._label = flat_domain.label()
self._data = flat_domain.data()
# Get geometric dimension from self._coordinates shape
gdim, = self._coordinates.ufl_shape
if gdim != self._cell.geometric_dimension():
warning("Using geometric dimension from coordinates!")
self._cell = Cell(self._cell.cellname(), gdim)
#ufl_assert(self._coordinates.ufl_shape == (self._cell.geometric_dimension(),),
# "Shape of coordinates %s does not match geometric dimension %d of cell." %\
# (self._coordinates.ufl_shape, self._cell.geometric_dimension()))
else:
ufl_error("Invalid first argument to Domain.")
# Now we should have a Cell or something went wrong
ufl_assert(isinstance(self._cell, Cell), "Failed to construct a Cell from input arguments.")
self._geometric_dimension = self._cell.geometric_dimension()
self._topological_dimension = self._cell.topological_dimension()
# Sanity checks
ufl_assert(isinstance(self._geometric_dimension, int),
"Expecting integer geometric dimension.")
ufl_assert(isinstance(self._topological_dimension, int),
"Expecting integer topological dimension.")
ufl_assert(self._topological_dimension <= self._geometric_dimension,
"Topological dimension cannot be greater than geometric dimension.")
ufl_assert(self._topological_dimension >= 0,
"Topological dimension must be non-negative.")
if self._coordinates is not None:
ufl_assert(isinstance(self._coordinates, Coefficient),
"Expecting None or Coefficient for coordinates.")
ufl_assert(self._coordinates.domain().coordinates() is None,
"Coordinates must be defined on a domain without coordinates of its own.")
ufl_assert(self._label is None or isinstance(self._label, str),
"Expecting None or str for label.")
ufl_assert(self._data is None or hasattr(self._data, "ufl_id"),
"Expecting data object to implement ufl_id().")
# Check that we didn't get any arguments that we havent interpreted
ufl_assert(not kwargs, "Got unused keyword arguments %s" % ', '.join(sorted(kwargs)))
def reconstruct(self, cell=None, coordinates=None, label=None, data=None):
"Create a new Domain object with possibly changed label or data."
if coordinates is None:
if cell is None:
cell = self.cell()
if label is None:
label = self.label()
if data is None:
data = self.data()
return Domain(cell, label=label, data=data)
else:
ufl_assert(all((cell is None, label is None, data is None)),
"No other arguments allowed with coordinates.")
return Domain(coordinates)
def geometric_dimension(self):
"Return the dimension of the space this domain is embedded in."
return self._geometric_dimension
def topological_dimension(self):
"Return the dimension of the topology of this domain."
return self._topological_dimension
def cell(self):
"Return the cell this domain is defined in terms of."
return self._cell
def coordinates(self):
"Return the coordinate vector field this domain is defined in terms of."
return self._coordinates
def coordinate_element(self):
"Return the finite element of the coordinate vector field of this domain."
x = self.coordinates()
if x is None:
from ufl import VectorElement
return VectorElement("Lagrange", self, 1)
else:
return x.element()
def label(self):
"Return the label identifying this domain. None means no label has been set."
return self._label
def is_piecewise_linear_simplex_domain(self):
return (self.coordinate_element().degree() == 1) and (self.cell().cellname() in affine_cells)
def data(self):
"Return attached data object."
return self._data
def signature_data(self, renumbering):
"Signature data of domain depend on the global domain numbering."
count = renumbering[self]
cdata = self.cell()
x = self.coordinates()
xdata = (None if x is None else x.signature_data(renumbering))
return (count, cdata, xdata)
def hash_data(self):
# Including only id of data here.
# If this is a problem in pydolfin, the user will just have
# to create explicit Domain objects to avoid problems.
# NB! This data is used in both __hash__ and __eq__.
return (self._label,
self._cell,
self._coordinates, # None or a Coefficient
id_or_none(self._data))
def __hash__(self):
return hash(self.hash_data())
def __eq__(self, other):
return type(self) == type(other) and self.hash_data() == other.hash_data()
def __lt__(self, other):
if type(self) != type(other):
return NotImplemented
return self.hash_data() < other.hash_data()
def __str__(self):
if self._coordinates is None:
c = ""
else:
c = " and coordinates %r" % self._coordinates
s = (self._cell, self._label, c)
return "<Domain built from %s with label %s%s>" % s
def reconstruction_signature(self):
"""Format as string for evaluation as Python object.
For use with cross language frameworks, stored in generated code
and evaluated later in Python to reconstruct this object.
This differs from repr in that it does not include domain
label and data or coordinates, which must be reconstructed
or supplied by other means.
"""
s = (self._cell,)
return "Domain(%r)" % s
def __repr__(self):
if self._coordinates is None:
d = None if self._data is None else "<data with id %s>" % id_or_none(self._data)
s = (self._cell, self._label, d)
return "Domain(%r, label=%r, data=%r)" % s
else:
s = (self._coordinates,)
return "Domain(%r)" % s
class OverlapDomain(Domain):
"""WARNING: This is work in progress, design is in no way completed."""
__slots__ = ("_child_domains",)
def __init__(self, domain1, domain2, label=None, data=None):
# Check domain compatibility
ufl_assert(domain1.cell() == domain2.cell(),
"Cell mismatch in overlap domain.")
ufl_assert(domain1.geometric_dimension() == domain2.geometric_dimension(),
"Dimension mismatch in overlap domain.")
ufl_assert(domain1.topological_dimension() == domain2.topological_dimension(),
"Dimension mismatch in overlap domain.")
# Initialize parent class
Domain.__init__(self, domain1.cell(), label=label, data=data)
# Save child domains for later
self._child_domains = (domain1, domain2)
def child_domains(self):
return self._child_domains
class IntersectionDomain(Domain):
"""WARNING: This is work in progress, design is in no way completed."""
__slots__ = ("_child_domains",)
def __init__(self, domain1, domain2, label=None, data=None):
# Check domain compatibility
ufl_assert(domain1.cell() == domain2.cell(),
"Cell mismatch in overlap domain.")
ufl_assert(domain1.geometric_dimension() == domain2.geometric_dimension(),
"Dimension mismatch in overlap domain.")
ufl_assert(domain1.topological_dimension() == domain2.topological_dimension(),
"Dimension mismatch in overlap domain.")
# Get the right properties of this domain
gdim = domain1.geometric_dimension()
tdim = domain1.topological_dimension()-1
cell = Cell(domain1.cell().facet_cellname(), gdim)
ufl_assert(cell.topological_dimension() == tdim)
# Initialize parent class
Domain.__init__(self, cell, gdim, tdim, label=label, data=data)
# Save child domains for later
self._child_domains = (domain1, domain2)
def child_domains(self):
return self._child_domains
class ProductDomain(Domain):
"""WARNING: This is work in progress, design is in no way completed."""
__slots__ = ("_child_domains",)
def __init__(self, domains, data=None):
# Get the right properties of this domain
gdim = sum(domain.geometric_dimension() for domain in domains)
tdim = sum(domain.topological_dimension() for domain in domains)
cell = ProductCell(*[domain.cell() for domain in domains])
label = "product_of_%s" % "_".join(str(domain.label()) for domain in domains)
# Initialize parent class
Domain.__init__(self, cell, gdim, tdim, label=label, data=data)
# Save child domains for later
self._child_domains = tuple(domains)
def child_domains(self):
return self._child_domains
# --- Utility conversion functions
def as_domain(domain):
"""Convert any valid object to a Domain (in particular, cell or cellname string),
or return domain if it is already a Domain."""
if isinstance(domain, Domain):
return domain
elif hasattr(domain, "ufl_domain"):
return domain.ufl_domain()
else:
return Domain(as_cell(domain))
def join_subdomain_data(subdomain_datas): # FIXME: Remove? Think it's unused now.
newdata = {}
for data in subdomain_datas:
for k, v in iteritems(data):
nv = newdata.get(k)
if nv is None:
# New item, just add it
newdata[k] = v
elif v is not None:
id1 = id_or_none(nv)
id2 = id_or_none(v)
if id1 != id2:
error("Found multiple data objects with key %s." % k)
return newdata
def check_domain_compatibility(domains):
# Validate that the domains are the same except for possibly the data
labels = set(domain.label() for domain in domains)
ufl_assert(len(labels) == 1 or (len(labels) == 2 and None in labels),
"Got incompatible domain labels %s in check_domain_compatibility." % (labels,))
all_cellnames = [dom.cell().cellname() for dom in domains]
if len(set(all_cellnames)) != 1:
error("Cellname mismatch between domains with same label.")
all_coordinates = set(dom.coordinates() for dom in domains) - set((None,))
if len(all_coordinates) > 1:
error("Coordinates mismatch between domains with same label.")
def join_domains(domains):
"""Take a list of Domains and return a list with only unique domain objects.
Checks that domains with the same label are compatible,
and allows data to be None or
"""
# Ignore Nones in input domains
domains = [domain for domain in domains if domain is not None]
# Build lists of domain objects with same label
label2domlist = defaultdict(list)
for domain in domains:
label2domlist[domain.label()].append(domain)
# Extract None list from this dict, map to label but only if only one exists
if None in label2domlist:
none_domains = {}
if len(label2domlist) == 1:
pass
elif len(label2domlist) == 2:
none_domains = label2domlist[None]
del label2domlist[None]
key, = list(label2domlist.keys())
label2domlist[key].extend(none_domains)
else:
error("Ambiguous mapping of domains with label None to multiple domains with different labels.")
else:
none_domains = {}
# Join domain data to get a list with only one domain for each label
newdomains = []
for label in sorted(label2domlist.keys()):
domlist = label2domlist[label]
if len(domlist) == 1:
dom, = domlist
else:
# Validate that the domains are the same except for possibly the data
check_domain_compatibility(domlist)
# Pick first non-None data object
for dom in domlist:
newdata = dom.data()
if newdata is not None:
break
cell = dom.cell()
gdim = dom.geometric_dimension()
tdim = dom.topological_dimension()
# Validate that data ids match if present
if newdata is not None:
data_ids = [id_or_none(dom.data()) for dom in domlist]
data_ids = set(i for i in data_ids if i is not None)
if len(data_ids) > 1:
error("Found data objects with different ids in domains with same label.")
# Pick first non-None coordinates object
for dom in domlist:
newcoordinates = dom.coordinates()
if newcoordinates is not None:
ufl_assert(newcoordinates.domain().coordinates() is None,
"A coordinate domain cannot have coordinates.")
break
# Validate that coordinates match if present
if newcoordinates is not None:
all_coordinates = [dom.coordinates() for dom in domlist]
all_coordinates = set(c for c in all_coordinates if c is not None)
if len(all_coordinates) > 1:
error("Found different coordinates in domains with same label.")
# Construct a new domain object with fully completed data
if newcoordinates is not None:
dom = Domain(newcoordinates)
else:
dom = Domain(cell, label=label, data=newdata)
newdomains.append(dom)
return tuple(newdomains)
def extract_domains(expr):
domainlist = []
for t in traverse_unique_terminals(expr):
domainlist.extend(t.domains())
return sorted(join_domains(domainlist))
|