From 1828b8f3e26ddbaa57343eac4d15e9943702efac Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Fri, 27 Apr 2012 18:58:42 +0000 Subject: [PATCH 01/17] introducing polycrystalline example, first used for IIMEC Winter School git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5224 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/USAGE.txt | 2 +- examples/phase/generated/polyxtal.png | Bin 0 -> 136643 bytes examples/phase/index.txt | 1 + examples/phase/polyxtal.py | 394 ++++++++++++++++++++++++++ examples/phase/test.py | 3 +- 5 files changed, 398 insertions(+), 2 deletions(-) create mode 100644 examples/phase/generated/polyxtal.png create mode 100755 examples/phase/polyxtal.py diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index c1ef4c9c0c..cb403848c9 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -361,7 +361,7 @@ Equations can now be coupled together so that the contributions from all the equations appear in a single system matrix. This results in tighter coupling for equations with spatial and temporal derivatives in more than one variable. The use of coupled equation is described in -:mod:`examples.diffusin.coupled`. Other examples that demonstrate the +:mod:`examples.diffusion.coupled`. Other examples that demonstrate the use of coupled equations are :mod:`examples.phase.binaryCoupled` and :mod:`examples.cahnHilliard.mesh2DCoupled`. As well as coupling equations, true vector equations can now be written in :term:`FiPy` diff --git a/examples/phase/generated/polyxtal.png b/examples/phase/generated/polyxtal.png new file mode 100644 index 0000000000000000000000000000000000000000..8b35a0f5411a41c07c00ea6e52c2e75eaea6f0c2 GIT binary patch literal 136643 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

QjUN!-H1i}tCv^Fb$2hY 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 L?_rUe#hd>NnKLwI literal 0 HcmV?d00001 diff --git a/examples/phase/index.txt b/examples/phase/index.txt index 9b7bb3e453..ba7ef13165 100644 --- a/examples/phase/index.txt +++ b/examples/phase/index.txt @@ -12,4 +12,5 @@ Phase Field Examples examples.phase.anisotropy examples.phase.impingement.mesh40x1 examples.phase.impingement.mesh20x20 + examples.phase.polyxtal diff --git a/examples/phase/polyxtal.py b/examples/phase/polyxtal.py new file mode 100755 index 0000000000..bea840d53a --- /dev/null +++ b/examples/phase/polyxtal.py @@ -0,0 +1,394 @@ +#!/usr/bin/env python + +## + # ################################################################### + # FiPy - Python-based finite volume PDE solver + # + # Author: Jonathan Guyer + # Author: Daniel Wheeler + # Author: James Warren + # mail: NIST + # www: http://www.ctcms.nist.gov/fipy/ + # + # ======================================================================== + # This software was developed at the National Institute of Standards + # and Technology by employees of the Federal Government in the course + # of their official duties. Pursuant to title 17 Section 105 of the + # United States Code this software is not subject to copyright + # protection and is in the public domain. FiPy is an experimental + # system. NIST assumes no responsibility whatsoever for its use by + # other parties, and makes no guarantees, expressed or implied, about + # its quality, reliability, or any other characteristic. We would + # appreciate acknowledgement if the software is used. + # + # This software can be redistributed and/or modified freely + # provided that any derivative works bear some notice that they are + # derived from it, and any modified versions bear some notice that + # they have been modified. + # ======================================================================== + # + # ################################################################### + ## + +r""" +To convert a liquid material to a solid, it must be cooled to a +temperature below its melting point (known as "undercooling" or "supercooling"). The rate of +solidification is often assumed (and experimentally found) to be proportional to the +undercooling. Under the right circumstances, the +solidification front can become unstable, leading to dendritic +patterns. +Warren, Kobayashi, Lobkovsky and Carter [WarrenPolycrystal]_ +have described a phase field model ("Allen-Cahn", "non-conserved +Ginsberg-Landau", or "model A" of Hohenberg & Halperin) of such a system, +including the effects of discrete crystalline orientations (anisotropy). + +We start with a regular 2D Cartesian mesh + +>>> from fipy import * +>>> dx = dy = 0.025 +>>> if __name__ == "__main__": +... nx = ny = 200 +... else: +... nx = ny = 200 +>>> mesh = Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) + +and we'll take fixed timesteps + +>>> dt = 5e-4 + +We consider the simultaneous evolution of a "phase field" variable +:math:`\phi` (taken to be 0 in the liquid phase and 1 in the solid) + +>>> phase = CellVariable(name=r'$\phi$', mesh=mesh, hasOld=True) + +a dimensionless undercooling +:math:`\Delta T` (:math:`\Delta T = 0` at the melting point) + +>>> dT = CellVariable(name=r'$\Delta T$', mesh=mesh, hasOld=True) + +and an orientation :math:`-\pi < \theta \le \pi` + +>>> theta = ModularVariable(name=r'$\theta$', mesh=mesh, hasOld=True) +>>> theta.value = -numerix.pi + 0.0001 + +The ``hasOld`` flag causes the storage of the value of variable from the +previous timestep. This is necessary for solving equations with +non-linear coefficients or for coupling between PDEs. + +The governing equation for the temperature field is the heat flux +equation, with a source due to the latent heat of solidification + +.. math:: + + \frac{\partial \Delta T}{\partial t} + = D_T \nabla^2 \Delta T + + \frac{\partial \phi}{\partial t} + + c\left(T_0 - T\right) + +>>> DT = 2.25 +>>> q = Variable(0.) +>>> T_0 = -0.1 +>>> heatEq = (TransientTerm() +... == DiffusionTerm(DT) +... + (phase - phase.old) / dt +... + q * T_0 - ImplicitSourceTerm(q)) +>>> # heatEq = (TransientTerm(var=dT) +... # == DiffusionTerm(coeff=DT, var=dT) +... # + TransientTerm(var=phase) +... # + q * T_0 - ImplicitSourceTerm(coeff=q, var=dT)) + +The governing equation for the phase field is + +.. math:: + + \tau_{\phi} \frac{\partial \phi}{\partial t} + = \nabla \cdot \mathsf{D} \nabla \phi + + \phi ( 1 - \phi ) m ( \phi , \Delta T) + - 2 s \phi | \nabla \theta | - \epsilon^2 \phi | \nabla \theta |^2 + +where + +.. math:: + + m(\phi, \Delta T) + = \phi - \frac{1}{2} + - \frac{ \kappa_1 }{ \pi } \arctan \left( \kappa_2 \Delta T \right) + +represents a source of anisotropy. The coefficient +:math:`\mathsf{D}` +is an anisotropic diffusion tensor in two dimensions + +.. math:: + + \mathsf{D} = \alpha^2 \left( 1 + c \beta \right) + \left[ + \begin{matrix} + 1 + c \beta & -c \frac{\partial \beta}{\partial \psi} \\ + c \frac{\partial \beta}{\partial \psi} & 1 + c \beta + \end{matrix} + \right] + +where :math:`\beta = \frac{ 1 - \Phi^2 } { 1 + \Phi^2}`, +:math:`\Phi = \tan \left( \frac{ N } { 2 } \psi \right)`, +:math:`\psi = \theta ++ \arctan \frac{\partial \phi / \partial y}{\partial \phi / \partial x}`, +:math:`\theta` is the orientation, and :math:`N` is the symmetry. + +>>> alpha = 0.015 +>>> c = 0.02 +>>> N = 4. + +>>> psi = theta.arithmeticFaceValue + numerix.arctan2(phase.faceGrad[1], +... phase.faceGrad[0]) +>>> Phi = numerix.tan(N * psi / 2) +>>> PhiSq = Phi**2 +>>> beta = (1. - PhiSq) / (1. + PhiSq) +>>> DbetaDpsi = -N * 2 * Phi / (1 + PhiSq) +>>> Ddia = (1.+ c * beta) + +>>> Doff = c * DbetaDpsi +>>> I0 = Variable(value=((1,0), (0,1))) +>>> I1 = Variable(value=((0,-1), (1,0))) +>>> D = alpha**2 * Ddia * (Ddia * I0 + Doff * I1) + +With these expressions defined, we can construct the phase field equation +as + +>>> tau_phase = 3e-4 +>>> kappa1 = 0.9 +>>> kappa2 = 20. +>>> epsilon = 0.008 +>>> s = 0.01 +>>> thetaMag = theta.grad.mag +>>> phaseEq = (TransientTerm(tau_phase) +... == DiffusionTerm(D) +... + ImplicitSourceTerm((phase - 0.5 - kappa1 / numerix.pi * numerix.arctan(kappa2 * dT)) +... * (1 - phase) +... - (2 * s + epsilon**2 * thetaMag) * thetaMag)) +>>> # phaseEq = (TransientTerm(coeff=tau_phase, var=phase) +... # == DiffusionTerm(coeff=D, var=phase) +... # + ImplicitSourceTerm(coeff=((phase - 0.5 - kappa1 / numerix.pi * numerix.arctan(kappa2 * dT)) +... # * (1 - phase) +... # - (2 * s + epsilon**2 * thetaMag) * thetaMag), +... # var=phase)) + +The governing equation for orientation is given by + +.. math:: + + P(\epsilon | \nabla \theta |) \tau_{\theta} \phi^2 + \frac{\partial \theta}{\partial t} + = \nabla \cdot \left[ \phi^2 \left( \frac{s}{| \nabla \theta |} + + \epsilon^2 \right) \nabla \theta \right] + +where + +.. math:: + + P(w) = 1 - \exp{(-\beta w)} + \frac{\mu}{\epsilon} \exp{(-\beta w)} + +The ``theta`` equation is built in the following way. The details for +this equation are fairly involved, see J.A. Warren *et al.*. The main +detail is that a source must be added to correct for the +discretization of ``theta`` on the circle. + +>>> tau_theta = 3e-3 +>>> mu = 1e3 +>>> gamma = 1e3 +>>> thetaSmallValue = 1e-6 +>>> phaseMod = phase + ( phase < thetaSmallValue ) * thetaSmallValue +>>> beta_theta = 1e5 +>>> expo = epsilon * beta_theta * theta.grad.mag +>>> expo = (expo < 100.) * (expo - 100.) + 100. +>>> Pfunc = 1. + numerix.exp(-expo) * (mu / epsilon - 1.) + +>>> gradMagTheta = theta.faceGrad.mag +>>> eps = 1. / gamma / 10. +>>> gradMagTheta += (gradMagTheta < eps) * eps +>>> IGamma = (gradMagTheta > 1. / gamma) * (1 / gradMagTheta - gamma) + gamma +>>> v_theta = phase.arithmeticFaceValue * (s * IGamma + epsilon**2) +>>> D_theta = phase.arithmeticFaceValue**2 * (s * IGamma + epsilon**2) + +The source term requires the evaluation of the face gradient without +the modular operator. ``theta``:meth:`~fipy.variables.modularVariable.ModularVariable.getFaceGradNoMod` +evaluates the gradient without modular arithmetic. + +>>> thetaEq = (TransientTerm(tau_theta * phaseMod**2 * Pfunc) +... == DiffusionTerm(D_theta) +... + (D_theta * (theta.faceGrad - theta.faceGradNoMod)).divergence) +>>> # thetaEq = (TransientTerm(coeff=tau_theta * phaseMod**2 * Pfunc, var=theta) +... # == DiffusionTerm(coeff=D_theta, var=theta) +... # + PowerLawConvectionTerm(coeff=v_theta * (theta.faceGrad - theta.faceGradNoMod), var=phase)) + +We seed a circular solidified region in the center + +>>> x, y = mesh.cellCenters +>>> numSeeds = 10 +>>> numerix.random.seed(12345) +>>> for Cx, Cy, orientation in numerix.random.random([numSeeds, 3]): +... radius = dx * 5. +... seed = ((x - Cx * nx * dx)**2 + (y - Cy * ny * dy)**2) < radius**2 +... phase[seed] = 1. +... theta[seed] = numerix.pi * (2 * orientation - 1) + +and quench the entire simulation domain below the melting point + +>>> dT.setValue(-0.5) + +In a real solidification process, dendritic branching is induced by small thermal +fluctuations along an otherwise smooth surface, but the granularity of the +:class:`~fipy.meshes.mesh.Mesh` is enough "noise" in this case, so we don't need to explicitly +introduce randomness, the way we did in the Cahn-Hilliard problem. + +FiPy's viewers are utilitarian, striving to let the user see *something*, +regardless of their operating system or installed packages, so you the default +color scheme of grain orientation won't be very informative "out of the box". +Because all of Python is accessible and FiPy is object oriented, it is not hard +to adapt one of the existing viewers to create a specialized display: + +>>> if __name__ == "__main__": +... try: +... class OrientationViewer(Matplotlib2DGridViewer): +... def __init__(self, phase, orientation, title=None, limits={}, **kwlimits): +... self.phase = phase +... Matplotlib2DGridViewer.__init__(self, vars=(orientation,), title=title, +... limits=limits, colorbar=None, **kwlimits) +... +... # make room for non-existent colorbar +... # stolen from matplotlib.colorbar.make_axes +... # https://github.com/matplotlib/matplotlib/blob +... # /ec1cd2567521c105a451ce15e06de10715f8b54d/lib +... # /matplotlib/colorbar.py#L838 +... fraction = 0.15 +... pb = self.axes.get_position(original=True).frozen() +... pad = 0.05 +... x1 = 1.0-fraction +... pb1, pbx, pbcb = pb.splitx(x1-pad, x1) +... panchor = (1.0, 0.5) +... self.axes.set_position(pb1) +... self.axes.set_anchor(panchor) +... +... # make the gnomon +... fig = self.axes.get_figure() +... self.gnomon = fig.add_axes([0.85, 0.425, 0.15, 0.15], polar=True) +... self.gnomon.set_thetagrids([180, 270, 0, 90], +... [r"$\pm\pi$", r"$-\frac{\pi}{2}$", "$0$", r"$+\frac{\pi}{2}$"], +... frac=1.3) +... self.gnomon.set_theta_zero_location("N") +... self.gnomon.set_theta_direction(-1) +... self.gnomon.set_rgrids([1.], [""]) +... N = 100 +... theta = numerix.arange(-numerix.pi, numerix.pi, 2 * numerix.pi / N) +... radii = numerix.ones((N,)) +... bars = self.gnomon.bar(theta, radii, width=2 * numerix.pi / N, bottom=0.0) +... colors = self._orientation_and_phase_to_rgb(orientation=numerix.array([theta]), phase=1.) +... for c, t, bar in zip(colors[0], theta, bars): +... bar.set_facecolor(c) +... bar.set_edgecolor(c) +... +... def _reshape(self, var): +... '''return values of var in an 2D array''' +... return numerix.reshape(numerix.array(var), +... var.mesh.shape[::-1])[::-1] +... +... @staticmethod +... def _orientation_and_phase_to_rgb(orientation, phase): +... from matplotlib import colors +... +... hsv = numerix.empty(orientation.shape + (3,)) +... hsv[..., 0] = (orientation / numerix.pi + 1) / 2. +... hsv[..., 1] = 1. +... hsv[..., 2] = phase +... +... return colors.hsv_to_rgb(hsv) +... +... @property +... def _data(self): +... '''convert phase and orientation to rgb image array +... +... orientation (-pi, pi) -> hue (0, 1) +... phase (0, 1) -> value (0, 1) +... ''' +... orientation = self._reshape(self.vars[0]) +... phase = self._reshape(self.phase) +... +... return self._orientation_and_phase_to_rgb(orientation, phase) +... +... def _plot(self): +... self.image.set_data(self._data) +... +... from matplotlib import pyplot +... pyplot.ion() +... w, h = pyplot.figaspect(1.) +... fig = pyplot.figure(figsize=(2*w, h)) +... timer = fig.text(0.1, 0.9, "t = %.3f" % 0, fontsize=18) +... +... viewer = MultiViewer(viewers=(MatplotlibViewer(vars=dT, +... cmap=pyplot.cm.hot, +... datamin=-0.5, +... datamax=0.5, +... axes=fig.add_subplot(121)), +... OrientationViewer(phase=phase, +... orientation=theta, +... title=theta.name, +... axes=fig.add_subplot(122)))) +... except ImportError: +... viewer = MultiViewer(viewers=(Viewer(vars=dT, +... datamin=-0.5, +... datamax=0.5), +... Viewer(vars=phase, +... datamin=0., +... datamax=1.), +... Viewer(vars=theta, +... datamin=-numerix.pi, +... datamax=numerix.pi))) +>>> viewer.plot() + +and iterate the solution in time, plotting as we go, + +>>> # eq = thetaEq & phaseEq & heatEq + +>>> if __name__ == "__main__": +... total_time = 2. +... else: +... total_time = dt * 10 +>>> elapsed = 0. +>>> step = 0 +>>> save_interval = 0.002 +>>> save_at = save_interval + +>>> while elapsed < total_time: +... if elapsed > 0.3: +... q.value = 100 +... phase.updateOld() +... dT.updateOld() +... theta.updateOld() +... # eq.solve(dt=dt) +... thetaEq.solve(theta, dt=dt) +... phaseEq.solve(phase, dt=dt) +... heatEq.solve(dT, dt=dt) +... elapsed += dt +... step += 1 +... if __name__ == "__main__" and elapsed >= save_at: +... timer.set_text("t = %.3f" % elapsed) +... viewer.plot() +... fig.savefig("uncoupled/%.3f.png" % elapsed) +... save_at += save_interval + +.. image:: polyxtal.* + :width: 90% + :align: center + :alt: undercooling and grain orientation during solidification of a collection of anisotropic seeds + +The non-uniform temperature results from the release of latent +heat at the solidifying interface. The dendrite arms grow fastest +where the temperature gradient is steepest. +""" +__docformat__ = 'restructuredtext' + +if __name__ == '__main__': + import fipy.tests.doctestPlus + exec(fipy.tests.doctestPlus._getScript()) + + raw_input('finished') + diff --git a/examples/phase/test.py b/examples/phase/test.py index 1fe7678a6e..d3dab76389 100755 --- a/examples/phase/test.py +++ b/examples/phase/test.py @@ -45,7 +45,8 @@ def _suite(): 'quaternary', 'simple', 'symmetry', - 'binaryCoupled' + 'binaryCoupled', + 'polyxtal' ), base = __name__) From 9bc25346cfc8dad470b3b2acf7fcd1702fddc073 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Fri, 27 Apr 2012 19:23:31 +0000 Subject: [PATCH 02/17] split polycrystalline example into uncoupled and couple variants git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5225 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/FAQ.txt | 6 +- documentation/USAGE.txt | 9 +- examples/phase/polyxtal.py | 19 -- examples/phase/polyxtalCoupled.py | 376 ++++++++++++++++++++++++++++++ examples/phase/test.py | 3 +- 5 files changed, 386 insertions(+), 27 deletions(-) create mode 100755 examples/phase/polyxtalCoupled.py diff --git a/documentation/FAQ.txt b/documentation/FAQ.txt index 12948d0529..7acbe59915 100644 --- a/documentation/FAQ.txt +++ b/documentation/FAQ.txt @@ -296,9 +296,9 @@ want, and then issue supplemental commands for the underlying plotting package. The better option is to make a "subclass" of the :term:`FiPy` :class:`Viewer ` that comes closest to producing the image you want. You can then override just the behavior you wan to change, while letting :term:`FiPy` do -most of the heavy lifting. See :mod:`examples.phase.anisotropy` for an -example of creating a custom :term:`Matplotlib` :class:`Viewer -` class. +most of the heavy lifting. See :mod:`examples.phase.anisotropy` and +:mod:`examples.phase.polyxtal` for examples of creating a custom +:term:`Matplotlib` :class:`Viewer ` class. .. _FAQ-IterationsTimestepsSweeps: diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index cb403848c9..c85a276627 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -362,10 +362,11 @@ all the equations appear in a single system matrix. This results in tighter coupling for equations with spatial and temporal derivatives in more than one variable. The use of coupled equation is described in :mod:`examples.diffusion.coupled`. Other examples that demonstrate the -use of coupled equations are :mod:`examples.phase.binaryCoupled` and -:mod:`examples.cahnHilliard.mesh2DCoupled`. As well as coupling -equations, true vector equations can now be written in :term:`FiPy` -(see :mod:`examples.diffusion.coupled` for more details). +use of coupled equations are :mod:`examples.phase.binaryCoupled`, +:mod:`examples.phase.polyxtalCoupled` and +:mod:`examples.cahnHilliard.mesh2DCoupled`. As well as coupling equations, +true vector equations can now be written in :term:`FiPy` (see +:mod:`examples.diffusion.coupled` for more details). ---------------------- Running under Python 3 diff --git a/examples/phase/polyxtal.py b/examples/phase/polyxtal.py index bea840d53a..b603bac64d 100755 --- a/examples/phase/polyxtal.py +++ b/examples/phase/polyxtal.py @@ -92,10 +92,6 @@ ... == DiffusionTerm(DT) ... + (phase - phase.old) / dt ... + q * T_0 - ImplicitSourceTerm(q)) ->>> # heatEq = (TransientTerm(var=dT) -... # == DiffusionTerm(coeff=DT, var=dT) -... # + TransientTerm(var=phase) -... # + q * T_0 - ImplicitSourceTerm(coeff=q, var=dT)) The governing equation for the phase field is @@ -165,12 +161,6 @@ ... + ImplicitSourceTerm((phase - 0.5 - kappa1 / numerix.pi * numerix.arctan(kappa2 * dT)) ... * (1 - phase) ... - (2 * s + epsilon**2 * thetaMag) * thetaMag)) ->>> # phaseEq = (TransientTerm(coeff=tau_phase, var=phase) -... # == DiffusionTerm(coeff=D, var=phase) -... # + ImplicitSourceTerm(coeff=((phase - 0.5 - kappa1 / numerix.pi * numerix.arctan(kappa2 * dT)) -... # * (1 - phase) -... # - (2 * s + epsilon**2 * thetaMag) * thetaMag), -... # var=phase)) The governing equation for orientation is given by @@ -216,9 +206,6 @@ >>> thetaEq = (TransientTerm(tau_theta * phaseMod**2 * Pfunc) ... == DiffusionTerm(D_theta) ... + (D_theta * (theta.faceGrad - theta.faceGradNoMod)).divergence) ->>> # thetaEq = (TransientTerm(coeff=tau_theta * phaseMod**2 * Pfunc, var=theta) -... # == DiffusionTerm(coeff=D_theta, var=theta) -... # + PowerLawConvectionTerm(coeff=v_theta * (theta.faceGrad - theta.faceGradNoMod), var=phase)) We seed a circular solidified region in the center @@ -346,14 +333,11 @@ and iterate the solution in time, plotting as we go, ->>> # eq = thetaEq & phaseEq & heatEq - >>> if __name__ == "__main__": ... total_time = 2. ... else: ... total_time = dt * 10 >>> elapsed = 0. ->>> step = 0 >>> save_interval = 0.002 >>> save_at = save_interval @@ -363,16 +347,13 @@ ... phase.updateOld() ... dT.updateOld() ... theta.updateOld() -... # eq.solve(dt=dt) ... thetaEq.solve(theta, dt=dt) ... phaseEq.solve(phase, dt=dt) ... heatEq.solve(dT, dt=dt) ... elapsed += dt -... step += 1 ... if __name__ == "__main__" and elapsed >= save_at: ... timer.set_text("t = %.3f" % elapsed) ... viewer.plot() -... fig.savefig("uncoupled/%.3f.png" % elapsed) ... save_at += save_interval .. image:: polyxtal.* diff --git a/examples/phase/polyxtalCoupled.py b/examples/phase/polyxtalCoupled.py new file mode 100755 index 0000000000..583e671349 --- /dev/null +++ b/examples/phase/polyxtalCoupled.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python + +## + # ################################################################### + # FiPy - Python-based finite volume PDE solver + # + # Author: Jonathan Guyer + # Author: Daniel Wheeler + # Author: James Warren + # mail: NIST + # www: http://www.ctcms.nist.gov/fipy/ + # + # ======================================================================== + # This software was developed at the National Institute of Standards + # and Technology by employees of the Federal Government in the course + # of their official duties. Pursuant to title 17 Section 105 of the + # United States Code this software is not subject to copyright + # protection and is in the public domain. FiPy is an experimental + # system. NIST assumes no responsibility whatsoever for its use by + # other parties, and makes no guarantees, expressed or implied, about + # its quality, reliability, or any other characteristic. We would + # appreciate acknowledgement if the software is used. + # + # This software can be redistributed and/or modified freely + # provided that any derivative works bear some notice that they are + # derived from it, and any modified versions bear some notice that + # they have been modified. + # ======================================================================== + # + # ################################################################### + ## + +r""" +To convert a liquid material to a solid, it must be cooled to a +temperature below its melting point (known as "undercooling" or "supercooling"). The rate of +solidification is often assumed (and experimentally found) to be proportional to the +undercooling. Under the right circumstances, the +solidification front can become unstable, leading to dendritic +patterns. +Warren, Kobayashi, Lobkovsky and Carter [WarrenPolycrystal]_ +have described a phase field model ("Allen-Cahn", "non-conserved +Ginsberg-Landau", or "model A" of Hohenberg & Halperin) of such a system, +including the effects of discrete crystalline orientations (anisotropy). + +We start with a regular 2D Cartesian mesh + +>>> from fipy import * +>>> dx = dy = 0.025 +>>> if __name__ == "__main__": +... nx = ny = 200 +... else: +... nx = ny = 200 +>>> mesh = Grid2D(dx=dx, dy=dy, nx=nx, ny=ny) + +and we'll take fixed timesteps + +>>> dt = 5e-4 + +We consider the simultaneous evolution of a "phase field" variable +:math:`\phi` (taken to be 0 in the liquid phase and 1 in the solid) + +>>> phase = CellVariable(name=r'$\phi$', mesh=mesh, hasOld=True) + +a dimensionless undercooling +:math:`\Delta T` (:math:`\Delta T = 0` at the melting point) + +>>> dT = CellVariable(name=r'$\Delta T$', mesh=mesh, hasOld=True) + +and an orientation :math:`-\pi < \theta \le \pi` + +>>> theta = ModularVariable(name=r'$\theta$', mesh=mesh, hasOld=True) +>>> theta.value = -numerix.pi + 0.0001 + +The ``hasOld`` flag causes the storage of the value of variable from the +previous timestep. This is necessary for solving equations with +non-linear coefficients or for coupling between PDEs. + +The governing equation for the temperature field is the heat flux +equation, with a source due to the latent heat of solidification + +.. math:: + + \frac{\partial \Delta T}{\partial t} + = D_T \nabla^2 \Delta T + + \frac{\partial \phi}{\partial t} + + c\left(T_0 - T\right) + +>>> DT = 2.25 +>>> q = Variable(0.) +>>> T_0 = -0.1 +>>> heatEq = (TransientTerm(var=dT) +... == DiffusionTerm(coeff=DT, var=dT) +... + TransientTerm(var=phase) +... + q * T_0 - ImplicitSourceTerm(coeff=q, var=dT)) + +The governing equation for the phase field is + +.. math:: + + \tau_{\phi} \frac{\partial \phi}{\partial t} + = \nabla \cdot \mathsf{D} \nabla \phi + + \phi ( 1 - \phi ) m ( \phi , \Delta T) + - 2 s \phi | \nabla \theta | - \epsilon^2 \phi | \nabla \theta |^2 + +where + +.. math:: + + m(\phi, \Delta T) + = \phi - \frac{1}{2} + - \frac{ \kappa_1 }{ \pi } \arctan \left( \kappa_2 \Delta T \right) + +represents a source of anisotropy. The coefficient +:math:`\mathsf{D}` +is an anisotropic diffusion tensor in two dimensions + +.. math:: + + \mathsf{D} = \alpha^2 \left( 1 + c \beta \right) + \left[ + \begin{matrix} + 1 + c \beta & -c \frac{\partial \beta}{\partial \psi} \\ + c \frac{\partial \beta}{\partial \psi} & 1 + c \beta + \end{matrix} + \right] + +where :math:`\beta = \frac{ 1 - \Phi^2 } { 1 + \Phi^2}`, +:math:`\Phi = \tan \left( \frac{ N } { 2 } \psi \right)`, +:math:`\psi = \theta ++ \arctan \frac{\partial \phi / \partial y}{\partial \phi / \partial x}`, +:math:`\theta` is the orientation, and :math:`N` is the symmetry. + +>>> alpha = 0.015 +>>> c = 0.02 +>>> N = 4. + +>>> psi = theta.arithmeticFaceValue + numerix.arctan2(phase.faceGrad[1], +... phase.faceGrad[0]) +>>> Phi = numerix.tan(N * psi / 2) +>>> PhiSq = Phi**2 +>>> beta = (1. - PhiSq) / (1. + PhiSq) +>>> DbetaDpsi = -N * 2 * Phi / (1 + PhiSq) +>>> Ddia = (1.+ c * beta) + +>>> Doff = c * DbetaDpsi +>>> I0 = Variable(value=((1,0), (0,1))) +>>> I1 = Variable(value=((0,-1), (1,0))) +>>> D = alpha**2 * Ddia * (Ddia * I0 + Doff * I1) + +With these expressions defined, we can construct the phase field equation +as + +>>> tau_phase = 3e-4 +>>> kappa1 = 0.9 +>>> kappa2 = 20. +>>> epsilon = 0.008 +>>> s = 0.01 +>>> thetaMag = theta.grad.mag +>>> phaseEq = (TransientTerm(coeff=tau_phase, var=phase) +... == DiffusionTerm(coeff=D, var=phase) +... + ImplicitSourceTerm(coeff=((phase - 0.5 - kappa1 / numerix.pi * numerix.arctan(kappa2 * dT)) +... * (1 - phase) +... - (2 * s + epsilon**2 * thetaMag) * thetaMag), +... var=phase)) + +The governing equation for orientation is given by + +.. math:: + + P(\epsilon | \nabla \theta |) \tau_{\theta} \phi^2 + \frac{\partial \theta}{\partial t} + = \nabla \cdot \left[ \phi^2 \left( \frac{s}{| \nabla \theta |} + + \epsilon^2 \right) \nabla \theta \right] + +where + +.. math:: + + P(w) = 1 - \exp{(-\beta w)} + \frac{\mu}{\epsilon} \exp{(-\beta w)} + +The ``theta`` equation is built in the following way. The details for +this equation are fairly involved, see J.A. Warren *et al.*. The main +detail is that a source must be added to correct for the +discretization of ``theta`` on the circle. + +>>> tau_theta = 3e-3 +>>> mu = 1e3 +>>> gamma = 1e3 +>>> thetaSmallValue = 1e-6 +>>> phaseMod = phase + ( phase < thetaSmallValue ) * thetaSmallValue +>>> beta_theta = 1e5 +>>> expo = epsilon * beta_theta * theta.grad.mag +>>> expo = (expo < 100.) * (expo - 100.) + 100. +>>> Pfunc = 1. + numerix.exp(-expo) * (mu / epsilon - 1.) + +>>> gradMagTheta = theta.faceGrad.mag +>>> eps = 1. / gamma / 10. +>>> gradMagTheta += (gradMagTheta < eps) * eps +>>> IGamma = (gradMagTheta > 1. / gamma) * (1 / gradMagTheta - gamma) + gamma +>>> v_theta = phase.arithmeticFaceValue * (s * IGamma + epsilon**2) +>>> D_theta = phase.arithmeticFaceValue**2 * (s * IGamma + epsilon**2) + +The source term requires the evaluation of the face gradient without +the modular operator. ``theta``:meth:`~fipy.variables.modularVariable.ModularVariable.getFaceGradNoMod` +evaluates the gradient without modular arithmetic. + +>>> thetaEq = (TransientTerm(coeff=tau_theta * phaseMod**2 * Pfunc, var=theta) +... == DiffusionTerm(coeff=D_theta, var=theta) +... + PowerLawConvectionTerm(coeff=v_theta * (theta.faceGrad - theta.faceGradNoMod), var=phase)) + +We seed a circular solidified region in the center + +>>> x, y = mesh.cellCenters +>>> numSeeds = 10 +>>> numerix.random.seed(12345) +>>> for Cx, Cy, orientation in numerix.random.random([numSeeds, 3]): +... radius = dx * 5. +... seed = ((x - Cx * nx * dx)**2 + (y - Cy * ny * dy)**2) < radius**2 +... phase[seed] = 1. +... theta[seed] = numerix.pi * (2 * orientation - 1) + +and quench the entire simulation domain below the melting point + +>>> dT.setValue(-0.5) + +In a real solidification process, dendritic branching is induced by small thermal +fluctuations along an otherwise smooth surface, but the granularity of the +:class:`~fipy.meshes.mesh.Mesh` is enough "noise" in this case, so we don't need to explicitly +introduce randomness, the way we did in the Cahn-Hilliard problem. + +FiPy's viewers are utilitarian, striving to let the user see *something*, +regardless of their operating system or installed packages, so you the default +color scheme of grain orientation won't be very informative "out of the box". +Because all of Python is accessible and FiPy is object oriented, it is not hard +to adapt one of the existing viewers to create a specialized display: + +>>> if __name__ == "__main__": +... try: +... class OrientationViewer(Matplotlib2DGridViewer): +... def __init__(self, phase, orientation, title=None, limits={}, **kwlimits): +... self.phase = phase +... Matplotlib2DGridViewer.__init__(self, vars=(orientation,), title=title, +... limits=limits, colorbar=None, **kwlimits) +... +... # make room for non-existent colorbar +... # stolen from matplotlib.colorbar.make_axes +... # https://github.com/matplotlib/matplotlib/blob +... # /ec1cd2567521c105a451ce15e06de10715f8b54d/lib +... # /matplotlib/colorbar.py#L838 +... fraction = 0.15 +... pb = self.axes.get_position(original=True).frozen() +... pad = 0.05 +... x1 = 1.0-fraction +... pb1, pbx, pbcb = pb.splitx(x1-pad, x1) +... panchor = (1.0, 0.5) +... self.axes.set_position(pb1) +... self.axes.set_anchor(panchor) +... +... # make the gnomon +... fig = self.axes.get_figure() +... self.gnomon = fig.add_axes([0.85, 0.425, 0.15, 0.15], polar=True) +... self.gnomon.set_thetagrids([180, 270, 0, 90], +... [r"$\pm\pi$", r"$-\frac{\pi}{2}$", "$0$", r"$+\frac{\pi}{2}$"], +... frac=1.3) +... self.gnomon.set_theta_zero_location("N") +... self.gnomon.set_theta_direction(-1) +... self.gnomon.set_rgrids([1.], [""]) +... N = 100 +... theta = numerix.arange(-numerix.pi, numerix.pi, 2 * numerix.pi / N) +... radii = numerix.ones((N,)) +... bars = self.gnomon.bar(theta, radii, width=2 * numerix.pi / N, bottom=0.0) +... colors = self._orientation_and_phase_to_rgb(orientation=numerix.array([theta]), phase=1.) +... for c, t, bar in zip(colors[0], theta, bars): +... bar.set_facecolor(c) +... bar.set_edgecolor(c) +... +... def _reshape(self, var): +... '''return values of var in an 2D array''' +... return numerix.reshape(numerix.array(var), +... var.mesh.shape[::-1])[::-1] +... +... @staticmethod +... def _orientation_and_phase_to_rgb(orientation, phase): +... from matplotlib import colors +... +... hsv = numerix.empty(orientation.shape + (3,)) +... hsv[..., 0] = (orientation / numerix.pi + 1) / 2. +... hsv[..., 1] = 1. +... hsv[..., 2] = phase +... +... return colors.hsv_to_rgb(hsv) +... +... @property +... def _data(self): +... '''convert phase and orientation to rgb image array +... +... orientation (-pi, pi) -> hue (0, 1) +... phase (0, 1) -> value (0, 1) +... ''' +... orientation = self._reshape(self.vars[0]) +... phase = self._reshape(self.phase) +... +... return self._orientation_and_phase_to_rgb(orientation, phase) +... +... def _plot(self): +... self.image.set_data(self._data) +... +... from matplotlib import pyplot +... pyplot.ion() +... w, h = pyplot.figaspect(1.) +... fig = pyplot.figure(figsize=(2*w, h)) +... timer = fig.text(0.1, 0.9, "t = %.3f" % 0, fontsize=18) +... +... viewer = MultiViewer(viewers=(MatplotlibViewer(vars=dT, +... cmap=pyplot.cm.hot, +... datamin=-0.5, +... datamax=0.5, +... axes=fig.add_subplot(121)), +... OrientationViewer(phase=phase, +... orientation=theta, +... title=theta.name, +... axes=fig.add_subplot(122)))) +... except ImportError: +... viewer = MultiViewer(viewers=(Viewer(vars=dT, +... datamin=-0.5, +... datamax=0.5), +... Viewer(vars=phase, +... datamin=0., +... datamax=1.), +... Viewer(vars=theta, +... datamin=-numerix.pi, +... datamax=numerix.pi))) +>>> viewer.plot() + +and iterate the solution in time, plotting as we go, + +>>> eq = thetaEq & phaseEq & heatEq + +>>> if __name__ == "__main__": +... total_time = 2. +... else: +... total_time = dt * 10 +>>> elapsed = 0. +>>> save_interval = 0.002 +>>> save_at = save_interval + +>>> while elapsed < total_time: +... if elapsed > 0.3: +... q.value = 100 +... phase.updateOld() +... dT.updateOld() +... theta.updateOld() +... eq.solve(dt=dt) +... elapsed += dt +... if __name__ == "__main__" and elapsed >= save_at: +... timer.set_text("t = %.3f" % elapsed) +... viewer.plot() +... save_at += save_interval + +.. image:: polyxtal.* + :width: 90% + :align: center + :alt: undercooling and grain orientation during solidification of a collection of anisotropic seeds + +The non-uniform temperature results from the release of latent +heat at the solidifying interface. The dendrite arms grow fastest +where the temperature gradient is steepest. +""" +__docformat__ = 'restructuredtext' + +if __name__ == '__main__': + import fipy.tests.doctestPlus + exec(fipy.tests.doctestPlus._getScript()) + + raw_input('finished') + diff --git a/examples/phase/test.py b/examples/phase/test.py index d3dab76389..5c47ba48fe 100755 --- a/examples/phase/test.py +++ b/examples/phase/test.py @@ -46,7 +46,8 @@ def _suite(): 'simple', 'symmetry', 'binaryCoupled', - 'polyxtal' + 'polyxtal', + 'polyxtalCoupled' ), base = __name__) From 91eac63bb7e5c9a29256df5bb14dc4e0fd2f73a4 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Thu, 2 Aug 2012 14:38:20 +0000 Subject: [PATCH 03/17] Add `polyxtalCoupled` to documentation git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5256 d80e17d7-ff13-0410-a124-85740d801063 --- examples/phase/index.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/phase/index.txt b/examples/phase/index.txt index ba7ef13165..329844a033 100644 --- a/examples/phase/index.txt +++ b/examples/phase/index.txt @@ -13,4 +13,5 @@ Phase Field Examples examples.phase.impingement.mesh40x1 examples.phase.impingement.mesh20x20 examples.phase.polyxtal + examples.phase.polyxtalCoupled From a1ca69da7cd4961aec24c2a3d0278a43bcefef8c Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Thu, 2 Aug 2012 14:39:04 +0000 Subject: [PATCH 04/17] Convert to doctest syntax git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5257 d80e17d7-ff13-0410-a124-85740d801063 --- examples/diffusion/coupled.py | 131 ++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 47 deletions(-) diff --git a/examples/diffusion/coupled.py b/examples/diffusion/coupled.py index 8ea65778c5..c64fb2b2ac 100644 --- a/examples/diffusion/coupled.py +++ b/examples/diffusion/coupled.py @@ -33,77 +33,114 @@ ## r""" -How to use coupled equations. +FiPy has only first order time derivatives and so expressions such as the +biharmonic wave equation +.. math:: + + \frac{\partial^4 v}{\partial x^4} + \frac{\partial^2 v}{\partial t^2} &= 0 + +cannot be represented as written. We can decompose this into two equations that are first order in time -## Coupled +.. math:: + + \frac{\partial^2 v_0}{\partial x^2} + \frac{\partial v_1}{\partial t} &= 0 \\ + \frac{\partial^2 v_1}{\partial x^2} - \frac{\partial v_0}{\partial t} &= 0 +Historically, FiPy required systems of coupled equations to be solved +successively, "sweeping" the equations to convergence. For instance, let's solve the system -from fipy import Grid1D, CellVariable, TransientTerm, DiffusionTerm, Viewer +.. math:: + + \frac{\partial v_0}{\partial t} &= 0.01 \nabla^2 v_0 - \nabla^2 v_1 \\ + \frac{\partial v_1}{\partial t} &= \nabla^2 v_0 + 0.01 \nabla^2 v_1 + +subject to the boundary conditions -m = Grid1D(nx=100, Lx=1.) +.. math:: + :nowrap: + + \begin{align*} + v_0|_{x=0} &= 0 & v_0|_{x=1} &= 1 \\ + v_1|_{x=0} &= 1 & v_1|_{x=1} &= 0 + \end{align*} -v0 = CellVariable(mesh=m, hasOld=True, value=0.5) -v1 = CellVariable(mesh=m, hasOld=True, value=0.5) +>>> from fipy import Grid1D, CellVariable, TransientTerm, DiffusionTerm, Viewer -v0.constrain(0, m.facesLeft) -v0.constrain(1, m.facesRight) +>>> m = Grid1D(nx=100, Lx=1.) -v1.constrain(1, m.facesLeft) -v1.constrain(0, m.facesRight) +>>> v0 = CellVariable(mesh=m, hasOld=True, value=0.5) +>>> v1 = CellVariable(mesh=m, hasOld=True, value=0.5) -eqn0 = TransientTerm(var=v0) == DiffusionTerm(-1, var=v1) + DiffusionTerm(0.01, var=v0) -eqn1 = TransientTerm(var=v1) == DiffusionTerm(1, var=v0) + DiffusionTerm(0.01, var=v1) +>>> v0.constrain(0, m.facesLeft) +>>> v0.constrain(1, m.facesRight) -eqn = eqn0 & eqn1 +>>> v1.constrain(1, m.facesLeft) +>>> v1.constrain(0, m.facesRight) -vi = Viewer((v0, v1)) +>>> eq0 = TransientTerm() == DiffusionTerm(coeff=0.01) - v1.faceGrad.divergence +>>> eq1 = TransientTerm() == v0.faceGrad.divergence + DiffusionTerm(coeff=0.01) -for t in range(1): - v0.updateOld() - v1.updateOld() - eqn.solve(dt=1.) - vi.plot() +>>> vi = Viewer((v0, v1)) -## Vector +>>> for t in range(100): +... v0.updateOld() +... v1.updateOld() +... res0 = res1 = 1e100 +... while max(res0, res1) > 0.1: +... res0 = eq0.sweep(var=v0, dt=1e-5) +... res1 = eq1.sweep(var=v1, dt=1e-5) +... if t % 10 == 0: +... vi.plot() -v = CellVariable(mesh=m, hasOld=True, value=0.5, elementshape=(2,)) +This uncoupled method still works, but it can be advantageous to solve the two +equations simultaneously. In this case, by coupling the equations, we can +eliminate the explicit sources and dramatically increase the time steps: -v.constrain(0, [m.facesLeft, m.facesRight]) -v.constrain(1, [m.facesRight, m.facesLeft]) +>>> v0.value = 0.5 +>>> v1.value = 0.5 -eqn = TransientTerm(((1, 0), (0, 1))) == DiffusionTerm([((0.01, -1), (1, 0.01))]) +>>> eqn0 = TransientTerm(var=v0) == DiffusionTerm(0.01, var=v0) - DiffusionTerm(1, var=v1) +>>> eqn1 = TransientTerm(var=v1) == DiffusionTerm(1, var=v0) + DiffusionTerm(0.01, var=v1) -vi = Viewer((v[0], v[1])) +>>> eqn = eqn0 & eqn1 -for t in range(1): - v.updateOld() - eqn.solve(var=v, dt=1.) - vi.plot() +>>> for t in range(1): +... v0.updateOld() +... v1.updateOld() +... eqn.solve(dt=1.e-3) +... vi.plot() -## Uncoupled +It is also possible to pose the same equations in vector form: -m = Grid1D(nx=100, Lx=1.) +>>> v = CellVariable(mesh=m, hasOld=True, value=[[0.5], [0.5]], elementshape=(2,)) -v0 = CellVariable(mesh=m, hasOld=True, value=0.5) -v1 = CellVariable(mesh=m, hasOld=True, value=0.5) +>>> v.constrain([[0], [1]], m.facesLeft) +>>> v.constrain([[1], [0]], m.facesRight) -v0.constrain(0, m.facesLeft) -v0.constrain(1, m.facesRight) +>>> eqn = TransientTerm([[1, 0], +... [0, 1]]) == DiffusionTerm([[[0.01, -1], +... [1, 0.01]]]) -v1.constrain(1, m.facesLeft) -v1.constrain(0, m.facesRight) +>>> vi = Viewer((v[0], v[1])) -eq0 = TransientTerm() == -v1.faceGrad.divergence + DiffusionTerm(0.01) -eq1 = TransientTerm() == v0.faceGrad.divergence + DiffusionTerm(0.01) +>>> for t in range(1): +... v.updateOld() +... eqn.solve(var=v, dt=1.e-3) +... vi.plot() -vi = Viewer((v0, v1)) +Whether you pose your problem in coupled or vector form should be dictated by +the underlying physics. If :math:`v_0` and :math:`v_1` represent the +concentrations of two conserved species, then it is natural to write two +seperate governing equations and to couple them. If they represent two +components of vector field, then the vector formulation is obviously more +natural. FiPy will solve the same matrix system either way. +""" +__docformat__ = 'restructuredtext' -for t in range(10000): - v0.updateOld() - v1.updateOld() - eq0.solve(var=v0, dt=1e-5) - eq1.solve(var=v1, dt=1e-5) - vi.plot() +if __name__ == '__main__': + import fipy.tests.doctestPlus + exec(fipy.tests.doctestPlus._getScript()) + + raw_input('finished') -""" From 252ea9e010fbc194427b10902490194a2544b824 Mon Sep 17 00:00:00 2001 From: Daniel Wheeler Date: Thu, 2 Aug 2012 17:23:17 +0000 Subject: [PATCH 05/17] Updated description of coupled equation usage with a abstract example. git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5259 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/USAGE.txt | 60 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index c85a276627..9666919b16 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -360,13 +360,65 @@ Coupled and Vector Equations Equations can now be coupled together so that the contributions from all the equations appear in a single system matrix. This results in tighter coupling for equations with spatial and temporal derivatives -in more than one variable. The use of coupled equation is described in +in more than one variable. In :term:`FiPy` equations are coupled +together using the ``&`` syntax:: + + >>> eqn0 = ... + >>> eqn1 = ... + >>> coupledEqn = eqn0 & eqn1 + +The ``coupledEqn`` will use a combined system matrix that includes +four quadrants for each of the different variable and equation +combinations. In previous versions of :term:`FiPy` there has been no +need to specify which variable a given term acts on when generating +equations. The variable is simply specified when calling ``solve`` or +``sweep`` and this functionality has been maintained in the case of +single equations. However, for coupled equations the variable that a +given term operates on now needs to be specified when the equation is +generated. The syntax for generating coupled equations has the form:: + + >>> eqn0 = Term00(coeff=..., var=var0) + Term01(coeff..., var=var1) == source0 + >>> eqn1 = Term10(coeff=..., var=var0) + Term11(coeff..., var=var1) == source1 + >>> coupledEqn = eqn1 & eqn2 + +and there is now no need to pass any variables when solving:: + + >>> coupledEqn.solve(dt=..., solver=...) + +In this case the matrix system will have the form + +.. math:: + + \left( + \begin{array}{c|c} + \text{\ttfamily Term00} & \text{\ttfamily Term01} \\ \hline + \text{\ttfamily Term10} & \text{\ttfamily Term11} + \end{array} \right) + \left( + \begin{array}{c} + \text{\ttfamily var0} \\ \hline + \text{\ttfamily var1} + \end{array} \right) + = + \left( + \begin{array}{c} + \text{\ttfamily source0} \\ \hline + \text{\ttfamily source1} + \end{array} \right) + +:term:`FiPy` tries to make sensible decisions regarding each term's +location in the matrix and the ordering of the variable column +array. For example, if ``Term01`` is a transient term then ``Term01`` +would appear in the upper left diagonal and the ordering of the +variable column array would be reversed. + +The use of coupled equation is described in detail in :mod:`examples.diffusion.coupled`. Other examples that demonstrate the use of coupled equations are :mod:`examples.phase.binaryCoupled`, :mod:`examples.phase.polyxtalCoupled` and -:mod:`examples.cahnHilliard.mesh2DCoupled`. As well as coupling equations, -true vector equations can now be written in :term:`FiPy` (see -:mod:`examples.diffusion.coupled` for more details). +:mod:`examples.cahnHilliard.mesh2DCoupled`. As well as coupling +equations, true vector equations can now be written in :term:`FiPy` +(see :mod:`examples.diffusion.coupled` for more details). ---------------------- Running under Python 3 From c719b4d500063e5a6d22bee460895f4670e3e1d5 Mon Sep 17 00:00:00 2001 From: Daniel Wheeler Date: Thu, 2 Aug 2012 19:47:46 +0000 Subject: [PATCH 06/17] Improved and expanded the documentation in the coupled example. git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5260 d80e17d7-ff13-0410-a124-85740d801063 --- examples/diffusion/coupled.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/diffusion/coupled.py b/examples/diffusion/coupled.py index c64fb2b2ac..16b58d8c65 100644 --- a/examples/diffusion/coupled.py +++ b/examples/diffusion/coupled.py @@ -33,29 +33,32 @@ ## r""" -FiPy has only first order time derivatives and so expressions such as the -biharmonic wave equation +:term:`FiPy` has only first order time derivatives so equations such +as the biharmonic wave equation written as .. math:: \frac{\partial^4 v}{\partial x^4} + \frac{\partial^2 v}{\partial t^2} &= 0 -cannot be represented as written. We can decompose this into two equations that are first order in time +cannot be represented as a single equation. We need to decompose the +biharmonic equation into two equations that are first order in time in +the following way, .. math:: \frac{\partial^2 v_0}{\partial x^2} + \frac{\partial v_1}{\partial t} &= 0 \\ \frac{\partial^2 v_1}{\partial x^2} - \frac{\partial v_0}{\partial t} &= 0 -Historically, FiPy required systems of coupled equations to be solved -successively, "sweeping" the equations to convergence. For instance, let's solve the system +Historically, :term:`FiPy` required systems of coupled equations to be +solved successively, "sweeping" the equations to convergence. As a +practical example, we use the following system .. math:: \frac{\partial v_0}{\partial t} &= 0.01 \nabla^2 v_0 - \nabla^2 v_1 \\ \frac{\partial v_1}{\partial t} &= \nabla^2 v_0 + 0.01 \nabla^2 v_1 -subject to the boundary conditions +subject to the boundary conditions .. math:: :nowrap: @@ -65,6 +68,11 @@ v_1|_{x=0} &= 1 & v_1|_{x=1} &= 0 \end{align*} +This system closely resembles the pure biharmonic equation, but has an +additional diffusion contribution to improve numerical stability. The +example system is solved with the following block of code using +explicit coupling for the cross-coupled terms. + >>> from fipy import Grid1D, CellVariable, TransientTerm, DiffusionTerm, Viewer >>> m = Grid1D(nx=100, Lx=1.) @@ -93,9 +101,10 @@ ... if t % 10 == 0: ... vi.plot() -This uncoupled method still works, but it can be advantageous to solve the two -equations simultaneously. In this case, by coupling the equations, we can -eliminate the explicit sources and dramatically increase the time steps: +The uncoupled method still works, but it can be advantageous to solve +the two equations simultaneously. In this case, by coupling the +equations, we can eliminate the explicit sources and dramatically +increase the time steps: >>> v0.value = 0.5 >>> v1.value = 0.5 From 0a0e8a8e999fe683519bc49ff06fad4dcaac594d Mon Sep 17 00:00:00 2001 From: Daniel Wheeler Date: Thu, 2 Aug 2012 19:56:46 +0000 Subject: [PATCH 07/17] Typo in USAGE spotted by Jon. git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5261 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/USAGE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index 9666919b16..dc6463f058 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -379,7 +379,7 @@ generated. The syntax for generating coupled equations has the form:: >>> eqn0 = Term00(coeff=..., var=var0) + Term01(coeff..., var=var1) == source0 >>> eqn1 = Term10(coeff=..., var=var0) + Term11(coeff..., var=var1) == source1 - >>> coupledEqn = eqn1 & eqn2 + >>> coupledEqn = eqn0 & eqn1 and there is now no need to pass any variables when solving:: From c97fb9728aae78d0f8a79770c557a96876a6a007 Mon Sep 17 00:00:00 2001 From: Daniel Wheeler Date: Thu, 2 Aug 2012 20:56:18 +0000 Subject: [PATCH 08/17] Moved the boundary condition discussion out of the FAQ and into the USAGE documentation. git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5262 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/FAQ.txt | 106 +----------------------------------- documentation/USAGE.txt | 118 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 105 deletions(-) diff --git a/documentation/FAQ.txt b/documentation/FAQ.txt index 44692deeb6..c240bdcc02 100644 --- a/documentation/FAQ.txt +++ b/documentation/FAQ.txt @@ -496,111 +496,7 @@ How do I represent boundary conditions? .. currentmodule:: fipy.variables.cellVariable -How do I represent a fixed value (Dirichlet) boundary condition? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Use the :meth:`~CellVariable.constrain` method. For -example, to fix `var` to have a value of `2` along the upper surface of a domain, -use - ->>> var.constrain(2., where=mesh.facesTop) - -.. note:: - - The old equivalent - :class:`~fipy.boundaryConditions.fixedValue.FixedValue` boundary - condition is now deprecated. - -How do I apply a (Neumann) fixed gradient boundary condition? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Use the :attr:`~.CellVariable.faceGrad`.\ :meth:`~fipy.variables.variable.Variable.constrain` -method. For example, to fix `var` to have a gradient of `(0,2)` along the upper -surface of a 2D domain, use - ->>> var.faceGrad.constrain(((0,),(2,)), where=mesh.facesTop) - -How do I apply a fixed flux boundary condition? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Generally this can be implemented with a judicious use of -:attr:`~.CellVariable.faceGrad`.\ :meth:`~fipy.variables.variable.Variable.constrain`. -Failing that, an exterior flux term can be added to the equation. Firstly, -set the terms' coefficients to be zero on the exterior faces, - ->>> diffCoeff.constrain(0., mesh.exteriorFaces) ->>> convCoeff.constrain(0., mesh.exteriorFaces) - -then create an equation with an extra term to account for the exterior flux, - ->>> eqn = (TransientTerm() + ConvectionTerm(convCoeff) -... == DiffusionCoeff(diffCoeff) -... + (mesh.exteriorFaces * exteriorFlux).divergence) - -where `exteriorFlux` is a rank 1 -:class:`~fipy.variables.faceVariable.FaceVariable`. - -.. note:: - - The old equivalent :class:`~fipy.boundaryConditions.fixedFlux.FixedFlux` - boundary condition is now deprecated. - -How do I apply an outlet or inlet boundary condition? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Convection terms default to a no flux boundary condition unless the -exterior faces are associated with a constraint, in which case either -an inlet or an outlet boundary condition is applied depending on the -flow direction. - -How do I apply spatially varying boundary conditions? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The use of spatial varying boundary conditions is best demonstrated with an -example. Given a 2D equation in the domain :math:`0 < x < 1` and :math:`0 < y < 1` with -boundary conditions, - -.. math:: - - \phi = \left\{ - \begin{aligned} - xy &\quad \text{on $x>1/2$ and $y>1/2$} \\ - \vec{n} \cdot \vec{F} = 0 &\quad \text{elsewhere} - \end{aligned} - \right. - -where :math:`\vec{F}` represents the flux. The boundary conditions in :term:`FiPy` can -be written with the following code, - ->>> x, y = mesh.faceCenters ->>> mask = ((x < 0.5) | (y < 0.5)) ->>> var.faceGrad.constrain(0, where=mesh.exteriorFaces & mask) ->>> var.constrain(x * y, where=mesh.exteriorFaces & ~mask) - -then - ->>> eqn.solve(...) - -Further demonstrations of spatially varying boundary condition can be found -in :mod:`examples.diffusion.mesh20x20` -and :mod:`examples.diffusion.circle` - -.. % http://thread.gmane.org/gmane.comp.python.fipy/726 - % http://thread.gmane.org/gmane.comp.python.fipy/846 - - % \subsection{Fourth order boundary conditions} - - % http://thread.gmane.org/gmane.comp.python.fipy/923 - - % \subsection{Periodic boundary conditions} - - % http://thread.gmane.org/gmane.comp.python.fipy/135 - - % \subsection{Time dependent boundary conditions} - - % http://thread.gmane.org/gmane.comp.python.fipy/2 - - % \subsection{Internal boundary conditions} +See the :ref:`BoundaryConditions` section for more details. What does this error message mean? ---------------------------------- diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index dc6463f058..a50c6c6e9f 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -420,6 +420,124 @@ use of coupled equations are :mod:`examples.phase.binaryCoupled`, equations, true vector equations can now be written in :term:`FiPy` (see :mod:`examples.diffusion.coupled` for more details). +.. _BoundaryConditions: + +------------------- +Boundary Conditions +------------------- + +.. currentmodule:: fipy.variables.cellVariable + +Applying Fixed value (Dirichlet) boundary conditions +==================================================== + +To apply a fixed value boundary condition use the +:meth:`~CellVariable.constrain` method. For example, to fix `var` to +have a value of `2` along the upper surface of a domain, use + +>>> var.constrain(2., where=mesh.facesTop) + +.. note:: + + The old equivalent + :class:`~fipy.boundaryConditions.fixedValue.FixedValue` boundary + condition is now deprecated. + +Applying Fixed gradient boundary conditions (Neumann) +===================================================== + +To apply a fixed Gradient boundary condition use the +:attr:`~.CellVariable.faceGrad`.\ +:meth:`~fipy.variables.variable.Variable.constrain` method. For +example, to fix `var` to have a gradient of `(0,2)` along the upper +surface of a 2D domain, use + +>>> var.faceGrad.constrain(((0,),(2,)), where=mesh.facesTop) + +Applying Fixed flux boundary conditions +======================================= + +Generally these can be implemented with a judicious use of +:attr:`~.CellVariable.faceGrad`.\ +:meth:`~fipy.variables.variable.Variable.constrain`. Failing that, an +exterior flux term can be added to the equation. Firstly, set the +terms' coefficients to be zero on the exterior faces, + +>>> diffCoeff.constrain(0., mesh.exteriorFaces) +>>> convCoeff.constrain(0., mesh.exteriorFaces) + +then create an equation with an extra term to account for the exterior flux, + +>>> eqn = (TransientTerm() + ConvectionTerm(convCoeff) +... == DiffusionCoeff(diffCoeff) +... + (mesh.exteriorFaces * exteriorFlux).divergence) + +where `exteriorFlux` is a rank 1 +:class:`~fipy.variables.faceVariable.FaceVariable`. + +.. note:: + + The old equivalent :class:`~fipy.boundaryConditions.fixedFlux.FixedFlux` + boundary condition is now deprecated. + +Applying outlet or inlet boundary conditions +============================================ + +Convection terms default to a no flux boundary condition unless the +exterior faces are associated with a constraint, in which case either +an inlet or an outlet boundary condition is applied depending on the +flow direction. + +Applying spatially varying boundary conditions +============================================== + +The use of spatial varying boundary conditions is best demonstrated with an +example. Given a 2D equation in the domain :math:`0 < x < 1` and :math:`0 < y < 1` with +boundary conditions, + +.. math:: + + \phi = \left\{ + \begin{aligned} + xy &\quad \text{on $x>1/2$ and $y>1/2$} \\ + \vec{n} \cdot \vec{F} = 0 &\quad \text{elsewhere} + \end{aligned} + \right. + +where :math:`\vec{F}` represents the flux. The boundary conditions in :term:`FiPy` can +be written with the following code, + +>>> x, y = mesh.faceCenters +>>> mask = ((x < 0.5) | (y < 0.5)) +>>> var.faceGrad.constrain(0, where=mesh.exteriorFaces & mask) +>>> var.constrain(x * y, where=mesh.exteriorFaces & ~mask) + +then + +>>> eqn.solve(...) + +Further demonstrations of spatially varying boundary condition can be found +in :mod:`examples.diffusion.mesh20x20` +and :mod:`examples.diffusion.circle` + +.. % http://thread.gmane.org/gmane.comp.python.fipy/726 + % http://thread.gmane.org/gmane.comp.python.fipy/846 + + % \subsection{Fourth order boundary conditions} + + % http://thread.gmane.org/gmane.comp.python.fipy/923 + + % \subsection{Periodic boundary conditions} + + % http://thread.gmane.org/gmane.comp.python.fipy/135 + + % \subsection{Time dependent boundary conditions} + + % http://thread.gmane.org/gmane.comp.python.fipy/2 + + % \subsection{Internal boundary conditions} + + ---------------------- Running under Python 3 ---------------------- From fe25eb09246fa376ff6d07e265dbd150eea6dd2f Mon Sep 17 00:00:00 2001 From: Daniel Wheeler Date: Thu, 2 Aug 2012 22:11:39 +0000 Subject: [PATCH 09/17] Updated the usage document to include a discussion of internal boundary conditions and included an example of using a cell variable constraint mistakenly in place of a source term constraint. git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5263 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/USAGE.txt | 69 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index a50c6c6e9f..d85c0ade93 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -428,7 +428,7 @@ Boundary Conditions .. currentmodule:: fipy.variables.cellVariable -Applying Fixed value (Dirichlet) boundary conditions +Applying fixed value (Dirichlet) boundary conditions ==================================================== To apply a fixed value boundary condition use the @@ -443,7 +443,7 @@ have a value of `2` along the upper surface of a domain, use :class:`~fipy.boundaryConditions.fixedValue.FixedValue` boundary condition is now deprecated. -Applying Fixed gradient boundary conditions (Neumann) +Applying fixed gradient boundary conditions (Neumann) ===================================================== To apply a fixed Gradient boundary condition use the @@ -454,7 +454,7 @@ surface of a 2D domain, use >>> var.faceGrad.constrain(((0,),(2,)), where=mesh.facesTop) -Applying Fixed flux boundary conditions +Applying fixed flux boundary conditions ======================================= Generally these can be implemented with a judicious use of @@ -520,6 +520,69 @@ Further demonstrations of spatially varying boundary condition can be found in :mod:`examples.diffusion.mesh20x20` and :mod:`examples.diffusion.circle` +Applying internal boundary conditions +===================================== + +Applying internal boundary conditions can be achieved through the use +of implicit and explicit sources. An equation of the form + +>>> eqn = TransientTerm() == DiffusionTerm() + +can be constrained to have a fixed internal ``value`` at a position +given by ``mask`` with the following alterations + +>>> eqn = TransientTerm() == DiffusionTerm() - ImplicitSourceTerm(mask * largeValue) + mask * largeValue * value + +The parameter ``largeValue`` must be chosen to be large enough to +completely dominate the matrix diagonal and the RHS vector in cells +that are masked. The ``mask`` variable would typically be a +``CellVariable`` boolean constructed using the cell center values. + +One must be careful to distinguish between constraining internal cell +values during the solve step and simply applying arbitrary constraints +to a ``CellVariable``. Applying a constraint, + +>>> var.constrain(value, where=mask) + +simply fixes the returned value of ``var`` at ``mask`` to be +``value``. It does not have any effect on the implicit value of ``var`` at the +``mask`` location during the linear solve so it is not a substitute +for the source term machinations described above. Future releases of +:term:`FiPy` may implicitly deal with this discrepancy, but the current +release does not. A simple example can be used to demonstrate this:: + +>>> m = Grid1D(nx=2, dx=1.) +>>> var = CellVariable(mesh=m) + +Apply a constraint to the faces for a right side boundary condition +(which works). + +>>> var.constrain(1., where=m.facesRight) + +Create the equation with the source term constraint described above + +>>> mask = m.x < 1. +>>> largeValue = 1e+10 +>>> value = 0.25 +>>> eqn = DiffusionTerm() - ImplicitSourceTerm(largeValue * mask) + largeValue * mask * value + +and the expected value is obtained. + +>>> eqn.solve(var) +>>> print var +[ 0.25 0.75] + +However, if a constraint is used without the source term constraint an +unexpected value is obtained + +>>> var.constrain(0.25, where=mask) +>>> eqn = DiffusionTerm() +>>> eqn.solve(var) +>>> print var +[ 0.25 1. ] + +although the left cell has the expected value as it is constrained. + .. % http://thread.gmane.org/gmane.comp.python.fipy/726 % http://thread.gmane.org/gmane.comp.python.fipy/846 From afba0f11a52d075baa1982dfb62905545af5de90 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Mon, 13 Aug 2012 17:23:43 +0000 Subject: [PATCH 10/17] restoring label to correct location git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5291 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/USAGE.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index d85c0ade93..e912d79990 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -324,8 +324,6 @@ you need to do something with the entire solution, you can use Different solvers, different preconditioners, or a less restrictive tolerance may help. -.. _RunningUnderPython3: - ----------------- Meshing with Gmsh ----------------- @@ -600,6 +598,7 @@ although the left cell has the expected value as it is constrained. % \subsection{Internal boundary conditions} +.. _RunningUnderPython3: ---------------------- Running under Python 3 From 9b2fc798724115e9e7f055d10725c926e4eae91c Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Mon, 13 Aug 2012 17:32:17 +0000 Subject: [PATCH 11/17] typos and tweaks git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5292 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/USAGE.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index e912d79990..2b859aa399 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -223,7 +223,7 @@ Solving in Parallel :term:`FiPy` can use :term:`Trilinos` to solve equations in parallel. Most mesh classes in :mod:`fipy.meshes` can solve in -paralled. This includes all "``...Grid...``" and "``...Gmsh...``" +parallel. This includes all "``...Grid...``" and "``...Gmsh...``" class meshes. Currently, the only remaining serial-only meshes are :class:`~fipy.meshes.tri2D.Tri2D` and :class:`~fipy.meshes.skewedGrid2D.SkewedGrid2D`. @@ -359,7 +359,7 @@ Equations can now be coupled together so that the contributions from all the equations appear in a single system matrix. This results in tighter coupling for equations with spatial and temporal derivatives in more than one variable. In :term:`FiPy` equations are coupled -together using the ``&`` syntax:: +together using the ``&`` operator:: >>> eqn0 = ... >>> eqn1 = ... @@ -505,10 +505,10 @@ boundary conditions, where :math:`\vec{F}` represents the flux. The boundary conditions in :term:`FiPy` can be written with the following code, ->>> x, y = mesh.faceCenters ->>> mask = ((x < 0.5) | (y < 0.5)) +>>> X, Y = mesh.faceCenters +>>> mask = ((X < 0.5) | (Y < 0.5)) >>> var.faceGrad.constrain(0, where=mesh.exteriorFaces & mask) ->>> var.constrain(x * y, where=mesh.exteriorFaces & ~mask) +>>> var.constrain(X * Y, where=mesh.exteriorFaces & ~mask) then From 8efb4378648c339a710ce021fb5e0c25a1899b4e Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Tue, 14 Aug 2012 19:06:50 +0000 Subject: [PATCH 12/17] documentation tweaks git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5293 d80e17d7-ff13-0410-a124-85740d801063 --- documentation/FAQ.txt | 16 +++++++--- documentation/USAGE.txt | 2 ++ documentation/numerical/discret.txt | 13 +++----- documentation/numerical/equation.txt | 2 +- documentation/numerical/index.txt | 2 +- documentation/tutorial/index.txt | 2 +- examples/cahnHilliard/mesh2DCoupled.py | 11 +++++-- examples/cahnHilliard/sphere.py | 6 ++-- examples/convection/exponential1D/mesh1D.py | 6 ++-- .../convection/exponential1DSource/mesh1D.py | 2 +- examples/convection/robin.py | 2 +- examples/convection/source.py | 5 +-- examples/diffusion/anisotropy.py | 7 ++--- examples/diffusion/circle.py | 31 ++++++++++--------- examples/diffusion/circleQuad.py | 3 +- examples/diffusion/coupled.py | 5 +-- examples/diffusion/electrostatics.py | 3 +- examples/diffusion/mesh1D.py | 9 +++--- examples/diffusion/mesh20x20.py | 12 +++---- examples/diffusion/mesh20x20Coupled.py | 2 +- .../diffusion/nthOrder/input4thOrder1D.py | 2 +- examples/flow/stokesCavity.py | 2 +- examples/levelSet/advection/circle.py | 3 +- examples/levelSet/advection/mesh1D.py | 3 +- examples/levelSet/distanceFunction/circle.py | 5 ++- examples/levelSet/distanceFunction/mesh1D.py | 4 +-- examples/levelSet/electroChem/gold.py | 3 +- .../levelSet/electroChem/howToWriteAScript.py | 2 +- examples/levelSet/electroChem/leveler.py | 3 +- .../electroChem/simpleTrenchSystem.py | 3 +- examples/phase/anisotropy.py | 3 +- examples/phase/binaryCoupled.py | 3 +- examples/phase/impingement/mesh20x20.py | 2 +- examples/phase/impingement/mesh40x1.py | 2 +- examples/phase/polyxtal.py | 3 +- examples/phase/polyxtalCoupled.py | 3 +- examples/phase/quaternary.py | 3 +- examples/phase/simple.py | 2 +- examples/reactiveWetting/liquidVapor1D.py | 2 +- examples/updating/update0_1to1_0.py | 16 +++++----- examples/updating/update1_0to2_0.py | 30 +++++++++--------- 41 files changed, 132 insertions(+), 108 deletions(-) diff --git a/documentation/FAQ.txt b/documentation/FAQ.txt index c240bdcc02..7979681e62 100644 --- a/documentation/FAQ.txt +++ b/documentation/FAQ.txt @@ -97,7 +97,7 @@ How do I represent a `...` term that *doesn't* involve the dependent variable? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is important to realize that, even though an expression may -superficially resemble one of those shown above, if the dependent variable +superficially resemble one of those shown in :ref:`section:discretization`, if the dependent variable *for that PDE* does not appear in the appropriate place, then that term should be treated as a source. @@ -193,6 +193,12 @@ For :term:`FiPy`'s purposes, however, this term represents the convection of >>> eq = TransientTerm() == (DiffusionTerm(coeff=D1) ... + ConvectionTerm(coeff=D2 * xi.faceGrad)) +.. note:: + + With the advent of :ref:`CoupledEquations` in FiPy 3.x, it is now + possible to represent both terms with + :class:`~fipy.terms.diffusionTerm.DiffusionTerm`. + What if the coefficient of a term depends on the variable that I'm solving for? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -298,7 +304,9 @@ package. The better option is to make a "subclass" of the :term:`FiPy` then override just the behavior you wan to change, while letting :term:`FiPy` do most of the heavy lifting. See :mod:`examples.phase.anisotropy` and :mod:`examples.phase.polyxtal` for examples of creating a custom -:term:`Matplotlib` :class:`Viewer ` class. +:term:`Matplotlib` :class:`Viewer ` class; see +:mod:`examples.cahnHilliard.sphere` for an example of creating a custom +:term:`Mayavi` :class:`Viewer ` class. .. _FAQ-IterationsTimestepsSweeps: @@ -390,7 +398,7 @@ sweeps Sweeps are used to achieve better solutions in :mod:`examples.diffusion.mesh1D`, :mod:`examples.phase.simple`, - :mod:`examples.phase.binary`, and :mod:`examples.flow.stokesCavity`. + :mod:`examples.phase.binaryCoupled`, and :mod:`examples.flow.stokesCavity`. timesteps This outermost layer of repetition is of most practical interest to @@ -436,7 +444,7 @@ timesteps chosen based on the expected interfacial velocity in :mod:`examples.phase.simple`. The timestep is gradually increased as the kinetics slow down in - :mod:`examples.cahnHilliard.mesh2D`. + :mod:`examples.cahnHilliard.mesh2DCoupled`. Finally, we can (and often do) combine all three layers of repetition: diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index 2b859aa399..aea35e28bc 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -351,6 +351,8 @@ parallel including :class:`~fipy.meshes.gmshImport.Gmsh2D` and :term:`FiPy` solution accuracy can be compromised with highly non-orthogonal or non-conjunctional meshes. +.. _CoupledEquations: + ---------------------------- Coupled and Vector Equations ---------------------------- diff --git a/documentation/numerical/discret.txt b/documentation/numerical/discret.txt index 41a41fa9f5..34dc5545bb 100644 --- a/documentation/numerical/discret.txt +++ b/documentation/numerical/discret.txt @@ -182,14 +182,10 @@ This term is represented in :term:`FiPy` as >>> DiffusionTerm(coeff=Gamma1) -which is synonymous with - ->>> ImplicitDiffusionTerm(coeff=Gamma1) - or >>> ExplicitDiffusionTerm(coeff=Gamma1) - + :class:`~explicitDiffusionTerm.ExplicitDiffusionTerm` is provided primarily for illustrative purposes, although :mod:`examples.diffusion.mesh1D` demonstrates its use in Crank-Nicolson time stepping. @@ -272,10 +268,9 @@ equation to a set of discrete linear equations that can then be solved to obtain the value of the dependent variable at each CV center. This results in a sparse linear system that requires an efficient iterative scheme to solve. The iterative schemes available to :term:`FiPy` are -currently encapsulated in the :term:`PySparse` suite of solvers -and include most common solvers such as the conjugate gradient method -and LU decomposition. There are plans to include other solver suites -that are compatible with :term:`Python`. +currently encapsulated in the :term:`PySparse` and :term:`PyTrilinos` +suites of solvers and include most common solvers such as the conjugate +gradient method and LU decomposition. Combining Equations :eq:`num:tra`, :eq:`num:con`, :eq:`num:dif` and :eq:`num:sou`, the complete diff --git a/documentation/numerical/equation.txt b/documentation/numerical/equation.txt index da213e558d..e3356b48dc 100644 --- a/documentation/numerical/equation.txt +++ b/documentation/numerical/equation.txt @@ -21,7 +21,7 @@ Examples of such systems are wide ranging, but include problems that exhibit a combination of diffusing and reacting species, as well as such diverse problems as determination of the electric potential in heart tissue, of fluid flow, stress evolution, and even the -Schr\"odinger equation. +Schroedinger equation. A general conservation equation, solved using :term:`FiPy`, can include any combination of the following terms, diff --git a/documentation/numerical/index.txt b/documentation/numerical/index.txt index 7253e0a763..71193e9cd5 100644 --- a/documentation/numerical/index.txt +++ b/documentation/numerical/index.txt @@ -24,7 +24,7 @@ The FVM can be thought of as a subset of the Finite Element Method system of equations fully equivalent to the FVM can be obtained with the FEM using as weighting functions the characteristic functions of FV cells, i.e., functions equal to unity [Mattiussi:1997]_. Analogously, -the the discretization of equations with the FVM reduces to the FDM on +the discretization of equations with the FVM reduces to the FDM on Cartesian grids. .. toctree:: diff --git a/documentation/tutorial/index.txt b/documentation/tutorial/index.txt index 07e3c4814f..f22a483a16 100644 --- a/documentation/tutorial/index.txt +++ b/documentation/tutorial/index.txt @@ -14,5 +14,5 @@ for their containing package. .. toctree:: :maxdepth: 4 - package/generated/subpackage + package/generated/package.subpackage diff --git a/examples/cahnHilliard/mesh2DCoupled.py b/examples/cahnHilliard/mesh2DCoupled.py index 8767ccd13a..f917d42759 100755 --- a/examples/cahnHilliard/mesh2DCoupled.py +++ b/examples/cahnHilliard/mesh2DCoupled.py @@ -31,7 +31,8 @@ # ################################################################### ## -r""" +r"""Solve the Cahn-Hilliard problem in two dimensions. + The spinodal decomposition phenomenon is a spontaneous separation of an initially homogenous mixture into two distinct regions of different properties (spin-up/spin-down, component A/component B). It is a @@ -171,12 +172,16 @@ has a shape `(2,)` >>> source = (- d2fdphi2 * v0 + dfdphi) * (0, 1) ->>> impCoeff = -d2fdphi2 * ((0, 0), (1., 0)) + ((0, 0), (0, -1.)) +>>> impCoeff = -d2fdphi2 * ((0, 0), +... (1., 0)) + ((0, 0), +... (0, -1.)) This is the same equation as the previous definition of `eq`, but now in a vector format. ->>> eq = TransientTerm(((1., 0.), (0., 0.))) == DiffusionTerm([((0., D), (-epsilon**2, 0.))]) + ImplicitSourceTerm(impCoeff) + source +>>> eq = TransientTerm(((1., 0.), +... (0., 0.))) == DiffusionTerm([((0., D), +... (-epsilon**2, 0.))]) + ImplicitSourceTerm(impCoeff) + source >>> dexp = -5 >>> elapsed = 0. diff --git a/examples/cahnHilliard/sphere.py b/examples/cahnHilliard/sphere.py index f4e7fb19e7..116388f9aa 100755 --- a/examples/cahnHilliard/sphere.py +++ b/examples/cahnHilliard/sphere.py @@ -31,9 +31,9 @@ # ################################################################### ## -r""" -Solves the Cahn-Hilliard problem on the surface of a sphere, such as -may occur on vesicles (http://www.youtube.com/watch?v=kDsFP67_ZSE). +r"""Solves the Cahn-Hilliard problem on the surface of a sphere. + +This phenomenon canoccur on vesicles (http://www.youtube.com/watch?v=kDsFP67_ZSE). >>> from fipy import * diff --git a/examples/convection/exponential1D/mesh1D.py b/examples/convection/exponential1D/mesh1D.py index fd3f8d36ae..dc1a566860 100755 --- a/examples/convection/exponential1D/mesh1D.py +++ b/examples/convection/exponential1D/mesh1D.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve the steady-state convection-diffusion equation in one dimension. This example solves the steady-state convection-diffusion equation given by @@ -41,7 +41,7 @@ \nabla \cdot \left(D \nabla \phi + \vec{u} \phi \right) = 0 -with coefficients :math:`D = 1` and :math:`\vec{u} = (10,)`, or +with coefficients :math:`D = 1` and :math:`\vec{u} = 10\hat{\i}`, or >>> diffCoeff = 1. >>> convCoeff = (10.,) @@ -61,7 +61,7 @@ The solution variable is initialized to ``valueLeft``: ->>> var = CellVariable(mesh=mesh, name = "variable") +>>> var = CellVariable(mesh=mesh, name="variable") and impose the boundary conditions diff --git a/examples/convection/exponential1DSource/mesh1D.py b/examples/convection/exponential1DSource/mesh1D.py index 94dbf34907..dc0e0e382f 100755 --- a/examples/convection/exponential1DSource/mesh1D.py +++ b/examples/convection/exponential1DSource/mesh1D.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve the steady-state convection-diffusion equation with a constant source. Like :mod:`examples.convection.exponential1D.mesh1D` this example solves a steady-state convection-diffusion equation, but adds a constant source, diff --git a/examples/convection/robin.py b/examples/convection/robin.py index dcb9d16591..dc1ac6803e 100644 --- a/examples/convection/robin.py +++ b/examples/convection/robin.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve an advection-diffusion equation with a Robin boundary condition. This example demonstrates how to apply a Robin boundary condition to an advection-diffusion equation. The equation we wish to solve is diff --git a/examples/convection/source.py b/examples/convection/source.py index 705e6db73d..9b5ab4f7c4 100644 --- a/examples/convection/source.py +++ b/examples/convection/source.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve a convection problem with a source. + This example solves the equation .. math:: @@ -44,7 +45,7 @@ implementation of an outflow boundary condition, which is not currently implemented in FiPy. An :class:`~fipy.terms.implicitSourceTerm.ImplicitSourceTerm` object will be used to represent this term. The derivative of :math:`\phi` can be -represented by a :class:`~fipy.terms.abstractConvectionTerm._AbstractConvectionTerm` with a constant unitary velocity +represented by a :class:`~fipy.terms.ConvectionTerm` with a constant unitary velocity field from left to right. The following is an example code that includes a test against the analytical result. diff --git a/examples/diffusion/anisotropy.py b/examples/diffusion/anisotropy.py index afbf042b57..df00d72820 100644 --- a/examples/diffusion/anisotropy.py +++ b/examples/diffusion/anisotropy.py @@ -32,10 +32,9 @@ # ################################################################### ## -r""" +r"""Solve the diffusion equation with an anisotropic diffusion coefficient. -This example demonstrates how to solve diffusion with an anisotropic -coefficient. We wish to solve the problem +We wish to solve the problem .. math:: @@ -86,7 +85,7 @@ >>> import os >>> mesh = Gmsh2D(os.path.splitext(__file__)[0] + '.msh', communicator=serial) # doctest: +GMSH -Set the center most cell to have a value. +Set the centermost cell to have a value. >>> var = CellVariable(mesh=mesh, hasOld=1) # doctest: +GMSH >>> x, y = mesh.cellCenters # doctest: +GMSH diff --git a/examples/diffusion/circle.py b/examples/diffusion/circle.py index db73a9888d..2497285a71 100755 --- a/examples/diffusion/circle.py +++ b/examples/diffusion/circle.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve the diffusion equation in a circular domain meshed with triangles. + This example demonstrates how to solve a simple diffusion problem on a non-standard mesh with varying boundary conditions. The :term:`Gmsh` package is used to create the mesh. Firstly, define some parameters for the @@ -54,20 +55,20 @@ >>> from fipy import * >>> mesh = Gmsh2D(''' -... cellSize = %(cellSize)g; -... radius = %(radius)g; -... Point(1) = {0, 0, 0, cellSize}; -... Point(2) = {-radius, 0, 0, cellSize}; -... Point(3) = {0, radius, 0, cellSize}; -... Point(4) = {radius, 0, 0, cellSize}; -... Point(5) = {0, -radius, 0, cellSize}; -... Circle(6) = {2, 1, 3}; -... Circle(7) = {3, 1, 4}; -... Circle(8) = {4, 1, 5}; -... Circle(9) = {5, 1, 2}; -... Line Loop(10) = {6, 7, 8, 9}; -... Plane Surface(11) = {10}; -... ''' % locals()) # doctest: +GMSH +... cellSize = %(cellSize)g; +... radius = %(radius)g; +... Point(1) = {0, 0, 0, cellSize}; +... Point(2) = {-radius, 0, 0, cellSize}; +... Point(3) = {0, radius, 0, cellSize}; +... Point(4) = {radius, 0, 0, cellSize}; +... Point(5) = {0, -radius, 0, cellSize}; +... Circle(6) = {2, 1, 3}; +... Circle(7) = {3, 1, 4}; +... Circle(8) = {4, 1, 5}; +... Circle(9) = {5, 1, 2}; +... Line Loop(10) = {6, 7, 8, 9}; +... Plane Surface(11) = {10}; +... ''' % locals()) # doctest: +GMSH Using this mesh, we can construct a solution variable diff --git a/examples/diffusion/circleQuad.py b/examples/diffusion/circleQuad.py index dd221a88bd..c0f80e3685 100755 --- a/examples/diffusion/circleQuad.py +++ b/examples/diffusion/circleQuad.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve the diffusion equation in a circular domain meshed with quadrangles. + This example demonstrates how to solve a simple diffusion problem on a non-standard mesh with varying boundary conditions. The :term:`Gmsh` package is used to create the mesh. Firstly, define some parameters for the diff --git a/examples/diffusion/coupled.py b/examples/diffusion/coupled.py index 16b58d8c65..6791caab70 100644 --- a/examples/diffusion/coupled.py +++ b/examples/diffusion/coupled.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve the biharmonic equation as a coupled pair of diffusion equations. + :term:`FiPy` has only first order time derivatives so equations such as the biharmonic wave equation written as @@ -142,7 +143,7 @@ the underlying physics. If :math:`v_0` and :math:`v_1` represent the concentrations of two conserved species, then it is natural to write two seperate governing equations and to couple them. If they represent two -components of vector field, then the vector formulation is obviously more +components of a vector field, then the vector formulation is obviously more natural. FiPy will solve the same matrix system either way. """ __docformat__ = 'restructuredtext' diff --git a/examples/diffusion/electrostatics.py b/examples/diffusion/electrostatics.py index 8b9321a26b..a4fac62047 100755 --- a/examples/diffusion/electrostatics.py +++ b/examples/diffusion/electrostatics.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve the Poisson equation in one dimension. + The Poisson equation is a particular example of the steady-state diffusion equation. We examine a few cases in one dimension. diff --git a/examples/diffusion/mesh1D.py b/examples/diffusion/mesh1D.py index adc5ad698d..497593d777 100755 --- a/examples/diffusion/mesh1D.py +++ b/examples/diffusion/mesh1D.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve a one-dimensional diffusion equation under different conditions. + To run this example from the base :term:`FiPy` directory, type:: $ python examples/diffusion/mesh1D.py @@ -57,7 +58,7 @@ >>> nx = 50 >>> dx = 1. ->>> mesh = Grid1D(nx = nx, dx = dx) +>>> mesh = Grid1D(nx=nx, dx=dx) :term:`FiPy` solves all equations at the centers of the cells of the mesh. We thus need a :class:`~fipy.variables.cellVariable.CellVariable` object to hold the values of the @@ -389,8 +390,8 @@ .. index:: FaceVariable >>> D = FaceVariable(mesh=mesh, value=1.0) ->>> x = mesh.faceCenters[0] ->>> D.setValue(0.1, where=(L / 4. <= x) & (x < 3. * L / 4.)) +>>> X = mesh.faceCenters[0] +>>> D.setValue(0.1, where=(L / 4. <= X) & (X < 3. * L / 4.)) The boundary conditions are a fixed value of diff --git a/examples/diffusion/mesh20x20.py b/examples/diffusion/mesh20x20.py index 6d79f8a125..d81acbdb36 100755 --- a/examples/diffusion/mesh20x20.py +++ b/examples/diffusion/mesh20x20.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve a two-dimensional diffusion problem in a square domain. This example solves a diffusion problem and demonstrates the use of applying boundary condition patches. @@ -68,11 +68,11 @@ to the top-left and bottom-right corners. Neumann boundary conditions are automatically applied to the top-right and bottom-left corners. ->>> x, y = mesh.faceCenters ->>> facesTopLeft = ((mesh.facesLeft & (y > L / 2)) -... | (mesh.facesTop & (x < L / 2))) ->>> facesBottomRight = ((mesh.facesRight & (y < L / 2)) -... | (mesh.facesBottom & (x > L / 2))) +>>> X, Y = mesh.faceCenters +>>> facesTopLeft = ((mesh.facesLeft & (Y > L / 2)) +... | (mesh.facesTop & (X < L / 2))) +>>> facesBottomRight = ((mesh.facesRight & (Y < L / 2)) +... | (mesh.facesBottom & (X > L / 2))) >>> phi.constrain(valueTopLeft, facesTopLeft) >>> phi.constrain(valueBottomRight, facesBottomRight) diff --git a/examples/diffusion/mesh20x20Coupled.py b/examples/diffusion/mesh20x20Coupled.py index 49ee67f2bc..1eb2ff18a1 100755 --- a/examples/diffusion/mesh20x20Coupled.py +++ b/examples/diffusion/mesh20x20Coupled.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve a coupled set of diffusion equations in two dimensions. This example solves a diffusion problem and demonstrates the use of applying boundary condition patches. diff --git a/examples/diffusion/nthOrder/input4thOrder1D.py b/examples/diffusion/nthOrder/input4thOrder1D.py index fd4aa8a80b..ccac613af0 100755 --- a/examples/diffusion/nthOrder/input4thOrder1D.py +++ b/examples/diffusion/nthOrder/input4thOrder1D.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve a fourth-order diffusion problem. This example uses the :class:`~fipy.terms.diffusionTerm.DiffusionTerm` class to solve the equation diff --git a/examples/flow/stokesCavity.py b/examples/flow/stokesCavity.py index a5f2ada8c1..23bad3d406 100755 --- a/examples/flow/stokesCavity.py +++ b/examples/flow/stokesCavity.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve the Navier-Stokes equation in the viscous limit. Many thanks to Benny Malengier for reworking this example and actually making it work correctly...see changeset:3799 diff --git a/examples/levelSet/advection/circle.py b/examples/levelSet/advection/circle.py index 7593cbe45c..da3a32de4b 100755 --- a/examples/levelSet/advection/circle.py +++ b/examples/levelSet/advection/circle.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve a circular distance function equation and then advect it. + This example first imposes a circular distance function: .. math:: diff --git a/examples/levelSet/advection/mesh1D.py b/examples/levelSet/advection/mesh1D.py index 3781fb9976..18a9e3d6d2 100755 --- a/examples/levelSet/advection/mesh1D.py +++ b/examples/levelSet/advection/mesh1D.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r"""Solve the distance function equation in one dimension and then advect it. + This example first solves the distance function equation in one dimension: .. math:: diff --git a/examples/levelSet/distanceFunction/circle.py b/examples/levelSet/distanceFunction/circle.py index ec0fbcc5f6..03f81db867 100755 --- a/examples/levelSet/distanceFunction/circle.py +++ b/examples/levelSet/distanceFunction/circle.py @@ -32,10 +32,9 @@ # ################################################################### ## -r""" +r"""Solve the level set equation in two dimensions for a circle. -Here we solve the level set equation in two dimensions for a circle. The 2D -level set equation can be written, +The 2D level set equation can be written, .. math:: diff --git a/examples/levelSet/distanceFunction/mesh1D.py b/examples/levelSet/distanceFunction/mesh1D.py index 2926429264..ebd7bd4f57 100755 --- a/examples/levelSet/distanceFunction/mesh1D.py +++ b/examples/levelSet/distanceFunction/mesh1D.py @@ -32,9 +32,9 @@ # ################################################################### ## -r""" +r"""Create a level set variable in one dimension. -Here we create a level set variable in one dimension. The level set +The level set variable calculates its value over the domain to be the distance from the zero level set. This can be represented succinctly in the following equation with a boundary condition at the zero level set diff --git a/examples/levelSet/electroChem/gold.py b/examples/levelSet/electroChem/gold.py index 67f78943ee..b371e47339 100644 --- a/examples/levelSet/electroChem/gold.py +++ b/examples/levelSet/electroChem/gold.py @@ -31,7 +31,8 @@ # ################################################################### ## -r""" +r"""Model electrochemical superfill of gold using the CEAC mechanism. + This input file is a demonstration of the use of :term:`FiPy` for modeling gold superfill. The material properties and experimental diff --git a/examples/levelSet/electroChem/howToWriteAScript.py b/examples/levelSet/electroChem/howToWriteAScript.py index c6968f820e..e18d8d4810 100644 --- a/examples/levelSet/electroChem/howToWriteAScript.py +++ b/examples/levelSet/electroChem/howToWriteAScript.py @@ -31,7 +31,7 @@ # ################################################################### ## -r""" +r"""Tutorial for writing an electrochemical superfill script. This input file demonstrates how to create a new superfill script if the existing suite of scripts do diff --git a/examples/levelSet/electroChem/leveler.py b/examples/levelSet/electroChem/leveler.py index 3c98c420e0..57263fc115 100755 --- a/examples/levelSet/electroChem/leveler.py +++ b/examples/levelSet/electroChem/leveler.py @@ -31,7 +31,8 @@ # ################################################################### ## -r""" +r"""Model electrochemical superfill of copper with leveler and accelerator additives. + This input file is a demonstration of the use of :term:`FiPy` for modeling copper superfill with leveler and accelerator additives. The material properties and experimental parameters diff --git a/examples/levelSet/electroChem/simpleTrenchSystem.py b/examples/levelSet/electroChem/simpleTrenchSystem.py index 0d78699d73..587b3a6f8c 100644 --- a/examples/levelSet/electroChem/simpleTrenchSystem.py +++ b/examples/levelSet/electroChem/simpleTrenchSystem.py @@ -31,7 +31,8 @@ # ################################################################### ## -r""" +r"""Model electrochemical superfill using the CEAC mechanism. + This input file is a demonstration of the use of :term:`FiPy` for modeling electrodeposition using the CEAC mechanism. The diff --git a/examples/phase/anisotropy.py b/examples/phase/anisotropy.py index 4b3f48d446..e457aed975 100755 --- a/examples/phase/anisotropy.py +++ b/examples/phase/anisotropy.py @@ -30,7 +30,8 @@ # ################################################################### ## -r""" +r"""Solve a dendritic solidification problem. + To convert a liquid material to a solid, it must be cooled to a temperature below its melting point (known as "undercooling" or "supercooling"). The rate of solidification is often assumed (and experimentally found) to be proportional to the diff --git a/examples/phase/binaryCoupled.py b/examples/phase/binaryCoupled.py index f4627b5dd9..8589e051f4 100755 --- a/examples/phase/binaryCoupled.py +++ b/examples/phase/binaryCoupled.py @@ -32,7 +32,8 @@ # ######################################################################## ## -r""" +r"""Simultaneously solve a phase-field evolution and solute diffusion problem in one-dimension. + It is straightforward to extend a phase field model to include binary alloys. As in :mod:`examples.phase.simple`, we will examine a 1D problem diff --git a/examples/phase/impingement/mesh20x20.py b/examples/phase/impingement/mesh20x20.py index b5302c88f1..a33162fa90 100755 --- a/examples/phase/impingement/mesh20x20.py +++ b/examples/phase/impingement/mesh20x20.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve for the impingement of four grains in two dimensions. In the following examples, we solve the same set of equations as in :mod:`examples.phase.impingement.mesh40x1` diff --git a/examples/phase/impingement/mesh40x1.py b/examples/phase/impingement/mesh40x1.py index d9df63519a..69215a3a65 100755 --- a/examples/phase/impingement/mesh40x1.py +++ b/examples/phase/impingement/mesh40x1.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve for the impingement of two grains in one dimension. In this example we solve a coupled phase and orientation equation on a one dimensional grid. This is another aspect of the model of Warren, Kobayashi, diff --git a/examples/phase/polyxtal.py b/examples/phase/polyxtal.py index b603bac64d..f20a6b353c 100755 --- a/examples/phase/polyxtal.py +++ b/examples/phase/polyxtal.py @@ -30,7 +30,8 @@ # ################################################################### ## -r""" +r"""Solve the dendritic growth of nuclei and subsequent grain impingement. + To convert a liquid material to a solid, it must be cooled to a temperature below its melting point (known as "undercooling" or "supercooling"). The rate of solidification is often assumed (and experimentally found) to be proportional to the diff --git a/examples/phase/polyxtalCoupled.py b/examples/phase/polyxtalCoupled.py index 583e671349..ec86cd34c0 100755 --- a/examples/phase/polyxtalCoupled.py +++ b/examples/phase/polyxtalCoupled.py @@ -30,7 +30,8 @@ # ################################################################### ## -r""" +r"""Simultaneously solve the dendritic growth of nuclei and subsequent grain impingement. + To convert a liquid material to a solid, it must be cooled to a temperature below its melting point (known as "undercooling" or "supercooling"). The rate of solidification is often assumed (and experimentally found) to be proportional to the diff --git a/examples/phase/quaternary.py b/examples/phase/quaternary.py index 3384c7d3bd..2a9142bce5 100755 --- a/examples/phase/quaternary.py +++ b/examples/phase/quaternary.py @@ -32,7 +32,8 @@ # ################################################################### ## -r""" +r""" Solve a phase-field evolution and diffusion of four species in one-dimension. + The same procedure used to construct the two-component phase field diffusion problem in :mod:`examples.phase.binary` can be used to build up a system of multiple components. Once again, we'll focus on 1D. diff --git a/examples/phase/simple.py b/examples/phase/simple.py index f87aa8f2d8..4e9c37faf1 100755 --- a/examples/phase/simple.py +++ b/examples/phase/simple.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve a phase-field (Allen-Cahn) problem in one-dimension. To run this example from the base FiPy directory, type ``python examples/phase/simple/input.py`` at the command line. A viewer diff --git a/examples/reactiveWetting/liquidVapor1D.py b/examples/reactiveWetting/liquidVapor1D.py index 2dd453c298..f72b0323e1 100755 --- a/examples/reactiveWetting/liquidVapor1D.py +++ b/examples/reactiveWetting/liquidVapor1D.py @@ -32,7 +32,7 @@ # ################################################################### ## -r""" +r"""Solve a single-component, liquid-vapor, van der Waals system. This example solves a single-component, liquid-vapor, van der Waals system as described by Wheeler et *al.* [PhysRevE.82.051601]_. The free energy for this diff --git a/examples/updating/update0_1to1_0.py b/examples/updating/update0_1to1_0.py index 87f1d7ad42..34210dd7d9 100755 --- a/examples/updating/update0_1to1_0.py +++ b/examples/updating/update0_1to1_0.py @@ -30,7 +30,7 @@ # ################################################################### ## -r""" +r"""How to update scripts from version 0.1 to 1.0. It seems unlikely that many users are still running :term:`FiPy` 0.1, but for those that are, the syntax of :term:`FiPy` scripts changed considerably between version 0.1 @@ -90,10 +90,10 @@ >>> from fipy.boundaryConditions.fixedValue import FixedValue >>> from fipy.boundaryConditions.fixedFlux import FixedFlux >>> boundaryConditions = ( -... FixedValue(mesh.facesLeft, valueLeft), -... FixedValue(mesh.facesRight, valueRight), -... FixedFlux(mesh.facesTop, 0.), -... FixedFlux(mesh.facesBottom, 0.) +... FixedValue(mesh.getFacesLeft(), valueLeft), +... FixedValue(mesh.getFacesRight(), valueRight), +... FixedFlux(mesh.getFacesTop(), 0.), +... FixedFlux(mesh.getFacesBottom(), 0.) ... ) The solution variable is initialized to `valueLeft`: @@ -161,7 +161,7 @@ .. index:: numerix >>> axis = 0 ->>> x = mesh.cellCenters[:,axis] +>>> x = mesh.getCellCenters()[:,axis] >>> from fipy.tools import numerix >>> CC = 1. - numerix.exp(-convCoeff[axis] * x / diffCoeff) >>> DD = 1. - numerix.exp(-convCoeff[axis] * L / diffCoeff) @@ -227,8 +227,8 @@ >>> valueRight = 1. >>> from fipy.boundaryConditions.fixedValue import FixedValue >>> boundaryConditions = ( -... FixedValue(mesh.facesLeft, valueLeft), -... FixedValue(mesh.facesRight, valueRight)) +... FixedValue(mesh.getFacesLeft(), valueLeft), +... FixedValue(mesh.getFacesRight(), valueRight)) The creation of the solution variable is unchanged: diff --git a/examples/updating/update1_0to2_0.py b/examples/updating/update1_0to2_0.py index 66868c3b76..a73a650a72 100644 --- a/examples/updating/update1_0to2_0.py +++ b/examples/updating/update1_0to2_0.py @@ -55,21 +55,21 @@ * The dimension axis of a :class:`~fipy.variables.variable.Variable` is now first, not last - >>> x = mesh.cellCenters[0] + >>> x = mesh.getCellCenters()[0] instead of - >>> x = mesh.cellCenters[...,0] + >>> x = mesh.getCellCenters()[...,0] This seemingly arbitrary change simplifies a great many things in :term:`FiPy`, but the one most noticeable to the user is that you can now write - >>> x, y = mesh.cellCenters + >>> x, y = mesh.getCellCenters() instead of - >>> x = mesh.cellCenters[...,0] - >>> y = mesh.cellCenters[...,1] + >>> x = mesh.getCellCenters()[...,0] + >>> y = mesh.getCellCenters()[...,1] Unfortunately, we cannot reliably automate this conversion, but we find that searching for "``...,``" and "``:,``" finds almost everything. Please don't @@ -110,12 +110,12 @@ Because vector fields are properly supported, use vector operations to manipulate them, such as - >>> phase.faceGrad.dot((( 0, 1), + >>> phase.getFaceGrad().dot((( 0, 1), ... (-1, 0))) instead of the hackish - >>> phase.faceGrad._take((1, 0), axis=1) * (-1, 1) + >>> phase.getFaceGrad()._take((1, 0), axis=1) * (-1, 1) * For internal reasons, :term:`FiPy` now supports :class:`~fipy.variables.cellVariable.CellVariable` and @@ -137,13 +137,13 @@ :class:`~fipy.boundaryConditions.boundaryCondition.BoundaryCondition` now takes a mask, instead of a list of :class:`~fipy.meshes.face.Face` IDs. Now you write - >>> X, Y = mesh.faceCenters - >>> FixedValue(faces=mesh.exteriorFaces & (X**2 < 1e-6), value=...) + >>> X, Y = mesh.getFaaceCenters() + >>> FixedValue(faces=mesh.getExteriorFaces() & (X**2 < 1e-6), value=...) instead of - >>> exteriorFaces = mesh.exteriorFaces - >>> X = exteriorFaces.centers[...,0] + >>> exteriorFaces = mesh.getExteriorFaces() + >>> X = exteriorFaces.getCenters()[...,0] >>> FixedValue(faces=exteriorFaces.where(X**2 < 1e-6), value=...) With the old syntax, a different call to @@ -152,11 +152,11 @@ difficult to specify boundary conditions that depended both on position in space and on the current values of any other :class:`~fipy.variables.variable.Variable`. - >>> FixedValue(faces=(mesh.exteriorFaces + >>> FixedValue(faces=(mesh.getExteriorFaces() ... & (((X**2 < 1e-6) ... & (Y > 3.)) - ... | (phi.arithmeticFaceValue - ... < sin(gamma.arithmeticFaceValue)))), value=...) + ... | (phi.getArithmeticFaceValue() + ... < sin(gamma.getArithmeticFaceValue())))), value=...) although it probably could have been done with a rather convoluted (and slow!) ``filter`` function passed to ``where``. There no longer are any ``filter`` @@ -177,7 +177,7 @@ >>> for cell in positiveCells: ... initialArray[cell.ID] = 1. - Although they still exist, we find very lille cause to ever call + Although they still exist, we find very little cause to ever call :meth:`~fipy.meshes.mesh.Mesh.getCells` or :meth:`fipy.meshes.mesh.Mesh.getFaces`. From d09a67970af19145ed2217d4eabc3a3dda01bb81 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Tue, 14 Aug 2012 20:03:03 +0000 Subject: [PATCH 13/17] how to update git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5294 d80e17d7-ff13-0410-a124-85740d801063 --- examples/updating/update2_0to3_0.py | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/examples/updating/update2_0to3_0.py b/examples/updating/update2_0to3_0.py index 5728fcb463..007a6ec88a 100644 --- a/examples/updating/update2_0to3_0.py +++ b/examples/updating/update2_0to3_0.py @@ -69,7 +69,40 @@ .. note:: the old behavior can be obtained, at least for now, by setting the :envvar:`FIPY_INCLUDE_NUMERIX_ALL` environment variable. + + * If your equation contains a :class:`~fipy.terms.transientTerm.TransientTerm`, + then you must specify the timestep by passing a ``dt=`` argument when calling + :meth:`~fipy.terms.term.Term.solve` or :meth:`~fipy.terms.term.Term.sweep`. +The remaining changes are not *required*, but they make scripts easier to read +and we recommend them. :term:`FiPy` may issue a :exc:`DeprecationWarning` for some cases, +to indicate that we may not maintain the old syntax indefinitely. + + * "getter" and "setter" methods have been replaced with properties, e.g., use + + >>> x, y = mesh.cellCenters + + instead of + + >>> x, y = mesh.getCellCenters() + + * Boundary conditions are better applied with the + :meth:`~fipy.variables.cellVariable.CellVariable.constrain` method than with + the old :class:`~fipy.boundaryConditions.fixedValue.FixedValue` and + :class:`~fipy.boundaryConditions.fixedFlux.FixedFlux` classes. See + :ref:`_BoundaryConditions`. + + * Individual :class:`~fipy.meshes.mesh.Mesh` classes should be imported + directly from :mod:`fipy.meshes` and not :mod:`fipy.meshes.numMesh`. + + * The :term:`Gmsh` meshes now have simplified names: + :class:`~fipy.meshes.gmshMesh.Gmsh2D` instead of + :class:`~fipy.meshes.gmshMesh.GmshImporter2D`, + :class:`~fipy.meshes.gmshMesh.Gmsh3D` instead of + :class:`~fipy.meshes.gmshMesh.GmshImporter3D`, and + :class:`~fipy.meshes.gmshMesh.Gmsh2DIn3DSpace` instead of + :class:`~fipy.meshes.gmshMesh.GmshImporter2DIn3DSpace`. + .. _mailing list: http://www.ctcms.nist.gov/fipy/mail.html """ __docformat__ = 'restructuredtext' From 58ae9d405a29fd614254185eef550349c2a26a6a Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Tue, 14 Aug 2012 20:22:02 +0000 Subject: [PATCH 14/17] what's new git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5295 d80e17d7-ff13-0410-a124-85740d801063 --- INSTALLATION.txt | 4 +--- README.txt | 18 +++++++++++++++--- documentation/USAGE.txt | 10 ++++++---- examples/updating/update2_0to3_0.py | 2 +- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/INSTALLATION.txt b/INSTALLATION.txt index 6d24c0ff87..4f42ac5f5c 100644 --- a/INSTALLATION.txt +++ b/INSTALLATION.txt @@ -168,10 +168,8 @@ If necessary, you can download_ and install it for your platform .. note:: :term:`FiPy` requires at least version 2.4.x of :term:`Python`. See - :ref:`RunningUnderPython3` for instructions on how to run - :term:`FiPy` with `Python 3.x`_. + the specialized instructions if you wish to :ref:`RunUnderPython3`. -.. _Python 3.x: http://www.nist.gov/cgi-bin/exit_nist.cgi?url=http://docs.python.org/py3k/ .. _download: http://www.nist.gov/cgi-bin/exit_nist.cgi?url=http://www.python.org/download/ :term:`Python` along with many of :term:`FiPy`'s required and optional diff --git a/README.txt b/README.txt index 2f5c6fdf26..33a31daf8e 100644 --- a/README.txt +++ b/README.txt @@ -54,12 +54,24 @@ necessary. The significant changes since version 2.1 are: -- Tests can now be run on a full install using `fipy.test()`. -- Grid classes now take an `Lx` argument. +- :ref:`CoupledEquations` are now supported. +- A more robust mechanism for specifying :ref:`BoundaryConditions` is now + used. +- Most :class:`~fipy.meshes.mesh.Mesh`\es can be partitioned by + :ref:`MeshingWithGmsh`. +- "getter" and "setter" methods have been pervasively changed to Python + properties. +- :ref:`PYAMG` and :ref:`SCIPY` have been added to the :ref:`SOLVERS`. +- FiPy can :ref:`RunUnderPython3`. - The functions of the :mod:`~fipy.tools.numerix` module are no longer included in the :mod:`fipy` namespace. See :mod:`examples.updating.update2_0to3_0` for details. -- Support for Python 3. Please see :ref:`RunningUnderPython3` for details. +- The test suite now runs much faster. +- Tests can now be run on a full install using `fipy.test()`. +- Grid classes now take an `Lx` argument. +- Equations containing a :class:`~fipy.terms.transientTerm.TransientTerm`, + must specify the timestep by passing a ``dt=`` argument when calling + :meth:`~fipy.terms.term.Term.solve` or :meth:`~fipy.terms.term.Term.sweep`. Tickets fixed in this release:: diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index aea35e28bc..d263af43a3 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -324,6 +324,8 @@ you need to do something with the entire solution, you can use Different solvers, different preconditioners, or a less restrictive tolerance may help. +.. _MeshingWithGmsh: + ----------------- Meshing with Gmsh ----------------- @@ -600,11 +602,11 @@ although the left cell has the expected value as it is constrained. % \subsection{Internal boundary conditions} -.. _RunningUnderPython3: +.. _RunUnderPython3: ----------------------- -Running under Python 3 ----------------------- +------------------ +Run under Python 3 +------------------ It is possible to run :term:`FiPy` scripts under :term:`Python 3`, but there is admittedly little advantage in doing so at this time. We still diff --git a/examples/updating/update2_0to3_0.py b/examples/updating/update2_0to3_0.py index 007a6ec88a..06d75eff66 100644 --- a/examples/updating/update2_0to3_0.py +++ b/examples/updating/update2_0to3_0.py @@ -90,7 +90,7 @@ :meth:`~fipy.variables.cellVariable.CellVariable.constrain` method than with the old :class:`~fipy.boundaryConditions.fixedValue.FixedValue` and :class:`~fipy.boundaryConditions.fixedFlux.FixedFlux` classes. See - :ref:`_BoundaryConditions`. + :ref:`BoundaryConditions`. * Individual :class:`~fipy.meshes.mesh.Mesh` classes should be imported directly from :mod:`fipy.meshes` and not :mod:`fipy.meshes.numMesh`. From d1181dd2f1f42bc4f85154704ca20308bb06da94 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Thu, 16 Aug 2012 14:36:33 +0000 Subject: [PATCH 15/17] minor tweaks git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5297 d80e17d7-ff13-0410-a124-85740d801063 --- README.txt | 6 +++--- documentation/USAGE.txt | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.txt b/README.txt index 33a31daf8e..987f3402d9 100644 --- a/README.txt +++ b/README.txt @@ -59,16 +59,16 @@ The significant changes since version 2.1 are: used. - Most :class:`~fipy.meshes.mesh.Mesh`\es can be partitioned by :ref:`MeshingWithGmsh`. +- :ref:`PYAMG` and :ref:`SCIPY` have been added to the :ref:`SOLVERS`. +- FiPy is capable of :ref:`RunningUnderPython3`. - "getter" and "setter" methods have been pervasively changed to Python properties. -- :ref:`PYAMG` and :ref:`SCIPY` have been added to the :ref:`SOLVERS`. -- FiPy can :ref:`RunUnderPython3`. - The functions of the :mod:`~fipy.tools.numerix` module are no longer included in the :mod:`fipy` namespace. See :mod:`examples.updating.update2_0to3_0` for details. - The test suite now runs much faster. - Tests can now be run on a full install using `fipy.test()`. -- Grid classes now take an `Lx` argument. +- `Grid` meshes now take `Lx`, `Ly`, and `Lz` arguments. - Equations containing a :class:`~fipy.terms.transientTerm.TransientTerm`, must specify the timestep by passing a ``dt=`` argument when calling :meth:`~fipy.terms.term.Term.solve` or :meth:`~fipy.terms.term.Term.sweep`. diff --git a/documentation/USAGE.txt b/documentation/USAGE.txt index d263af43a3..c6942b68d1 100644 --- a/documentation/USAGE.txt +++ b/documentation/USAGE.txt @@ -602,11 +602,11 @@ although the left cell has the expected value as it is constrained. % \subsection{Internal boundary conditions} -.. _RunUnderPython3: +.. _RunningUnderPython3: ------------------- -Run under Python 3 ------------------- +---------------------- +Running under Python 3 +---------------------- It is possible to run :term:`FiPy` scripts under :term:`Python 3`, but there is admittedly little advantage in doing so at this time. We still From d24d16fa2724985a6f18c7dbfe73cbadcad17570 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Thu, 16 Aug 2012 14:52:42 +0000 Subject: [PATCH 16/17] tweaks to recent changes git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5298 d80e17d7-ff13-0410-a124-85740d801063 --- README.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.txt b/README.txt index 987f3402d9..5f8e0c4f82 100644 --- a/README.txt +++ b/README.txt @@ -63,12 +63,11 @@ The significant changes since version 2.1 are: - FiPy is capable of :ref:`RunningUnderPython3`. - "getter" and "setter" methods have been pervasively changed to Python properties. +- The test suite now runs much faster. +- Tests can now be run on a full install using `fipy.test()`. - The functions of the :mod:`~fipy.tools.numerix` module are no longer included in the :mod:`fipy` namespace. See :mod:`examples.updating.update2_0to3_0` for details. -- The test suite now runs much faster. -- Tests can now be run on a full install using `fipy.test()`. -- `Grid` meshes now take `Lx`, `Ly`, and `Lz` arguments. - Equations containing a :class:`~fipy.terms.transientTerm.TransientTerm`, must specify the timestep by passing a ``dt=`` argument when calling :meth:`~fipy.terms.term.Term.solve` or :meth:`~fipy.terms.term.Term.sweep`. From df597ce3b385cb9e81bb091957174bc69ab885c8 Mon Sep 17 00:00:00 2001 From: "Jonathan E. Guyer" Date: Thu, 16 Aug 2012 15:34:34 +0000 Subject: [PATCH 17/17] tickets fixed git-svn-id: svn+ssh://code.matforge.org/fipy/branches/documentation@5299 d80e17d7-ff13-0410-a124-85740d801063 --- README.txt | 75 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 10 deletions(-) diff --git a/README.txt b/README.txt index 5f8e0c4f82..ed1fa20656 100644 --- a/README.txt +++ b/README.txt @@ -74,16 +74,71 @@ The significant changes since version 2.1 are: Tickets fixed in this release:: - 171 update the mayavi viewer to use mayavi 2 - 286 'matplotlib: list index out of range' when no title given, but only sometimes - 197 ~binOp doesn't work on branches/version-2_0 - 194 `easy_install` instructions for MacOSX are broken - 192 broken setuptools url with python 2.6 - 184 The FiPy webpage seems to be broken on Internet Explorer - 168 Switch documentation to use `:math:` directive - 198 FiPy2.0.2 LinearJORSolver.__init__ calls Solver rather than PysparseSolver - 199 `gmshExport.exportAsMesh()` doesn't work - 195 broken arithmetic face to cell distance calculations + 45 Navier Stokes + 85 CellVariable hasOld() should set self.old + 101 Grids should take Lx, Ly, Lz arguments + 145 tests should be run with fipy.tests() + 177 remove ones and zeros from numerix.py + 178 Default time steps should be infinite + 291 term multiplication changes result + 296 FAQ gives bad guidance for anisotropic diffusion + 297 Use physical velocity in the manual/FAQ + 298 mesh manipulation of periodic meshes leads to errors + 299 Give helpfull error on - or / of meshes + 301 wrong cell to cell normal in periodic meshes + 302 gnuplot1d gives error on plot of facevariable + 309 pypi is failing + 312 Fresh FiPy gives ""ImportError: No viewers found""" + 314 Absence of enthought.tvtk causes test failures + 319 mesh in FiPy name space + 324 --pysparse configuration should never attempt MPI imports + 327 factoryMeshes.py not up to date with respect to keyword arguments + 331 changed constraints don't propagate + 332 anisotropic diffusion and constraints don't mix + 333 `--Trilinos --no-pysparse` uses PySparse?!? + 336 Profile and merge reconstrain branch + 339 close out reconstrain branch + 341 Fix fipy.terms._BinaryTerm test failure in parallel + 343 diffusionTerm(var=var1).solver(var=var0) should fail sensibly + 346 TeX is wrong in examples.phase.quaternary + 348 Include Benny's improved interpolation patch + 354 GmshExport is not tested and does not work + 355 Introduce mesh.x as shorthand for mesh.cellCenters[0] etc + 356 GmshImport should support all element types + 357 GmshImport should read element colors + 363 Reduce the run times for chemotaxis tests + 366 tests take *too* long!!! + 369 Make DiffusionTermNoCorrection the default + 370 Epetra Norm2 failure in parallel + 373 remove deprecated `steps=` from Solver + 376 remove deprecated `diffusionTerm=` argument to ConvectionTerm + 377 remove deprecated `NthOrderDiffusionTerm` + 380 remove deprecated Variable.transpose() + 381 remove deprecated viewers.make() + 382 get running in Py3k + 384 gmsh importer and gmsh tests don't clean up after themselves + 385 `diffusionTerm._test()` requires PySparse + 390 Improve test reporting to avoid inconsequential buildbot failures + 391 efficiency_test chokes on liquidVapor2D.py + 393 two `--scipy` failures + 395 `--pysparse --inline` failures + 417 Memory consumption growth with repeated meshing, especially with Gmsh + 418 Viewers not working when plotting meshes with zero cells in parallel + 419 examples/cahnHilliard/mesh2D.py broken with --trilinos + 420 Epetra.PyComm() broken on Debian + 421 cellVariable.min() broken in parallel + 426 Add in parallel buildbot testing on more than 2 processors + 427 Slow PyAMG solutions + 434 Gmsh I/O + 438 changes to gmshImport.py caused --inline problems + 439 gmshImport tests fail on Windows due to shared file + 441 Explicit convetion terms should fail when the equation has no TransientTerm (dt=None) + 445 getFaceCenters() should return a FaceVariable + 446 constraining values with ImplictSourceTerm not documented? + 448 Gmsh2D does not respect background mesh + 452 Gmsh background mesh doesn't work in parallel + 453 faceValue as FaceCenters gives inline failures + 454 Py3k and Windows test failures .. warning::