examples.updating package¶
Submodules¶
examples.updating.update0_1to1_0 module¶
How to update scripts from version 0.1 to 1.0.
It seems unlikely that many users are still running FiPy 0.1, but for those that are, the syntax of FiPy scripts changed considerably between version 0.1 and version 1.0. We incremented the full version-number to stress that previous scripts are incompatible. We strongly believe that these changes are for the better, resulting in easier code to write and read as well as slightly improved efficiency, but we realize that this represents an inconvenience to our users that have already written scripts of their own. We will strive to avoid any such incompatible changes in the future.
Any scripts you have written for FiPy 0.1 should be updated in two steps,
first to work with FiPy 1.0, and then with FiPy 2.0. As a tutorial for
updating your scripts, we will walk through updating
examples/convection/exponential1D/input.py from FiPy 0.1. If you attempt to
run that script with FiPy 1.0, the script will fail and you will see the
errors shown below:
This example solves the steady-state convection-diffusion equation given by:
with coefficients and
, or
>>> diffCoeff = 1.
>>> convCoeff = (10., 0.)
We define a 1D mesh
>>> L = 10.
>>> nx = 1000
>>> ny = 1
>>> from fipy.meshes.grid2D import Grid2D
>>> mesh = Grid2D(L / nx, L / ny, nx, ny)
and impose the boundary conditions
or
>>> valueLeft = 0.
>>> valueRight = 1.
>>> from fipy.boundaryConditions.fixedValue import FixedValue
>>> from fipy.boundaryConditions.fixedFlux import FixedFlux
>>> boundaryConditions = (
... FixedValue(mesh.getFacesLeft(), valueLeft),
... FixedValue(mesh.getFacesRight(), valueRight),
... FixedFlux(mesh.getFacesTop(), 0.),
... FixedFlux(mesh.getFacesBottom(), 0.)
... )
The solution variable is initialized to valueLeft:
>>> from fipy.variables.cellVariable import CellVariable
>>> var = CellVariable(
... name = "concentration",
... mesh = mesh,
... value = valueLeft)
The SteadyConvectionDiffusionScEquation object is
used to create the equation. It needs to be passed a convection term
instantiator as follows:
>>> from fipy.terms.exponentialConvectionTerm import ExponentialConvectionTerm
>>> from fipy.solvers import *
>>> from fipy.equations.stdyConvDiffScEquation import SteadyConvectionDiffusionScEquation
Traceback (most recent call last):
...
ImportError: No module named equations.stdyConvDiffScEquation
>>> eq = SteadyConvectionDiffusionScEquation(
... var = var,
... diffusionCoeff = diffCoeff,
... convectionCoeff = convCoeff,
... solver = LinearLUSolver(tolerance = 1.e-15, steps = 2000),
... convectionScheme = ExponentialConvectionTerm,
... boundaryConditions = boundaryConditions
... )
Traceback (most recent call last):
...
NameError: name 'SteadyConvectionDiffusionScEquation' is not defined
More details of the benefits and drawbacks of each type of convection
term can be found in the numerical section of the manual. Essentially
the ExponentialConvectionTerm and PowerLawConvectionTerm will both
handle most types of convection diffusion cases with the
PowerLawConvectionTerm being more efficient.
We iterate to equilibrium
>>> from fipy.iterators.iterator import Iterator
>>> it = Iterator((eq,))
Traceback (most recent call last):
...
NameError: name 'eq' is not defined
>>> it.timestep()
Traceback (most recent call last):
...
NameError: name 'it' is not defined
and test the solution against the analytical result
or
>>> axis = 0
>>> 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)
>>> analyticalArray = CC / DD
>>> numerix.allclose(analyticalArray, var, rtol = 1e-10, atol = 1e-10)
0
If the problem is run interactively, we can view the result:
>>> if __name__ == '__main__':
... from fipy.viewers.grid2DGistViewer import Grid2DGistViewer
Traceback (most recent call last):
...
ImportError: No module named grid2DGistViewer
... viewer = Grid2DGistViewer(var)
... viewer.plot()
We see that a number of errors are thrown:
ImportError: No module named equations.stdyConvDiffScEquation
NameError: name 'SteadyConvectionDiffusionScEquation' is not defined
NameError: name 'eq' is not defined
NameError: name 'it' is not defined
ImportError: No module named grid2DGistViewer
As is usually the case with computer programming, many of these errors are caused by earlier errors. Let us update the script, section by section:
Although no error was generated by the use of Grid2D, FiPy 1.0 supports
a true 1D mesh class, so we instantiate the mesh as
>>> L = 10.
>>> nx = 1000
>>> from fipy.meshes.grid1D import Grid1D
>>> mesh = Grid1D(dx = L / nx, nx = nx)
The Grid2D class with ny = 1 still works perfectly well for 1D
problems, but the Grid1D class is slightly more efficient, and it makes
the code clearer when a 1D geometry is actually desired.
Because the mesh is now 1D, we must update the convection coefficient vector to be 1D as well
>>> diffCoeff = 1.
>>> convCoeff = (10.,)
The FixedValue boundary conditions at the left and right are unchanged,
but a Grid1D mesh does not even have top and bottom faces:
>>> valueLeft = 0.
>>> valueRight = 1.
>>> from fipy.boundaryConditions.fixedValue import FixedValue
>>> boundaryConditions = (
... FixedValue(mesh.getFacesLeft(), valueLeft),
... FixedValue(mesh.getFacesRight(), valueRight))
The creation of the solution variable is unchanged:
>>> from fipy.variables.cellVariable import CellVariable
>>> var = CellVariable(name = "concentration",
... mesh = mesh,
... value = valueLeft)
The biggest change between FiPy 0.1 and FiPy 1.0 is that Equation
objects no longer exist at all. Instead, Term objects can be simply
added, subtracted, and equated to assemble an equation. Where before the
assembly of the equation occurred in the black-box of
SteadyConvectionDiffusionScEquation, we now assemble it directly:
>>> from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm
>>> diffTerm = ImplicitDiffusionTerm(coeff = diffCoeff)
>>> from fipy.terms.exponentialConvectionTerm import ExponentialConvectionTerm
>>> eq = diffTerm + ExponentialConvectionTerm(coeff = convCoeff,
... diffusionTerm = diffTerm)
One thing that SteadyConvectionDiffusionScEquation took care of
automatically was that a ConvectionTerm must know about any
DiffusionTerm in the equation in order to calculate a Péclet number.
Now, the DiffusionTerm must be explicitly passed to the ConvectionTerm
in the diffusionTerm parameter.
The Iterator class still exists, but it is no longer necessary. Instead,
the solution to an implicit steady-state problem like this can simply be
obtained by telling the equation to solve itself (with an appropriate
solver if desired, although the default LinearPCGSolver is usually
suitable):
>>> from fipy.solvers import *
>>> eq.solve(var = var,
... solver = LinearLUSolver(tolerance = 1.e-15, steps = 2000),
... boundaryConditions = boundaryConditions)
Note
In version 0.1, the Equation object had to be
told about the Variable, Solver,
and BoundaryCondition objects
when it was created (and it, in turn, passed much of this information to
the Term objects in order to create them). In version
1.0, the Term objects (and the equation assembled
from them) are abstract.
The Variable, Solver,
and BoundaryCondition objects
are only needed by the solve() method (and, in fact, the same equation
could be used to solve different variables, with different solvers, subject
to different boundary conditions, if desired).
The analytical solution is unchanged, and we can test as before
>>> numerix.allclose(analyticalArray, var, rtol = 1e-10, atol = 1e-10)
1
or we can use the slightly simpler syntax
>>> print(var.allclose(analyticalArray, rtol = 1e-10, atol = 1e-10))
1
The ImportError: No module named grid2DGistViewer results because the
Viewer classes have been moved and renamed. This error could be resolved
by changing the import statement appropriately:
>>> if __name__ == '__main__':
... from fipy.viewers.gistViewer.gist1DViewer import Gist1DViewer
... viewer = Gist1DViewer(vars = var)
... viewer.plot()
Instead, rather than instantiating a particular Viewer (which you can
still do, if you desire), a generic “factory” method will return a Viewer
appropriate for the supplied Variable object(s):
>>> if __name__ == '__main__':
... import fipy.viewers
... viewer = fipy.viewers.make(vars = var)
... viewer.plot()
Please do not hesitate to contact us if this example does not help you convert your existing scripts to FiPy 1.0.
examples.updating.update1_0to2_0 module¶
How to update scripts from version 1.0 to 2.0.
FiPy 2.0 introduces several syntax changes from FiPy 1.0. We appreciate that this is very inconvenient for our users, but we hope you’ll agree that the new syntax is easier to read and easier to use. We assure you that this is not something we do casually; it has been over three years since our last incompatible change (when FiPy 1.0 superceded FiPy 0.1).
All examples included with version 2.0 have been updated to use the new syntax, but any scripts you have written for FiPy 1.0 will need to be updated. A complete listing of the changes needed to take the FiPy examples scripts from version 1.0 to version 2.0 can be found with:
$ git diff version-1_2 version-2_0 examples/
but we summarize the necessary changes here. If these tips are not sufficient to make your scripts compatible with FiPy 2.0, please don’t hesitate to ask for help on the mailing list.
The following items must be changed in your scripts
The dimension axis of a
Variableis now first, not last>>> x = mesh.getCellCenters()[0]instead of
>>> x = mesh.getCellCenters()[..., 0]This seemingly arbitrary change simplifies a great many things in FiPy, but the one most noticeable to the user is that you can now write
>>> x, y = mesh.getCellCenters()instead of
>>> 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 blindly “search & replace all” as that is almost bound to create more problems than it’s worth.Note
Any vector constants must be reoriented. For instance, in order to offset a
Mesh, you must write>>> mesh = Grid2D(...) + ((deltax,), (deltay,))or
>>> mesh = Grid2D(...) + [[deltax], [deltay]]instead of
>>> mesh = Grid2D(...) + (deltax, deltay)
VectorCellVariableandVectorFaceVariableno longer exist.CellVariableand andFaceVariablenow both inherit fromMeshVariable, which can have arbitrary rank. A field of scalars (default) will haverank=0, a field of vectors will haverank=1, etc. You should write>>> vectorField = CellVariable(mesh=mesh, rank=1)instead of
>>> vectorField = VectorCellVariable(mesh=mesh)Note
Because vector fields are properly supported, use vector operations to manipulate them, such as
>>> phase.getFaceGrad().dot((( 0, 1), ... (-1, 0)))instead of the hackish
>>> phase.getFaceGrad()._take((1, 0), axis=1) * (-1, 1)For internal reasons, FiPy now supports
CellVariableandFaceVariableobjects that contain integers, but it is not meaningful to solve a PDE for an integer field (FiPy should issue a warning if you try). As a result, when given, initial values must be specified as floating-point values:>>> var = CellVariable(mesh=mesh, value=1.)where they used to be quietly accepted as integers
>>> var = CellVariable(mesh=mesh, value=1)If the
valueargument is not supplied, theCellVariablewill contain floats, as before.The
facesargument toBoundaryConditionnow takes a mask, instead of a list ofFaceIDs. Now you write>>> X, Y = mesh.getFaceCenters() >>> FixedValue(faces=mesh.getExteriorFaces() & (X**2 < 1e-6), value=...)instead of
>>> exteriorFaces = mesh.getExteriorFaces() >>> X = exteriorFaces.getCenters()[..., 0] >>> FixedValue(faces=exteriorFaces.where(X**2 < 1e-6), value=...)With the old syntax, a different call to
getCenters()had to be made for each set ofFaceobjects. It was also extremely difficult to specify boundary conditions that depended both on position in space and on the current values of any otherVariable.>>> FixedValue(faces=(mesh.getExteriorFaces() ... & (((X**2 < 1e-6) ... & (Y > 3.)) ... | (phi.getArithmeticFaceValue() ... < sin(gamma.getArithmeticFaceValue())))), value=...)although it probably could have been done with a rather convoluted (and slow!)
filterfunction passed towhere. There no longer are anyfiltermethods used in FiPy. You now would write>>> x, y = mesh.cellCenters >>> initialArray[(x < dx) | (x > (Lx - dx)) | (y < dy) | (y > (Ly - dy))] = 1.instead of the much slower
>>> def cellFilter(cell): ... return ((cell.center[0] < dx) ... or (cell.center[0] > (Lx - dx)) ... or (cell.center[1] < dy) ... or (cell.center[1] > (Ly - dy)))>>> positiveCells = mesh.getCells(filter=cellFilter) >>> for cell in positiveCells: ... initialArray[cell.ID] = 1.Although they still exist, we find very little cause to ever call
getCells()orfipy.meshes.mesh.Mesh.getFaces().Some modules, such as
fipy.solvers, have been significantly rearranged. For example, you need to change>>> from fipy.solvers.linearPCGSolver import LinearPCGSolverto either
>>> from fipy import LinearPCGSolveror
>>> from fipy.solvers.pysparse.linearPCGSolver import LinearPCGSolverThe
numerix.max()andnumerix.min()functions no longer exist. Either callmax()andmin()or themax()andmin()methods of aVariable.The
Numericmodule has not been supported for a long time. Be sure to use>>> from fipy import numerixinstead of
>>> import Numeric
The remaining changes are not required, but they make scripts easier to read
and we recommend them. FiPy may issue a DeprecationWarning for some cases,
to indicate that we may not maintain the old syntax indefinitely.
All of the most commonly used classes and functions in FiPy are directly accessible in the
fipynamespace. For brevity, our examples now start with>>> from fipy import *instead of the explicit
>>> from fipy.meshes.grid1D import Grid1D >>> from fipy.terms.powerLawConvectionTerm import PowerLawConvectionTerm >>> from fipy.variables.cellVariable import CellVariableimports that we used to use. Most of the explicit imports should continue to work, so you do not need to change them if you don’t wish to, but we find our own scripts much easier to read without them.
All of the
numerixmodule is now imported into thefipynamespace, so you can callnumerixfunctions a number of different ways, including:>>> from fipy import * >>> y = exp(x)or
>>> from fipy import numerix >>> y = numerix.exp(x)or
>>> from fipy.tools.numerix import exp >>> y = exp(x)We generally use the first, but you may see us use the others, and should feel free to use whichever form you find most comfortable.
Note
Internally, FiPy uses explicit imports, as is considered best Python practice, but we feel that clarity trumps orthodoxy when it comes to the examples.
The function
fipy.viewers.make()has been renamed tofipy.viewers.Viewer(). All of thelimitscan now be supplied as direct arguments, as well (although this is not required). The result is a more natural syntax:>>> from fipy import Viewer >>> viewer = Viewer(vars=(alpha, beta, gamma), datamin=0, datamax=1)instead of
>>> from fipy import viewers >>> viewer = viewers.make(vars=(alpha, beta, gamma), ... limits={'datamin': 0, 'datamax': 1})With the old syntax, there was also a temptation to write
>>> from fipy.viewers import make >>> viewer = make(vars=(alpha, beta, gamma))which can be very hard to understand after the fact (
make?makewhat?).A
ConvectionTermcan now calculate its Péclet number automatically, so thediffusionTermargument is no longer required>>> eq = (TransientTerm() ... == DiffusionTerm(coeff=diffCoeff) ... + PowerLawConvectionTerm(coeff=convCoeff))instead of
>>> diffTerm = DiffusionTerm(coeff=diffCoeff) >>> eq = (TransientTerm() ... == diffTerm ... + PowerLawConvectionTerm(coeff=convCoeff, diffusionTerm=diffTerm))An
ImplicitSourceTermnow “knows” how to partition itself onto the solution matrix, so you can write>>> S0 = mXi * phase * (1 - phase) - phase * S1 >>> source = S0 + ImplicitSourceTerm(coeff=S1)instead of
>>> S0 = mXi * phase * (1 - phase) - phase * S1 * (S1 < 0) >>> source = S0 + ImplicitSourceTerm(coeff=S1 * (S1 < 0))It is definitely still advantageous to hand-linearize your source terms, but it is no longer necessary to worry about putting the “wrong” sign on the diagonal of the matrix.
To make clearer the distinction between iterations, timesteps, and sweeps (see FAQ Iterations, timesteps, and sweeps? Oh, my!) the
stepsargument to aSolverobject has been renamediterations.
ImplicitDiffusionTermhas been renamed toDiffusionTerm.
examples.updating.update2_0to3_0 module¶
How to update scripts from version 2.0 to 3.0.
FiPy 3.0 introduces several syntax changes from FiPy 2.0. We appreciate that this is very inconvenient for our users, but we hope you’ll agree that the new syntax is easier to read and easier to use. We assure you that this is not something we do casually; it has been over two and a half years since our last incompatible change (when FiPy 2.0 superceded FiPy 1.0).
All examples included with version 3.0 have been updated to use the new syntax, but any scripts you have written for FiPy 2.0 will need to be updated. A complete listing of the changes needed to take the FiPy examples scripts from version 2.0 to version 3.0 can be found with
$ git diff version-2_1 version-3_0 examples/
but we summarize the necessary changes here. If these tips are not sufficient to make your scripts compatible with FiPy 3.0, please don’t hesitate to ask for help on the mailing list.
The following items must be changed in your scripts
We have reconsidered the change in FiPy 2.0 that included all of the functions of the
numerixmodule in thefipynamespace. You now must be more explicit when referring to any of these functions:>>> from fipy import * >>> y = numerix.exp(x)>>> from fipy.tools.numerix import exp >>> y = exp(x)We generally use the first, but you may see us import specific functions if we feel it improves readability. You should feel free to use whichever form you find most comfortable.
Note
the old behavior can be obtained, at least for now, by setting the
FIPY_INCLUDE_NUMERIX_ALLenvironment variable.If your equation contains a
TransientTerm, then you must specify the timestep by passing adt=argument when callingsolve()orsweep().
The remaining changes are not required, but they make scripts easier to read
and we recommend them. FiPy may issue a 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.cellCentersinstead of
>>> x, y = mesh.getCellCenters()Boundary conditions are better applied with the
constrain()method than with the oldFixedValueandFixedFluxclasses. See Boundary Conditions.Individual
Meshclasses should be imported directly fromfipy.meshesand notfipy.meshes.numMesh.The Gmsh meshes now have simplified names:
Gmsh2Dinstead ofGmshImporter2D,Gmsh3Dinstead ofGmshImporter3D, andGmsh2DIn3DSpaceinstead ofGmshImporter2DIn3DSpace.
FiPy