diff -Nru ufl-2017.1.0/bitbucket-pipelines.yml ufl-2017.2.0.0/bitbucket-pipelines.yml --- ufl-2017.1.0/bitbucket-pipelines.yml 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/bitbucket-pipelines.yml 2017-12-04 10:19:20.000000000 +0000 @@ -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 -Nru ufl-2017.1.0/ChangeLog.rst ufl-2017.2.0.0/ChangeLog.rst --- ufl-2017.1.0/ChangeLog.rst 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ChangeLog.rst 2017-12-04 10:19:20.000000000 +0000 @@ -1,6 +1,26 @@ Changelog ========= +2017.2.0 (2017-11-30) +--------------------- + +- Add geometric quantity ``CellDiameter`` defined as a set diameter + of the cell, i.e., maximal distance between any two points of the + cell; implemented on simplices and quads/hexes +- Rename internally used reference quantities + ``(Cell|Facet)EdgeVectors`` to ``Reference(Cell|Facet)EdgeVectors`` +- Add internally used quantites ``CellVertices``, + ``(Cell|Facet)EdgeVectors`` which are physical-coordinates-valued; + will be useful for further geometry lowering implementations + for quads/hexes +- Implement geometry lowering of ``(Min|Max)(Cell|Facet)EdgeLength`` + for quads and hexes + +2017.1.0.post1 (2017-09-12) +--------------------------- + +- Change PyPI package name to fenics-ufl. + 2017.1.0 (2017-05-09) --------------------- diff -Nru ufl-2017.1.0/.circleci/config.yml ufl-2017.2.0.0/.circleci/config.yml --- ufl-2017.1.0/.circleci/config.yml 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/.circleci/config.yml 2017-12-04 10:19:20.000000000 +0000 @@ -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 -Nru ufl-2017.1.0/debian/changelog ufl-2017.2.0.0/debian/changelog --- ufl-2017.1.0/debian/changelog 2017-09-09 06:24:16.000000000 +0000 +++ ufl-2017.2.0.0/debian/changelog 2018-02-21 14:34:08.000000000 +0000 @@ -1,3 +1,29 @@ +ufl (2017.2.0.0-2) unstable; urgency=medium + + * debian/control: update VCS tags to salsa.debian.org + + -- Drew Parsons Wed, 21 Feb 2018 22:34:08 +0800 + +ufl (2017.2.0.0-1exp1) experimental; urgency=medium + + * New upstream release. + - this is the official 2017.2.0 release. The preceding 2017.2.0 + version was a mislabelled beta release. + * Standards-Version: 4.1.3 + * debhelper compatibility level 11 + + -- Drew Parsons Fri, 19 Jan 2018 23:19:11 +0800 + +ufl (2017.2.0-1) experimental; urgency=medium + + * Team upload. + * New upstream release. + - updated debian/upstream/signing-key.asc for signature + from the FEniCS Project Steering Council (key BED06106DD22BAB3) + * Standards-Version: 4.1.1 + + -- Drew Parsons Sat, 07 Oct 2017 16:01:28 +0800 + ufl (2017.1.0-2) unstable; urgency=medium * Team upload. diff -Nru ufl-2017.1.0/debian/compat ufl-2017.2.0.0/debian/compat --- ufl-2017.1.0/debian/compat 2017-09-09 06:24:16.000000000 +0000 +++ ufl-2017.2.0.0/debian/compat 2018-02-21 14:34:08.000000000 +0000 @@ -1 +1 @@ -10 +11 diff -Nru ufl-2017.1.0/debian/control ufl-2017.2.0.0/debian/control --- ufl-2017.1.0/debian/control 2017-09-09 06:24:16.000000000 +0000 +++ ufl-2017.2.0.0/debian/control 2018-02-21 14:34:08.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Debian Science Team Uploaders: Johannes Ring , Drew Parsons Build-Depends: - debhelper (>= 10), + debhelper (>= 11), dh-python, python-all (>= 2.7), python3-all (>= 3.4), @@ -16,12 +16,12 @@ python3-six, python-pytest, python3-pytest -Standards-Version: 4.1.0 +Standards-Version: 4.1.3 X-Python-Version: >= 2.7 X-Python3-Version: >= 3.4 Homepage: http://fenicsproject.org -Vcs-Git: https://anonscm.debian.org/git/debian-science/packages/fenics/ufl.git -Vcs-Browser: https://anonscm.debian.org/git/debian-science/packages/fenics/ufl.git +Vcs-Git: https://salsa.debian.org/science-team/fenics/ufl.git +Vcs-Browser: https://salsa.debian.org/science-team/fenics/ufl Package: python-ufl Architecture: all diff -Nru ufl-2017.1.0/debian/upstream/signing-key.asc ufl-2017.2.0.0/debian/upstream/signing-key.asc --- ufl-2017.1.0/debian/upstream/signing-key.asc 2017-09-09 06:24:16.000000000 +0000 +++ ufl-2017.2.0.0/debian/upstream/signing-key.asc 2018-02-21 14:34:08.000000000 +0000 @@ -1,121 +1,30 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -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 -CAkHCg4MDw4ODA0NDxEWEw8QFRENDRMaExUXGBkZGQ8SGx0bGB0WGBkY/9sAQwEE -BAQGBQYLBgYLGBANEBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgY -GBgYGBgYGBgYGBgYGBgY/8AAEQgAXQBLAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEB -AAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUS -ITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5 -OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeY -mZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq -8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALUR -AAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1Lw -FWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdo -aWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLD -xMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A -95opKKAA1ia74s0bw9GfttxumxkQR8uf8KyvGvjBNBt/sdowN665J/55g9Pxrxia -ae+vWuJnMjsclmOSaAPQ7r4r3rTH7FplukXbzWLN/SrNp8WVVV/tHSeCcFreTkf8 -BP8AjXmzQsTiq0kRB2mgD6H0TxLoviK1abSb1Jin+siPDxn/AGl7Vq18mStqOk6m -NR0e9ltp1IdXQ8gj+Y9q+kfBHieLxd4KtdYVQkxzFcRj+CVeGH07j2NAHQmiikxQ -A7NQ3VzHaWU11KcJEjSN9AM08tXNePLsWvw71VvNVGaExrk4JJOMD1PWgDwvU9Xn -1jW5765kJaZy5yeme3+fSrNoqAbgc1hQRSP84BOPSte3WeMAMDigDVCx7QxYAfrV -O52tkqM471IMkhW70s8AWEuCMYxxQBhXI3IVJ4PUV6B8DtRMOo65oLsMEJeRj/xx -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 -YHKWQMEC6P91bHPbCe5ReMb/ktjI9vI4G0Q= -=0kz9 +mQENBFm3qPYBCADLVRsKIH2xwxzrRyax3SXsd3pcV1K0fAXC8C1P32wh5o8NLX80 +QGNWKIln4kdrYtL5MHChZipNFmYCRT/vrFOaVftj/TM2QebOBwoGVIhQ2ueIQ9mO +GYTKKwNLPugUTf04l/+37B/WX/t8JsWfo1EVQ6FRjdY1P7iQpWDzhSMouKJE3+Xy +SH3Okh/OiumPSM/fNGLN6b/OE0K6BBH/RWWJVT/cbdSm3FrjYflTPPtP9yLWRj0o +TW81E7lYiKPL6pzi7kVtxicUu8MzOPpESBDty8M/xUmkdVzUU5E7NkRFnkCjhoJF +scLwdpdLRWaaLqAYp6W5puU/95X6Ddn9utLFABEBAAG0SkZFbmlDUyBQcm9qZWN0 +IFN0ZWVyaW5nIENvdW5jaWwgPGZlbmljcy1zdGVlcmluZy1jb3VuY2lsQGdvb2ds +ZWdyb3Vwcy5jb20+iQE+BBMBAgAoBQJZt6j2AhsDBQkDwmcABgsJCAcDAgYVCAIJ +CgsEFgIDAQIeAQIXgAAKCRC+0GEG3SK6szJ2B/9Zxea+l83Q9il/Z21VFZRWBETx +y189cqlOeVsMPJm/KpSDtjAC1iJWi9ogN2zyZej/m8Su+eAJ7QUHgz8StJUXOO6J +Y7OZ/v/SlJbf6ADcT9p981H9gFzufzU6NqjynFQRLjaApToZtSiAM4lsL21zk8Z+ +B7SMSouKGGn/ODWuZeVA1QT6pJTAX31lT1oFbdPRHc4j41qU+ogyjcwPh2dYFOBc +ZEp5XyU+7ZCGK1A2p/0i6orXBUVKw/1zm9jCSwxgd5FpEvnB6BXvHV3lXdiqxJuN +Xr+3OBoq0k5vQPkBKTDhvCf3UFEODJ98mFAKD1zezLTex+3yzOSmXpoLXTEcuQEN +BFm3qPYBCACqGoAPALpcUGwMgullThXVEEUJ2WY7wXoNvX6qAZ0gyf/vkJnuNyQH +Qd6ZJJVLzP28vHGLkftqcyjVLlu6Ok7dTrFobXTEeR9GO2cqxccfVTUUbURQ65kl +QhL6g+w/MeLtvMdAomClODvz7jRGAZUsezQcWrFnT8R25S94O4kPfky7fP+gNcwM +YT4SyScFvFTFGy6PSjnGIzGQUchBQRam56K8tP2FrCOMIWryeXjTcyixJPFfzmc3 +N3ifnTQPtu7VQtUkmq6L6dBtf8cCvi42Cnscq6HmcgGqkZTm81af/FPOI5SoY+gZ +8Oiur4KnOhkHJDg0+MzM8sKYVHmUf84hABEBAAGJASUEGAECAA8FAlm3qPYCGwwF +CQPCZwAACgkQvtBhBt0iurPTYwgAyIKm3ySpEcJlIVquiq9Xx52yCtdaNfIkwLOo +GwoTF4uIxGLWHNZn7nMn3HNMLxohNpuVmbDW++bK1ui0eqzeAFkvjCULwFU5RRsW +lVgN5xxtmjuSsVZBuE4KZMQevv6HcUUe6nEMERHUnujJdJKydXPOrWC3/+B/NYUR +8KoUFPL1+4si2wIdFOQZ8194Ic/JA4/FBhwMKG/rNNvRU2MNAzWzZCP7V0FeRLUs +fIsWs/CSG7SnPKs3o45D9tSiKVcBUilTbJYwmUnmTCwYD71OWa3q8t1ZmvHY/XMk +BSGJR5XcHeZKG/tjm5aSVp8yLsP4xEiRZcAFapBcMnaSDOTWOA== +=vY8l -----END PGP PUBLIC KEY BLOCK----- diff -Nru ufl-2017.1.0/demo/Poisson.ufl ufl-2017.2.0.0/demo/Poisson.ufl --- ufl-2017.1.0/demo/Poisson.ufl 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/demo/Poisson.ufl 2017-12-04 10:19:20.000000000 +0000 @@ -28,5 +28,5 @@ 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 -Nru ufl-2017.1.0/doc/sphinx/source/conf.py ufl-2017.2.0.0/doc/sphinx/source/conf.py --- ufl-2017.1.0/doc/sphinx/source/conf.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/doc/sphinx/source/conf.py 2017-12-04 10:19:20.000000000 +0000 @@ -58,7 +58,7 @@ 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 -Nru ufl-2017.1.0/doc/sphinx/source/releases/next.rst ufl-2017.2.0.0/doc/sphinx/source/releases/next.rst --- ufl-2017.1.0/doc/sphinx/source/releases/next.rst 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/doc/sphinx/source/releases/next.rst 2017-12-04 10:19:20.000000000 +0000 @@ -11,6 +11,7 @@ be published (and renamed) to list the most important changes in the new release. + Detailed changes ================ diff -Nru ufl-2017.1.0/doc/sphinx/source/releases/v2017.1.0.post1.rst ufl-2017.2.0.0/doc/sphinx/source/releases/v2017.1.0.post1.rst --- ufl-2017.1.0/doc/sphinx/source/releases/v2017.1.0.post1.rst 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/doc/sphinx/source/releases/v2017.1.0.post1.rst 2017-12-04 10:19:20.000000000 +0000 @@ -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 -Nru ufl-2017.1.0/doc/sphinx/source/releases/v2017.2.0.rst ufl-2017.2.0.0/doc/sphinx/source/releases/v2017.2.0.rst --- ufl-2017.1.0/doc/sphinx/source/releases/v2017.2.0.rst 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/doc/sphinx/source/releases/v2017.2.0.rst 2017-12-04 10:19:20.000000000 +0000 @@ -0,0 +1,13 @@ +=========================== +Changes in version 2017.2.0 +=========================== + +UFL 2017.2.0 was released on 2017-11-30. + +Summary of changes +================== + +- Add ``CellDiameter`` expression giving diameter of a cell, i.e., + maximal distance between any two points of the cell. Implemented + for all simplices and quads/hexes. +- Make ``(Min|Max)(Cell|Facet)EdgeLength`` working for quads/hexes diff -Nru ufl-2017.1.0/doc/sphinx/source/releases.rst ufl-2017.2.0.0/doc/sphinx/source/releases.rst --- ufl-2017.1.0/doc/sphinx/source/releases.rst 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/doc/sphinx/source/releases.rst 2017-12-04 10:19:20.000000000 +0000 @@ -9,6 +9,8 @@ :maxdepth: 2 releases/next + releases/v2017.2.0 + releases/v2017.1.0.post1 releases/v2017.1.0 releases/v2016.2.0 releases/v2016.1.0 diff -Nru ufl-2017.1.0/.mailmap ufl-2017.2.0.0/.mailmap --- ufl-2017.1.0/.mailmap 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/.mailmap 2017-12-04 10:19:20.000000000 +0000 @@ -0,0 +1,132 @@ +Anders Logg +Anders Logg +Anders Logg +Anders Logg +Anders Logg logg +Anders Logg fenics +Anders Logg hg +Anders Logg root +Anders Logg +Anders Logg +Anders Logg +Anders Logg +Anders Logg +Anders Logg anders +Anders Logg logg +Anders Logg logg +Anders Logg logg +Anders Logg logg +Andy R. Terrel +Andy R. Terrel +Andy R. Terrel aterrel +Andy R. Terrel +Benjamin Kehlet +Benjamin Kehlet +Benjamin Kehlet +Benjamin Kehlet +Benjamin Kehlet +Chris Richardson +Chris Richardson chris +Chris Richardson Chris Richardson +Chris Richardson root +Corrado Maurini +Corrado Maurini +Dag Lindbo +Dag Lindbo dag +Dag Lindbo dag +David Ham +David Ham david.ham@imperial.ac.uk <> +Evan Lezar +Evan Lezar +Evan Lezar elezar +Evan Lezar elezar +Fredrik Valdmanis +Fredrik Valdmanis Fredrik Valdmanis +Garth N. Wells +Garth N. Wells root +Garth N. Wells garth +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells +Garth N. Wells gnw20@cam.ac.uk <> +gideonsimpson +Gustav Magnus Vikström +Gustav Magnus Vikström +Gustav Magnus Vikström +Gustav Magnus Vikström +Harish Narayanan +Harish Narayanan Harish Narayanan +Johan Hoffman +Johan Hoffman hoffman +Johan Hoffman +Johan Hoffman +Ilmar Wilbers +Ilmar Wilbers +Ilmar Wilbers +Jack S. Hale +Jack S. Hale +Johan Hake +Johan Hake +Johan Hake +Johan Jansson +Johan Jansson johan +Johan Jansson johan +Johan Jansson johanjan +Johan Jansson johanjan +Johan Jansson Johan Jansson +Johannes Ring +Johannes Ring +Kent-Andre Mardal +Kent-Andre Mardal +Kristian B. Ølgaard +Kristian B. Ølgaard +Kristian B. Ølgaard +Magnus Vikstrøm +Marco Morandini +Marco Morandini +Marie E. Rognes +Marie E. Rognes +Marie E. Rognes +Marie E. Rognes Marie E. Rognes (meg@simula.no) +Marie E. Rognes meg@simula.no <> +Martin Sandve Alnæs +Martin Sandve Alnæs +Martin Sandve Alnæs +Michele Zaffalon +Mikael Mortensen +Mikael Mortensen +Nate Sime +Nate Sime +Nuno Lopes +Nuno Lopes N.Lopes +Patrick Farrell +Patrick Farrell +Patrick Farrell +Quang Ha +Kristoffer Selim +Kristoffer Selim +Simon Funke +Simon Funke +Simon Funke +Solveig Bruvoll +Solveig Masvie +Steven Vandekerckhove +Steven Vandekerckhove +stockli +stockli +Tianyi Li +Steffen Müthing +Steffen Müthing Steffen Müthing steffen.muething@ipvs.uni-stuttgart.de <> +Miklós Homolya +Åsmund Ødegård +Åsmund Ødegård +Ola Skavhaug +Andre Massing +Andrew McRae diff -Nru ufl-2017.1.0/release.conf ufl-2017.2.0.0/release.conf --- ufl-2017.1.0/release.conf 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/release.conf 2017-12-04 10:19:20.000000000 +0000 @@ -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 -Nru ufl-2017.1.0/scripts/ufl-convert ufl-2017.2.0.0/scripts/ufl-convert --- ufl-2017.1.0/scripts/ufl-convert 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/scripts/ufl-convert 2017-12-04 10:19:20.000000000 +0000 @@ -11,6 +11,7 @@ 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 @@ 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 @@ 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 @@ 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 -Nru ufl-2017.1.0/setup.cfg ufl-2017.2.0.0/setup.cfg --- ufl-2017.1.0/setup.cfg 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/setup.cfg 2017-12-04 10:19:20.000000000 +0000 @@ -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 -Nru ufl-2017.1.0/setup.py ufl-2017.2.0.0/setup.py --- ufl-2017.1.0/setup.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/setup.py 2017-12-04 10:19:20.000000000 +0000 @@ -12,12 +12,12 @@ 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 :: 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 -Nru ufl-2017.1.0/test/conftest.py ufl-2017.2.0.0/test/conftest.py --- ufl-2017.1.0/test/conftest.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/conftest.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ 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 + +@pytest.fixture(params=_example_paths()) +def example_files(request): + return request.param diff -Nru ufl-2017.1.0/test/test_algorithms.py ufl-2017.2.0.0/test/test_algorithms.py --- ufl-2017.1.0/test/test_algorithms.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_algorithms.py 2017-12-04 10:19:20.000000000 +0000 @@ -9,11 +9,14 @@ 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 @@ 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 -Nru ufl-2017.1.0/test/test_automatic_differentiation.py ufl-2017.2.0.0/test/test_automatic_differentiation.py --- ufl-2017.1.0/test/test_automatic_differentiation.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_automatic_differentiation.py 2017-12-04 10:19:20.000000000 +0000 @@ -32,9 +32,17 @@ x = SpatialCoordinate(cell) n = FacetNormal(cell) c = CellVolume(cell) - h = Circumradius(cell) + R = Circumradius(cell) + h = CellDiameter(cell) f = FacetArea(cell) # s = CellSurfaceArea(cell) + mince = MinCellEdgeLength(cell) + maxce = MaxCellEdgeLength(cell) + minfe = MinFacetEdgeLength(cell) + maxfe = MaxFacetEdgeLength(cell) + J = Jacobian(cell) + detJ = JacobianDeterminant(cell) + invJ = JacobianInverse(cell) # FIXME: Add all new geometry types here! I = Identity(d) @@ -58,7 +66,7 @@ setattr(self.shared_objects, key, value) self.literals = list(map(as_ufl, [0, 1, 3.14, I, eps])) - self.geometry = [x, n, c, h, f] + self.geometry = [x, n, c, R, h, f, mince, maxce, minfe, maxfe, J, detJ, invJ] self.functions = [u, du, v, dv, w, dw] self.terminals = [] diff -Nru ufl-2017.1.0/test/test_change_to_reference_frame.py ufl-2017.2.0.0/test/test_change_to_reference_frame.py --- ufl-2017.1.0/test/test_change_to_reference_frame.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_change_to_reference_frame.py 2017-12-04 10:19:20.000000000 +0000 @@ -25,7 +25,7 @@ Jacobian, JacobianInverse, JacobianDeterminant, FacetJacobian, FacetJacobianInverse, FacetJacobianDeterminant, CellFacetJacobian, - CellEdgeVectors, FacetEdgeVectors, + ReferenceCellEdgeVectors, ReferenceFacetEdgeVectors, FacetNormal, CellNormal, ReferenceNormal, CellVolume, FacetArea, CellOrientation, FacetOrientation, QuadratureWeight, diff -Nru ufl-2017.1.0/test/test_classcoverage.py ufl-2017.2.0.0/test/test_classcoverage.py --- ufl-2017.1.0/test/test_classcoverage.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_classcoverage.py 2017-12-04 10:19:20.000000000 +0000 @@ -193,6 +193,8 @@ g = CellVolume(cell) _test_object(g, (), ()) + g = CellDiameter(cell) + _test_object(g, (), ()) g = Circumradius(cell) _test_object(g, (), ()) # g = CellSurfaceArea(cell) diff -Nru ufl-2017.1.0/test/test_derivative.py ufl-2017.2.0.0/test/test_derivative.py --- ufl-2017.1.0/test/test_derivative.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_derivative.py 2017-12-04 10:19:20.000000000 +0000 @@ -155,6 +155,13 @@ _test(self, f, df) +def testCellDiameter(self): + def f(w): return CellDiameter(triangle) + + def df(w, v): return zero() + _test(self, f, df) + + def testCircumradius(self): def f(w): return Circumradius(triangle) diff -Nru ufl-2017.1.0/test/test_piecewise_checks.py ufl-2017.2.0.0/test/test_piecewise_checks.py --- ufl-2017.1.0/test/test_piecewise_checks.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_piecewise_checks.py 2017-12-04 10:19:20.000000000 +0000 @@ -139,6 +139,8 @@ "Test geometric quantities that are always constant over a cell." e = CellVolume(domains) assert is_cellwise_constant(e) + e = CellDiameter(domains) + assert is_cellwise_constant(e) e = Circumradius(domains) assert is_cellwise_constant(e) e = FacetArea(domains) diff -Nru ufl-2017.1.0/test/test_signature.py ufl-2017.2.0.0/test/test_signature.py --- ufl-2017.1.0/test/test_signature.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_signature.py 2017-12-04 10:19:20.000000000 +0000 @@ -111,6 +111,7 @@ d = cell.geometric_dimension() x = SpatialCoordinate(cell) n = FacetNormal(cell) + h = CellDiameter(cell) r = Circumradius(cell) a = FacetArea(cell) # s = CellSurfaceArea(cell) @@ -118,7 +119,7 @@ I = Identity(d) ws = (x, n) - qs = (r, a, v) # , s) + qs = (h, r, a, v) # , s) for w in ws: for q in qs: expr = (I[0, j]*(q*w[j])) @@ -128,7 +129,7 @@ yield compute_terminal_hashdata(expr, domain_numbering(*cells)) c, d, r, h = compute_unique_terminal_hashdatas(forms()) - assert c == 2*3*2 # len(ws)*len(qs)*len(cells) + assert c == 2*4*2 # len(ws)*len(qs)*len(cells) assert d == c assert r == c assert h == c diff -Nru ufl-2017.1.0/test/test_str.py ufl-2017.2.0.0/test/test_str.py --- ufl-2017.1.0/test/test_str.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/test/test_str.py 2017-12-04 10:19:20.000000000 +0000 @@ -38,6 +38,10 @@ assert str(Circumradius(triangle)) == "circumradius" +def test_str_diameter(self): + assert str(CellDiameter(triangle)) == "diameter" + + # def test_str_cellsurfacearea(self): # assert str(CellSurfaceArea(triangle)) == "surfacearea" diff -Nru ufl-2017.1.0/test/test_unicode_convert.py ufl-2017.2.0.0/test/test_unicode_convert.py --- ufl-2017.1.0/test/test_unicode_convert.py 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/test/test_unicode_convert.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 -Nru ufl-2017.1.0/.travis.yml ufl-2017.2.0.0/.travis.yml --- ufl-2017.1.0/.travis.yml 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/.travis.yml 2017-12-04 10:19:20.000000000 +0000 @@ -0,0 +1,18 @@ +notifications: + slack: + secure: r9t4/J1Y85Tv/D/bJBVPGaW153mSU+I5r+EZrq7E6HnYqFRQ0X0AJw0pUX1ap/MXGtSrHFmQRYmIN1TTUMLPAHlzF4YA4rFA1LxJxxlPQ1TuhmkLbu5DEf5qkSsVeOjIe8+ptx8E8rSUSVfzv1g/RpdgO6mOD6qge94gQhQ4XekrWkZE1OudkqPvHfznCvxtFs3T5dxZWX3suQsGA+l1Gn3gp2YFITTGEfCXFek+rRWL3aqn6Oq+nvI6jfrooei7NSmNQOpGawAW868uvOlWQ2NiH1nsUkOH9U9c4YpTPD7RLLc2r3pAisSzdhZ5LsT+9o+lycqJleGizcVqtF7BP0tBzc1G4uJQwOCCcypLG62VwuwF6HD3zx4bDXD2MTqEneUaLVNlT2JiAsXmg2RKn/z8+5OKrPNe23pDvD3h+NdtHzJxPSnSRynpKD1FBXh1tfiGSVvgY+Mm7Bdu1unuK2tbpb6OLhcq50kYzqW1sbH8GEceb2v10YWV1tWDQ/JORFUtSuM3DFLlTO5XFjTCHqcGMkPQnpmXo+KF4D4uMHmkqVQu1aHdWn99uxoJzyoQrYwa7+94Z/UJuhwSCc+HOr28vXfd5O9ouo3E4FlEMMaAeRiCIGh88Ota6x+7BHmihijroKb9NdB2J2E0HpbLtEQha1yWIsuF0UbWywCojo4= +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 -Nru ufl-2017.1.0/ufl/algorithms/apply_derivatives.py ufl-2017.2.0.0/ufl/algorithms/apply_derivatives.py --- ufl-2017.1.0/ufl/algorithms/apply_derivatives.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/apply_derivatives.py 2017-12-04 10:19:20.000000000 +0000 @@ -158,8 +158,11 @@ # cell_facet_jacobian = unexpected # cell_facet_jacobian_determinant = unexpected # cell_facet_jacobian_inverse = unexpected + # cell_vertices = unexpected # cell_edge_vectors = unexpected # facet_edge_vectors = unexpected + # reference_cell_edge_vectors = unexpected + # reference_facet_edge_vectors = unexpected # cell_normal = unexpected # TODO: Expecting rename # cell_normals = unexpected # facet_tangents = unexpected diff -Nru ufl-2017.1.0/ufl/algorithms/apply_geometry_lowering.py ufl-2017.2.0.0/ufl/algorithms/apply_geometry_lowering.py --- ufl-2017.1.0/ufl/algorithms/apply_geometry_lowering.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/apply_geometry_lowering.py 2017-12-04 10:19:20.000000000 +0000 @@ -24,6 +24,9 @@ from six.moves import xrange as range +from functools import reduce +from itertools import combinations + from ufl.log import error, warning from ufl.core.multiindex import Index, indices @@ -37,10 +40,10 @@ CellOrientation, CellOrigin, CellCoordinate, FacetJacobian, FacetJacobianDeterminant, CellFacetJacobian, - CellEdgeVectors, FacetEdgeVectors, + MaxCellEdgeLength, + CellEdgeVectors, FacetEdgeVectors, CellVertices, ReferenceNormal, - ReferenceCellVolume, ReferenceFacetVolume, - CellVolume, FacetArea, + ReferenceCellVolume, ReferenceFacetVolume, CellVolume, SpatialCoordinate, FloatValue) # FacetJacobianInverse, @@ -135,7 +138,8 @@ 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 +148,6 @@ return o domain = o.ufl_domain() - #tdim = domain.topological_dimension() FJ = self.facet_jacobian(FacetJacobian(domain)) detFJ = determinant_expr(FJ) @@ -233,38 +236,29 @@ return o domain = o.ufl_domain() + if not domain.is_piecewise_linear_simplex_domain(): - # Don't lower for non-affine cells, instead leave it to - # form compiler - warning("Only know how to compute the circumradius of an affine cell.") - return o + error("Circumradius only makes sense for affine simplex cells") cellname = domain.ufl_cell().cellname() cellvolume = self.cell_volume(CellVolume(domain)) if cellname == "interval": - r = 0.5 * cellvolume + # Optimization for square interval; no square root needed + return 0.5 * cellvolume - elif cellname == "triangle": - J = self.jacobian(Jacobian(domain)) - trev = CellEdgeVectors(domain) - num_edges = 3 - i, j, k = indices(3) - elen = [sqrt((J[i, j]*trev[edge, j])*(J[i, k]*trev[edge, k])) - for edge in range(num_edges)] + # Compute lengths of cell edges + edges = CellEdgeVectors(domain) + num_edges = edges.ufl_shape[0] + j = Index() + elen = [sqrt(edges[e, j]*edges[e, j]) for e in range(num_edges)] - r = (elen[0] * elen[1] * elen[2]) / (4.0 * cellvolume) + if cellname == "triangle": + return (elen[0] * elen[1] * elen[2]) / (4.0 * cellvolume) elif cellname == "tetrahedron": - J = self.jacobian(Jacobian(domain)) - trev = CellEdgeVectors(domain) - num_edges = 6 - i, j, k = indices(3) - elen = [sqrt((J[i, j]*trev[edge, j])*(J[i, k]*trev[edge, k])) - for edge in range(num_edges)] - - # elen[3] = length of edge 3 # la, lb, lc = lengths of the sides of an intermediate triangle + # NOTE: Is here some hidden numbering assumption? la = elen[3] * elen[2] lb = elen[4] * elen[1] lc = elen[5] * elen[0] @@ -274,126 +268,92 @@ s = p / 2 # area of intermediate triangle with Herons formula triangle_area = sqrt(s * (s - la) * (s - lb) * (s - lc)) - r = triangle_area / (6.0 * cellvolume) + return triangle_area / (6.0 * cellvolume) - else: - error("Unhandled cell type %s." % cellname) - - return r + @memoized_handler + def max_cell_edge_length(self, o): + return self._reduce_cell_edge_length(o, max_value) @memoized_handler def min_cell_edge_length(self, o): + return self._reduce_cell_edge_length(o, min_value) + + def _reduce_cell_edge_length(self, o, reduction_op): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() - if not domain.is_piecewise_linear_simplex_domain(): - # Don't lower for non-affine cells, instead leave it to - # form compiler - warning("Only know how to compute the min_cell_edge_length of an affine cell.") - return o - cellname = domain.ufl_cell().cellname() + if not domain.ufl_coordinate_element().degree() == 1: + # Don't lower bendy cells, instead leave it to form compiler + warning("Only know how to compute cell edge lengths of P1 or Q1 cell.") + return o - J = self.jacobian(Jacobian(domain)) - trev = CellEdgeVectors(domain) - num_edges = trev.ufl_shape[0] - i, j, k = indices(3) - elen = [sqrt((J[i, j]*trev[edge, j])*(J[i, k]*trev[edge, k])) - for edge in range(num_edges)] + elif domain.ufl_cell().cellname() == "interval": + # Interval optimization, square root not needed + return self.cell_volume(CellVolume(domain)) - if cellname == "triangle": - return min_value(elen[0], min_value(elen[1], elen[2])) - elif cellname == "tetrahedron": - min1 = min_value(elen[0], min_value(elen[1], elen[2])) - min2 = min_value(elen[3], min_value(elen[4], elen[5])) - return min_value(min1, min2) else: - error("Unhandled cell type %s." % cellname) + # Other P1 or Q1 cells + edges = CellEdgeVectors(domain) + num_edges = edges.ufl_shape[0] + j = Index() + elen2 = [edges[e, j]*edges[e, j] for e in range(num_edges)] + return sqrt(reduce(reduction_op, elen2)) @memoized_handler - def max_cell_edge_length(self, o): + def cell_diameter(self, o): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() - if not domain.is_piecewise_linear_simplex_domain(): - # Don't lower for non-affine cells, instead leave it to - # form compiler - warning("Only know how to compute the max_cell_edge_length of an affine cell.") - return o - cellname = domain.ufl_cell().cellname() + if not domain.ufl_coordinate_element().degree() == 1: + # Don't lower bendy cells, instead leave it to form compiler + warning("Only know how to compute cell diameter of P1 or Q1 cell.") + return o - J = self.jacobian(Jacobian(domain)) - trev = CellEdgeVectors(domain) - num_edges = trev.ufl_shape[0] - i, j, k = indices(3) - elen = [sqrt((J[i, j]*trev[edge, j])*(J[i, k]*trev[edge, k])) - for edge in range(num_edges)] + elif domain.is_piecewise_linear_simplex_domain(): + # Simplices + return self.max_cell_edge_length(MaxCellEdgeLength(domain)) - if cellname == "triangle": - return max_value(elen[0], max_value(elen[1], elen[2])) - elif cellname == "tetrahedron": - max1 = max_value(elen[0], max_value(elen[1], elen[2])) - max2 = max_value(elen[3], max_value(elen[4], elen[5])) - return max_value(max1, max2) else: - error("Unhandled cell type %s." % cellname) + # Q1 cells, maximal distance between any two vertices + verts = CellVertices(domain) + verts = [verts[v, ...] for v in range(verts.ufl_shape[0])] + j = Index() + elen2 = ((v0-v1)[j]*(v0-v1)[j] for v0, v1 in combinations(verts, 2)) + return sqrt(reduce(max_value, elen2)) + + @memoized_handler + def max_facet_edge_length(self, o): + return self._reduce_facet_edge_length(o, max_value) @memoized_handler def min_facet_edge_length(self, o): + return self._reduce_facet_edge_length(o, min_value) + + def _reduce_facet_edge_length(self, o, reduction_op): if self._preserve_types[o._ufl_typecode_]: return o domain = o.ufl_domain() - if not domain.is_piecewise_linear_simplex_domain(): - # Don't lower for non-affine cells, instead leave it to - # form compiler - warning("Only know how to compute the min_facet_edge_length of an affine cell.") - return o - - cellname = domain.ufl_cell().cellname() - - if cellname == "triangle": - return self.facet_area(FacetArea(domain)) - elif cellname == "tetrahedron": - J = self.jacobian(Jacobian(domain)) - trev = FacetEdgeVectors(domain) - num_edges = 3 - i, j, k = indices(3) - elen = [sqrt((J[i, j]*trev[edge, j])*(J[i, k]*trev[edge, k])) - for edge in range(num_edges)] - return min_value(elen[0], min_value(elen[1], elen[2])) - else: - error("Unhandled cell type %s." % cellname) - @memoized_handler - def max_facet_edge_length(self, o): - if self._preserve_types[o._ufl_typecode_]: - return o + if domain.ufl_cell().topological_dimension() < 3: + error("Facet edge lengths only make sense for topological dimension >= 3.") - domain = o.ufl_domain() - if not domain.is_piecewise_linear_simplex_domain(): - # Don't lower for non-affine cells, instead leave it to - # form compiler - warning("Only know how to compute the max_facet_edge_length of an affine cell.") + elif not domain.ufl_coordinate_element().degree() == 1: + # Don't lower bendy cells, instead leave it to form compiler + warning("Only know how to compute facet edge lengths of P1 or Q1 cell.") return o - cellname = domain.ufl_cell().cellname() - - if cellname == "triangle": - return self.facet_area(FacetArea(domain)) - elif cellname == "tetrahedron": - J = self.jacobian(Jacobian(domain)) - trev = FacetEdgeVectors(domain) - num_edges = 3 - i, j, k = indices(3) - elen = [sqrt((J[i, j]*trev[edge, j])*(J[i, k]*trev[edge, k])) - for edge in range(num_edges)] - return max_value(elen[0], max_value(elen[1], elen[2])) else: - error("Unhandled cell type %s." % cellname) + # P1 tetrahedron or Q1 hexahedron + edges = FacetEdgeVectors(domain) + num_edges = edges.ufl_shape[0] + j = Index() + elen2 = [edges[e, j]*edges[e, j] for e in range(num_edges)] + return sqrt(reduce(reduction_op, elen2)) @memoized_handler def cell_normal(self, o): diff -Nru ufl-2017.1.0/ufl/algorithms/compute_form_data.py ufl-2017.2.0.0/ufl/algorithms/compute_form_data.py --- ufl-2017.1.0/ufl/algorithms/compute_form_data.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/compute_form_data.py 2017-12-04 10:19:20.000000000 +0000 @@ -23,6 +23,7 @@ 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 @@ """ # 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 -Nru ufl-2017.1.0/ufl/algorithms/domain_analysis.py ufl-2017.2.0.0/ufl/algorithms/domain_analysis.py --- ufl-2017.1.0/ufl/algorithms/domain_analysis.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/domain_analysis.py 2017-12-04 10:19:20.000000000 +0000 @@ -18,8 +18,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with UFL. If not, see . -# import six from collections import defaultdict +from six import iteritems from six.moves import zip import ufl @@ -28,20 +28,22 @@ 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 @@ # 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 -Nru ufl-2017.1.0/ufl/algorithms/elementtransformations.py ufl-2017.2.0.0/ufl/algorithms/elementtransformations.py --- ufl-2017.1.0/ufl/algorithms/elementtransformations.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/elementtransformations.py 2017-12-04 10:19:20.000000000 +0000 @@ -48,6 +48,9 @@ def _increase_degree(element, degree_rise): if isinstance(element, (FiniteElement, VectorElement, TensorElement)): + # Can't increase degree for reals + if element.family() == "Real": + return element return element.reconstruct(degree=(element.degree() + degree_rise)) elif isinstance(element, MixedElement): return MixedElement([_increase_degree(e, degree_rise) diff -Nru ufl-2017.1.0/ufl/algorithms/estimate_degrees.py ufl-2017.2.0.0/ufl/algorithms/estimate_degrees.py --- ufl-2017.1.0/ufl/algorithms/estimate_degrees.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/estimate_degrees.py 2017-12-04 10:19:20.000000000 +0000 @@ -27,6 +27,7 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/algorithms/formdata.py ufl-2017.2.0.0/ufl/algorithms/formdata.py --- ufl-2017.1.0/ufl/algorithms/formdata.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/formdata.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ return tstr(geometry + subdomains + functions) -# @six.python_2_unicode_compatible class ExprData(object): """ Class collecting various information extracted from a Expr by diff -Nru ufl-2017.1.0/ufl/algorithms/__init__.py ufl-2017.2.0.0/ufl/algorithms/__init__.py --- ufl-2017.1.0/ufl/algorithms/__init__.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/__init__.py 2017-12-04 10:19:20.000000000 +0000 @@ -64,17 +64,17 @@ "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 @@ 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 @@ # 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_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 -Nru ufl-2017.1.0/ufl/algorithms/renumbering.py ufl-2017.2.0.0/ufl/algorithms/renumbering.py --- ufl-2017.1.0/ufl/algorithms/renumbering.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/renumbering.py 2017-12-04 10:19:20.000000000 +0000 @@ -33,7 +33,7 @@ self.variable_map = {} def variable(self, o): - e, l = o.ufl_operands + e, l = o.ufl_operands # noqa: E741 v = self.variable_map.get(l) if v is None: e = self.visit(e) diff -Nru ufl-2017.1.0/ufl/algorithms/transformer.py ufl-2017.2.0.0/ufl/algorithms/transformer.py --- ufl-2017.1.0/ufl/algorithms/transformer.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/algorithms/transformer.py 2017-12-04 10:19:20.000000000 +0000 @@ -149,7 +149,7 @@ def reuse_variable(self, o): # Check variable cache to reuse previously transformed # variable if possible - e, l = o.ufl_operands + e, l = o.ufl_operands # noqa: E741 v = self._variable_cache.get(l) if v is not None: return v @@ -171,7 +171,7 @@ def reconstruct_variable(self, o): # Check variable cache to reuse previously transformed # variable if possible - e, l = o.ufl_operands + e, l = o.ufl_operands # noqa: E741 v = self._variable_cache.get(l) if v is not None: return v diff -Nru ufl-2017.1.0/ufl/argument.py ufl-2017.2.0.0/ufl/argument.py --- ufl-2017.1.0/ufl/argument.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/argument.py 2017-12-04 10:19:20.000000000 +0000 @@ -96,11 +96,6 @@ # 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 -Nru ufl-2017.1.0/ufl/cell.py ufl-2017.2.0.0/ufl/cell.py --- ufl-2017.1.0/ufl/cell.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/cell.py 2017-12-04 10:19:20.000000000 +0000 @@ -41,11 +41,12 @@ # --- 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 -Nru ufl-2017.1.0/ufl/coefficient.py ufl-2017.2.0.0/ufl/coefficient.py --- ufl-2017.1.0/ufl/coefficient.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/coefficient.py 2017-12-04 10:19:20.000000000 +0000 @@ -84,11 +84,6 @@ "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 -Nru ufl-2017.1.0/ufl/constantvalue.py ufl-2017.2.0.0/ufl/constantvalue.py --- ufl-2017.1.0/ufl/constantvalue.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/constantvalue.py 2017-12-04 10:19:20.000000000 +0000 @@ -141,8 +141,8 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/core/expr.py ufl-2017.2.0.0/ufl/core/expr.py --- ufl-2017.1.0/ufl/core/expr.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/core/expr.py 2017-12-04 10:19:20.000000000 +0000 @@ -319,12 +319,6 @@ 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): @@ -340,7 +334,7 @@ "Try to evaluate as scalar and cast to float." try: v = float(self._ufl_evaluate_scalar_()) - except: + except Exception: v = NotImplemented return v @@ -436,67 +430,11 @@ # --- 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 -Nru ufl-2017.1.0/ufl/core/multiindex.py ufl-2017.2.0.0/ufl/core/multiindex.py --- ufl-2017.1.0/ufl/core/multiindex.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/core/multiindex.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ 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 @@ 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 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/core/operator.py ufl-2017.2.0.0/ufl/core/operator.py --- ufl-2017.1.0/ufl/core/operator.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/core/operator.py 2017-12-04 10:19:20.000000000 +0000 @@ -58,5 +58,5 @@ "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 -Nru ufl-2017.1.0/ufl/core/terminal.py ufl-2017.2.0.0/ufl/core/terminal.py --- ufl-2017.1.0/ufl/core/terminal.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/core/terminal.py 2017-12-04 10:19:20.000000000 +0000 @@ -61,7 +61,7 @@ if derivatives: f = 0.0 return f - except: + except Exception: pass # If it has an ufl_evaluate function, call it if hasattr(self, 'ufl_evaluate'): diff -Nru ufl-2017.1.0/ufl/domain.py ufl-2017.2.0.0/ufl/domain.py --- ufl-2017.1.0/ufl/domain.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/domain.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ 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 @@ # 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 @@ 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 @@ "MeshView", typespecific) -# @six.python_2_unicode_compatible @attach_operators_from_hash_data @attach_ufl_id class TensorProductMesh(AbstractDomain): @@ -278,7 +262,10 @@ 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 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 -Nru ufl-2017.1.0/ufl/finiteelement/elementlist.py ufl-2017.2.0.0/ufl/finiteelement/elementlist.py --- ufl-2017.1.0/ufl/finiteelement/elementlist.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/finiteelement/elementlist.py 2017-12-04 10:19:20.000000000 +0000 @@ -26,6 +26,8 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/finiteelement/enrichedelement.py ufl-2017.2.0.0/ufl/finiteelement/enrichedelement.py --- ufl-2017.1.0/ufl/finiteelement/enrichedelement.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/finiteelement/enrichedelement.py 2017-12-04 10:19:20.000000000 +0000 @@ -78,7 +78,7 @@ # 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 -Nru ufl-2017.1.0/ufl/finiteelement/finiteelementbase.py ufl-2017.2.0.0/ufl/finiteelement/finiteelementbase.py --- ufl-2017.1.0/ufl/finiteelement/finiteelementbase.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/finiteelement/finiteelementbase.py 2017-12-04 10:19:20.000000000 +0000 @@ -34,16 +34,14 @@ 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 -Nru ufl-2017.1.0/ufl/finiteelement/finiteelement.py ufl-2017.2.0.0/ufl/finiteelement/finiteelement.py --- ufl-2017.1.0/ufl/finiteelement/finiteelement.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/finiteelement/finiteelement.py 2017-12-04 10:19:20.000000000 +0000 @@ -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.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 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/finiteelement/mixedelement.py ufl-2017.2.0.0/ufl/finiteelement/mixedelement.py --- ufl-2017.1.0/ufl/finiteelement/mixedelement.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/finiteelement/mixedelement.py 2017-12-04 10:19:20.000000000 +0000 @@ -31,7 +31,7 @@ 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 @@ # 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 @@ # @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): @@ -363,7 +367,7 @@ if cell is not None: cell = as_cell(cell) # Create scalar sub element - sub_element = FiniteElement(family, cell, degree, quad_scheme) + sub_element = FiniteElement(family, cell, degree, quad_scheme=quad_scheme) if sub_element.value_shape() != (): error("Expecting only scalar valued subelement for TensorElement.") @@ -392,8 +396,7 @@ 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 @@ -461,7 +464,7 @@ self._check_component(i) i = self.symmetry().get(i, i) - l = len(self._shape) + l = len(self._shape) # noqa: E741 ii = i[:l] jj = i[l:] if ii not in self._sub_element_mapping: diff -Nru ufl-2017.1.0/ufl/finiteelement/restrictedelement.py ufl-2017.2.0.0/ufl/finiteelement/restrictedelement.py --- ufl-2017.1.0/ufl/finiteelement/restrictedelement.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/finiteelement/restrictedelement.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ 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 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/formatting/ufl2latex.py ufl-2017.2.0.0/ufl/formatting/ufl2latex.py --- ufl-2017.1.0/ufl/formatting/ufl2latex.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/formatting/ufl2latex.py 2017-12-04 10:19:20.000000000 +0000 @@ -185,7 +185,7 @@ def variable(self, o): # TODO: Ensure variable has been handled - e, l = o.ufl_operands + e, l = o.ufl_operands # noqa: E741 return "s_{%d}" % l._count # --- Non-terminal objects --- @@ -330,13 +330,13 @@ shape = o.ufl_shape if len(shape) == 1: ops = [self.visit(op) for op in o.ufl_operands] - l = " \\\\ \n ".join(ops) + l = " \\\\ \n ".join(ops) # noqa: E741 elif len(shape) == 2: rows = [] for row in o.ufl_operands: cols = (self.visit(op) for op in row.ufl_operands) rows.append(" & \n ".join(cols)) - l = " \\\\ \n ".join(rows) + l = " \\\\ \n ".join(rows) # noqa: E741 else: error("TODO: LaTeX handler for list tensor of rank 3 or higher not implemented!") return "\\left[\\begin{matrix}{%s}\\end{matrix}\\right]^T" % l @@ -382,10 +382,10 @@ return "!(%s)" % (a,) def conditional(self, o, c, t, f): - l = "\\begin{cases}\n" - l += "%s, &\text{if }\quad %s, \\\\\n" % (t, c) - l += "%s, &\text{otherwise.}\n" % f - l += "\\end{cases}" + l = "\\begin{cases}\n" # noqa: E741 + l += "%s, &\text{if }\quad %s, \\\\\n" % (t, c) # noqa: E741 + l += "%s, &\text{otherwise.}\n" % f # noqa: E741 + l += "\\end{cases}" # noqa: E741 return l def min_value(self, o, a, b): @@ -472,7 +472,7 @@ for itg in integrals: variables = _extract_variables(itg.integrand()) for v in variables: - l = v._label + l = v._label # noqa: E741 if l not in handled_variables: handled_variables.add(l) exprlatex = expression2latex(v._expression, diff -Nru ufl-2017.1.0/ufl/formatting/ufl2unicode.py ufl-2017.2.0.0/ufl/formatting/ufl2unicode.py --- ufl-2017.1.0/ufl/formatting/ufl2unicode.py 1970-01-01 00:00:00.000000000 +0000 +++ ufl-2017.2.0.0/ufl/formatting/ufl2unicode.py 2017-12-04 10:19:20.000000000 +0000 @@ -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) # noqa: E741 + 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)) # noqa: E741 + 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 -Nru ufl-2017.1.0/ufl/form.py ufl-2017.2.0.0/ufl/form.py --- ufl-2017.1.0/ufl/form.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/form.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ 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 @@ 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 @@ "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 @@ 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 @@ 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 @@ M = a(f, f, coefficients={ g: 1 }) Is equivalent to M == grad(f)**2*dx. + """ repdict = {} @@ -384,7 +376,7 @@ 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 "" @@ -392,7 +384,7 @@ 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 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 -Nru ufl-2017.1.0/ufl/geometry.py ufl-2017.2.0.0/ufl/geometry.py --- ufl-2017.1.0/ufl/geometry.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/geometry.py 2017-12-04 10:19:20.000000000 +0000 @@ -367,10 +367,10 @@ @ufl_type() -class CellEdgeVectors(GeometricCellQuantity): +class ReferenceCellEdgeVectors(GeometricCellQuantity): """UFL geometry representation: The vectors between reference cell vertices for each edge in cell.""" __slots__ = () - name = "CEV" + name = "RCEV" def __init__(self, domain): GeometricCellQuantity.__init__(self, domain) @@ -392,10 +392,10 @@ @ufl_type() -class FacetEdgeVectors(GeometricFacetQuantity): +class ReferenceFacetEdgeVectors(GeometricFacetQuantity): """UFL geometry representation: The vectors between reference cell vertices for each edge in current facet.""" __slots__ = () - name = "FEV" + name = "RFEV" def __init__(self, domain): GeometricFacetQuantity.__init__(self, domain) @@ -416,6 +416,78 @@ return True +@ufl_type() +class CellVertices(GeometricCellQuantity): + """UFL geometry representation: Physical cell vertices.""" + __slots__ = () + name = "CV" + + def __init__(self, domain): + GeometricCellQuantity.__init__(self, domain) + + @property + def ufl_shape(self): + cell = self.ufl_domain().ufl_cell() + nv = cell.num_vertices() + g = cell.geometric_dimension() + return (nv, g) + + def is_cellwise_constant(self): + "Return whether this expression is spatially constant over each cell." + # This is always constant for a given cell type + return True + + +@ufl_type() +class CellEdgeVectors(GeometricCellQuantity): + """UFL geometry representation: The vectors between physical cell vertices for each edge in cell.""" + __slots__ = () + name = "CEV" + + def __init__(self, domain): + GeometricCellQuantity.__init__(self, domain) + t = self._domain.topological_dimension() + if t < 2: + error("CellEdgeVectors is only defined for topological dimensions >= 2.") + + @property + def ufl_shape(self): + cell = self.ufl_domain().ufl_cell() + ne = cell.num_edges() + g = cell.geometric_dimension() + return (ne, g) + + def is_cellwise_constant(self): + "Return whether this expression is spatially constant over each cell." + # This is always constant for a given cell type + return True + + +@ufl_type() +class FacetEdgeVectors(GeometricFacetQuantity): + """UFL geometry representation: The vectors between physical cell vertices for each edge in current facet.""" + __slots__ = () + name = "FEV" + + def __init__(self, domain): + GeometricFacetQuantity.__init__(self, domain) + t = self._domain.topological_dimension() + if t < 3: + error("FacetEdgeVectors is only defined for topological dimensions >= 3.") + + @property + def ufl_shape(self): + cell = self.ufl_domain().ufl_cell() + nfe = cell.num_facet_edges() + g = cell.geometric_dimension() + return (nfe, g) + + def is_cellwise_constant(self): + "Return whether this expression is spatially constant over each cell." + # This is always constant for a given cell type + return True + + # --- Determinants (signed or pseudo) of geometry mapping Jacobians @ufl_type() @@ -684,6 +756,15 @@ __slots__ = () name = "circumradius" + +@ufl_type() +class CellDiameter(GeometricCellQuantity): + """UFL geometry representation: The diameter of the cell, i.e., + maximal distance of two points in the cell.""" + __slots__ = () + name = "diameter" + + # @ufl_type() # class CellSurfaceArea(GeometricCellQuantity): # """UFL geometry representation: The total surface area of the cell.""" diff -Nru ufl-2017.1.0/ufl/__init__.py ufl-2017.2.0.0/ufl/__init__.py --- ufl-2017.1.0/ufl/__init__.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/__init__.py 2017-12-04 10:19:20.000000000 +0000 @@ -9,8 +9,7 @@ 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 * @@ -121,6 +120,7 @@ - FacetNormal - CellNormal - CellVolume + - CellDiameter - Circumradius - MinCellEdgeLength - MaxCellEdgeLength @@ -244,7 +244,7 @@ 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 *", @@ -268,7 +268,7 @@ from ufl.geometry import ( SpatialCoordinate, FacetNormal, CellNormal, - CellVolume, Circumradius, MinCellEdgeLength, MaxCellEdgeLength, + CellVolume, CellDiameter, Circumradius, MinCellEdgeLength, MaxCellEdgeLength, FacetArea, MinFacetEdgeLength, MaxFacetEdgeLength, Jacobian, JacobianDeterminant, JacobianInverse ) @@ -373,7 +373,8 @@ 'as_domain', 'AbstractDomain', 'Mesh', 'MeshView', 'TensorProductMesh', 'L2', 'H1', 'H2', 'HCurl', 'HDiv', 'SpatialCoordinate', - 'CellVolume', 'Circumradius', 'MinCellEdgeLength', 'MaxCellEdgeLength', + 'CellVolume', 'CellDiameter', 'Circumradius', + 'MinCellEdgeLength', 'MaxCellEdgeLength', 'FacetArea', 'MinFacetEdgeLength', 'MaxFacetEdgeLength', 'FacetNormal', 'CellNormal', 'Jacobian', 'JacobianDeterminant', 'JacobianInverse', @@ -419,4 +420,4 @@ 'quadrilateral', 'hexahedron', 'facet', 'i', 'j', 'k', 'l', 'p', 'q', 'r', 's', 'e', 'pi', - ]) +]) diff -Nru ufl-2017.1.0/ufl/integral.py ufl-2017.2.0.0/ufl/integral.py --- ufl-2017.1.0/ufl/integral.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/integral.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ __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 @@ 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: 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 @@ "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 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/mathfunctions.py ufl-2017.2.0.0/ufl/mathfunctions.py --- ufl-2017.1.0/ufl/mathfunctions.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/mathfunctions.py 2017-12-04 10:19:20.000000000 +0000 @@ -327,7 +327,7 @@ a = self.ufl_operands[1].evaluate(x, mapping, component, index_values) try: import scipy.special - except: + except ImportError: error("You must have scipy installed to evaluate bessel functions in python.") name = self._name[-1] if isinstance(self.ufl_operands[0], IntValue): diff -Nru ufl-2017.1.0/ufl/measure.py ufl-2017.2.0.0/ufl/measure.py --- ufl-2017.1.0/ufl/measure.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/measure.py 2017-12-04 10:19:20.000000000 +0000 @@ -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 @@ 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 @@ # 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 @@ 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 @@ """ 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 @@ 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 @@ 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: @@ -232,6 +226,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ return Form([integral]) -# @six.python_2_unicode_compatible class MeasureSum(object): """Represents a sum of measures. @@ -506,6 +501,7 @@ 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 @@ 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 -Nru ufl-2017.1.0/ufl/objects.py ufl-2017.2.0.0/ufl/objects.py --- ufl-2017.1.0/ufl/objects.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/objects.py 2017-12-04 10:19:20.000000000 +0000 @@ -27,7 +27,7 @@ from ufl.measure import integral_type_to_measure_name # Default indices -i, j, k, l = indices(4) +i, j, k, l = indices(4) # noqa: E741 p, q, r, s = indices(4) for integral_type, measure_name in integral_type_to_measure_name.items(): diff -Nru ufl-2017.1.0/ufl/operators.py ufl-2017.2.0.0/ufl/operators.py --- ufl-2017.1.0/ufl/operators.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/operators.py 2017-12-04 10:19:20.000000000 +0000 @@ -708,7 +708,7 @@ else: try: element = f.ufl_element() - except: + except Exception: error("Unable to determine element from %s" % f) # Extract the family and the geometric dimension diff -Nru ufl-2017.1.0/ufl/sobolevspace.py ufl-2017.2.0.0/ufl/sobolevspace.py --- ufl-2017.1.0/ufl/sobolevspace.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/sobolevspace.py 2017-12-04 10:19:20.000000000 +0000 @@ -25,12 +25,10 @@ # 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 DirectionalSobolevSpace(SobolevSpace): """Symbolic representation of a Sobolev space with varying smoothness in differerent spatial directions. + """ def __init__(self, orders): diff -Nru ufl-2017.1.0/ufl/tensoralgebra.py ufl-2017.2.0.0/ufl/tensoralgebra.py --- ufl-2017.1.0/ufl/tensoralgebra.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/tensoralgebra.py 2017-12-04 10:19:20.000000000 +0000 @@ -122,10 +122,8 @@ @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 @@ @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 @@ 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 @@ @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 @@ @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 -Nru ufl-2017.1.0/ufl/tensors.py ufl-2017.2.0.0/ufl/tensors.py --- ufl-2017.1.0/ufl/tensors.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/tensors.py 2017-12-04 10:19:20.000000000 +0000 @@ -214,7 +214,7 @@ import numpy if isinstance(expressions, numpy.ndarray): expressions = numpy2nestedlists(expressions) - except: + except Exception: pass return expressions @@ -397,11 +397,11 @@ "TODO: Develop this concept, can e.g. write A[i,j]*dyad(j,i) for the transpose." from ufl.constantvalue import Identity from ufl.operators import outer # a bit of circular dependency issue here - I = Identity(d) + Id = Identity(d) i = iota[0] - e = as_vector(I[i, :], i) + e = as_vector(Id[i, :], i) for i in iota[1:]: - e = outer(e, as_vector(I[i, :], i)) + e = outer(e, as_vector(Id[i, :], i)) return e diff -Nru ufl-2017.1.0/ufl/utils/formatting.py ufl-2017.2.0.0/ufl/utils/formatting.py --- ufl-2017.1.0/ufl/utils/formatting.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/utils/formatting.py 2017-12-04 10:19:20.000000000 +0000 @@ -31,7 +31,7 @@ # Don't insert _ between multiple upper case letters if lastlower: letters.append("_") - l = l.lower() + l = l.lower() # noqa: E741 lastlower = thislower letters.append(l) return "".join(letters) diff -Nru ufl-2017.1.0/ufl/utils/sequences.py ufl-2017.2.0.0/ufl/utils/sequences.py --- ufl-2017.1.0/ufl/utils/sequences.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/utils/sequences.py 2017-12-04 10:19:20.000000000 +0000 @@ -18,9 +18,13 @@ # You should have received a copy of the GNU Lesser General Public License # along with UFL. If not, see . -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 @@ 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 -Nru ufl-2017.1.0/ufl/utils/sorting.py ufl-2017.2.0.0/ufl/utils/sorting.py --- ufl-2017.1.0/ufl/utils/sorting.py 2017-05-09 12:48:03.000000000 +0000 +++ ufl-2017.2.0.0/ufl/utils/sorting.py 2017-12-04 10:19:20.000000000 +0000 @@ -78,15 +78,6 @@ 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.