[ufl] 02/03: New upstream version 2017.2.0
Drew Parsons
dparsons at moszumanska.debian.org
Sat Oct 7 07:25:19 UTC 2017
This is an automated email from the git hooks/post-receive script.
dparsons pushed a commit to branch experimental
in repository ufl.
commit 896e94a9b7232ca6913ea6e49a9b7e90b9c8b71c
Author: Drew Parsons <dparsons at debian.org>
Date: Sat Oct 7 15:16:45 2017 +0800
New upstream version 2017.2.0
---
.circleci/config.yml | 22 +
.mailmap | 132 +++++
.travis.yml | 18 +
ChangeLog.rst | 10 +
bitbucket-pipelines.yml | 12 +
demo/Poisson.ufl | 2 +-
doc/sphinx/source/conf.py | 2 +-
doc/sphinx/source/releases.rst | 1 +
doc/sphinx/source/releases/v2017.1.0.post1.rst | 10 +
doc/sphinx/source/releases/v2017.2.0.rst | 8 +
release.conf | 8 +
scripts/ufl-convert | 11 +-
setup.cfg | 2 +-
setup.py | 6 +-
shippable.yml | 12 +
test/conftest.py | 61 +++
test/test_algorithms.py | 16 +-
test/test_unicode_convert.py | 36 ++
ufl/__init__.py | 7 +-
ufl/algorithms/__init__.py | 20 +-
ufl/algorithms/apply_geometry_lowering.py | 4 +-
ufl/algorithms/compute_form_data.py | 3 +-
ufl/algorithms/domain_analysis.py | 22 +-
ufl/algorithms/estimate_degrees.py | 31 +-
ufl/algorithms/formdata.py | 7 +-
ufl/argument.py | 5 -
ufl/cell.py | 11 +-
ufl/coefficient.py | 5 -
ufl/constantvalue.py | 7 +-
ufl/core/expr.py | 62 ---
ufl/core/multiindex.py | 12 +-
ufl/core/operator.py | 2 +-
ufl/domain.py | 33 +-
ufl/finiteelement/elementlist.py | 6 +-
ufl/finiteelement/enrichedelement.py | 2 +-
ufl/finiteelement/finiteelement.py | 18 +-
ufl/finiteelement/finiteelementbase.py | 18 +-
ufl/finiteelement/mixedelement.py | 17 +-
ufl/finiteelement/restrictedelement.py | 18 +-
ufl/form.py | 59 +--
ufl/formatting/ufl2unicode.py | 702 +++++++++++++++++++++++++
ufl/integral.py | 30 +-
ufl/measure.py | 63 ++-
ufl/sobolevspace.py | 3 +-
ufl/tensoralgebra.py | 29 +-
ufl/utils/sequences.py | 18 +-
ufl/utils/sorting.py | 9 -
47 files changed, 1267 insertions(+), 325 deletions(-)
diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..bd57d63
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,22 @@
+version: 2
+jobs:
+ build:
+ docker:
+ - image: circleci/python:3.6
+ working_directory: ~/ufl-test
+ steps:
+ - checkout
+ - run:
+ name: Install dependencies # Install with sudo as tests not run as superuser in circleci/python
+ command: sudo pip install flake8 numpy pytest six --upgrade
+ - run:
+ name: Install UFL
+ command: pip install --user .
+ - run:
+ name: Run flake8 tests
+ command: python -m flake8 .
+ - run:
+ name: Run unit tests
+ command: python -m pytest --junitxml=test-output test/
+ - store_test_results:
+ path: test-output/
\ No newline at end of file
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..e267362
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,132 @@
+Anders Logg <logg at chalmers.se>
+Anders Logg <logg at chalmers.se> <ffc at bamse>
+Anders Logg <logg at chalmers.se> <logg at yavanna>
+Anders Logg <logg at chalmers.se> <logg at aule>
+Anders Logg <logg at chalmers.se> logg <logg at localhost.localdomain>
+Anders Logg <logg at chalmers.se> fenics <devnull at localhost>
+Anders Logg <logg at chalmers.se> hg <hg at numenor>
+Anders Logg <logg at chalmers.se> root <root at leja>
+Anders Logg <logg at chalmers.se> <logg at glaurung>
+Anders Logg <logg at chalmers.se> <logg at simula.no>
+Anders Logg <logg at chalmers.se> <anders.logg+bitbucket at gmail.com>
+Anders Logg <logg at chalmers.se> <logg at olorin>
+Anders Logg <logg at chalmers.se> <logg at tti-c.org>
+Anders Logg <logg at chalmers.se> anders <anders at localhost.localdomain>
+Anders Logg <logg at chalmers.se> logg <devnull at localhost>
+Anders Logg <logg at chalmers.se> logg <logg at bigblue.simula.no>
+Anders Logg <logg at chalmers.se> logg <logg at bunjil.simula.no>
+Anders Logg <logg at chalmers.se> logg <logg at olorin>
+Andy R. Terrel <andy.terrel at gmail.com>
+Andy R. Terrel <andy.terrel at gmail.com> <aterrel at uchicago.edu>
+Andy R. Terrel <andy.terrel at gmail.com> aterrel <devnull at localhost>
+Andy R. Terrel <andy.terrel at gmail.com> <aterrel at dhcp-11-20.cs.uchicago.edu>
+Benjamin Kehlet <benjamik at simula.no>
+Benjamin Kehlet <benjamik at simula.no> <benjamik at benjamik-hp.simula.no>
+Benjamin Kehlet <benjamik at simula.no> <benjamik at ifi.uio.no>
+Benjamin Kehlet <benjamik at simula.no> <benjamik at login.ifi.uio.no>
+Benjamin Kehlet <benjamik at simula.no> <bkehlet at bkehlet-laptop>
+Chris Richardson <chris at bpi.cam.ac.uk>
+Chris Richardson <chris at bpi.cam.ac.uk> chris <chris at Lenovo-Edge.(none)>
+Chris Richardson <chris at bpi.cam.ac.uk> Chris Richardson <bpi.cam.ac.uk>
+Chris Richardson <chris at bpi.cam.ac.uk> root <root at bpi.cam.ac.uk>
+Corrado Maurini <corrado.maurini at upmc.fr>
+Corrado Maurini <corrado.maurini at upmc.fr> <cmaurini at gmail.com>
+Dag Lindbo <dag at csc.kth.se>
+Dag Lindbo <dag at csc.kth.se> dag <dag at dag-laptop>
+Dag Lindbo <dag at csc.kth.se> dag <dag at na55.nada.kth.se>
+David Ham <david.ham at imperial.ac.uk>
+David Ham <david.ham at imperial.ac.uk> david.ham at imperial.ac.uk <>
+Evan Lezar <evanlezar at gmail.com>
+Evan Lezar <evanlezar at gmail.com> <mail at evanlezar.com>
+Evan Lezar <evanlezar at gmail.com> elezar <elezar at labby>
+Evan Lezar <evanlezar at gmail.com> elezar <elezar at lefauve>
+Fredrik Valdmanis <fredrik at valdmanis.com>
+Fredrik Valdmanis <fredrik at valdmanis.com> Fredrik Valdmanis <fredva at ifi.uio.no>
+Garth N. Wells <gnw20 at cam.ac.uk>
+Garth N. Wells <gnw20 at cam.ac.uk> root <root at fornax.esc.cam.ac.uk>
+Garth N. Wells <gnw20 at cam.ac.uk> garth <devnull at localhost>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at debian.eng.cam.ac.uk>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at fedora32-virtual>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at gnw20pc>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at home-laptop>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at localhost.localdomain>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at ubuntu32-virtual>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at ubuntu.eng.cam.ac.uk>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at garth-laptop>
+Garth N. Wells <gnw20 at cam.ac.uk> <garth at gnw20pc>
+Garth N. Wells <gnw20 at cam.ac.uk> <g.n.wells at tudelft.nl>
+Garth N. Wells <gnw20 at cam.ac.uk> gnw20 at cam.ac.uk <>
+gideonsimpson <gideonsimpson at dyn-128-59-151-14.dyn.columbia.edu>
+Gustav Magnus Vikström <gustavv at simula.no>
+Gustav Magnus Vikström <gustavv at simula.no> <gustavv at ifi.uio.no>
+Gustav Magnus Vikström <gustavv at simula.no> <gustavv at ifi.uio.no>
+Gustav Magnus Vikström <gustavv at simula.no> <gustavv at utlaan-laptop-1>
+Harish Narayanan <hnarayanan at gmail.com>
+Harish Narayanan <hnarayanan at gmail.com> Harish Narayanan <harish at simula.no>
+Johan Hoffman <jhoffman at csc.kth.se>
+Johan Hoffman <jhoffman at csc.kth.se> hoffman <devnull at localhost>
+Johan Hoffman <jhoffman at csc.kth.se> <jhoffman at na41.nada.kth.se>
+Johan Hoffman <jhoffman at csc.kth.se> <jhoffman at na42.nada.kth.se>
+Ilmar Wilbers <ilmarw at simula.no>
+Ilmar Wilbers <ilmarw at simula.no> <ilmarw at gogmagog.simula.no>
+Ilmar Wilbers <ilmarw at simula.no> <ilmarw at multiboot.local>
+Jack S. Hale <jack.hale at uni.lu>
+Jack S. Hale <jack.hale at uni.lu> <j.hale09 at imperial.ac.uk>
+Johan Hake <hake.dev at gmail.com>
+Johan Hake <hake.dev at gmail.com> <johan.hake at gmail.com>
+Johan Hake <hake.dev at gmail.com> <hake at simula.no>
+Johan Jansson <jjan at csc.kth.se>
+Johan Jansson <jjan at csc.kth.se> johan <johan at localhost.localdomain>
+Johan Jansson <jjan at csc.kth.se> johan <johan at nova>
+Johan Jansson <jjan at csc.kth.se> johanjan <devnull at localhost>
+Johan Jansson <jjan at csc.kth.se> johanjan <johanjan at localhost.localdomain>
+Johan Jansson <jjan at csc.kth.se> Johan Jansson <johanjan at math.chalmers.se>
+Johannes Ring <johannr at simula.no>
+Johannes Ring <johannr at simula.no> <johannr at communalis.simula.no>
+Kent-Andre Mardal <kent-and at simula.no>
+Kent-Andre Mardal <kent-and at simula.no> <kent-and at localhost>
+Kristian B. Ølgaard <k.b.oelgaard at gmail.com>
+Kristian B. Ølgaard <k.b.oelgaard at gmail.com> <k.b.oelgaard at tudelft.nl>
+Kristian B. Ølgaard <k.b.oelgaard at gmail.com> <oelgaard at localhost.localdomain>
+Magnus Vikstrøm <gustavv at ifi.uio.no>
+Marco Morandini <marco.morandini at polimi.it>
+Marco Morandini <marco.morandini at polimi.it> <morandini at aero.polimi.it>
+Marie E. Rognes <meg at simula.no>
+Marie E. Rognes <meg at simula.no> <meg at math.uio.no>
+Marie E. Rognes <meg at simula.no> <meg at meg-laptop>
+Marie E. Rognes <meg at simula.no> Marie E. Rognes (meg at simula.no) <Marie E. Rognes (meg at simula.no)>
+Marie E. Rognes <meg at simula.no> meg at simula.no <>
+Martin Sandve Alnæs <martinal at simula.no>
+Martin Sandve Alnæs <martinal at simula.no> <martinal at localhost>
+Martin Sandve Alnæs <martinal at simula.no> <martinal at martinal-desktop>
+Michele Zaffalon <michele.zaffalon at gmail.com>
+Mikael Mortensen <mikaem at math.uio.no>
+Mikael Mortensen <mikaem at math.uio.no> <mikael.mortensen at gmail.com>
+Nate Sime <njcs4 at cam.ac.uk>
+Nate Sime <njcs4 at cam.ac.uk> <njcs4 at galah.bpi.cam.ac.uk>
+Nuno Lopes <ndl at ptmat.fc.ul.pt>
+Nuno Lopes <ndl at ptmat.fc.ul.pt> N.Lopes <devnull at localhost>
+Patrick Farrell <patrick.farrell at maths.ox.ac.uk>
+Patrick Farrell <patrick.farrell at maths.ox.ac.uk> <patrick.farrell06 at imperial.ac.uk>
+Patrick Farrell <patrick.farrell at maths.ox.ac.uk> <patrick.farrell at imperial.ac.uk>
+Quang Ha <qth20 at cam.ac.uk>
+Kristoffer Selim <selim at simula.no>
+Kristoffer Selim <selim at simula.no> <selim at selim-laptop>
+Simon Funke <simon at simula.no>
+Simon Funke <simon at simula.no> <simon.funke at gmail.com>
+Simon Funke <simon at simula.no> <s.funke09 at imperial.ac.uk>
+Solveig Bruvoll <solveio at ifi.uio.no>
+Solveig Masvie <smasvie at gmail.com>
+Steven Vandekerckhove <steven.vandekerckhove at kuleuven-kulak.be>
+Steven Vandekerckhove <steven.vandekerckhove at kuleuven-kulak.be> <Steven.Vandekerckhove at kuleuven-kulak.be>
+stockli <stockli at carleman.nada.kth.se>
+stockli <stockli at carleman.nada.kth.se> <stockli at localhost>
+Tianyi Li <tianyikillua at gmail.com>
+Steffen Müthing <steffen.muething at ipvs.uni-stuttgart.de>
+Steffen Müthing <steffen.muething at ipvs.uni-stuttgart.de> Steffen Müthing steffen.muething at ipvs.uni-stuttgart.de <>
+Miklós Homolya <m.homolya14 at imperial.ac.uk>
+Åsmund Ødegård <aasmund at simula.no>
+Åsmund Ødegård <aasmund at simula.no> <aasmundo at manpower.local>
+Ola Skavhaug <skavhaug at simula.no>
+Andre Massing <massing at simula.no>
+Andrew McRae <a.mcrae12 at imperial.ac.uk>
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9caaa01
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,18 @@
+notifications:
+ slack:
+ secure: r9t4/J1Y85Tv/D/bJBVPGaW153mSU+I5r+EZrq7E6HnYqFRQ0X0AJw0pUX1ap/MXGtSrHFmQRYmIN1TTUMLPAHlzF4YA4rFA1LxJxxlPQ1TuhmkLbu5DEf5qkSsVeOjIe8+ptx8E8rSUSVfzv1g/RpdgO6mOD6qge94gQhQ4XekrWkZE1OudkqPvHfznCvxtFs3T5dxZWX3suQsGA+l1Gn3gp2YFITTGEfCXFek+rRWL3aqn6Oq+nvI6jfrooei7NSmNQOpGawAW868uvOlWQ2NiH1nsUkOH9U9c4YpTPD7RLLc2r3pAisSzdhZ5LsT+9o+lycqJleGizcVqtF7BP0tBzc1G4uJQwOCCcypLG62VwuwF6HD3zx4bDXD2MTqEneUaLVNlT2JiAsXmg2RKn/z8+5OKrPNe23pDvD3h+NdtHzJxPSnSRynpKD1FBXh1tfiGSVvgY+Mm7Bdu1unuK2tbpb6OLhcq [...]
+language: python
+python:
+ - "2.7"
+ - "3.4"
+
+before_install:
+ - pip install flake8
+ - pip install pytest
+
+install:
+ - pip install .
+
+script:
+ - flake8 ufl/
+ - py.test test/
diff --git a/ChangeLog.rst b/ChangeLog.rst
index caa2be5..bbfa1a9 100644
--- a/ChangeLog.rst
+++ b/ChangeLog.rst
@@ -1,6 +1,16 @@
Changelog
=========
+2017.2.0 (2017-09-15)
+---------------------
+
+- Testing release method
+
+2017.1.0.post1 (2017-09-12)
+---------------------------
+
+- Change PyPI package name to fenics-ufl.
+
2017.1.0 (2017-05-09)
---------------------
diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
new file mode 100644
index 0000000..c47e4d5
--- /dev/null
+++ b/bitbucket-pipelines.yml
@@ -0,0 +1,12 @@
+image: quay.io/fenicsproject/pipelines
+
+pipelines:
+ default:
+ - step:
+ script:
+ - pip2 install .
+ - pip3 install .
+ - python2 -m flake8 ufl/
+ - python3 -m flake8 ufl/
+ - python2 -m pytest -v test/
+ - python3 -m pytest -v test/
diff --git a/demo/Poisson.ufl b/demo/Poisson.ufl
index 0a09bc1..23f81ed 100644
--- a/demo/Poisson.ufl
+++ b/demo/Poisson.ufl
@@ -28,5 +28,5 @@ u = TrialFunction(element)
v = TestFunction(element)
f = Coefficient(element)
-a = dot(grad(v), grad(u))*dx(degree=1)
+a = inner(grad(v), grad(u))*dx(degree=1)
L = v*f*dx(degree=2)
diff --git a/doc/sphinx/source/conf.py b/doc/sphinx/source/conf.py
index d8a68e5..f89d46c 100644
--- a/doc/sphinx/source/conf.py
+++ b/doc/sphinx/source/conf.py
@@ -58,7 +58,7 @@ project = u'Unified Form Language (UFL)'
this_year = datetime.date.today().year
copyright = u'%s, FEniCS Project' % this_year
author = u'FEniCS Project'
-version = pkg_resources.get_distribution("ufl").version
+version = pkg_resources.get_distribution("fenics-ufl").version
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
diff --git a/doc/sphinx/source/releases.rst b/doc/sphinx/source/releases.rst
index ee8b507..4758874 100644
--- a/doc/sphinx/source/releases.rst
+++ b/doc/sphinx/source/releases.rst
@@ -9,6 +9,7 @@ Release notes
:maxdepth: 2
releases/next
+ releases/v2017.1.0.post1
releases/v2017.1.0
releases/v2016.2.0
releases/v2016.1.0
diff --git a/doc/sphinx/source/releases/v2017.1.0.post1.rst b/doc/sphinx/source/releases/v2017.1.0.post1.rst
new file mode 100644
index 0000000..8bbdad8
--- /dev/null
+++ b/doc/sphinx/source/releases/v2017.1.0.post1.rst
@@ -0,0 +1,10 @@
+=================================
+Changes in version 2017.1.0.post1
+=================================
+
+UFL 2017.1.0.post1 was released on 2017-09-12.
+
+Summary of changes
+==================
+
+- Change PyPI package name to fenics-ufl.
diff --git a/doc/sphinx/source/releases/v2017.2.0.rst b/doc/sphinx/source/releases/v2017.2.0.rst
new file mode 100644
index 0000000..ea1fb3f
--- /dev/null
+++ b/doc/sphinx/source/releases/v2017.2.0.rst
@@ -0,0 +1,8 @@
+===========================
+Changes in version 2017.2.0
+===========================
+
+UFL 2017.2.0 was released on 2017-09-15.
+
+Summary of changes
+==================
diff --git a/release.conf b/release.conf
new file mode 100644
index 0000000..cfe8c7c
--- /dev/null
+++ b/release.conf
@@ -0,0 +1,8 @@
+# Configuration file for fenics-release
+
+PACKAGE="ufl"
+BRANCH="master"
+FILES="ChangeLog.rst \
+ setup.py \
+ doc/sphinx/source/releases/next.rst \
+ doc/sphinx/source/releases.rst"
diff --git a/scripts/ufl-convert b/scripts/ufl-convert
index 8da9b9d..567bd56 100755
--- a/scripts/ufl-convert
+++ b/scripts/ufl-convert
@@ -11,6 +11,7 @@ from pprint import pprint
from ufl.algorithms import tree_format, compute_form_data
from ufl.formatting.ufl2dot import ufl2dot
from ufl.formatting.ufl2latex import forms2latexdocument
+from ufl.formatting.ufl2unicode import form2unicode
from ufl.algorithms.formfiles import load_ufl_file
# --- Utilities
@@ -62,7 +63,7 @@ option_list = [ \
opt("labeling", "l", "str", "repr", "Set to 'repr' or 'compact' for different naming of graph nodes."),
opt("compile", "c", "int", 0, "'Compile' forms: apply expression transformations like in a quadrature based form compilation. Only used for latex formatting."),
# Output formats:
- opt("format", "f", "str", "", "Rendering format (str, repr, tree, dot, latex)."),
+ opt("format", "f", "str", "", "Rendering format (str, repr, tree, dot, latex, unicode)."),
opt("filetype", "t", "str", "", "Output file type (txt, py, dot, tex, ps, pdf, png)."),
]
@@ -105,6 +106,12 @@ for arg in args:
format = "tex"
if format == "tex":
rendered = forms2latexdocument(forms, uflfilename, compile=options.compile)
+ elif format == "unicode":
+ data = []
+ for form, form_data in zip(forms, form_datas):
+ tmp = form2unicode(form, form_data)
+ data.append(tmp)
+ rendered = "\n\n".join(data)
elif format in ("str", "repr", "tree"):
data = []
for i, fd in enumerate(form_datas):
@@ -154,6 +161,8 @@ for arg in args:
filetype = "dot"
elif format == "tex":
filetype = "tex"
+ elif format == "unicode":
+ filetype = "txt"
# Guess that the filetype is the ext, usually the case
ext = filetype
diff --git a/setup.cfg b/setup.cfg
index f597cbd..2d79134 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,3 +1,3 @@
[flake8]
-ignore = E305,E501,E226,W503,E127,E123,E128,E265
+ignore = E501,E226
exclude = .git,__pycache__,doc/sphinx/source/conf.py,build,dist,test
diff --git a/setup.py b/setup.py
index dd79757..4d65742 100755
--- a/setup.py
+++ b/setup.py
@@ -12,12 +12,12 @@ if sys.version_info < (2, 7):
print("Python 2.7 or higher required, please upgrade.")
sys.exit(1)
-version = "2017.1.0"
+version = "2017.2.0"
url = "https://bitbucket.org/fenics-project/%s/" % module_name
tarball = None
if 'dev' not in version:
- tarball = url + "downloads/%s-%s.tar.gz" % (module_name, version)
+ tarball = url + "downloads/fenics-%s-%s.tar.gz" % (module_name, version)
script_names = ("ufl-analyse", "ufl-convert", "ufl-version", "ufl2py")
@@ -57,7 +57,7 @@ Topic :: Scientific/Engineering :: Mathematics
Topic :: Software Development :: Libraries :: Python Modules
"""
-setup(name="UFL",
+setup(name="fenics-ufl",
version=version,
description="Unified Form Language",
author="Martin Sandve Alnæs, Anders Logg",
diff --git a/shippable.yml b/shippable.yml
new file mode 100644
index 0000000..ab12e61
--- /dev/null
+++ b/shippable.yml
@@ -0,0 +1,12 @@
+language: python
+python:
+ - 2.7
+ - 3.6
+
+build:
+ ci:
+ - pip install --upgrade pip
+ - pip install flake8 pytest
+ - pip install .
+ - python -m flake8 ufl/
+ - python -m pytest -v test/
diff --git a/test/conftest.py b/test/conftest.py
index aeb0dd3..489ffd4 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -2,9 +2,14 @@
import pytest
+import os
+import glob
+
import ufl
from ufl import as_ufl, inner, dx
from ufl.algorithms import compute_form_data
+from ufl.algorithms.formfiles import load_ufl_file
+
class Tester:
@@ -56,9 +61,65 @@ class Tester:
def self():
return Tester()
+
+def testspath():
+ return os.path.abspath(os.path.dirname(__file__))
+
+
+def filespath():
+ return os.path.abspath(os.path.join(testspath(), "../demo"))
+
+
+class UFLTestDataBase(object):
+ def __init__(self):
+ self.filespath = filespath()
+ self.cache = {}
+ self.names = glob.glob(os.path.join(self.filespath, "*.ufl"))
+ # Filter out files startign with udnerscore
+ self.names = [n for n in self.names
+ if not os.path.basename(n).startswith('_')]
+
+ def __len__(self):
+ return len(self.names)
+
+ def __iter__(self):
+ return self.keys()
+
+ def __hasitem__(self, name):
+ return names in self.names
+
+ def keys(self):
+ return iter(self.names)
+
+ def values(self):
+ return (self[name] for name in self.names)
+
+ def items(self):
+ return ((name, self[name]) for name in self.names)
+
+ def __getitem__(self, name):
+ if isinstance(name, int):
+ name = self.names[name]
+ # Cache file reads
+ content = self.cache.get(name)
+ if content is None:
+ content = load_ufl_file(name)
+ self.cache[name] = content
+ return content
+
+_db = UFLTestDataBase()
+
+
+def _example_paths():
+ return _db.values()
+
_all_cells = [ufl.interval, ufl.triangle, ufl.tetrahedron]
@pytest.fixture(params=_all_cells)
def cell(request):
return request.param
+
+ at pytest.fixture(params=_example_paths())
+def example_files(request):
+ return request.param
diff --git a/test/test_algorithms.py b/test/test_algorithms.py
index 315be4d..b5484de 100755
--- a/test/test_algorithms.py
+++ b/test/test_algorithms.py
@@ -9,11 +9,14 @@ __date__ = "2008-03-12 -- 2009-01-28"
import pytest
from pprint import *
-from ufl import *
-from ufl.algorithms import *
-from ufl.classes import Sum, Product
-
-from ufl.corealg.traversal import *
+from ufl import (FiniteElement, TestFunction, TrialFunction, triangle,
+ div, grad, Argument, dx, adjoint, Coefficient,
+ FacetNormal, inner, dot, ds)
+from ufl.algorithms import (extract_arguments, expand_derivatives,
+ expand_indices, extract_elements,
+ extract_unique_elements, extract_coefficients)
+from ufl.corealg.traversal import (pre_traversal, post_traversal,
+ unique_pre_traversal, unique_post_traversal)
# TODO: add more tests, covering all utility algorithms
@@ -84,7 +87,8 @@ def test_pre_and_post_traversal():
s = p1 + p2
# NB! These traversal algorithms are intended to guarantee only
- # parent before child and vice versa, not this particular ordering:
+ # parent before child and vice versa, not this particular
+ # ordering:
assert list(pre_traversal(s)) == [s, p2, g, v, p1, f, v]
assert list(post_traversal(s)) == [g, v, p2, f, v, p1, s]
assert list(unique_pre_traversal(s)) == [s, p2, g, v, p1, f]
diff --git a/test/test_unicode_convert.py b/test/test_unicode_convert.py
new file mode 100644
index 0000000..c9eccbd
--- /dev/null
+++ b/test/test_unicode_convert.py
@@ -0,0 +1,36 @@
+
+from six import text_type
+
+from ufl.algorithms import compute_form_data
+from ufl.formatting.ufl2unicode import form2unicode
+
+
+def valid_forms(forms_list):
+ forms = []
+ form_datas = []
+ for f in forms_list:
+ fd = None
+ try:
+ fd = compute_form_data(f)
+ except:
+ fd = None
+ if fd is not None:
+ forms.append(f)
+ form_datas.append(fd)
+ return forms, form_datas
+
+
+def test_convert_examples(example_files):
+ # Get example forms that can be analysed
+ forms, form_datas = valid_forms(example_files.forms)
+ if not forms:
+ return
+
+ # Mainly tests for execution without errors
+ data = []
+ for form, form_data in zip(forms, form_datas):
+ tmp = form2unicode(form, form_data)
+ data.append(tmp)
+ rendered = u"\n\n".join(data)
+ assert isinstance(rendered, text_type)
+ assert len(rendered)
diff --git a/ufl/__init__.py b/ufl/__init__.py
index 674c14c..b043db5 100644
--- a/ufl/__init__.py
+++ b/ufl/__init__.py
@@ -9,8 +9,7 @@ notation close to the mathematical one.
This Python module contains the language as well as algorithms to work
with it.
-* To import the language, type
-::
+* To import the language, type::
from ufl import *
@@ -244,7 +243,7 @@ A very brief overview of the language contents follows:
import pkg_resources
-__version__ = pkg_resources.get_distribution("ufl").version
+__version__ = pkg_resources.get_distribution("fenics-ufl").version
########## README
# Imports here should be what the user sees when doing "from ufl import *",
@@ -419,4 +418,4 @@ __all__ = as_native_strings([
'quadrilateral', 'hexahedron', 'facet',
'i', 'j', 'k', 'l', 'p', 'q', 'r', 's',
'e', 'pi',
- ])
+])
diff --git a/ufl/algorithms/__init__.py b/ufl/algorithms/__init__.py
index fab1ff4..fb751c0 100644
--- a/ufl/algorithms/__init__.py
+++ b/ufl/algorithms/__init__.py
@@ -64,17 +64,17 @@ __all__ = as_native_strings([
"compute_form_functional",
"compute_form_signature",
"tree_format",
- ])
+])
# Utilities for traversing over expression trees in different ways
-#from ufl.algorithms.traversal import iter_expressions
+# from ufl.algorithms.traversal import iter_expressions
# Keeping these imports here for backwards compatibility, doesn't cost
# anything. Prefer importing from ufl.corealg.traversal in future
# code.
-#from ufl.corealg.traversal import pre_traversal
+# from ufl.corealg.traversal import pre_traversal
from ufl.corealg.traversal import post_traversal
-#from ufl.corealg.traversal import traverse_terminals, traverse_unique_terminals
+# from ufl.corealg.traversal import traverse_terminals, traverse_unique_terminals
# Utilities for extracting information from forms and expressions
@@ -87,11 +87,11 @@ from ufl.algorithms.analysis import (
extract_unique_elements,
extract_sub_elements,
sort_elements,
- )
+)
# Preprocessing a form to extract various meta data
-#from ufl.algorithms.formdata import FormData
+# from ufl.algorithms.formdata import FormData
from ufl.algorithms.compute_form_data import compute_form_data
# Utilities for checking properties of forms
@@ -103,14 +103,14 @@ from ufl.algorithms.checks import validate_form
# Utilites for modifying expressions and forms
from ufl.corealg.multifunction import MultiFunction
from ufl.algorithms.transformer import Transformer, ReuseTransformer
-#from ufl.algorithms.transformer import is_post_handler
+# from ufl.algorithms.transformer import is_post_handler
from ufl.algorithms.transformer import apply_transformer
from ufl.algorithms.transformer import strip_variables
-#from ufl.algorithms.replace import Replacer
+# from ufl.algorithms.replace import Replacer
from ufl.algorithms.replace import replace
from ufl.algorithms.change_to_reference import change_to_reference_grad
from ufl.algorithms.expand_compounds import expand_compounds
-#from ufl.algorithms.estimate_degrees import SumDegreeEstimator
+# from ufl.algorithms.estimate_degrees import SumDegreeEstimator
from ufl.algorithms.estimate_degrees import estimate_total_polynomial_degree
from ufl.algorithms.expand_indices import expand_indices, purge_list_tensors
@@ -134,6 +134,6 @@ from ufl.algorithms.formfiles import load_ufl_file
from ufl.algorithms.formfiles import load_forms
# Utilities for UFL object printing
-#from ufl.formatting.printing import integral_info, form_info
+# from ufl.formatting.printing import integral_info, form_info
from ufl.formatting.printing import tree_format
from ufl.formatting.ufl2latex import ufl2latex
diff --git a/ufl/algorithms/apply_geometry_lowering.py b/ufl/algorithms/apply_geometry_lowering.py
index ff4fdfc..8b10a97 100644
--- a/ufl/algorithms/apply_geometry_lowering.py
+++ b/ufl/algorithms/apply_geometry_lowering.py
@@ -135,7 +135,8 @@ class GeometryLoweringApplier(MultiFunction):
domain = o.ufl_domain()
FJ = self.facet_jacobian(FacetJacobian(domain))
- # This could in principle use preserve_types[JacobianDeterminant] with minor refactoring:
+ # This could in principle use
+ # preserve_types[JacobianDeterminant] with minor refactoring:
return inverse_expr(FJ)
@memoized_handler
@@ -144,7 +145,6 @@ class GeometryLoweringApplier(MultiFunction):
return o
domain = o.ufl_domain()
- #tdim = domain.topological_dimension()
FJ = self.facet_jacobian(FacetJacobian(domain))
detFJ = determinant_expr(FJ)
diff --git a/ufl/algorithms/compute_form_data.py b/ufl/algorithms/compute_form_data.py
index f700bf7..55b06ac 100644
--- a/ufl/algorithms/compute_form_data.py
+++ b/ufl/algorithms/compute_form_data.py
@@ -23,6 +23,7 @@ raw input form given by a user."""
from itertools import chain
from ufl.log import error, info
+from ufl.utils.sequences import max_degree
from ufl.classes import GeometricFacetQuantity, Coefficient, Form
from ufl.corealg.traversal import traverse_unique_terminals
@@ -55,7 +56,7 @@ def _auto_select_degree(elements):
"""
# Use max degree of all elements, at least 1 (to work with
# Lagrange elements)
- return max({e.degree() for e in elements} - {None} | {1})
+ return max_degree({e.degree() for e in elements} - {None} | {1})
def _compute_element_mapping(form):
diff --git a/ufl/algorithms/domain_analysis.py b/ufl/algorithms/domain_analysis.py
index a5ed720..416f087 100644
--- a/ufl/algorithms/domain_analysis.py
+++ b/ufl/algorithms/domain_analysis.py
@@ -18,8 +18,8 @@
# You should have received a copy of the GNU Lesser General Public License
# along with UFL. If not, see <http://www.gnu.org/licenses/>.
-# import six
from collections import defaultdict
+from six import iteritems
from six.moves import zip
import ufl
@@ -28,20 +28,22 @@ from ufl.utils.py23 import as_native_strings
from ufl.integral import Integral
from ufl.form import Form
from ufl.sorting import cmp_expr, sorted_expr
-from ufl.utils.sorting import canonicalize_metadata, sorted_by_key, sorted_by_tuple_key
+from ufl.utils.sorting import canonicalize_metadata, sorted_by_key
import numbers
-# @six.python_2_unicode_compatible
class IntegralData(object):
- """Utility class with the members
- (domain, integral_type, subdomain_id, integrals, metadata)
+ """Utility class with the members (domain, integral_type,
+ subdomain_id, integrals, metadata)
where metadata is an empty dictionary that may be used for
associating metadata with each object.
+
"""
- __slots__ = as_native_strings(('domain', 'integral_type', 'subdomain_id', 'integrals',
- 'metadata', 'integral_coefficients', 'enabled_coefficients'))
+ __slots__ = as_native_strings(('domain', 'integral_type', 'subdomain_id',
+ 'integrals', 'metadata',
+ 'integral_coefficients',
+ 'enabled_coefficients'))
def __init__(self, domain, integral_type, subdomain_id, integrals,
metadata):
@@ -274,8 +276,12 @@ def build_integral_data(integrals):
# Build list with canonical ordering, iteration over dicts
# is not deterministic across python versions
+ def keyfunc(item):
+ (d, itype, sid), integrals = item
+ return (d._ufl_sort_key_(), itype, (type(sid).__name__, sid))
+
integral_datas = []
- for (d, itype, sid), integrals in sorted_by_tuple_key(itgs):
+ for (d, itype, sid), integrals in sorted(iteritems(itgs), key=keyfunc):
integral_datas.append(IntegralData(d, itype, sid, integrals, {}))
return integral_datas
diff --git a/ufl/algorithms/estimate_degrees.py b/ufl/algorithms/estimate_degrees.py
index 68715a4..0c400dd 100644
--- a/ufl/algorithms/estimate_degrees.py
+++ b/ufl/algorithms/estimate_degrees.py
@@ -27,6 +27,7 @@ from ufl.integral import Integral
from ufl.algorithms.multifunction import MultiFunction
from ufl.corealg.map_dag import map_expr_dags
from ufl.checks import is_cellwise_constant
+from ufl.constantvalue import IntValue
class IrreducibleInt(int):
@@ -221,25 +222,23 @@ class SumDegreeEstimator(MultiFunction):
return self._add_degrees(v, *ops)
def power(self, v, a, b):
- """If b is an integer:
+ """If b is a positive integer:
degree(a**b) == degree(a)*b
otherwise use the heuristic
- degree(a**b) == degree(a)*2"""
+ degree(a**b) == degree(a) + 2"""
f, g = v.ufl_operands
- try:
- gi = abs(int(g))
- if isinstance(a, int):
- return a*gi
- else:
- return tuple(foo*gi for foo in a)
- except:
- pass
- # Something to a non-integer power, this is just a heuristic
- # with no background
- if isinstance(a, int):
- return a*2
- else:
- return tuple(foo*2 for foo in a)
+
+ if isinstance(g, IntValue):
+ gi = g.value()
+ if gi >= 0:
+ if isinstance(a, int):
+ return a*gi
+ else:
+ return tuple(foo*gi for foo in a)
+
+ # Something to a non-(positive integer) power, e.g. float,
+ # negative integer, Coefficient, etc.
+ return self._add_degrees(v, a, 2)
def atan_2(self, v, a, b):
"""Using the heuristic
diff --git a/ufl/algorithms/formdata.py b/ufl/algorithms/formdata.py
index 445fb3f..2782057 100644
--- a/ufl/algorithms/formdata.py
+++ b/ufl/algorithms/formdata.py
@@ -20,15 +20,13 @@
#
# Modified by Anders Logg, 2008.
-#import six
from ufl.utils.formatting import lstr, tstr, estr
-# @six.python_2_unicode_compatible
class FormData(object):
- """
- Class collecting various information extracted from a Form by
+ """Class collecting various information extracted from a Form by
calling preprocess.
+
"""
def __init__(self):
@@ -60,7 +58,6 @@ class FormData(object):
return tstr(geometry + subdomains + functions)
-# @six.python_2_unicode_compatible
class ExprData(object):
"""
Class collecting various information extracted from a Expr by
diff --git a/ufl/argument.py b/ufl/argument.py
index e9f3ac7..0aafa72 100644
--- a/ufl/argument.py
+++ b/ufl/argument.py
@@ -96,11 +96,6 @@ class Argument(FormArgument):
# use .ufl_function_space().ufl_element() instead.")
return self._ufl_function_space.ufl_element()
- # def element(self):
- # "Deprecated, please use .ufl_function_space().ufl_element() instead."
- # deprecate("Argument.element() is deprecated, please use Argument.ufl_element() instead.")
- # return self.ufl_element()
-
def number(self):
"Return the Argument number."
return self._number
diff --git a/ufl/cell.py b/ufl/cell.py
index 51f8771..204bb77 100644
--- a/ufl/cell.py
+++ b/ufl/cell.py
@@ -41,11 +41,12 @@ __all_classes__ = as_native_strings(["AbstractCell", "Cell", "TensorProductCell"
# --- The most abstract cell class, base class for other cell types
class AbstractCell(object):
- "Representation of an abstract finite element cell with only the dimensions known."
- __slots__ = as_native_strings((
- "_topological_dimension",
- "_geometric_dimension",
- ))
+ """Representation of an abstract finite element cell with only the
+ dimensions known.
+
+ """
+ __slots__ = as_native_strings(("_topological_dimension",
+ "_geometric_dimension"))
def __init__(self, topological_dimension, geometric_dimension):
# Validate dimensions
diff --git a/ufl/coefficient.py b/ufl/coefficient.py
index 414ef87..c97ab8d 100644
--- a/ufl/coefficient.py
+++ b/ufl/coefficient.py
@@ -84,11 +84,6 @@ class Coefficient(FormArgument):
"Shortcut to get the finite element of the function space of this coefficient."
return self._ufl_function_space.ufl_element()
- # def element(self):
- # "Deprecated, please use Coefficient.ufl_element() instead."
- # deprecate("Coefficient.element() is deprecated, please use Coefficient.ufl_element() instead.")
- # return self.ufl_element()
-
def is_cellwise_constant(self):
"Return whether this expression is spatially constant over each cell."
return self.ufl_element().is_cellwise_constant()
diff --git a/ufl/constantvalue.py b/ufl/constantvalue.py
index da5f1fe..37f0e62 100644
--- a/ufl/constantvalue.py
+++ b/ufl/constantvalue.py
@@ -141,8 +141,8 @@ class Zero(ConstantValue):
all(isinstance(i, int) for i in index_dimensions)):
error("Expecting tuple of integer index dimensions, not %s" % str(index_dimensions))
- # Assuming sorted now to avoid this cost, enable for debuggin:
- #if sorted(free_indices) != list(free_indices):
+ # Assuming sorted now to avoid this cost, enable for debugging:
+ # if sorted(free_indices) != list(free_indices):
# error("Expecting sorted input. Remove this check later for efficiency.")
self.ufl_free_indices = free_indices
@@ -164,8 +164,7 @@ class Zero(ConstantValue):
r = "Zero(%s, %s, %s)" % (
repr(self.ufl_shape),
repr(self.ufl_free_indices),
- repr(self.ufl_index_dimensions),
- )
+ repr(self.ufl_index_dimensions))
return as_native_str(r)
def __eq__(self, other):
diff --git a/ufl/core/expr.py b/ufl/core/expr.py
index a72fb78..42d6e21 100644
--- a/ufl/core/expr.py
+++ b/ufl/core/expr.py
@@ -319,12 +319,6 @@ class Expr(object):
from ufl.domain import extract_unique_domain
return extract_unique_domain(self)
- #def is_cellwise_constant(self): # TODO: Deprecate this and use is_cellwise_constant(expr)
- # "Return whether this expression is spatially constant over each cell."
- # from ufl.checks import is_cellwise_constant
- # deprecate("Expr.is_cellwise_constant() is deprecated, please use is_cellwise_constant(expr) instead.")
- # return is_cellwise_constant(self)
-
# --- Functions for float evaluation ---
def evaluate(self, x, mapping, component, index_values):
@@ -436,67 +430,11 @@ class Expr(object):
# --- Deprecated functions
- #def reconstruct(self, *operands):
- # """Return a new object of the same type with new operands.
- # Deprecated, please use Expr._ufl_expr_reconstruct_() instead."""
- # deprecate("Expr.reconstruct() is deprecated, please use Expr._ufl_expr_reconstruct_() instead.")
- # return self._ufl_expr_reconstruct_(*operands)
-
def geometric_dimension(self):
"Return the geometric dimension this expression lives in."
from ufl.domain import find_geometric_dimension
return find_geometric_dimension(self)
- #def domains(self):
- # "Deprecated, please use .ufl_domains() instead."
- # deprecate("Expr.domains() is deprecated, please use .ufl_domains() instead.")
- # return self.ufl_domains()
-
- #def cell(self):
- # "Deprecated, please use .ufl_domain().ufl_cell() instead."
- # deprecate("Expr.cell() is deprecated, please use .ufl_domain() instead.")
- # domain = self.ufl_domain()
- # return domain.ufl_cell() if domain is not None else None
-
- #def domain(self):
- # "Deprecated, please use .ufl_domain() instead."
- # deprecate("Expr.domain() is deprecated, please use .ufl_domain() instead.")
- # return self.ufl_domain()
-
- #def operands(self):
- # "Deprecated, please use Expr.ufl_operands instead."
- # deprecate("Expr.operands() is deprecated, please use property Expr.ufl_operands instead.")
- # return self.ufl_operands
-
- #def shape(self):
- # """Return the tensor shape of the expression.
- # Deprecated, please use Expr.ufl_shape instead."""
- # deprecate("Expr.shape() is deprecated, please use Expr.ufl_shape instead.")
- # return self.ufl_shape
-
- #def rank(self):
- # """Return the tensor rank of the expression.
- # Deprecated, please use len(expr.ufl_shape) instead."""
- # deprecate("Expr.rank() is deprecated," +
- # " please use len(expr.ufl_shape) instead.")
- # return len(self.ufl_shape)
-
- #def free_indices(self):
- # "Deprecated, please use property Expr.ufl_free_indices instead."
- # from ufl.core.multiindex import Index
- # deprecate("Expr.free_indices() is deprecated," +
- # " please use property Expr.ufl_free_indices instead.")
- # return tuple(Index(count=i) for i in self.ufl_free_indices)
-
- #def index_dimensions(self):
- # "Deprecated, please use property Expr.ufl_index_dimensions instead."
- # from ufl.core.multiindex import Index
- # from ufl.utils.dicts import EmptyDict
- # deprecate("Expr.index_dimensions() is deprecated," +
- # " please use property Expr.ufl_index_dimensions instead.")
- # idims = {Index(count=i): d for i, d in zip(self.ufl_free_indices, self.ufl_index_dimensions)}
- # return idims or EmptyDict
-
# Initializing traits here because Expr is not defined in the class
# declaration
diff --git a/ufl/core/multiindex.py b/ufl/core/multiindex.py
index 8c8c422..b7dfa97 100644
--- a/ufl/core/multiindex.py
+++ b/ufl/core/multiindex.py
@@ -20,7 +20,6 @@
#
# Modified by Massimiliano Leoni, 2016.
-#import six
from six.moves import xrange as range
from ufl.utils.py23 import as_native_str
@@ -46,7 +45,6 @@ class IndexBase(object):
return str(self).decode("utf-8")
-# @six.python_2_unicode_compatible
class FixedIndex(IndexBase):
"""UFL value: An index with a specific value assigned."""
__slots__ = as_native_strings(("_value", "_hash"))
@@ -91,7 +89,6 @@ class FixedIndex(IndexBase):
return as_native_str(r)
-# @six.python_2_unicode_compatible
class Index(IndexBase):
"""UFL value: An index with no value assigned.
@@ -139,7 +136,8 @@ class MultiIndex(Terminal):
error("Expecting a tuple of indices.")
if all(isinstance(ind, FixedIndex) for ind in indices):
- # Cache multiindices consisting of purely fixed indices (aka flyweight pattern)
+ # Cache multiindices consisting of purely fixed indices
+ # (aka flyweight pattern)
key = tuple(ind._value for ind in indices)
self = MultiIndex._cache.get(key)
if self is not None:
@@ -147,12 +145,14 @@ class MultiIndex(Terminal):
self = Terminal.__new__(cls)
MultiIndex._cache[key] = self
else:
- # Create a new object if we have any free indices (too many combinations to cache)
+ # Create a new object if we have any free indices (too
+ # many combinations to cache)
if not all(isinstance(ind, IndexBase) for ind in indices):
error("Expecting only Index and FixedIndex objects.")
self = Terminal.__new__(cls)
- # Initialize here instead of in __init__ to avoid overwriting self._indices from cached objects
+ # Initialize here instead of in __init__ to avoid overwriting
+ # self._indices from cached objects
self._init(indices)
return self
diff --git a/ufl/core/operator.py b/ufl/core/operator.py
index f6aef18..228850d 100644
--- a/ufl/core/operator.py
+++ b/ufl/core/operator.py
@@ -58,5 +58,5 @@ class Operator(Expr):
"Default repr string construction for operators."
# This should work for most cases
r = "%s(%s)" % (self._ufl_class_.__name__,
- ", ".join(repr(op) for op in self.ufl_operands))
+ ", ".join(repr(op) for op in self.ufl_operands))
return as_native_str(r)
diff --git a/ufl/domain.py b/ufl/domain.py
index d2bf651..f8d862b 100644
--- a/ufl/domain.py
+++ b/ufl/domain.py
@@ -22,7 +22,6 @@
# Modified by Kristian B. Oelgaard, 2009
# Modified by Marie E. Rognes 2012
-# import six
import numbers
from ufl.utils.py23 import as_native_str
@@ -40,7 +39,10 @@ __all_classes__ = as_native_strings(["AbstractDomain", "Mesh", "MeshView", "Tens
class AbstractDomain(object):
- """Symbolic representation of a geometric domain with only a geometric and topological dimension."""
+ """Symbolic representation of a geometric domain with only a geometric
+ and topological dimension.
+
+ """
def __init__(self, topological_dimension, geometric_dimension):
# Validate dimensions
if not isinstance(geometric_dimension, numbers.Integral):
@@ -74,7 +76,6 @@ class AbstractDomain(object):
# AbstractDomain.__init__(self, geometric_dimension, geometric_dimension)
-# @six.python_2_unicode_compatible
@attach_operators_from_hash_data
@attach_ufl_id
class Mesh(AbstractDomain):
@@ -140,23 +141,7 @@ class Mesh(AbstractDomain):
return (self.geometric_dimension(), self.topological_dimension(),
"Mesh", typespecific)
- # Deprecations inherited from Domain
- #def cell(self):
- # deprecate("Mesh.cell() is deprecated, please use .ufl_cell() instead.")
- # return self.ufl_cell()
-
- #def coordinates(self):
- # error("Coordinate function support has been removed!\n"
- # "Use mesh.ufl_coordinate_element() to get the coordinate element,\n"
- # "and SpatialCoordinate(mesh) to represent the coordinate field in a form.")
-
- #def ufl_coordinates(self):
- # error("Coordinate function support has been removed!\n"
- # "Use mesh.ufl_coordinate_element() to get the coordinate element,\n"
- # "and SpatialCoordinate(mesh) to represent the coordinate field in a form.")
-
-# @six.python_2_unicode_compatible
@attach_operators_from_hash_data
@attach_ufl_id
class MeshView(AbstractDomain):
@@ -206,7 +191,6 @@ class MeshView(AbstractDomain):
"MeshView", typespecific)
-# @six.python_2_unicode_compatible
@attach_operators_from_hash_data
@attach_ufl_id
class TensorProductMesh(AbstractDomain):
@@ -278,7 +262,10 @@ _default_domains = {}
def default_domain(cell):
- "Create a singular default Mesh from a cell, always returning the same Mesh object for the same cell."
+ """Create a singular default Mesh from a cell, always returning the
+ same Mesh object for the same cell.
+
+ """
global _default_domains
assert isinstance(cell, AbstractCell)
domain = _default_domains.get(cell)
@@ -316,9 +303,11 @@ def sort_domains(domains):
def join_domains(domains):
- """Take a list of domains and return a tuple with only unique domain objects.
+ """Take a list of domains and return a tuple with only unique domain
+ objects.
Checks that domains with the same id are compatible.
+
"""
# Use hashing to join domains, ignore None
domains = set(domains) - set((None,))
diff --git a/ufl/finiteelement/elementlist.py b/ufl/finiteelement/elementlist.py
index e776041..6b7906b 100644
--- a/ufl/finiteelement/elementlist.py
+++ b/ufl/finiteelement/elementlist.py
@@ -26,6 +26,8 @@ elements by calling the function register_element."""
from __future__ import print_function
+from numpy import asarray
+
from ufl.log import warning, error
from ufl.sobolevspace import L2, H1, H2, HDiv, HCurl, HEin, HDivDiv
from ufl.utils.formatting import istr
@@ -354,10 +356,10 @@ def canonical_element_description(family, cell, order, form_degree):
error('Order "%s" invalid for "%s" finite element, '
'should be None.' % (order, family))
kmin, kmax = krange
- if not (kmin is None or order >= kmin):
+ if not (kmin is None or (asarray(order) >= kmin).all()):
error('Order "%s" invalid for "%s" finite element.' %
(order, family))
- if not (kmax is None or order <= kmax):
+ if not (kmax is None or (asarray(order) <= kmax).all()):
error('Order "%s" invalid for "%s" finite element.' %
(istr(order), family))
diff --git a/ufl/finiteelement/enrichedelement.py b/ufl/finiteelement/enrichedelement.py
index cb702ce..ac047c4 100644
--- a/ufl/finiteelement/enrichedelement.py
+++ b/ufl/finiteelement/enrichedelement.py
@@ -78,7 +78,7 @@ class EnrichedElementBase(FiniteElementBase):
# Cache repr string
self._repr = as_native_str("%s(%s)" %
- (class_name, ", ".join(repr(e) for e in self._elements)))
+ (class_name, ", ".join(repr(e) for e in self._elements)))
def mapping(self):
return self._elements[0].mapping()
diff --git a/ufl/finiteelement/finiteelement.py b/ufl/finiteelement/finiteelement.py
index 6cbfb81..a5dcccd 100644
--- a/ufl/finiteelement/finiteelement.py
+++ b/ufl/finiteelement/finiteelement.py
@@ -23,7 +23,6 @@
# Modified by Anders Logg 2014
# Modified by Massimiliano Leoni, 2016
-# import six
from ufl.log import error
from ufl.utils.py23 import as_native_str
from ufl.utils.py23 import as_native_strings
@@ -35,16 +34,13 @@ from ufl.finiteelement.elementlist import canonical_element_description, simplic
from ufl.finiteelement.finiteelementbase import FiniteElementBase
-# @six.python_2_unicode_compatible
class FiniteElement(FiniteElementBase):
"The basic finite element class for all simple finite elements."
# TODO: Move these to base?
- __slots__ = as_native_strings((
- "_short_name",
- "_sobolev_space",
- "_mapping",
- "_variant",
- ))
+ __slots__ = as_native_strings(("_short_name",
+ "_sobolev_space",
+ "_mapping",
+ "_variant"))
def __new__(cls,
family,
@@ -169,9 +165,9 @@ class FiniteElement(FiniteElementBase):
self._short_name = short_name
self._variant = variant
- # Finite elements on quadrilaterals have an IrreducibleInt as degree
+ # Finite elements on quadrilaterals and hexahedrons have an IrreducibleInt as degree
if cell is not None:
- if cell.cellname() == "quadrilateral":
+ if cell.cellname() in ["quadrilateral", "hexahedron"]:
from ufl.algorithms.estimate_degrees import IrreducibleInt
degree = IrreducibleInt(degree)
@@ -193,7 +189,7 @@ class FiniteElement(FiniteElementBase):
if v is None:
var_str = ""
else:
- var_str = ", variant=%s" % repr(qs)
+ var_str = ", variant=%s" % repr(v)
self._repr = as_native_str("FiniteElement(%s, %s, %s%s%s)" % (
repr(self.family()), repr(self.cell()), repr(self.degree()), quad_str, var_str))
assert '"' not in self._repr
diff --git a/ufl/finiteelement/finiteelementbase.py b/ufl/finiteelement/finiteelementbase.py
index 0b3141c..8752b9c 100644
--- a/ufl/finiteelement/finiteelementbase.py
+++ b/ufl/finiteelement/finiteelementbase.py
@@ -34,16 +34,14 @@ from ufl.cell import AbstractCell, as_cell
class FiniteElementBase(object):
"Base class for all finite elements."
- __slots__ = as_native_strings((
- "_family",
- "_cell",
- "_degree",
- "_quad_scheme",
- "_value_shape",
- "_reference_value_shape",
- "_repr",
- "__weakref__",
- ))
+ __slots__ = as_native_strings(("_family",
+ "_cell",
+ "_degree",
+ "_quad_scheme",
+ "_value_shape",
+ "_reference_value_shape",
+ "_repr",
+ "__weakref__"))
# TODO: Not all these should be in the base class! In particular
# family, degree, and quad_scheme do not belong here.
diff --git a/ufl/finiteelement/mixedelement.py b/ufl/finiteelement/mixedelement.py
index 5a54f93..4879076 100644
--- a/ufl/finiteelement/mixedelement.py
+++ b/ufl/finiteelement/mixedelement.py
@@ -31,7 +31,7 @@ from six.moves import xrange as range
from ufl.log import error
from ufl.utils.py23 import as_native_strings
from ufl.permutation import compute_indices
-from ufl.utils.sequences import product
+from ufl.utils.sequences import product, max_degree
from ufl.utils.dicts import EmptyDict
from ufl.utils.indexflattening import flatten_multiindex, unflatten_index, shape_to_strides
from ufl.cell import as_cell
@@ -101,7 +101,7 @@ class MixedElement(FiniteElementBase):
# Initialize element data
degrees = {e.degree() for e in self._sub_elements} - {None}
- degree = max(degrees) if degrees else None
+ degree = max_degree(degrees) if degrees else None
FiniteElementBase.__init__(self, "Mixed", cell, degree, quad_scheme,
value_shape, reference_value_shape)
@@ -338,10 +338,14 @@ class VectorElement(MixedElement):
# @six.python_2_unicode_compatible
class TensorElement(MixedElement):
- "A special case of a mixed finite element where all elements are equal."
+ """A special case of a mixed finite element where all elements are
+ equal.
+
+ """
__slots__ = as_native_strings(("_sub_element", "_shape", "_symmetry",
- "_sub_element_mapping", "_flattened_sub_element_mapping",
- "_mapping"))
+ "_sub_element_mapping",
+ "_flattened_sub_element_mapping",
+ "_mapping"))
def __init__(self, family, cell=None, degree=None, shape=None,
symmetry=None, quad_scheme=None):
@@ -392,8 +396,7 @@ class TensorElement(MixedElement):
if len(i) != len(j):
error("Non-matching length of symmetry index tuples.")
for k in range(len(i)):
- if not (i[k] >= 0 and j[k] >= 0
- and i[k] < shape[k] and j[k] < shape[k]):
+ if not (i[k] >= 0 and j[k] >= 0 and i[k] < shape[k] and j[k] < shape[k]):
error("Symmetry dimensions out of bounds.")
# Compute all index combinations for given shape
diff --git a/ufl/finiteelement/restrictedelement.py b/ufl/finiteelement/restrictedelement.py
index 467f993..d82b5cc 100644
--- a/ufl/finiteelement/restrictedelement.py
+++ b/ufl/finiteelement/restrictedelement.py
@@ -22,7 +22,6 @@
# Modified by Marie E. Rognes 2010, 2012
# Modified by Massimiliano Leoni, 2016
-# import six
from ufl.utils.py23 import as_native_str
from ufl.finiteelement.finiteelementbase import FiniteElementBase
from ufl.log import error
@@ -30,7 +29,6 @@ from ufl.log import error
valid_restriction_domains = ("interior", "facet", "face", "edge", "vertex")
-# @six.python_2_unicode_compatible
class RestrictedElement(FiniteElementBase):
"Represents the restriction of a finite element to a type of cell entity."
def __init__(self, element, restriction_domain):
@@ -53,19 +51,16 @@ class RestrictedElement(FiniteElementBase):
repr(self._element), repr(self._restriction_domain)))
def is_cellwise_constant(self):
- """Return whether the basis functions of this
- element is spatially constant over each cell."""
+ """Return whether the basis functions of this element is spatially
+ constant over each cell.
+
+ """
return self._element.is_cellwise_constant()
def sub_element(self):
"Return the element which is restricted."
return self._element
- #def element(self):
- # "Deprecated."
- # deprecate("RestrictedElement.element() is deprecated, please use .sub_element() instead.")
- # return self.sub_element()
-
def mapping(self):
return self._element.mapping()
@@ -89,8 +84,9 @@ class RestrictedElement(FiniteElementBase):
def symmetry(self):
"""Return the symmetry dict, which is a mapping :math:`c_0 \\to c_1`
meaning that component :math:`c_0` is represented by component
- :math:`c_1`.
- A component is a tuple of one or more ints."""
+ :math:`c_1`. A component is a tuple of one or more ints.
+
+ """
return self._element.symmetry()
def num_sub_elements(self):
diff --git a/ufl/form.py b/ufl/form.py
index e88a288..41ab57a 100644
--- a/ufl/form.py
+++ b/ufl/form.py
@@ -21,11 +21,11 @@
# Modified by Anders Logg, 2009-2011.
# Modified by Massimiliano Leoni, 2016.
-# import six
from itertools import chain
from collections import defaultdict
from ufl.log import error, warning
+from ufl.domain import sort_domains
from ufl.integral import Integral
from ufl.checks import is_scalar_constant_expression
from ufl.equation import Equation
@@ -58,7 +58,7 @@ def _sorted_integrals(integrals):
all_integrals = []
# Order integrals canonically to increase signature stability
- for d in sorted(integrals_dict): # Assuming Domain is sortable
+ for d in sort_domains(integrals_dict):
for it in sorted(integrals_dict[d]): # str is sortable
for si in sorted(integrals_dict[d][it],
key=lambda x: (type(x).__name__, x)): # int/str are sortable
@@ -76,7 +76,6 @@ def _sorted_integrals(integrals):
return tuple(all_integrals) # integrals_dict
-# @six.python_2_unicode_compatible
class Form(object):
"""Description of a weak form consisting of a sum of integrals over subdomains."""
__slots__ = (
@@ -142,11 +141,6 @@ class Form(object):
"Returns whether the form has no integrals."
return self.integrals() == ()
- #def domains(self):
- # "Deprecated, please use .ufl_domains() instead."
- # deprecate("Form.domains() is deprecated, please use .ufl_domains() instead.")
- # return self.ufl_domains()
-
def ufl_domains(self):
"""Return the geometric integration domains occuring in the form.
@@ -158,27 +152,23 @@ class Form(object):
self._analyze_domains()
return self._integration_domains
- #def cell(self):
- # "Deprecated, please use .ufl_cell() instead."
- # deprecate("Form.cell() is deprecated, please use .ufl_cell() instead.")
- # return self.ufl_cell()
-
- #def domain(self):
- # "Deprecated, please use .ufl_domain() instead."
- # deprecate("Form.domain() is deprecated, please use .ufl_domain() instead.")
- # return self.ufl_domain()
-
def ufl_cell(self):
- "Return the single cell this form is defined on, fails if multiple cells are found."
+ """Return the single cell this form is defined on, fails if multiple
+ cells are found.
+
+ """
return self.ufl_domain().ufl_cell()
def ufl_domain(self):
- """Return the single geometric integration domain occuring in the form.
+ """Return the single geometric integration domain occuring in the
+ form.
Fails if multiple domains are found.
- NB! This does not include domains of coefficients defined on other
- meshes, look at form data for that additional information.
+ NB! This does not include domains of coefficients defined on
+ other meshes, look at form data for that additional
+ information.
+
"""
# Collect all domains
domains = self.ufl_domains()
@@ -326,11 +316,12 @@ class Form(object):
return NotImplemented
def __call__(self, *args, **kwargs):
- """UFL form operator: Evaluate form by replacing arguments and coefficients.
+ """UFL form operator: Evaluate form by replacing arguments and
+ coefficients.
- Replaces form.arguments() with given positional arguments
- in same number and ordering. Number of positional arguments
- must be 0 or equal to the number of Arguments in the form.
+ Replaces form.arguments() with given positional arguments in
+ same number and ordering. Number of positional arguments must
+ be 0 or equal to the number of Arguments in the form.
The optional keyword argument coefficients can be set to a dict
to replace Coefficients with expressions of matching shapes.
@@ -346,6 +337,7 @@ class Form(object):
M = a(f, f, coefficients={ g: 1 })
Is equivalent to M == grad(f)**2*dx.
+
"""
repdict = {}
@@ -384,7 +376,7 @@ class Form(object):
def __str__(self):
"Compute shorter string representation of form. This can be huge for complicated forms."
# Warning used for making sure we don't use this in the general pipeline:
- #warning("Calling str on form is potentially expensive and should be avoided except during debugging.")
+ # warning("Calling str on form is potentially expensive and should be avoided except during debugging.")
# Not caching this because it can be huge
s = "\n + ".join(str(itg) for itg in self.integrals())
return s or "<empty Form>"
@@ -392,7 +384,7 @@ class Form(object):
def __repr__(self):
"Compute repr string of form. This can be huge for complicated forms."
# Warning used for making sure we don't use this in the general pipeline:
- #warning("Calling repr on form is potentially expensive and should be avoided except during debugging.")
+ # warning("Calling repr on form is potentially expensive and should be avoided except during debugging.")
# Not caching this because it can be huge
itgs = ", ".join(repr(itg) for itg in self.integrals())
r = "Form([" + itgs + "])"
@@ -491,11 +483,14 @@ def as_form(form):
def replace_integral_domains(form, common_domain): # TODO: Move elsewhere
- """Given a form and a domain, assign a common integration domain to all integrals.
+ """Given a form and a domain, assign a common integration domain to
+ all integrals.
+
+ Does not modify the input form (``Form`` should always be
+ immutable). This is to support ill formed forms with no domain
+ specified, sometimes occurring in pydolfin, e.g. assemble(1*dx,
+ mesh=mesh).
- Does not modify the input form (``Form`` should always be immutable).
- This is to support ill formed forms with no domain specified,
- sometimes occurring in pydolfin, e.g. assemble(1*dx, mesh=mesh).
"""
domains = form.ufl_domains()
if common_domain is not None:
diff --git a/ufl/formatting/ufl2unicode.py b/ufl/formatting/ufl2unicode.py
new file mode 100644
index 0000000..04ece3a
--- /dev/null
+++ b/ufl/formatting/ufl2unicode.py
@@ -0,0 +1,702 @@
+# coding: utf-8
+
+from __future__ import unicode_literals
+from six import unichr
+
+import numbers
+
+import ufl
+from ufl.log import error
+from ufl.corealg.multifunction import MultiFunction
+from ufl.corealg.map_dag import map_expr_dag
+from ufl.core.multiindex import Index, FixedIndex
+from ufl.form import Form
+from ufl.algorithms import compute_form_data
+
+
+class PrecedenceRules(MultiFunction):
+ "An enum-like class for C operator precedence levels."
+ def __init__(self):
+ MultiFunction.__init__(self)
+
+ def highest(self, o):
+ return 0
+ terminal = highest
+ list_tensor = highest
+ component_tensor = highest
+
+ def restricted(self, o):
+ return 5
+ cell_avg = restricted
+ facet_avg = restricted
+
+ def call(self, o):
+ return 10
+ indexed = call
+ min_value = call
+ max_value = call
+ math_function = call
+ bessel_function = call
+
+ def power(self, o):
+ return 12
+
+ def mathop(self, o):
+ return 15
+ derivative = mathop
+ trace = mathop
+ deviatoric = mathop
+ cofactor = mathop
+ skew = mathop
+ sym = mathop
+
+ def not_condition(self, o):
+ return 20
+
+ def product(self, o):
+ return 30
+ division = product
+ # mod = product
+ dot = product
+ inner = product
+ outer = product
+ cross = product
+
+ def add(self, o):
+ return 40
+ # sub = add
+ index_sum = add
+
+ def lt(self, o):
+ return 50
+ le = lt
+ gt = lt
+ ge = lt
+
+ def eq(self, o):
+ return 60
+ ne = eq
+
+ def and_condition(self, o):
+ return 70
+
+ def or_condition(self, o):
+ return 71
+
+ def conditional(self, o):
+ return 72
+
+ def lowest(self, o):
+ return 80
+ operator = lowest
+
+
+_precrules = PrecedenceRules()
+
+
+def precedence(expr):
+ return _precrules(expr)
+
+
+try:
+ import colorama
+ has_colorama = True
+except ImportError:
+ has_colorama = False
+
+
+class UC:
+ "An enum-like class for unicode characters."
+
+ # Letters in this alphabet have contiguous code point numbers
+ bold_math_a = u"𝐚"
+ bold_math_A = u"𝐀"
+
+ thin_space = u"\u2009"
+
+ superscript_plus = u'⁺'
+ superscript_minus = u'⁻'
+ superscript_equals = u'⁼'
+ superscript_left_paren = u'⁽'
+ superscript_right_paren = u'⁾'
+ superscript_digits = ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"]
+
+ subscript_plus = u'₊'
+ subscript_minus = u'₋'
+ subscript_equals = u'₌'
+ subscript_left_paren = u'₍'
+ subscript_right_paren = u'₎'
+ subscript_digits = ["₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉"]
+
+ sqrt = u'√'
+ transpose = u'ᵀ'
+
+ integral = u'∫'
+ integral_double = u'∬'
+ integral_triple = u'∭'
+ integral_contour = u'∮'
+ integral_surface = u'∯'
+ integral_volume = u'∰'
+
+ sum = u'∑'
+ division_slash = '∕'
+ partial = u'∂'
+ epsilon = u'ε'
+ omega = u'ω'
+ Omega = u'Ω'
+ gamma = u'γ'
+ Gamma = u'Γ'
+ nabla = u'∇'
+ for_all = u'∀'
+
+ dot = u'⋅'
+ cross_product = u'⨯'
+ circled_times = u'⊗'
+ nary_product = u'∏'
+
+ ne = u'≠'
+ lt = u'<'
+ le = u'≤'
+ gt = u'>'
+ ge = u'≥'
+
+ logical_and = u'∧'
+ logical_or = u'∨'
+ logical_not = u'¬'
+
+ element_of = u'∈'
+ not_element_of = u'∉'
+
+ left_white_square_bracket = u'⟦'
+ right_white_squared_bracket = u'⟧'
+ left_angled_bracket = u'⟨'
+ right_angled_bracket = u'⟩'
+ left_double_angled_bracket = u'⟪'
+ right_double_angled_bracket = u'⟫'
+
+ combining_right_arrow_above = '\u20D7'
+ combining_overline = '\u0305'
+
+
+def bolden_letter(c):
+ if ord("A") <= ord(c) <= ord("Z"):
+ c = unichr(ord(c) - ord(u"A") + ord(UC.bold_math_A))
+ elif ord("a") <= ord(c) <= ord("z"):
+ c = unichr(ord(c) - ord(u"a") + ord(UC.bold_math_a))
+ return c
+
+
+def superscript_digit(digit):
+ return UC.superscript_digits[ord(digit) - ord("0")]
+
+
+def subscript_digit(digit):
+ return UC.subscript_digits[ord(digit) - ord("0")]
+
+
+def bolden_string(s):
+ return u"".join(bolden_letter(c) for c in s)
+
+
+def overline_string(f):
+ return u"".join("%s%s" % (c, UC.combining_overline) for c in f)
+
+
+def subscript_number(number):
+ assert isinstance(number, int)
+ prefix = UC.subscript_minus if number < 0 else ''
+ number = str(number)
+ return prefix + ''.join(subscript_digit(c) for c in str(number))
+
+
+def superscript_number(number):
+ assert isinstance(number, int)
+ prefix = UC.superscript_minus if number < 0 else ''
+ number = str(number)
+ return prefix + ''.join(superscript_digit(c) for c in str(number))
+
+
+def opfont(opname):
+ return bolden_string(opname)
+
+
+def measure_font(dx):
+ return bolden_string(dx)
+
+
+integral_by_dim = {
+ 3: UC.integral_triple,
+ 2: UC.integral_double,
+ 1: UC.integral,
+}
+
+integral_type_to_codim = {
+ "cell": 0,
+ "exterior_facet": 1,
+ "interior_facet": 1,
+ "vertex": "tdim",
+ "point": "tdim",
+ "custom": 0,
+ "overlap": 0,
+ "interface": 1,
+ "cutcell": 0,
+}
+
+integral_symbols = {
+ "cell": UC.integral_volume,
+ "exterior_facet": UC.integral_surface,
+ "interior_facet": UC.integral_surface,
+ "vertex": UC.integral,
+ "point": UC.integral,
+ "custom": UC.integral,
+ "overlap": UC.integral,
+ "interface": UC.integral,
+ "cutcell": UC.integral,
+}
+
+integral_postfixes = {
+ "cell": "",
+ "exterior_facet": "ext",
+ "interior_facet": "int",
+ "vertex": "vertex",
+ "point": "point",
+ "custom": "custom",
+ "overlap": "overlap",
+ "interface": "interface",
+ "cutcell": "cutcell",
+}
+
+
+def get_integral_symbol(integral_type, domain, subdomain_id):
+ tdim = domain.topological_dimension()
+ codim = integral_type_to_codim[integral_type]
+ itgdim = tdim - codim
+
+ # ipost = integral_postfixes[integral_type]
+ istr = integral_by_dim[itgdim]
+
+ # TODO: Render domain description
+
+ if isinstance(subdomain_id, numbers.Integral):
+ istr += subscript_number(int(subdomain_id))
+ elif subdomain_id == "everywhere":
+ pass
+ elif subdomain_id == "otherwise":
+ istr += "[rest of domain]"
+ elif isinstance(subdomain_id, tuple):
+ istr += ",".join([subscript_number(int(i)) for i in subdomain_id])
+
+ dxstr = ufl.measure.integral_type_to_measure_name[integral_type]
+ dxstr = measure_font(dxstr)
+
+ return istr, dxstr
+
+
+def par(s):
+ return "(%s)" % s
+
+
+def prec(expr):
+ return 0 # FIXME
+ # return precedence[expr._ufl_class_]
+
+
+def is_int(s):
+ try:
+ int(s)
+ return True
+ except ValueError:
+ return False
+
+
+def format_index(ii):
+ if isinstance(ii, FixedIndex):
+ s = "%d" % ii._value
+ elif isinstance(ii, Index):
+ s = "i%s" % subscript_number(ii._count)
+ else:
+ error("Invalid index type %s." % type(ii))
+ return s
+
+
+def ufl2unicode(expression):
+ "Generate Unicode string for a UFL expression or form."
+ if isinstance(expression, Form):
+ form_data = compute_form_data(expression)
+ preprocessed_form = form_data.preprocessed_form
+ return form2unicode(preprocessed_form, form_data)
+ else:
+ return expression2unicode(expression)
+
+
+def expression2unicode(expression, argument_names=None, coefficient_names=None):
+ rules = Expression2UnicodeHandler(argument_names, coefficient_names)
+ return map_expr_dag(rules, expression)
+
+
+def form2unicode(form, formdata):
+ # formname = formdata.name
+ argument_names = None
+ coefficient_names = None
+
+ # Define form as sum of integrals
+ lines = []
+ integrals = form.integrals()
+ for itg in integrals:
+ integrand_string = expression2unicode(
+ itg.integrand(), argument_names, coefficient_names)
+
+ istr, dxstr = get_integral_symbol(itg.integral_type(), itg.ufl_domain(), itg.subdomain_id())
+
+ line = "%s %s %s" % (istr, integrand_string, dxstr)
+ lines.append(line)
+
+ return '\n + '.join(lines)
+
+
+def binop(expr, a, b, op, sep=" "):
+ eprec = precedence(expr)
+ op0, op1 = expr.ufl_operands
+ aprec = precedence(op0)
+ bprec = precedence(op1)
+ # Assuming left-to-right evaluation, therefore >= and > here:
+ if aprec >= eprec:
+ a = par(a)
+ if bprec > eprec:
+ b = par(b)
+ return sep.join((a, op, b))
+
+
+def mathop(expr, arg, opname):
+ eprec = precedence(expr)
+ aprec = precedence(expr.ufl_operands[0])
+ op = opfont(opname)
+ if aprec > eprec:
+ arg = par(arg)
+ sep = ""
+ else:
+ sep = UC.thin_space
+ return "%s%s%s" % (op, sep, arg)
+
+
+class Expression2UnicodeHandler(MultiFunction):
+ def __init__(self, argument_names=None, coefficient_names=None, colorama_bold=False):
+ MultiFunction.__init__(self)
+ self.argument_names = argument_names
+ self.coefficient_names = coefficient_names
+ self.colorama_bold = colorama_bold and has_colorama
+
+ # --- Terminal objects ---
+
+ def scalar_value(self, o):
+ if o.ufl_shape and self.colorama_bold:
+ return "%s%s%s" % (colorama.Style.BRIGHT, o._value, colorama.Style.RESET_ALL)
+ return "%s" % o._value
+
+ def zero(self, o):
+ if o.ufl_shape and self.colorama_bold:
+ if len(o.ufl_shape) == 1:
+ return "0%s" % UC.combining_right_arrow_above
+ return "%s0%s" % (colorama.Style.BRIGHT, colorama.Style.RESET_ALL)
+ return "0"
+
+ def identity(self, o):
+ if self.colorama_bold:
+ return "%sI%s" % (colorama.Style.BRIGHT, colorama.Style.RESET_ALL)
+ return "I"
+
+ def permutation_symbol(self, o):
+ if self.colorama_bold:
+ return "%s%s%s" % (colorama.Style.BRIGHT, UC.epsilon, colorama.Style.RESET_ALL)
+ return UC.epsilon
+
+ def facet_normal(self, o):
+ return "n%s" % UC.combining_right_arrow_above
+
+ def spatial_coordinate(self, o):
+ return "x%s" % UC.combining_right_arrow_above
+
+ def argument(self, o):
+ # Using ^ for argument numbering and _ for indexing since
+ # indexing is more common than exponentiation
+ if self.argument_names is None:
+ i = o.number()
+ bfn = "v" if i == 0 else "u"
+ if not o.ufl_shape:
+ return bfn
+ elif len(o.ufl_shape) == 1:
+ return "%s%s" % (bfn, UC.combining_right_arrow_above)
+ elif self.colorama_bold:
+ return "%s%s%s" % (colorama.Style.BRIGHT, bfn, colorama.Style.RESET_ALL)
+ else:
+ return bfn
+ return self.argument_names[(o.number(), o.part())]
+
+ def coefficient(self, o):
+ # Using ^ for coefficient numbering and _ for indexing since
+ # indexing is more common than exponentiation
+ if self.coefficient_names is None:
+ i = o.count()
+ var = "w"
+ if len(o.ufl_shape) == 1:
+ var += UC.combining_right_arrow_above
+ elif len(o.ufl_shape) > 1 and self.colorama_bold:
+ var = "%s%s%s" % (colorama.Style.BRIGHT, var, colorama.Style.RESET_ALL)
+ return "%s%s" % (var, superscript_number(i))
+ return self.coefficient_names[o.count()]
+
+ def multi_index(self, o):
+ return ",".join(format_index(i) for i in o)
+
+ def label(self, o):
+ return "l%s" % (subscript_number(o.count()),)
+
+ # --- Non-terminal objects ---
+
+ def variable(self, o, f, l):
+ return "var(%s,%s)" % (f, l)
+
+ def index_sum(self, o, f, i):
+ if 1: # prec(o.ufl_operands[0]) >? prec(o):
+ f = par(f)
+ return "%s[%s]%s" % (UC.sum, i, f)
+
+ def sum(self, o, a, b):
+ return binop(o, a, b, "+")
+
+ def product(self, o, a, b):
+ return binop(o, a, b, " ", sep="")
+
+ def division(self, o, a, b):
+ if is_int(b):
+ b = subscript_number(int(b))
+ if is_int(a):
+ # Return as a fraction
+ # NOTE: Maybe consider using fractional slash
+ # with normal numbers if terminals can handle it
+ a = superscript_number(int(a))
+ else:
+ a = par(a)
+ return "%s %s %s" % (a, UC.division_slash, b)
+ return binop(o, a, b, UC.division_slash)
+
+ def abs(self, o, a):
+ return "|%s|" % (a,)
+
+ def transposed(self, o, a):
+ a = par(a)
+ return "%s%s" % (a, UC.transpose)
+
+ def indexed(self, o, A, ii):
+ op0, op1 = o.ufl_operands
+ Aprec = precedence(op0)
+ oprec = precedence(o)
+ if Aprec > oprec:
+ A = par(A)
+ return "%s[%s]" % (A, ii)
+
+ def variable_derivative(self, o, f, v):
+ f = par(f)
+ v = par(v)
+ nom = r"%s%s" % (UC.partial, f)
+ denom = r"%s%s" % (UC.partial, v)
+ return par(r"%s%s%s" % (nom, UC.division_slash, denom))
+
+ def coefficient_derivative(self, o, f, w, v, cd):
+ f = par(f)
+ w = par(w)
+ nom = r"%s%s" % (UC.partial, f)
+ denom = r"%s%s" % (UC.partial, w)
+ return par(r"%s%s%s[%s]" % (nom, UC.division_slash, denom, v)) # TODO: Fix this syntax...
+
+ def grad(self, o, f):
+ return mathop(o, f, "grad")
+
+ def div(self, o, f):
+ return mathop(o, f, "div")
+
+ def nabla_grad(self, o, f):
+ oprec = precedence(o)
+ fprec = precedence(o.ufl_operands[0])
+ if fprec > oprec:
+ f = par(f)
+ return "%s%s%s" % (UC.nabla, UC.thin_space, f)
+
+ def nabla_div(self, o, f):
+ oprec = precedence(o)
+ fprec = precedence(o.ufl_operands[0])
+ if fprec > oprec:
+ f = par(f)
+ return "%s%s%s%s%s" % (UC.nabla, UC.thin_space, UC.dot, UC.thin_space, f)
+
+ def curl(self, o, f):
+ oprec = precedence(o)
+ fprec = precedence(o.ufl_operands[0])
+ if fprec > oprec:
+ f = par(f)
+ return "%s%s%s%s%s" % (UC.nabla, UC.thin_space, UC.cross_product, UC.thin_space, f)
+
+ def math_function(self, o, f):
+ op = opfont(self._name)
+ f = par(f)
+ return "%s%s" % (op, f)
+
+ def sqrt(self, o, f):
+ f = par(f)
+ return "%s%s" % (UC.sqrt, f)
+
+ def exp(self, o, f):
+ op = opfont("exp")
+ f = par(f)
+ return "%s%s" % (op, f)
+
+ def atan2(self, o, f1, f2):
+ f1 = par(f1)
+ f2 = par(f2)
+ op = opfont("arctan2")
+ return "%s(%s, %s)" % (op, f1, f2)
+
+ def bessel_j(self, o, nu, f):
+ op = opfont("J")
+ f = par(f)
+ nu = subscript_number(int(nu))
+ return "%s%s%s" % (op, nu, f)
+
+ def bessel_y(self, o, nu, f):
+ op = opfont("Y")
+ f = par(f)
+ nu = subscript_number(int(nu))
+ return "%s%s%s" % (op, nu, f)
+
+ def bessel_i(self, o, nu, f):
+ op = opfont("I")
+ f = par(f)
+ nu = subscript_number(int(nu))
+ return "%s%s%s" % (op, nu, f)
+
+ def bessel_K(self, o, nu, f):
+ op = opfont("K")
+ f = par(f)
+ nu = subscript_number(int(nu))
+ return "%s%s%s" % (op, nu, f)
+
+ def power(self, o, a, b):
+ if is_int(b):
+ b = superscript_number(int(b))
+ return binop(o, a, b, "", sep="")
+ return binop(o, a, b, "^", sep="")
+
+ def outer(self, o, a, b):
+ return binop(o, a, b, UC.circled_times)
+
+ def inner(self, o, a, b):
+ return "%s%s, %s%s" % (UC.left_angled_bracket, a, b, UC.right_angled_bracket)
+
+ def dot(self, o, a, b):
+ return binop(o, a, b, UC.dot)
+
+ def cross(self, o, a, b):
+ return binop(o, a, b, UC.cross_product)
+
+ def determinant(self, o, A):
+ return "|%s|" % (A,)
+
+ def inverse(self, o, A):
+ A = par(A)
+ return "%s%s" % (A, superscript_number(-1))
+
+ def trace(self, o, A):
+ return mathop(o, A, "tr")
+
+ def deviatoric(self, o, A):
+ return mathop(o, A, "dev")
+
+ def cofactor(self, o, A):
+ return mathop(o, A, "cofac")
+
+ def skew(self, o, A):
+ return mathop(o, A, "skew")
+
+ def sym(self, o, A):
+ return mathop(o, A, "sym")
+
+ def list_tensor(self, o, *ops):
+ l = ", ".join(ops)
+ return "%s%s%s" % ("[", l, "]")
+
+ def component_tensor(self, o, A, ii):
+ return "[%s %s %s]" % (A, UC.for_all, ii)
+
+ def positive_restricted(self, o, f):
+ f = par(f)
+ return "%s%s" % (f, UC.superscript_plus)
+
+ def negative_restricted(self, o, f):
+ f = par(f)
+ return "%s%s" % (f, UC.superscript_minus)
+
+ def cell_avg(self, o, f):
+ f = overline_string(f)
+ return f
+
+ def facet_avg(self, o, f):
+ f = overline_string(f)
+ return f
+
+ def eq(self, o, a, b):
+ return binop(o, a, b, "=")
+
+ def ne(self, o, a, b):
+ return binop(o, a, b, UC.ne)
+
+ def le(self, o, a, b):
+ return binop(o, a, b, UC.le)
+
+ def ge(self, o, a, b):
+ return binop(o, a, b, UC.ge)
+
+ def lt(self, o, a, b):
+ return binop(o, a, b, UC.lt)
+
+ def gt(self, o, a, b):
+ return binop(o, a, b, UC.gt)
+
+ def and_condition(self, o, a, b):
+ return binop(o, a, b, UC.logical_and)
+
+ def or_condition(self, o, a, b):
+ return binop(o, a, b, UC.logical_or)
+
+ def not_condition(self, o, a):
+ a = par(a)
+ return "%s%s" % (UC.logical_not, a)
+
+ def conditional(self, o, c, t, f):
+ c = par(c)
+ t = par(t)
+ f = par(t)
+ If = opfont("if")
+ Else = opfont("else")
+ l = " ".join((t, If, c, Else, f))
+ return l
+
+ def min_value(self, o, a, b):
+ op = opfont("min")
+ return "%s(%s, %s)" % (op, a, b)
+
+ def max_value(self, o, a, b):
+ op = opfont("max")
+ return "%s(%s, %s)" % (op, a, b)
+
+ def expr_list(self, o, *ops):
+ items = ", ".join(ops)
+ return "%s %s %s" % (UC.left_white_square_bracket, items,
+ UC.right_white_squared_bracket)
+
+ def expr_mapping(self, o, *ops):
+ items = ", ".join(ops)
+ return "%s %s %s" % (UC.left_double_angled_bracket, items,
+ UC.left_double_angled_bracket)
+
+ def expr(self, o):
+ raise ValueError("Missing handler for type %s" % str(type(o)))
diff --git a/ufl/integral.py b/ufl/integral.py
index c127ff9..c164d41 100644
--- a/ufl/integral.py
+++ b/ufl/integral.py
@@ -21,7 +21,6 @@
# Modified by Anders Logg, 2008-2009
# Modified by Massimiliano Leoni, 2016.
-# import six
import ufl
from ufl.log import error
from ufl.core.expr import Expr
@@ -35,7 +34,6 @@ from ufl.utils.py23 import as_native_strings
__all_classes__ = as_native_strings(["Integral"])
-# @six.python_2_unicode_compatible
class Integral(object):
"An integral over a single domain."
__slots__ = as_native_strings((
@@ -61,12 +59,14 @@ class Integral(object):
def reconstruct(self, integrand=None,
integral_type=None, domain=None, subdomain_id=None,
metadata=None, subdomain_data=None):
- """Construct a new Integral object with some properties replaced with new values.
+ """Construct a new Integral object with some properties replaced with
+ new values.
Example:
<a = Integral instance>
b = a.reconstruct(expand_compounds(a.integrand()))
c = a.reconstruct(metadata={'quadrature_degree':2})
+
"""
if integrand is None:
integrand = self.integrand()
@@ -90,11 +90,6 @@ class Integral(object):
"Return the domain type of this integral."
return self._integral_type
- #def domain(self):
- # "Deprecated, please use .ufl_domain() instead."
- # deprecate("Integral.domain() is deprecated, please use .ufl_domain() instead.")
- # return self.ufl_domain()
-
def ufl_domain(self):
"Return the integration domain of this integral."
return self._ufl_domain
@@ -136,14 +131,12 @@ class Integral(object):
return s
def __repr__(self):
- r = "Integral(%s, %s, %s, %s, %s, %s)" % (
- repr(self._integrand),
- repr(self._integral_type),
- repr(self._ufl_domain),
- repr(self._subdomain_id),
- repr(self._metadata),
- repr(self._subdomain_data),
- )
+ r = "Integral(%s, %s, %s, %s, %s, %s)" % (repr(self._integrand),
+ repr(self._integral_type),
+ repr(self._ufl_domain),
+ repr(self._subdomain_id),
+ repr(self._metadata),
+ repr(self._subdomain_data))
return as_native_str(r)
def __eq__(self, other):
@@ -156,8 +149,9 @@ class Integral(object):
id_or_none(self._subdomain_data) == id_or_none(other._subdomain_data))
def __hash__(self):
- # Assuming few collisions by ignoring hash(self._metadata)
- # (a dict is not hashable but we assume it is immutable in practice)
+ # Assuming few collisions by ignoring hash(self._metadata) (a
+ # dict is not hashable but we assume it is immutable in
+ # practice)
hashdata = (hash(self._integrand),
self._integral_type,
hash(self._ufl_domain),
diff --git a/ufl/measure.py b/ufl/measure.py
index 473d972..db6bd57 100644
--- a/ufl/measure.py
+++ b/ufl/measure.py
@@ -21,7 +21,6 @@
# Modified by Anders Logg 2008-2016
# Modified by Massimiliano Leoni, 2016.
-#import six
from six import string_types
import numbers
@@ -112,19 +111,18 @@ def measure_names():
return tuple(sorted(measure_name_to_integral_type.keys()))
-# @six.python_2_unicode_compatible
class Measure(object):
- __slots__ = as_native_strings((
- "_integral_type",
- "_domain",
- "_subdomain_id",
- "_metadata",
- "_subdomain_data",
- ))
+ __slots__ = as_native_strings(("_integral_type",
+ "_domain",
+ "_subdomain_id",
+ "_metadata",
+ "_subdomain_data"))
"""Representation of an integration measure.
- The Measure object holds information about integration properties to be
- transferred to a Form on multiplication with a scalar expression.
+ The Measure object holds information about integration properties
+ to be transferred to a Form on multiplication with a scalar
+ expression.
+
"""
def __init__(self,
@@ -159,8 +157,7 @@ class Measure(object):
# Check that we either have a proper AbstractDomain or none
self._domain = None if domain is None else as_domain(domain)
- if not (self._domain is None
- or isinstance(self._domain, AbstractDomain)):
+ if not (self._domain is None or isinstance(self._domain, AbstractDomain)):
error("Invalid domain.")
# Store subdomain data
@@ -177,8 +174,7 @@ class Measure(object):
if not isinstance(did, numbers.Integral):
error("Invalid subdomain_id %s." % (did,))
else:
- if not (subdomain_id in ("everywhere",)
- or isinstance(subdomain_id, numbers.Integral)):
+ if not (subdomain_id in ("everywhere",) or isinstance(subdomain_id, numbers.Integral)):
error("Invalid subdomain_id %s." % (subdomain_id,))
self._subdomain_id = subdomain_id
@@ -194,11 +190,6 @@ class Measure(object):
"""
return self._integral_type
- #def domain(self):
- # "Deprecated, please use .ufl_domain() instead."
- # deprecate("Measure.domain() is deprecated, please use .ufl_domain() instead.")
- # return self.ufl_domain()
-
def ufl_domain(self):
"""Return the domain associated with this measure.
@@ -212,8 +203,10 @@ class Measure(object):
def metadata(self):
"""Return the integral metadata. This data is not interpreted by UFL.
- It is passed to the form compiler which can ignore it or use it to
- compile each integral of a form in a different way."""
+ It is passed to the form compiler which can ignore it or use
+ it to compile each integral of a form in a different way.
+
+ """
return self._metadata
def reconstruct(self,
@@ -222,7 +215,8 @@ class Measure(object):
domain=None,
metadata=None,
subdomain_data=None):
- """Construct a new Measure object with some properties replaced with new values.
+ """Construct a new Measure object with some properties replaced with
+ new values.
Example:
<dm = Measure instance>
@@ -232,6 +226,7 @@ class Measure(object):
Used by the call operator, so this is equivalent:
b = dm(2)
c = dm(0, { "quadrature_degree": 3 })
+
"""
if subdomain_id is None:
subdomain_id = self.subdomain_id()
@@ -302,11 +297,12 @@ class Measure(object):
def __getitem__(self, data):
"""This operator supports legacy syntax in python dolfin programs.
- The old documentation reads:
- Return a new Measure for same integration type with an attached
- context for interpreting domain ids. By default this new Measure
- integrates over everywhere, but it can be restricted with a domain id
- as usual. Example: dx = dx[boundaries]; L = f*v*dx + g*v+dx(1).
+ The old documentation reads: Return a new Measure for same
+ integration type with an attached context for interpreting
+ domain ids. By default this new Measure integrates over
+ everywhere, but it can be restricted with a domain id as
+ usual. Example: dx = dx[boundaries]; L = f*v*dx + g*v+dx(1).
+
"""
deprecate("Notation dx[meshfunction] is deprecated. Please use dx(subdomain_data=meshfunction) instead.")
return self(subdomain_data=data)
@@ -400,7 +396,7 @@ class Measure(object):
def __rmul__(self, integrand):
"""Multiply a scalar expression with measure to construct a form with
-a single integral.
+ a single integral.
This is to implement the notation
@@ -426,7 +422,7 @@ a single integral.
if not is_true_ufl_scalar(integrand):
error("Can only integrate scalar expressions. The integrand is a "
"tensor expression with value shape %s and free indices with labels %s." %
- (integrand.ufl_shape, integrand.ufl_free_indices))
+ (integrand.ufl_shape, integrand.ufl_free_indices))
# If we have a tuple of domain ids, delegate composition to
# Integral.__add__:
@@ -461,7 +457,6 @@ a single integral.
return Form([integral])
-# @six.python_2_unicode_compatible
class MeasureSum(object):
"""Represents a sum of measures.
@@ -506,6 +501,7 @@ class MeasureProduct(object):
This is work in progress and not functional. It needs support
in other parts of ufl and the rest of the code generation chain.
+
"""
__slots__ = as_native_strings(("_measures",))
@@ -518,8 +514,9 @@ class MeasureProduct(object):
def __mul__(self, other):
"""Flatten multiplication of product measures.
- This is to ensure that (dm1*dm2)*dm3 is stored as a
- simple list (dm1,dm2,dm3) in a single MeasureProduct.
+ This is to ensure that (dm1*dm2)*dm3 is stored as a simple
+ list (dm1,dm2,dm3) in a single MeasureProduct.
+
"""
if isinstance(other, Measure):
measures = self.sub_measures() + [other]
diff --git a/ufl/sobolevspace.py b/ufl/sobolevspace.py
index f0814d8..2e151a8 100644
--- a/ufl/sobolevspace.py
+++ b/ufl/sobolevspace.py
@@ -25,12 +25,10 @@ symbolic reasoning about the spaces in which finite elements lie."""
# Modified by Lizao Li 2015
# Modified by Thomas Gibson 2017
-#import six
from ufl.utils.py23 import as_native_str
from functools import total_ordering
-# @six.python_2_unicode_compatible
@total_ordering
class SobolevSpace(object):
"""Symbolic representation of a Sobolev space. This implements a
@@ -123,6 +121,7 @@ class SobolevSpace(object):
class DirectionalSobolevSpace(SobolevSpace):
"""Symbolic representation of a Sobolev space with varying smoothness
in differerent spatial directions.
+
"""
def __init__(self, orders):
diff --git a/ufl/tensoralgebra.py b/ufl/tensoralgebra.py
index c5f7946..82da808 100644
--- a/ufl/tensoralgebra.py
+++ b/ufl/tensoralgebra.py
@@ -122,10 +122,8 @@ class Transposed(CompoundTensorOperator):
@ufl_type(num_ops=2)
class Outer(CompoundTensorOperator):
- __slots__ = as_native_strings((
- "ufl_free_indices",
- "ufl_index_dimensions",
- ))
+ __slots__ = as_native_strings(("ufl_free_indices",
+ "ufl_index_dimensions"))
def __new__(cls, a, b):
ash, bsh = a.ufl_shape, b.ufl_shape
@@ -153,10 +151,8 @@ class Outer(CompoundTensorOperator):
@ufl_type(num_ops=2)
class Inner(CompoundTensorOperator):
- __slots__ = as_native_strings((
- "ufl_free_indices",
- "ufl_index_dimensions",
- ))
+ __slots__ = as_native_strings(("ufl_free_indices",
+ "ufl_index_dimensions"))
def __new__(cls, a, b):
# Checks
@@ -174,9 +170,8 @@ class Inner(CompoundTensorOperator):
return CompoundTensorOperator.__new__(cls)
def __init__(self, a, b):
- # sort operands for unique representation,
- # must be independent of various counts etc.
- # as explained in cmp_expr
+ # sort operands for unique representation, must be independent
+ # of various counts etc. as explained in cmp_expr
a, b = sorted_expr((a, b))
CompoundTensorOperator.__init__(self, (a, b))
@@ -194,10 +189,8 @@ class Inner(CompoundTensorOperator):
@ufl_type(num_ops=2)
class Dot(CompoundTensorOperator):
- __slots__ = as_native_strings((
- "ufl_free_indices",
- "ufl_index_dimensions",
- ))
+ __slots__ = as_native_strings(("ufl_free_indices",
+ "ufl_index_dimensions"))
def __new__(cls, a, b):
ash = a.ufl_shape
@@ -239,10 +232,8 @@ class Dot(CompoundTensorOperator):
@ufl_type(num_ops=2)
class Cross(CompoundTensorOperator):
- __slots__ = as_native_strings((
- "ufl_free_indices",
- "ufl_index_dimensions",
- ))
+ __slots__ = as_native_strings(("ufl_free_indices",
+ "ufl_index_dimensions"))
def __new__(cls, a, b):
ash = a.ufl_shape
diff --git a/ufl/utils/sequences.py b/ufl/utils/sequences.py
index 20ee3e1..8ca0b88 100644
--- a/ufl/utils/sequences.py
+++ b/ufl/utils/sequences.py
@@ -18,9 +18,13 @@
# You should have received a copy of the GNU Lesser General Public License
# along with UFL. If not, see <http://www.gnu.org/licenses/>.
-from six.moves import zip
+from functools import reduce
+
+from six.moves import map, zip
from six import string_types
+import numpy
+
def product(sequence):
"Return the product of all elements in a sequence."
@@ -67,3 +71,15 @@ def recursive_chain(lists):
else:
for s in recursive_chain(l):
yield s
+
+
+def max_degree(degrees):
+ """Maximum degree for mixture of scalar and tuple degrees."""
+ # numpy.maximum broadcasts scalar degrees to tuple degrees if
+ # necessary. reduce applies numpy.maximum pairwise.
+ degree = reduce(numpy.maximum, map(numpy.asarray, degrees))
+ if degree.ndim:
+ degree = tuple(map(int, degree)) # tuple degree
+ else:
+ degree = int(degree) # scalar degree
+ return degree
diff --git a/ufl/utils/sorting.py b/ufl/utils/sorting.py
index 6c1dc62..4a45841 100644
--- a/ufl/utils/sorting.py
+++ b/ufl/utils/sorting.py
@@ -78,15 +78,6 @@ def sorted_by_key(mapping):
return sorted(iteritems(mapping), key=_key)
-def sorted_by_tuple_key(mapping):
- "Sort dict items by tuple valued keys, allowing different types as items of the key tuples."
- # Python3 doesn't allow comparing builtins of different type,
- # therefore the typename trick here
- def _tuple_key(x):
- return tuple((type(k).__name__, k) for k in x[0])
- return sorted(iteritems(mapping), key=_tuple_key)
-
-
def canonicalize_metadata(metadata):
"""Assuming metadata to be a dict with string keys and builtin python types as values.
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/fenics/ufl.git
More information about the debian-science-commits
mailing list