Bookmark and Share FiPy: A Finite Volume PDE Solver Using Python
Version 3.0.1-dev25-ga11c4b0

Previous topic

topologies Package

Next topic

levelSet Package

This Page

Contact

FiPy developers
Jonathan Guyer
Daniel Wheeler
James Warren

Join our mailing list

100 Bureau Drive, M/S 6555
Gaithersburg, MD 20899

301-975-5329 Telephone
301-975-4553 Facsimile

models Package

models Package

class fipy.models.DistanceVariable(mesh, name='', value=0.0, unit=None, hasOld=0, narrowBandWidth=10000000000.0)

Bases: fipy.variables.cellVariable.CellVariable

A DistanceVariable object calculates \phi so it satisfies,

\abs{\nabla \phi} = 1

using the fast marching method with an initial condition defined by the zero level set.

Currently the solution is first order, This suffices for initial conditions with straight edges (e.g. trenches in electrodeposition). The method should work for unstructured 2D grids but testing on unstructured grids is untested thus far. This is a 2D implementation as it stands. Extending to 3D should be relatively simple.

Here we will define a few test cases. Firstly a 1D test case

>>> from fipy.meshes import Grid1D
>>> from fipy.tools import serial
>>> mesh = Grid1D(dx = .5, nx = 8, communicator=serial)
>>> from distanceVariable import DistanceVariable
>>> var = DistanceVariable(mesh = mesh, value = (-1, -1, -1, -1, 1, 1, 1, 1))
>>> var.calcDistanceFunction()
>>> answer = (-1.75, -1.25, -.75, -0.25, 0.25, 0.75, 1.25, 1.75)
>>> print var.allclose(answer)
1

A 1D test case with very small dimensions.

>>> dx = 1e-10
>>> mesh = Grid1D(dx = dx, nx = 8, communicator=serial)
>>> var = DistanceVariable(mesh = mesh, value = (-1, -1, -1, -1, 1, 1, 1, 1))
>>> var.calcDistanceFunction()
>>> answer = numerix.arange(8) * dx - 3.5 * dx
>>> print var.allclose(answer)
1

A 2D test case to test _calcTrialValue for a pathological case.

>>> dx = 1.
>>> dy = 2.
>>> from fipy.meshes import Grid2D
>>> mesh = Grid2D(dx = dx, dy = dy, nx = 2, ny = 3)
>>> var = DistanceVariable(mesh = mesh, value = (-1, 1, 1, 1, -1, 1))
>>> var.calcDistanceFunction()
>>> vbl = -dx * dy / numerix.sqrt(dx**2 + dy**2) / 2.
>>> vbr = dx / 2
>>> vml = dy / 2.
>>> crossProd = dx * dy
>>> dsq = dx**2 + dy**2
>>> top = vbr * dx**2 + vml * dy**2
>>> sqrt = crossProd**2 *(dsq - (vbr - vml)**2)
>>> sqrt = numerix.sqrt(max(sqrt, 0))
>>> vmr = (top + sqrt) / dsq
>>> answer = (vbl, vbr, vml, vmr, vbl, vbr)
>>> print var.allclose(answer)
1

The extendVariable method solves the following equation for a given extensionVariable.

\nabla u \cdot \nabla \phi = 0

using the fast marching method with an initial condition defined at the zero level set. Essentially the equation solves a fake distance function to march out the velocity from the interface.

>>> from fipy.variables.cellVariable import CellVariable
>>> mesh = Grid2D(dx = 1., dy = 1., nx = 2, ny = 2)
>>> var = DistanceVariable(mesh = mesh, value = (-1, 1, 1, 1))
>>> var.calcDistanceFunction()
>>> extensionVar = CellVariable(mesh = mesh, value = (-1, .5, 2, -1))
>>> tmp = 1 / numerix.sqrt(2)
>>> print var.allclose((-tmp / 2, 0.5, 0.5, 0.5 + tmp))
1
>>> var.extendVariable(extensionVar)
>>> print extensionVar.allclose((1.25, .5, 2, 1.25))
1
>>> mesh = Grid2D(dx = 1., dy = 1., nx = 3, ny = 3)
>>> var = DistanceVariable(mesh = mesh, value = (-1, 1, 1,
...                                               1, 1, 1,
...                                               1, 1, 1))
>>> var.calcDistanceFunction()
>>> extensionVar = CellVariable(mesh = mesh, value = (-1, .5, -1,
...                                                    2, -1, -1,
...                                                   -1, -1, -1))
>>> v1 = 0.5 + tmp
>>> v2 = 1.5
>>> tmp1 = (v1 + v2) / 2 + numerix.sqrt(2. - (v1 - v2)**2) / 2
>>> tmp2 = tmp1 + 1 / numerix.sqrt(2)
>>> print var.allclose((-tmp / 2, 0.5, 1.5, 0.5, 0.5 + tmp, 
...                      tmp1, 1.5, tmp1, tmp2))
1
>>> answer = (1.25, .5, .5, 2, 1.25, 0.9544, 2, 1.5456, 1.25)
>>> var.extendVariable(extensionVar)
>>> print extensionVar.allclose(answer, rtol = 1e-4)
1

Test case for a bug that occurs when initializing the distance variable at the interface. Currently it is assumed that adjacent cells that are opposite sign neighbors have perpendicular normal vectors. In fact the two closest cells could have opposite normals.

>>> mesh = Grid1D(dx = 1., nx = 3)
>>> var = DistanceVariable(mesh = mesh, value = (-1, 1, -1))
>>> var.calcDistanceFunction()
>>> print var.allclose((-0.5, 0.5, -0.5))
1

For future reference, the minimum distance for the interface cells can be calculated with the following functions. The trial cell values will also be calculated with these functions. In essence it is not difficult to calculate the level set distance function on an unstructured 3D grid. However a lot of testing will be required. The minimum distance functions will take the following form.

X_{\text{min}} = \frac{\left| \vec{s} \times \vec{t} \right|} {\left|
\vec{s} - \vec{t} \right|}

and in 3D,

X_{\text{min}} = \frac{1}{3!} \left| \vec{s} \cdot \left( \vec{t} \times
\vec{u} \right) \right|

where the vectors \vec{s}, \vec{t} and \vec{u} represent the vectors from the cell of interest to the neighboring cell.

Creates a distanceVariable object.

Parameters :
  • mesh: The mesh that defines the geometry of this variable.
  • name: The name of the variable.
  • value: The initial value.
  • unit: the physical units of the variable
  • hasOld: Whether the variable maintains an old value.
  • narrowBandWidth: The width of the region about the zero level set within which the distance function is evaluated.
calcDistanceFunction(narrowBandWidth=None, deleteIslands=False)

Calculates the distanceVariable as a distance function.

Parameters :
  • narrowBandWidth: The width of the region about the zero level set within which the distance function is evaluated.
  • deleteIslands: Sets the temporary level set value to zero in isolated cells.
cellInterfaceAreas

Returns the length of the interface that crosses the cell

A simple 1D test:

>>> from fipy.meshes import Grid1D
>>> mesh = Grid1D(dx = 1., nx = 4)
>>> distanceVariable = DistanceVariable(mesh = mesh, 
...                                     value = (-1.5, -0.5, 0.5, 1.5))
>>> answer = CellVariable(mesh=mesh, value=(0, 0., 1., 0))
>>> print numerix.allclose(distanceVariable.cellInterfaceAreas, 
...                        answer)
True

A 2D test case:

>>> from fipy.meshes import Grid2D
>>> from fipy.variables.cellVariable import CellVariable
>>> mesh = Grid2D(dx = 1., dy = 1., nx = 3, ny = 3)
>>> distanceVariable = DistanceVariable(mesh = mesh, 
...                                     value = (1.5, 0.5, 1.5,
...                                              0.5,-0.5, 0.5,
...                                              1.5, 0.5, 1.5))
>>> answer = CellVariable(mesh=mesh,
...                       value=(0, 1, 0, 1, 0, 1, 0, 1, 0))
>>> print numerix.allclose(distanceVariable.cellInterfaceAreas, answer)
True

Another 2D test case:

>>> mesh = Grid2D(dx = .5, dy = .5, nx = 2, ny = 2)
>>> from fipy.variables.cellVariable import CellVariable
>>> distanceVariable = DistanceVariable(mesh = mesh, 
...                                     value = (-0.5, 0.5, 0.5, 1.5))
>>> answer = CellVariable(mesh=mesh,
...                       value=(0, numerix.sqrt(2) / 4,  numerix.sqrt(2) / 4, 0))
>>> print numerix.allclose(distanceVariable.cellInterfaceAreas, 
...                        answer)
True

Test to check that the circumfrence of a circle is, in fact, 2\pi r.

>>> mesh = Grid2D(dx = 0.05, dy = 0.05, nx = 20, ny = 20)
>>> r = 0.25
>>> x, y = mesh.cellCenters
>>> rad = numerix.sqrt((x - .5)**2 + (y - .5)**2) - r
>>> distanceVariable = DistanceVariable(mesh = mesh, value = rad)
>>> print numerix.allclose(distanceVariable.cellInterfaceAreas.sum(), 1.57984690073)
1
extendVariable(extensionVariable, deleteIslands=False)

Takes a cellVariable and extends the variable from the zero to the region encapuslated by the narrowBandWidth.

Parameters :
  • extensionVariable: The variable to extend from the zero level set.
  • deleteIslands: Sets the temporary level set value to zero in isolated cells.
getCellInterfaceAreas(*args, **kwds)

Deprecated since version 3.0: use the cellInterfaceAreas property instead

class fipy.models.SurfactantVariable(value=0.0, distanceVar=None, name='surfactant variable', hasOld=False)

Bases: fipy.variables.cellVariable.CellVariable

The SurfactantVariable maintains a conserved volumetric concentration on cells adjacent to, but in front of, the interface. The value argument corresponds to the initial concentration of surfactant on the interface (moles divided by area). The value held by the SurfactantVariable is actually a volume density (moles divided by volume).

A simple 1D test:

>>> from fipy.meshes import Grid1D
>>> mesh = Grid1D(dx = 1., nx = 4)
>>> from fipy.models.levelSet.distanceFunction.distanceVariable import DistanceVariable
>>> distanceVariable = DistanceVariable(mesh = mesh, 
...                                     value = (-1.5, -0.5, 0.5, 941.5))
>>> surfactantVariable = SurfactantVariable(value = 1, 
...                                         distanceVar = distanceVariable)
>>> print numerix.allclose(surfactantVariable, (0, 0., 1., 0))
1

A 2D test case:

>>> from fipy.meshes import Grid2D
>>> mesh = Grid2D(dx = 1., dy = 1., nx = 3, ny = 3)
>>> distanceVariable = DistanceVariable(mesh = mesh,
...                                     value = (1.5, 0.5, 1.5,
...                                              0.5,-0.5, 0.5,
...                                              1.5, 0.5, 1.5))
>>> surfactantVariable = SurfactantVariable(value = 1, 
...                                         distanceVar = distanceVariable)
>>> print numerix.allclose(surfactantVariable, (0, 1, 0, 1, 0, 1, 0, 1, 0))
1

Another 2D test case:

>>> mesh = Grid2D(dx = .5, dy = .5, nx = 2, ny = 2)
>>> distanceVariable = DistanceVariable(mesh = mesh, 
...                                     value = (-0.5, 0.5, 0.5, 1.5))
>>> surfactantVariable = SurfactantVariable(value = 1, 
...                                         distanceVar = distanceVariable)
>>> print numerix.allclose(surfactantVariable, 
...                  (0, numerix.sqrt(2), numerix.sqrt(2), 0))
1
Parameters :
  • value: The initial value.
  • distanceVar: A DistanceVariable object.
  • name: The name of the variable.
copy()
getInterfaceVar(*args, **kwds)

Deprecated since version 3.0: use the interfaceVar property instead

interfaceVar

Returns the SurfactantVariable rendered as an _InterfaceSurfactantVariable which evaluates the surfactant concentration as an area concentration the interface rather than a volumetric concentration.

class fipy.models.SurfactantEquation(distanceVar=None)

A SurfactantEquation aims to evolve a surfactant on an interface defined by the zero level set of the distanceVar. The method should completely conserve the total coverage of surfactant. The surfactant is only in the cells immediately in front of the advancing interface. The method only works for a positive velocity as it stands.

Creates a SurfactantEquation object.

Parameters :
  • distanceVar: The DistanceVariable that marks the interface.
solve(var, boundaryConditions=(), solver=None, dt=None)

Builds and solves the SurfactantEquation‘s linear system once.

Parameters :
  • var: A SurfactantVariable to be solved for. Provides the initial condition, the old value and holds the solution on completion.
  • solver: The iterative solver to be used to solve the linear system of equations.
  • boundaryConditions: A tuple of boundaryConditions.
  • dt: The time step size.
sweep(var, solver=None, boundaryConditions=(), dt=None, underRelaxation=None, residualFn=None)

Builds and solves the Term‘s linear system once. This method also recalculates and returns the residual as well as applying under-relaxation.

Parameters :
  • var: The variable to be solved for. Provides the initial condition, the old value and holds the solution on completion.
  • solver: The iterative solver to be used to solve the linear system of equations.
  • boundaryConditions: A tuple of boundaryConditions.
  • dt: The time step size.
  • underRelaxation: Usually a value between 0 and 1 or None in the case of no under-relaxation
class fipy.models.AdsorbingSurfactantEquation(surfactantVar=None, distanceVar=None, bulkVar=None, rateConstant=None, otherVar=None, otherBulkVar=None, otherRateConstant=None, consumptionCoeff=None)

Bases: fipy.models.levelSet.surfactant.surfactantEquation.SurfactantEquation

The AdsorbingSurfactantEquation object solves the SurfactantEquation but with an adsorbing species from some bulk value. The equation that describes the surfactant adsorbing is given by,

\dot{\theta} = J v \theta + k c (1 - \theta - \theta_{\text{other}}) - \theta c_{\text{other}} k_{\text{other}} - k^- \theta

where \theta, J, v, k, c, k^- and n represent the surfactant coverage, the curvature, the interface normal velocity, the adsorption rate, the concentration in the bulk at the interface, the consumption rate and an exponent of consumption, respectively. The \text{other} subscript refers to another surfactant with greater surface affinity.

The terms on the RHS of the above equation represent conservation of surfactant on a non-uniform surface, Langmuir adsorption, removal of surfactant due to adsorption of the other surfactant onto non-vacant sites and consumption of the surfactant respectively. The adsorption term is added to the source by setting :math:` S_c = k c (1 - theta_{text{other}})` and S_p = -k c. The other terms are added to the source in a similar way.

The following is a test case:

>>> from fipy.models.levelSet.distanceFunction.distanceVariable \
...     import DistanceVariable
>>> from fipy.models.levelSet.surfactant.surfactantVariable \
...     import SurfactantVariable
>>> from fipy.meshes import Grid2D
>>> dx = .5
>>> dy = 2.3
>>> dt = 0.25
>>> k = 0.56
>>> initialValue = 0.1
>>> c = 0.2
>>> from fipy.meshes import Grid2D
>>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1)
>>> distanceVar = DistanceVariable(mesh = mesh, 
...                                value = (-dx*3/2, -dx/2, dx/2, 
...                                          3*dx/2,  5*dx/2),
...                                hasOld = 1)
>>> surfactantVar = SurfactantVariable(value = (0, 0, initialValue, 0 ,0), 
...                                    distanceVar = distanceVar)
>>> bulkVar = CellVariable(mesh = mesh, value = (c , c, c, c, c))
>>> eqn = AdsorbingSurfactantEquation(surfactantVar = surfactantVar,
...                                   distanceVar = distanceVar,
...                                   bulkVar = bulkVar,
...                                   rateConstant = k)
>>> eqn.solve(surfactantVar, dt = dt)
>>> answer = (initialValue + dt * k * c) / (1 + dt * k * c)
>>> print numerix.allclose(surfactantVar.interfaceVar, 
...                  numerix.array((0, 0, answer, 0, 0)))
1

The following test case is for two surfactant variables. One has more surface affinity than the other.

>>> from fipy.models.levelSet.distanceFunction.distanceVariable \
...     import DistanceVariable
>>> from fipy.models.levelSet.surfactant.surfactantVariable \
...     import SurfactantVariable
>>> from fipy.meshes import Grid2D
>>> dx = 0.5
>>> dy = 2.73
>>> dt = 0.001
>>> k0 = 1.
>>> k1 = 10.
>>> theta0 = 0.
>>> theta1 = 0.
>>> c0 = 1.
>>> c1 = 1.
>>> totalSteps = 10
>>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1)
>>> distanceVar = DistanceVariable(mesh = mesh, 
...                                value = dx * (numerix.arange(5) - 1.5),
...                                hasOld = 1)
>>> var0 = SurfactantVariable(value = (0, 0, theta0, 0 ,0), 
...                           distanceVar = distanceVar)
>>> var1 = SurfactantVariable(value = (0, 0, theta1, 0 ,0), 
...                           distanceVar = distanceVar)
>>> bulkVar0 = CellVariable(mesh = mesh, value = (c0, c0, c0, c0, c0))
>>> bulkVar1 = CellVariable(mesh = mesh, value = (c1, c1, c1, c1, c1))
>>> eqn0 = AdsorbingSurfactantEquation(surfactantVar = var0,
...                                    distanceVar = distanceVar,
...                                    bulkVar = bulkVar0,
...                                    rateConstant = k0)
>>> eqn1 = AdsorbingSurfactantEquation(surfactantVar = var1,
...                                    distanceVar = distanceVar,
...                                    bulkVar = bulkVar1,
...                                    rateConstant = k1,
...                                    otherVar = var0,
...                                    otherBulkVar = bulkVar0,
...                                    otherRateConstant = k0)
>>> for step in range(totalSteps):
...     eqn0.solve(var0, dt = dt)
...     eqn1.solve(var1, dt = dt)
>>> answer0 = 1 - numerix.exp(-k0 * c0 * dt * totalSteps)
>>> answer1 = (1 - numerix.exp(-k1 * c1 * dt * totalSteps)) * (1 - answer0)
>>> print numerix.allclose(var0.interfaceVar, 
...                  numerix.array((0, 0, answer0, 0, 0)), rtol = 1e-2)
1
>>> print numerix.allclose(var1.interfaceVar, 
...                  numerix.array((0, 0, answer1, 0, 0)), rtol = 1e-2)
1
>>> dt = 0.1
>>> for step in range(10):
...     eqn0.solve(var0, dt = dt)
...     eqn1.solve(var1, dt = dt)
>>> x, y = mesh.cellCenters
>>> check = var0.interfaceVar + var1.interfaceVar
>>> answer = CellVariable(mesh=mesh, value=check)
>>> answer[x==1.25] = 1.
>>> print check.allequal(answer)
True

The following test case is to fix a bug where setting the adosrbtion coefficient to zero leads to the solver not converging and an eventual failure.

>>> var0 = SurfactantVariable(value = (0, 0, theta0, 0 ,0), 
...                           distanceVar = distanceVar)
>>> bulkVar0 = CellVariable(mesh = mesh, value = (c0, c0, c0, c0, c0))
>>> eqn0 = AdsorbingSurfactantEquation(surfactantVar = var0,
...                                    distanceVar = distanceVar,
...                                    bulkVar = bulkVar0,
...                                    rateConstant = 0)
>>> eqn0.solve(var0, dt = dt)
>>> eqn0.solve(var0, dt = dt)
>>> answer = CellVariable(mesh=mesh, value=var0.interfaceVar)
>>> answer[x==1.25] = 0.
>>> print var0.interfaceVar.allclose(answer)
True

The following test case is to fix a bug that allows the accelerator to become negative.

>>> nx = 5
>>> ny = 5
>>> dx = 1.
>>> dy = 1.
>>> mesh = Grid2D(dx=dx, dy=dy, nx = nx, ny = ny)
>>> x, y = mesh.cellCenters
>>> disVar = DistanceVariable(mesh=mesh, value=1., hasOld=True)
>>> disVar[y < dy] = -1
>>> disVar[x < dx] = -1
>>> disVar.calcDistanceFunction()
>>> levVar = SurfactantVariable(value = 0.5, distanceVar = disVar)
>>> accVar = SurfactantVariable(value = 0.5, distanceVar = disVar)
>>> levEq = AdsorbingSurfactantEquation(levVar,
...                                     distanceVar = disVar,
...                                     bulkVar = 0,
...                                     rateConstant = 0)
>>> accEq = AdsorbingSurfactantEquation(accVar,
...                                     distanceVar = disVar,
...                                     bulkVar = 0,
...                                     rateConstant = 0,
...                                     otherVar = levVar,
...                                     otherBulkVar = 0,
...                                     otherRateConstant = 0)
>>> extVar = CellVariable(mesh = mesh, value = accVar.interfaceVar)
>>> from fipy.models.levelSet.advection.higherOrderAdvectionEquation \
...     import buildHigherOrderAdvectionEquation
>>> advEq = buildHigherOrderAdvectionEquation(advectionCoeff = extVar)
>>> dt = 0.1
>>> for i in range(50):
...     disVar.calcDistanceFunction()
...     extVar.value = (numerix.array(accVar.interfaceVar))
...     disVar.extendVariable(extVar)
...     disVar.updateOld()
...     advEq.solve(disVar, dt = dt)
...     levEq.solve(levVar, dt = dt)
...     accEq.solve(accVar, dt = dt)
>>> print (accVar >= -1e-10).all()
True

Create a AdsorbingSurfactantEquation object.

Parameters :
  • surfactantVar: The SurfactantVariable to be solved for.
  • distanceVar: The DistanceVariable that marks the interface.
  • bulkVar: The value of the surfactantVar in the bulk.
  • rateConstant: The adsorption rate of the surfactantVar.
  • otherVar: Another SurfactantVariable with more surface affinity.
  • otherBulkVar: The value of the otherVar in the bulk.
  • otherRateConstant: The adsorption rate of the otherVar.
  • consumptionCoeff: The rate that the surfactantVar is consumed during deposition.
solve(var, boundaryConditions=(), solver=None, dt=None)

Builds and solves the AdsorbingSurfactantEquation‘s linear system once.

Parameters :
  • var: A SurfactantVariable to be solved for. Provides the initial condition, the old value and holds the solution on completion.
  • solver: The iterative solver to be used to solve the linear system of equations.
  • boundaryConditions: A tuple of boundaryConditions.
  • dt: The time step size.
sweep(var, solver=None, boundaryConditions=(), dt=None, underRelaxation=None, residualFn=None)

Builds and solves the AdsorbingSurfactantEquation‘s linear system once. This method also recalculates and returns the residual as well as applying under-relaxation.

Parameters :
  • var: The variable to be solved for. Provides the initial condition, the old value and holds the solution on completion.
  • solver: The iterative solver to be used to solve the linear system of equations.
  • boundaryConditions: A tuple of boundaryConditions.
  • dt: The time step size.
  • underRelaxation: Usually a value between 0 and 1 or None in the case of no under-relaxation
fipy.models.buildSurfactantBulkDiffusionEquation(bulkVar=None, distanceVar=None, surfactantVar=None, otherSurfactantVar=None, diffusionCoeff=None, transientCoeff=1.0, rateConstant=None)

The buildSurfactantBulkDiffusionEquation function returns a bulk diffusion of a species with a source term for the jump from the bulk to an interface. The governing equation is given by,

\frac{\partial c}{\partial t} = \nabla \cdot D \nabla  c

where,

D = \begin{cases}
    D_c & \text{when $\phi > 0$} \\
    0  & \text{when $\phi \le 0$}
\end{cases}

The jump condition at the interface is defined by Langmuir adsorption. Langmuir adsorption essentially states that the ability for a species to jump from an electrolyte to an interface is proportional to the concentration in the electrolyte, available site density and a jump coefficient. The boundary condition at the interface is given by

D \hat{n} \cdot \nabla c = -k c (1 - \theta) \qquad \text{at $\phi = 0$}.

Parameters :
  • bulkVar: The bulk surfactant concentration variable.
  • distanceVar: A DistanceVariable object
  • surfactantVar: A SurfactantVariable object
  • otherSurfactantVar: Any other surfactants that may remove this one.
  • diffusionCoeff: A float or a FaceVariable.
  • transientCoeff: In general 1 is used.
  • rateConstant: The adsorption coefficient.
class fipy.models.MayaviSurfactantViewer(distanceVar, surfactantVar=None, levelSetValue=0.0, title=None, smooth=0, zoomFactor=1.0, animate=False, limits={}, **kwlimits)

Bases: fipy.viewers.viewer.AbstractViewer

The MayaviSurfactantViewer creates a viewer with the Mayavi python plotting package that displays a DistanceVariable.

Create a MayaviSurfactantViewer.

>>> from fipy import *
>>> dx = 1.
>>> dy = 1.
>>> nx = 11
>>> ny = 11
>>> Lx = ny * dy
>>> Ly = nx * dx
>>> mesh = Grid2D(dx = dx, dy = dy, nx = nx, ny = ny)
>>> # from fipy.models.levelSet.distanceFunction.distanceVariable import DistanceVariable
>>> var = DistanceVariable(mesh = mesh, value = -1)
>>> x, y = mesh.cellCenters
>>> var.setValue(1, where=(x - Lx / 2.)**2 + (y - Ly / 2.)**2 < (Lx / 4.)**2)
>>> var.calcDistanceFunction()
>>> viewer = MayaviSurfactantViewer(var, smooth = 2)
>>> viewer.plot()
>>> viewer._promptForOpinion()
>>> del viewer
>>> var = DistanceVariable(mesh = mesh, value = -1)
>>> var.setValue(1, where=(y > 2. * Ly / 3.) | ((x > Lx / 2.) & (y > Ly / 3.)) | ((y < Ly / 6.) & (x > Lx / 2)))
>>> var.calcDistanceFunction()
>>> viewer = MayaviSurfactantViewer(var)
>>> viewer.plot()
>>> viewer._promptForOpinion()
>>> del viewer
>>> viewer = MayaviSurfactantViewer(var, smooth = 2)
>>> viewer.plot()
>>> viewer._promptForOpinion()
>>> del viewer
Parameters :
  • distanceVar: a DistanceVariable object.
  • levelSetValue: the value of the contour to be displayed
  • title: displayed at the top of the Viewer window
  • animate: whether to show only the initial condition and the
  • limits: a dictionary with possible keys xmin, xmax, ymin, ymax, zmin, zmax, datamin, datamax. A 1D Viewer will only use xmin and xmax, a 2D viewer will also use ymin and ymax, and so on. All viewers will use datamin and datamax. Any limit set to a (default) value of None will autoscale. moving top boundary or to show all contours (Default)
plot(filename=None)
class fipy.models.MatplotlibSurfactantViewer(distanceVar, surfactantVar=None, levelSetValue=0.0, title=None, smooth=0, zoomFactor=1.0, animate=False, limits={}, **kwlimits)

Bases: fipy.viewers.matplotlibViewer.matplotlibViewer.AbstractMatplotlibViewer

The MatplotlibSurfactantViewer creates a viewer with the Matplotlib python plotting package that displays a DistanceVariable.

Create a MatplotlibSurfactantViewer.

>>> from fipy import *
>>> m = Grid2D(nx=100, ny=100)
>>> x, y = m.cellCenters
>>> v = CellVariable(mesh=m, value=x**2 + y**2 - 10**2)
>>> s = CellVariable(mesh=m, value=sin(x / 10) * cos(y / 30))
>>> viewer = MatplotlibSurfactantViewer(distanceVar=v, surfactantVar=s)
>>> for r in range(1,200):
...     v.setValue(x**2 + y**2 - r**2)
...     viewer.plot()
>>> from fipy import *
>>> dx = 1.
>>> dy = 1.
>>> nx = 11
>>> ny = 11
>>> Lx = ny * dy
>>> Ly = nx * dx
>>> mesh = Grid2D(dx = dx, dy = dy, nx = nx, ny = ny)
>>> # from fipy.models.levelSet.distanceFunction.distanceVariable import DistanceVariable
>>> var = DistanceVariable(mesh = mesh, value = -1)
>>> x, y = mesh.cellCenters
>>> var.setValue(1, where=(x - Lx / 2.)**2 + (y - Ly / 2.)**2 < (Lx / 4.)**2)
>>> var.calcDistanceFunction()
>>> viewer = MatplotlibSurfactantViewer(var, smooth = 2)
>>> viewer.plot()
>>> viewer._promptForOpinion()
>>> del viewer
>>> var = DistanceVariable(mesh = mesh, value = -1)
>>> var.setValue(1, where=(y > 2. * Ly / 3.) | ((x > Lx / 2.) & (y > Ly / 3.)) | ((y < Ly / 6.) & (x > Lx / 2)))
>>> var.calcDistanceFunction()
>>> viewer = MatplotlibSurfactantViewer(var)
>>> viewer.plot()
>>> viewer._promptForOpinion()
>>> del viewer
>>> viewer = MatplotlibSurfactantViewer(var, smooth = 2)
>>> viewer.plot()
>>> viewer._promptForOpinion()
>>> del viewer
Parameters :
  • distanceVar: a DistanceVariable object.
  • levelSetValue: the value of the contour to be displayed
  • title: displayed at the top of the Viewer window
  • animate: whether to show only the initial condition and the
  • limits: a dictionary with possible keys xmin, xmax, ymin, ymax, zmin, zmax, datamin, datamax. A 1D Viewer will only use xmin and xmax, a 2D viewer will also use ymin and ymax, and so on. All viewers will use datamin and datamax. Any limit set to a (default) value of None will autoscale. moving top boundary or to show all contours (Default)
fipy.models.buildAdvectionEquation(advectionCoeff=None, advectionTerm=None)

The buildAdvectionEquation function constructs and returns an advection equation. The advection equation is given by:

\frac{\partial \phi}{\partial t} + u \abs{\nabla \phi} = 0.

This solution method for the _AdvectionTerm is set up specifically to evolve var while preserving var as a distance function. This equation is used in conjunction with the DistanceFunction object. Further details of the numerical method can be found in “Level Set Methods and Fast Marching Methods” by J.A. Sethian, Cambridge University Press, 1999. Testing for the advection equation is in examples.levelSet.advection

Parameters :
  • advectionCoeff: The coeff to pass to the advectionTerm.
  • advectionTerm: An advection term class.
fipy.models.buildHigherOrderAdvectionEquation(advectionCoeff=None)

The buildHigherOrderAdvectionEquation function returns an advection equation that uses the _HigherOrderAdvectionTerm. The advection equation is given by,

\frac{\partial \phi}{\partial t} + u \abs{\nabla \phi} = 0.

Parameters :
  • advectionCoeff: The coeff to pass to the _HigherOrderAdvectionTerm
fipy.models.buildMetalIonDiffusionEquation(ionVar=None, distanceVar=None, depositionRate=1, transientCoeff=1, diffusionCoeff=1, metalIonMolarVolume=1)

The MetalIonDiffusionEquation solves the diffusion of the metal species with a source term at the electrolyte interface. The governing equation is given by,

\frac{\partial c}{\partial t} = \nabla \cdot D \nabla  c

where,

D = \begin{cases}
    D_c & \text{when $\phi > 0$} \\
    0  & \text{when $\phi \le 0$}
\end{cases}

The velocity of the interface generally has a linear dependence on ion concentration. The following boundary condition applies at the zero level set,

D \hat{n} \cdot \nabla c = \frac{v(c)}{\Omega} \qquad \text{at $phi = 0$}

where

v(c) = c V_0

The test case below is for a 1D steady state problem. The solution is given by:

c(x) = \frac{c^{\infty}}{\Omega D / V_0 + L}\left(x - L\right) + c^{\infty}

This is the test case,

>>> from fipy.meshes import Grid1D
>>> nx = 11
>>> dx = 1.
>>> from fipy.tools import serial
>>> mesh = Grid1D(nx = nx, dx = dx, communicator=serial)
>>> x, = mesh.cellCenters
>>> from fipy.variables.cellVariable import CellVariable
>>> ionVar = CellVariable(mesh = mesh, value = 1.)
>>> from fipy.models.levelSet.distanceFunction.distanceVariable \
...     import DistanceVariable
>>> disVar = DistanceVariable(mesh = mesh, 
...                           value = (x - 0.5) - 0.99,
...                           hasOld = 1)
>>> v = 1.
>>> diffusion = 1.
>>> omega = 1.
>>> cinf = 1.
>>> eqn = buildMetalIonDiffusionEquation(ionVar = ionVar,
...                                      distanceVar = disVar,
...                                      depositionRate = v * ionVar,
...                                      diffusionCoeff = diffusion,
...                                      metalIonMolarVolume = omega)
>>> ionVar.constrain(cinf, mesh.facesRight)
>>> for i in range(10):
...     eqn.solve(ionVar, dt = 1000)
>>> L = (nx - 1) * dx - dx / 2
>>> gradient = cinf / (omega * diffusion / v + L)
>>> answer = gradient * (x - L - dx * 3 / 2) + cinf
>>> answer[x < dx] = 1
>>> print ionVar.allclose(answer)
1
Parameters :
  • ionVar: The metal ion concentration variable.
  • distanceVar: A DistanceVariable object.
  • depositionRate: A float or a CellVariable representing the interface deposition rate.
  • transientCoeff: The transient coefficient.
  • diffusionCoeff: The diffusion coefficient
  • metalIonMolarVolume: Molar volume of the metal ions.
class fipy.models.TrenchMesh(trenchDepth=None, trenchSpacing=None, boundaryLayerDepth=None, cellSize=None, aspectRatio=None, angle=0.0, bowWidth=0.0, overBumpRadius=0.0, overBumpWidth=0.0)

Bases: fipy.models.levelSet.electroChem.gapFillMesh.GapFillMesh

The trench mesh takes the parameters generally used to define a trench region and recasts then for the general GapFillMesh.

The following test case tests for diffusion across the domain.

>>> cellSize = 0.05e-6
>>> trenchDepth = 0.5e-6
>>> boundaryLayerDepth = 50e-6
>>> domainHeight = 10 * cellSize + trenchDepth + boundaryLayerDepth
>>> mesh = TrenchMesh(trenchSpacing = 1e-6,
...                   cellSize = cellSize,
...                   trenchDepth = trenchDepth,
...                   boundaryLayerDepth = boundaryLayerDepth,
...                   aspectRatio = 1.) 
>>> import fipy.tools.dump as dump
>>> (f, filename) = dump.write(mesh) 
>>> mesh = dump.read(filename, f) 
>>> mesh.numberOfCells - len(numerix.nonzero(mesh.electrolyteMask)[0]) 
150
>>> from fipy.variables.cellVariable import CellVariable
>>> var = CellVariable(mesh = mesh, value = 0.) 
>>> from fipy.terms.diffusionTerm import DiffusionTerm
>>> eq = DiffusionTerm() 
>>> var.constrain(0., mesh.facesBottom) 
>>> var.constrain(domainHeight, mesh.facesTop) 
>>> eq.solve(var) 

Evaluate the result:

>>> centers = mesh.cellCenters[1].copy() 

Note

the copy makes the array contiguous for inlining

>>> localErrors = (centers - var)**2 / centers**2 
>>> globalError = numerix.sqrt(numerix.sum(localErrors) / mesh.numberOfCells) 
>>> argmax = numerix.argmax(localErrors) 
>>> print numerix.sqrt(localErrors[argmax]) < 0.051 
1
>>> print globalError < 0.02 
1

trenchDepth - Depth of the trench.

trenchSpacing - The distance between the trenches.

boundaryLayerDepth - The depth of the hydrodynamic boundary layer.

cellSize - The cell Size.

aspectRatio - trenchDepth / trenchWidth

angle - The angle for the taper of the trench.

bowWidth - The maximum displacement for any bow in the trench shape.

overBumpWidth - The width of the over bump.

overBumpRadius - The radius of the over bump.

electrolyteMask
getElectrolyteMask(*args, **kwds)

Deprecated since version 3.0: use the electrolyteMask property instead

test Module