diff --git a/.appveyor.yml b/.appveyor.yml index fba65ca0c9..77817b746b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -64,8 +64,9 @@ install: - cmd: conda.exe config --add channels conda-forge # Configure the VM. - - cmd: if "%TARGET_ARCH%" == "x64" if "%CONDA_PY%" == "27" conda.exe install --quiet --name root --only-deps python=2.7 fipy - - cmd: if "%TARGET_ARCH%" == "x64" if "%CONDA_PY%" == "36" conda.exe install --quiet --name root --only-deps python=3.6 fipy + - cmd: if "%TARGET_ARCH%" == "x64" if "%CONDA_PY%" == "27" conda.exe install --quiet --name root python=2.7 fipy + - cmd: if "%TARGET_ARCH%" == "x64" if "%CONDA_PY%" == "36" conda.exe install --quiet --name root python=3.6 fipy "gmsh<4.0" + - cmd: conda.exe remove --quiet --force fipy # FIXME: fipy recipe on conda-forge doesn't have gmsh compatible with Python 2.7 - ps: | $ErrorActionPreference = "Stop"; diff --git a/.circleci/config.yml b/.circleci/config.yml index 8b9c38055b..188e94e5b8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,7 +36,7 @@ commands: - run: name: Create Conda Environment command: | - conda create -v --quiet --prefix << parameters.condaenv >> --show-channel-urls --channel conda-forge --only-deps << parameters.packages >> + conda create -v --quiet --prefix << parameters.condaenv >> --show-channel-urls --channel conda-forge << parameters.packages >> "gmsh<4.0" source activate ~/project/<< parameters.condaenv >> pip install future pip install scikit-fmm diff --git a/.travis.yml b/.travis.yml index 8c8a40459b..ec01b49b19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ before_install: - hash -r - conda config --set always_yes yes --set changeps1 no - conda update -q conda - - conda create --quiet --name test-environment --show-channel-urls --channel conda-forge --only-deps python=$TRAVIS_PYTHON_VERSION fipy; + - conda create --quiet --name test-environment --show-channel-urls --channel conda-forge python=$TRAVIS_PYTHON_VERSION fipy "gmsh<4.0"; - source activate test-environment # Useful for debugging any issues with conda - conda info -a diff --git a/INSTALLATION.rst b/INSTALLATION.rst index 470b4abab0..0ed4985410 100644 --- a/INSTALLATION.rst +++ b/INSTALLATION.rst @@ -256,6 +256,8 @@ Gmsh http://www.geuz.org/gmsh/ :term:`Gmsh` is an application that allows the creation of irregular meshes. +When running in parallel, :term:`FiPy` requires a version of :term:`Gmsh` +>= 2.5 and < 4.0. SciPy ===== diff --git a/fipy/meshes/gmshMesh.py b/fipy/meshes/gmshMesh.py index 363d1f5767..48b942e77e 100755 --- a/fipy/meshes/gmshMesh.py +++ b/fipy/meshes/gmshMesh.py @@ -92,7 +92,15 @@ def gmshVersion(communicator=parallelComm): def _gmshVersion(communicator=parallelComm): version = gmshVersion(communicator) or "0.0" - return StrictVersion(version) + try: + version = StrictVersion(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") + + return version def openMSHFile(name, dimensions=None, coordDimensions=None, communicator=parallelComm, order=1, mode='r', background=None): """Open a Gmsh `MSH` file @@ -164,8 +172,8 @@ def openMSHFile(name, dimensions=None, coordDimensions=None, communicator=parall gmshFlags = ["-%d" % dimensions, "-nopopup"] if communicator.Nproc > 1: - if version < StrictVersion("2.5"): - warnstr = "Cannot partition with Gmsh version < 2.5. " \ + if not (StrictVersion("2.5") < version <= StrictVersion("4.0")): + warnstr = "Cannot partition with Gmsh version < 2.5 or >= 4.0. " \ + "Reverting to serial." warnings.warn(warnstr, RuntimeWarning, stacklevel=2) communicator = serialComm @@ -176,6 +184,11 @@ 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"): + # Gmsh 4.x needs to be told to generate ghost cells + # Unfortunately, the ghosts are broken + # https://gitlab.onelab.info/gmsh/gmsh/issues/733 + gmshFlags += ["-part_ghosts"] gmshFlags += ["-format", "msh2"] @@ -1514,23 +1527,24 @@ class Gmsh2D(Mesh2D): >>> from fipy import CellVariable, numerix - >>> std = [] + >>> error = [] >>> bkg = None >>> from builtins import range >>> for refine in range(4): ... square = Gmsh2D(geo, background=bkg) # doctest: +GMSH ... x, y = square.cellCenters # doctest: +GMSH ... bkg = CellVariable(mesh=square, value=abs(x / 4) + 0.01) # doctest: +GMSH - ... std.append((numerix.sqrt(2 * square.cellVolumes) / bkg).std()) # doctest: +GMSH + ... error.append(((2 * numerix.sqrt(square.cellVolumes) / bkg - 1)**2).cellVolumeAverage) # doctest: +GMSH - Check that the mesh is monotonically approaching the desired density + Check that the mesh is (semi)monotonically approaching the desired density + (the first step may increase, depending on the number of partitions) - >>> print(numerix.greater(std[:-1], std[1:]).all()) # doctest: +GMSH + >>> print(numerix.greater(error[:-1], error[1:]).all()) # doctest: +GMSH True and that the final density is close enough to the desired density - >>> print(std[-1] < 0.2) # doctest: +GMSH + >>> print(error[-1] < 0.02) # doctest: +GMSH True The initial mesh doesn't have to be from Gmsh @@ -1578,6 +1592,10 @@ def __init__(self, mode='r', background=background) + # openMSHFile may have "downgraded" the communicator + # if, e.g., too many overlaps were requested + communicator = self.mshFile.communicator + (verts, faces, cells, @@ -1947,6 +1965,10 @@ def __init__(self, arg, communicator=parallelComm, order=1, background=None): mode='r', background=background) + # openMSHFile may have "downgraded" the communicator + # if, e.g., too many overlaps were requested + communicator = self.mshFile.communicator + (verts, faces, cells, @@ -2225,7 +2247,7 @@ def _test(self): >>> yogmsh.cellCenters.value.size == yogrid.cellCenters.value.size # doctest: +GMSH True - >>> mesh = GmshGrid2D(nx=2, ny=2) # doctest: +GMSH + >>> mesh = GmshGrid2D(nx=2, ny=2, communicator=serialComm) # doctest: +GMSH >>> mesh.numberOfCells == 4 # doctest: +GMSH True @@ -2310,7 +2332,8 @@ def _test(self): >>> numerix.allclose(yogmsh._faceAreas, yogrid._faceAreas) # doctest: +GMSH True - >>> mesh = GmshGrid3D(nx=2, ny=2, nz=2) # doctest: +GMSH + >>> mesh = GmshGrid3D(nx=2, ny=2, nz=2, + ... communicator=serialComm) # doctest: +GMSH >>> ccs = [[ 0.5, 0.5, 0.5, 0.5, 1.5, 1.5, 1.5, 1.5], ... [ 0.5, 0.5, 1.5, 1.5, 0.5, 0.5, 1.5, 1.5],