diff --git a/fipy/meshes/gmshMesh.py b/fipy/meshes/gmshMesh.py index fc3ff6c8..d529d532 100755 --- a/fipy/meshes/gmshMesh.py +++ b/fipy/meshes/gmshMesh.py @@ -13,11 +13,11 @@ import sys import tempfile from textwrap import dedent import warnings -from distutils.version import StrictVersion from fipy.tools import numerix as nx from fipy.tools import parallelComm from fipy.tools import serialComm +from fipy.tools.version import Version, parse_version from fipy.tests.doctestPlus import register_skipper from fipy.meshes.mesh import Mesh @@ -38,7 +38,7 @@ def _checkForGmsh(): hasGmsh = True try: version = _gmshVersion(communicator=parallelComm) - hasGmsh = version >= StrictVersion("2.0") + hasGmsh = version >= Version("2.0") except Exception: hasGmsh = False return hasGmsh @@ -68,6 +68,7 @@ def gmshVersion(communicator=parallelComm): while True: try: # gmsh returns version in stderr (Why?!?) + # (newer versions of gmsh return the version in stdout) # spyder on Windows throws # OSError: [WinError 6] The handle is invalid # if we don't PIPE stdout, too @@ -77,8 +78,11 @@ def gmshVersion(communicator=parallelComm): break try: - out, verStr = p.communicate() - verStr = verStr.decode('ascii').strip() + out, err = p.communicate() + verStr = err.decode('ascii').strip() + if not verStr: + # newer versions of gmsh return the version in stdout + verStr = out.decode('ascii').strip() break except IOError: # some weird conflict with things like PyQT can cause @@ -93,12 +97,12 @@ def gmshVersion(communicator=parallelComm): def _gmshVersion(communicator=parallelComm): version = gmshVersion(communicator) or "0.0" try: - version = StrictVersion(version) + version = parse_version(version) except ValueError: # gmsh returns the version string in stderr, # which means it's often unparsable due to irrelevant warnings # assume it's OK and move on - version = StrictVersion("3.0") + version = Version("3.0") return version @@ -133,7 +137,7 @@ def openMSHFile(name, dimensions=None, coordDimensions=None, communicator=parall # Enforce gmsh version to be either >= 2 or 2.5, based on Nproc. version = _gmshVersion(communicator=communicator) - if version < StrictVersion("2.0"): + if version < Version("2.0"): raise EnvironmentError("Gmsh version must be >= 2.0.") # If we're being passed a .msh file, leave it be. Otherwise, @@ -176,9 +180,11 @@ def openMSHFile(name, dimensions=None, coordDimensions=None, communicator=parall gmshFlags = ["-%d" % dimensions, "-nopopup"] if communicator.Nproc > 1: - if not (StrictVersion("2.5") < version <= StrictVersion("4.0")): - warnstr = "Cannot partition with Gmsh version < 2.5 or >= 4.0. " \ - + "Reverting to serial." + if ((version < Version("2.5")) + or (Version("4.0") <= version < Version("4.5.2"))): + warnstr = ("Cannot partition with Gmsh version < 2.5 " + "or 4.0 <= version < 4.5.2. " + "Reverting to serial.") warnings.warn(warnstr, RuntimeWarning, stacklevel=2) communicator = serialComm @@ -188,13 +194,13 @@ def openMSHFile(name, dimensions=None, coordDimensions=None, communicator=parall raise ValueError("'dimensions' must be specified to generate a mesh from a geometry script") else: # gmsh version is adequate for partitioning gmshFlags += ["-part", "%d" % communicator.Nproc] - if version >= StrictVersion("4.0"): + if version >= Version("4.0"): # Gmsh 4.x needs to be told to generate ghost cells - # Unfortunately, the ghosts are broken + # Unfortunately, the ghosts are broken in Gmsh 4.0--4.5.1 # https://gitlab.onelab.info/gmsh/gmsh/issues/733 gmshFlags += ["-part_ghosts"] - gmshFlags += ["-format", "msh2"] + gmshFlags += ["-format", "msh2", "-smooth", "8"] if background is not None: if communicator.procID == 0: @@ -1387,6 +1393,11 @@ class _GmshTopology(_MeshTopology): class Gmsh2D(Mesh2D): """Construct a 2D Mesh using Gmsh + If called in parallel, the mesh will be partitioned based on the value + of `parallelComm.Nproc`. If an `MSH` file is supplied, it must have + been previously partitioned with the number of partitions matching + `parallelComm.Nproc`. + >>> radius = 5. >>> side = 4. >>> squaredCircle = Gmsh2D(''' @@ -1875,6 +1886,11 @@ class Gmsh2D(Mesh2D): class Gmsh2DIn3DSpace(Gmsh2D): """Create a topologically 2D Mesh in 3D coordinates using Gmsh + If called in parallel, the mesh will be partitioned based on the value + of `parallelComm.Nproc`. If an `MSH` file is supplied, it must have + been previously partitioned with the number of partitions matching + `parallelComm.Nproc`. + Parameters ---------- arg : str @@ -1959,6 +1975,11 @@ class Gmsh2DIn3DSpace(Gmsh2D): class Gmsh3D(Mesh): """Create a 3D Mesh using Gmsh + If called in parallel, the mesh will be partitioned based on the value + of `parallelComm.Nproc`. If an `MSH` file is supplied, it must have + been previously partitioned with the number of partitions matching + `parallelComm.Nproc`. + Parameters ---------- arg : str @@ -2225,7 +2246,7 @@ class GmshGrid2D(Gmsh2D): width = nx * dx numLayers = int(ny / float(dy)) - if _gmshVersion() < StrictVersion("2.7"): + if _gmshVersion() < Version("2.7"): # kludge: must offset cellSize by `eps` to work properly eps = float(dx)/(nx * 10) else: @@ -2299,7 +2320,7 @@ class GmshGrid3D(Gmsh3D): width = nx * dx depth = nz * dz - if _gmshVersion() < StrictVersion("2.7"): + if _gmshVersion() < Version("2.7"): # kludge: must offset cellSize by `eps` to work properly eps = float(dx)/(nx * 10) else: diff --git a/fipy/tools/version.py b/fipy/tools/version.py new file mode 100644 index 00000000..93d89c18 --- /dev/null +++ b/fipy/tools/version.py @@ -0,0 +1,18 @@ +"""Shim for version checking + +`distutils.version` is deprecated, but `packaging.version` is unavailable +in Python 2.7 +""" +from __future__ import unicode_literals + +__docformat__ = 'restructuredtext' + + +__all__ = ["Version", "parse_version"] +from future.utils import text_to_native_str +__all__ = [text_to_native_str(n) for n in __all__] + +try: + from packaging.version import Version, parse as parse_version +except ImportError: + from distutils.version import StrictVersion as Version, StrictVersion as parse_version