def __init__(self, surfactantVar = None, distanceVar = None, bulkVar = None, rateConstant = None, otherVar = None, otherBulkVar = None, otherRateConstant = None, consumptionCoeff = None): """ 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. """ self.eq = TransientTerm(coeff = 1) - ExplicitUpwindConvectionTerm(SurfactantConvectionVariable(distanceVar)) self.dt = Variable(0.) mesh = distanceVar.mesh adsorptionCoeff = self.dt * bulkVar * rateConstant spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes self.eq += ImplicitSourceTerm(spCoeff) - scCoeff if otherVar is not None: otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag otherScCoeff = -otherVar.interfaceVar * scCoeff self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff vars = (surfactantVar, otherVar) else: vars = (surfactantVar,) total = 0 for var in vars: total += var.interfaceVar maxVar = (total > 1) * distanceVar._cellInterfaceFlag val = distanceVar.cellInterfaceAreas / mesh.cellVolumes for var in vars[1:]: val -= distanceVar._cellInterfaceFlag * var spMaxCoeff = 1e20 * maxVar scMaxCoeff = spMaxCoeff * val * (val > 0) self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40 if consumptionCoeff is not None: self.eq += ImplicitSourceTerm(consumptionCoeff)
def buildPhaseEquation(phase, theta): mPhiVar = phase - 0.5 + temperature * phase * (1 - phase) thetaMag = theta.getOld().getGrad().getMag() implicitSource = mPhiVar * (phase - (mPhiVar < 0)) implicitSource += (2 * s + epsilon**2 * thetaMag) * thetaMag return TransientTerm(phaseTransientCoeff) == \ ExplicitDiffusionTerm(alpha**2) \ - ImplicitSourceTerm(implicitSource) \ + (mPhiVar > 0) * mPhiVar * phase
def buildThetaEquation(phase, theta): phaseMod = phase + (phase < thetaSmallValue) * thetaSmallValue phaseModSq = phaseMod * phaseMod expo = epsilon * beta * theta.getGrad().getMag() expo = (expo < 100.) * (expo - 100.) + 100. pFunc = 1. + numerix.exp(-expo) * (mu / epsilon - 1.) phaseFace = phase.getArithmeticFaceValue() phaseSq = phaseFace * phaseFace gradMag = theta.getFaceGrad().getMag() eps = 1. / gamma / 10. gradMag += (gradMag < eps) * eps IGamma = (gradMag > 1. / gamma) * (1 / gradMag - gamma) + gamma diffusionCoeff = phaseSq * (s * IGamma + epsilon**2) thetaGradDiff = theta.getFaceGrad() - theta.getFaceGradNoMod() sourceCoeff = (diffusionCoeff * thetaGradDiff).getDivergence() from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm return TransientTerm(thetaTransientCoeff * phaseModSq * pFunc) == \ ImplicitDiffusionTerm(diffusionCoeff) \ + sourceCoeff
def buildSurfactantBulkDiffusionEquation(bulkVar=None, distanceVar=None, surfactantVar=None, otherSurfactantVar=None, diffusionCoeff=None, transientCoeff=1., rateConstant=None): r""" 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, .. math:: \frac{\partial c}{\partial t} = \nabla \cdot D \nabla c where, .. math:: 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 .. math:: D \hat{n} \cdot \nabla c = -k c (1 - \theta) \qquad \text{at $\phi = 0$}. Parameters ---------- bulkVar : ~fipy.variables.cellVariable.CellVariable The bulk surfactant concentration variable. distanceVar : ~fipy.variables.distanceVariable.DistanceVariable surfactantVar : ~fipy.variables.surfactantVariable.SurfactantVariable otherSurfactantVar : ~fipy.variables.surfactantVariable.SurfactantVariable Any other surfactants that may remove this one. diffusionCoeff : float or ~fipy.variables.faceVariable.FaceVariable transientCoeff : float In general 1 is used. rateConstant : float The adsorption coefficient. """ spCoeff = rateConstant * distanceVar.cellInterfaceAreas / bulkVar.mesh.cellVolumes spSourceTerm = ImplicitSourceTerm(spCoeff) bulkSpCoeff = spCoeff * bulkVar coeff = bulkSpCoeff * surfactantVar.interfaceVar diffusionCoeff = _LevelSetDiffusionVariable(distanceVar, diffusionCoeff) eq = TransientTerm(transientCoeff) - DiffusionTermNoCorrection( diffusionCoeff) if otherSurfactantVar is not None: otherCoeff = bulkSpCoeff * otherSurfactantVar.interfaceVar else: otherCoeff = 0 return eq - coeff + spSourceTerm - otherCoeff
mesh = Grid1D(nx=nx, dx=dx) from fipy.variables.cellVariable import CellVariable phi = CellVariable(name="solution variable", mesh=mesh, value=0) D = 1 valueLeft = 1 valueRight = 0 from fipy.boundaryConditions.fixedValue import FixedValue BCs = (FixedValue(faces=mesh.getFacesRight(), value=valueRight), FixedValue(faces=mesh.getFacesLeft(), value=valueLeft)) from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm eqX = TransientTerm() == ExplicitDiffusionTerm(coeff=D) timeStepDuration = 0.9 * dx**2 / (2 * D) steps = 100 from fipy import viewers viewer = viewers.make(vars=(phi), limits={'datamin': 0., 'datamax': 1.}) def hit_continue(Prompt='Hit any key to continue'): raw_input(Prompt) for step in range(steps): eqX.solve(var=phi, boundaryConditions=BCs, dt=timeStepDuration) viewer.plot()
from fipy.meshes.periodicGrid1D import PeriodicGrid1D periodicMesh = PeriodicGrid1D(dx=dx, nx=nx / 2) startingArray = numerix.zeros(nx, 'd') startingArray[2 * nx / 10:3 * nx / 10] = 1. from fipy.variables.cellVariable import CellVariable var1 = CellVariable(name="non-periodic", mesh=mesh, value=startingArray) var2 = CellVariable(name="periodic", mesh=periodicMesh, value=startingArray[:nx / 2]) from fipy.terms.transientTerm import TransientTerm from fipy.terms.vanLeerConvectionTerm import VanLeerConvectionTerm eq1 = TransientTerm() - VanLeerConvectionTerm(coeff=(-velocity, )) eq2 = TransientTerm() - VanLeerConvectionTerm(coeff=(-velocity, )) if __name__ == '__main__': import fipy.viewers viewer1 = fipy.viewers.make(vars=var1) viewer2 = fipy.viewers.make(vars=var2) viewer1.plot() viewer2.plot() from fipy.solvers.linearLUSolver import LinearLUSolver newVar2 = var2.copy() for step in range(steps): eq1.solve(var=var1, dt=dt, solver=LinearLUSolver())
class AdsorbingSurfactantEquation(): r""" 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, .. math:: \dot{\theta} = J v \theta + k c (1 - \theta - \theta_{\text{other}}) - \theta c_{\text{other}} k_{\text{other}} - k^- \theta where :math:`\theta`, :math:`J`, :math:`v`, :math:`k`, :math:`c`, :math:`k^-` and :math:`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 :math:`\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 :math:`S_p = -k c`. The other terms are added to the source in a similar way. The following is a test case: >>> from fipy.variables.distanceVariable \ ... import DistanceVariable >>> from fipy import SurfactantVariable >>> from fipy.meshes import Grid2D >>> from fipy.tools import numerix >>> from fipy.variables.cellVariable import CellVariable >>> dx = .5 >>> dy = 2.3 >>> dt = 0.25 >>> k = 0.56 >>> initialValue = 0.1 >>> c = 0.2 >>> from fipy.meshes import Grid2D >>> from fipy import serialComm >>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1, communicator=serialComm) >>> 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.variables.distanceVariable \ ... import DistanceVariable >>> from fipy 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, communicator=serialComm) >>> 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, communicator=serialComm) >>> x, y = mesh.cellCenters >>> disVar = DistanceVariable(mesh=mesh, value=1., hasOld=True) >>> disVar[y < dy] = -1 >>> disVar[x < dx] = -1 >>> disVar.calcDistanceFunction() #doctest: +LSM >>> 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 import TransientTerm, AdvectionTerm >>> advEq = TransientTerm() + AdvectionTerm(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) #doctest: +LSM >>> print (accVar >= -1e-10).all() True """ def __init__(self, surfactantVar = None, distanceVar = None, bulkVar = None, rateConstant = None, otherVar = None, otherBulkVar = None, otherRateConstant = None, consumptionCoeff = None): """ 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. """ self.eq = TransientTerm(coeff = 1) - ExplicitUpwindConvectionTerm(SurfactantConvectionVariable(distanceVar)) self.dt = Variable(0.) mesh = distanceVar.mesh adsorptionCoeff = self.dt * bulkVar * rateConstant spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes self.eq += ImplicitSourceTerm(spCoeff) - scCoeff if otherVar is not None: otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag otherScCoeff = -otherVar.interfaceVar * scCoeff self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff vars = (surfactantVar, otherVar) else: vars = (surfactantVar,) total = 0 for var in vars: total += var.interfaceVar maxVar = (total > 1) * distanceVar._cellInterfaceFlag val = distanceVar.cellInterfaceAreas / mesh.cellVolumes for var in vars[1:]: val -= distanceVar._cellInterfaceFlag * var spMaxCoeff = 1e20 * maxVar scMaxCoeff = spMaxCoeff * val * (val > 0) self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40 if consumptionCoeff is not None: self.eq += ImplicitSourceTerm(consumptionCoeff) def solve(self, 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. """ self.dt.setValue(dt) if solver is None: import fipy.solvers.solver if fipy.solvers.solver == 'pyamg': from fipy.solvers.pyAMG.linearGeneralSolver import LinearGeneralSolver solver = LinearGeneralSolver(tolerance=1e-15, iterations=2000) else: from fipy.solvers import LinearPCGSolver solver = LinearPCGSolver() if type(boundaryConditions) not in (type(()), type([])): boundaryConditions = (boundaryConditions,) var.constrain(0, var.mesh.exteriorFaces) self.eq.solve(var, boundaryConditions=boundaryConditions, solver = solver, dt=1.) def sweep(self, var, solver=None, boundaryConditions=(), dt=None, underRelaxation=None, residualFn=None): r""" 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 """ self.dt.setValue(dt) if solver is None: from fipy.solvers import DefaultAsymmetricSolver solver = DefaultAsymmetricSolver() if type(boundaryConditions) not in (type(()), type([])): boundaryConditions = (boundaryConditions,) var.constrain(0, var.mesh.exteriorFaces) return self.eq.sweep(var, solver=solver, boundaryConditions=boundaryConditions, underRelaxation=underRelaxation, residualFn=residualFn, dt=1.)
phaseY = phase.getFaceGrad().dot((0, 1)) phaseX = phase.getFaceGrad().dot((1, 0)) psi = theta + numerix.arctan2(phaseY, phaseX) Phi = numerix.tan(N * psi / 2) PhiSq = Phi**2 beta = (1. - PhiSq) / (1. + PhiSq) betaPsi = -N * 2 * Phi / (1 + PhiSq) A = alpha**2 * c * (1. + c * beta) * betaPsi D = alpha**2 * (1. + c * beta)**2 dxi = phase.getFaceGrad()._take((1, 0), axis=1) * (-1, 1) anisotropySource = (A * dxi).getDivergence() from fipy.terms.transientTerm import TransientTerm from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm from fipy.terms.implicitSourceTerm import ImplicitSourceTerm phaseEq = TransientTerm(tau) == ExplicitDiffusionTerm(D) + \ ImplicitSourceTerm(mVar * ((mVar < 0) - phase)) + \ ((mVar > 0.) * mVar * phase + anisotropySource) from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm temperatureEq = TransientTerm() == \ ImplicitDiffusionTerm(tempDiffusionCoeff) + \ (phase - phase.getOld()) / timeStepDuration bench.stop('terms') phase.updateOld() temperature.updateOld() phaseEq.solve(phase, dt=timeStepDuration) temperatureEq.solve(temperature, dt=timeStepDuration)
shift = 1. KMVar = CellVariable(mesh = mesh, value = params['KM'] * shift, hasOld = 1) KCVar = CellVariable(mesh = mesh, value = params['KC'] * shift, hasOld = 1) TMVar = CellVariable(mesh = mesh, value = params['TM'] * shift, hasOld = 1) TCVar = CellVariable(mesh = mesh, value = params['TC'] * shift, hasOld = 1) P3Var = CellVariable(mesh = mesh, value = params['P3'] * shift, hasOld = 1) P2Var = CellVariable(mesh = mesh, value = params['P2'] * shift, hasOld = 1) RVar = CellVariable(mesh = mesh, value = params['R'], hasOld = 1) PN = P3Var + P2Var KMscCoeff = params['chiK'] * (RVar + 1) * (1 - KCVar - KMVar.getCellVolumeAverage()) KMspCoeff = params['lambdaK'] / (1 + PN / params['kappaK']) KMEq = TransientTerm() - KMscCoeff + ImplicitSourceTerm(KMspCoeff) TMscCoeff = params['chiT'] * (1 - TCVar - TMVar.getCellVolumeAverage()) TMspCoeff = params['lambdaT'] * (KMVar + params['zetaT']) TMEq = TransientTerm() - TMscCoeff + ImplicitSourceTerm(TMspCoeff) TCscCoeff = params['lambdaT'] * (TMVar * KMVar).getCellVolumeAverage() TCspCoeff = params['lambdaTstar'] TCEq = TransientTerm() - TCscCoeff + ImplicitSourceTerm(TCspCoeff) PIP2PITP = PN / (PN / params['kappam'] + PN.getCellVolumeAverage() / params['kappac'] + 1) + params['zetaPITP'] P3spCoeff = params['lambda3'] * (TMVar + params['zeta3T']) P3scCoeff = params['chi3'] * KMVar * (PIP2PITP / (1 + KMVar / params['kappa3']) + params['zeta3PITP']) + params['zeta3'] P3Eq = TransientTerm() - ImplicitDiffusionTerm(params['diffusionCoeff']) - P3scCoeff + ImplicitSourceTerm(P3spCoeff)
from fipy.variables.cellVariable import CellVariable from fipy.tools.numerix import random var = CellVariable(name = "phase field", mesh = mesh, value = random.random(nx * ny)) faceVar = var.getArithmeticFaceValue() doubleWellDerivative = asq * ( 1 - 6 * faceVar * (1 - faceVar)) from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm diffTerm2 = ImplicitDiffusionTerm(coeff = (diffusionCoeff * doubleWellDerivative,)) diffTerm4 = ImplicitDiffusionTerm(coeff = (diffusionCoeff, -epsilon**2)) eqch = TransientTerm() - diffTerm2 - diffTerm4 from fipy.solvers.linearPCGSolver import LinearPCGSolver from fipy.solvers.linearLUSolver import LinearLUSolver ##solver = LinearLUSolver(tolerance = 1e-15,steps = 1000) solver = LinearPCGSolver(tolerance = 1e-15,steps = 1000) from fipy.boundaryConditions.fixedValue import FixedValue from fipy.boundaryConditions.fixedFlux import FixedFlux from fipy.boundaryConditions.nthOrderBoundaryCondition import NthOrderBoundaryCondition BCs = (FixedFlux(mesh.getFacesRight(), 0), FixedFlux(mesh.getFacesLeft(), 0), NthOrderBoundaryCondition(mesh.getFacesLeft(), 0, 3), NthOrderBoundaryCondition(mesh.getFacesRight(), 0, 3), NthOrderBoundaryCondition(mesh.getFacesTop(), 0, 3), NthOrderBoundaryCondition(mesh.getFacesBottom(), 0, 3))
startingArray[50:90] = 1. var = CellVariable( name = "advection variable", mesh = mesh, value = startingArray) boundaryConditions = ( FixedValue(mesh.getFacesLeft(), valueLeft), FixedValue(mesh.getFacesRight(), valueRight) ) from fipy.terms.transientTerm import TransientTerm from fipy.terms.powerLawConvectionTerm import PowerLawConvectionTerm eq = TransientTerm() - PowerLawConvectionTerm(coeff = (velocity,)) if __name__ == '__main__': viewer = fipy.viewers.make(vars=(var,)) viewer.plot() raw_input("press key to continue") for step in range(steps): eq.solve(var, dt = timeStepDuration, boundaryConditions = boundaryConditions, solver = LinearLUSolver(tolerance = 1.e-15)) viewer.plot() viewer.plot() raw_input('finished')
shift = 1. KMVar = CellVariable(mesh=mesh, value=params['KM'] * shift, hasOld=1) KCVar = CellVariable(mesh=mesh, value=params['KC'] * shift, hasOld=1) TMVar = CellVariable(mesh=mesh, value=params['TM'] * shift, hasOld=1) TCVar = CellVariable(mesh=mesh, value=params['TC'] * shift, hasOld=1) P3Var = CellVariable(mesh=mesh, value=params['P3'] * shift, hasOld=1) P2Var = CellVariable(mesh=mesh, value=params['P2'] * shift, hasOld=1) RVar = CellVariable(mesh=mesh, value=params['R'], hasOld=1) PN = P3Var + P2Var KMscCoeff = params['chiK'] * (RVar + 1) * (1 - KCVar - KMVar.getCellVolumeAverage()) KMspCoeff = params['lambdaK'] / (1 + PN / params['kappaK']) KMEq = TransientTerm() - KMscCoeff + ImplicitSourceTerm(KMspCoeff) TMscCoeff = params['chiT'] * (1 - TCVar - TMVar.getCellVolumeAverage()) TMspCoeff = params['lambdaT'] * (KMVar + params['zetaT']) TMEq = TransientTerm() - TMscCoeff + ImplicitSourceTerm(TMspCoeff) TCscCoeff = params['lambdaT'] * (TMVar * KMVar).getCellVolumeAverage() TCspCoeff = params['lambdaTstar'] TCEq = TransientTerm() - TCscCoeff + ImplicitSourceTerm(TCspCoeff) PIP2PITP = PN / (PN / params['kappam'] + PN.getCellVolumeAverage() / params['kappac'] + 1) + params['zetaPITP'] P3spCoeff = params['lambda3'] * (TMVar + params['zeta3T']) P3scCoeff = params['chi3'] * KMVar * (PIP2PITP / (1 + KMVar / params['kappa3']) +
phase = CellVariable(name = 'PhaseField', mesh = mesh, value = 1.) from fipy.variables.modularVariable import ModularVariable theta = ModularVariable(name = 'Theta', mesh = mesh, value = 1.) x, y = mesh.getCellCenters()[...,0], mesh.getCellCenters()[...,1] theta.setValue(0., where=(x - L / 2.)**2 + (y - L / 2.)**2 < (L / 4.)**2) from fipy.terms.implicitSourceTerm import ImplicitSourceTerm mPhiVar = phase - 0.5 + temperature * phase * (1 - phase) thetaMag = theta.getOld().getGrad().getMag() implicitSource = mPhiVar * (phase - (mPhiVar < 0)) implicitSource += (2 * s + epsilon**2 * thetaMag) * thetaMag from fipy.terms.transientTerm import TransientTerm from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm phaseEq = TransientTerm(phaseTransientCoeff) == \ ExplicitDiffusionTerm(alpha**2) \ - ImplicitSourceTerm(implicitSource) \ + (mPhiVar > 0) * mPhiVar * phase if __name__ == '__main__': import fipy.viewers phaseViewer = fipy.viewers.make(vars = phase) phaseViewer.plot() for step in range(steps): phase.updateOld() phaseEq.solve(phase, dt = timeStepDuration) phaseViewer.plot() raw_input('finished')
phi = CellVariable(name="solution variable", mesh=mesh, value=0) D = 1 valueLeft = 1 valueRight = 0 from fipy.boundaryConditions.fixedValue import FixedValue BCs = (FixedValue(faces=mesh.getFacesRight(), value=valueRight), FixedValue(faces=mesh.getFacesLeft(), value=valueLeft)) from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm eqX = TransientTerm() == ExplicitDiffusionTerm(coeff=D) timeStepDuration = 0.9 * dx**2 / (2 * D) steps=100 from fipy import viewers viewer = viewers.make(vars=(phi), limits={'datamin': 0., 'datamax': 1.}) def hit_continue(Prompt='Hit any key to continue'): raw_input(Prompt) for step in range(steps):
startingArray[2 * nx / 10: 3 * nx / 10] = 1. from fipy.variables.cellVariable import CellVariable var1 = CellVariable( name = "non-periodic", mesh = mesh, value = startingArray) var2 = CellVariable( name = "periodic", mesh = periodicMesh, value = startingArray[:nx / 2]) from fipy.terms.transientTerm import TransientTerm from fipy.terms.vanLeerConvectionTerm import VanLeerConvectionTerm eq1 = TransientTerm() - VanLeerConvectionTerm(coeff = (-velocity,)) eq2 = TransientTerm() - VanLeerConvectionTerm(coeff = (-velocity,)) if __name__ == '__main__': import fipy.viewers viewer1 = fipy.viewers.make(vars=var1) viewer2 = fipy.viewers.make(vars=var2) viewer1.plot() viewer2.plot() from fipy.solvers.linearLUSolver import LinearLUSolver newVar2 = var2.copy() for step in range(steps): eq1.solve(var = var1, dt = dt, solver = LinearLUSolver())
else: return 0 def allOthers(face): if ((leftSide(face) or inMiddle(face) or rightSide(face)) or not (face.getID() in bigMesh.getExteriorFaces())): return 0 else: return 1 var = CellVariable(name="concentration", mesh=bigMesh, value=valueLeft) eqn = TransientTerm() == ExplicitDiffusionTerm() exteriorFaces = bigMesh.getExteriorFaces() xFace = exteriorFaces.getCenters()[..., 0] boundaryConditions = ( FixedValue(exteriorFaces.where(xFace**2 < 0.000000000000001), valueLeft), FixedValue(exteriorFaces.where((xFace - (dx * nx))**2 < 0.000000000000001), (valueLeft + valueRight) * 0.5), FixedValue( exteriorFaces.where((xFace - (2 * dx * nx))**2 < 0.000000000000001), valueRight)) answer = numerix.array([ 0.00000000e+00, 8.78906250e-23, 1.54057617e-19, 1.19644866e-16, 5.39556276e-14, 1.55308505e-11, 2.94461712e-09, 3.63798469e-07,
# create a field variable, set the initial conditions: from fipy.variables.cellVariable import CellVariable var = CellVariable(mesh=mesh, value=0) def centerCells(cell): return abs(cell.getCenter()[0] - L / 2.0) < L / 10 var.setValue(value=1.0, cells=mesh.getCells(filter=centerCells)) # create the equation: from fipy.terms.transientTerm import TransientTerm from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm eq = TransientTerm() - ImplicitDiffusionTerm(coeff=1) == 0 # create a viewer: from fipy.viewers.gist2DViewer import Gist1DViewer viewer = Gist1DViewer(vars=(var,), limits=('e', 'e', 0, 1)) viwer.plot() # solve for i in range(steps): var.updateOld() eq.solve() viewer.plot()
startingArray = numerix.zeros(nx, 'd') startingArray[50:90] = 1. var = CellVariable( name = "advection variable", mesh = mesh, value = startingArray) boundaryConditions = ( FixedValue(mesh.getFacesLeft(), valueLeft), FixedValue(mesh.getFacesRight(), valueRight) ) from fipy.terms.transientTerm import TransientTerm from fipy.terms.explicitUpwindConvectionTerm import ExplicitUpwindConvectionTerm eq = TransientTerm() - ExplicitUpwindConvectionTerm(coeff = (velocity,)) if __name__ == '__main__': viewer = fipy.viewers.make(vars=(var,)) for step in range(steps): eq.solve(var, dt = timeStepDuration, boundaryConditions = boundaryConditions, solver = LinearCGSSolver(tolerance = 1.e-15, steps = 2000)) viewer.plot() viewer.plot() raw_input('finished')
bench.start() from fipy.variables.cellVariable import CellVariable C = CellVariable(mesh = mesh) C.setValue(1, where=abs(mesh.getCellCenters()[...,0] - L/2.) < L / 10.) bench.stop('variables') bench.start() D = 1. from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm eq = TransientTerm() == ImplicitDiffusionTerm(coeff = D) bench.stop('terms') ## from fipy import viewers ## viewer = viewers.make(vars = C, limits = {'datamin': 0, 'datamax': 1}) ## viewer.plot() ## raw_input("initial") bench.start() dt = 1e0 steps = 1 for step in range(steps): eq.solve(var = C, dt = dt) ## viewer.plot()
def buildMetalIonDiffusionEquation(ionVar=None, distanceVar=None, depositionRate=1, transientCoeff=1, diffusionCoeff=1, metalIonMolarVolume=1): r""" The `MetalIonDiffusionEquation` solves the diffusion of the metal species with a source term at the electrolyte interface. The governing equation is given by, .. math:: \frac{\partial c}{\partial t} = \nabla \cdot D \nabla c where, .. math:: 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, .. math:: D \hat{n} \cdot \nabla c = \frac{v(c)}{\Omega} \qquad \text{at $phi = 0$} where .. math:: v(c) = c V_0 The test case below is for a 1D steady state problem. The solution is given by: .. math:: 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 serialComm >>> mesh = Grid1D(nx = nx, dx = dx, communicator=serialComm) >>> x, = mesh.cellCenters >>> from fipy.variables.cellVariable import CellVariable >>> ionVar = CellVariable(mesh = mesh, value = 1.) >>> from fipy.variables.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) >>> from builtins import range >>> 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 Testing the interface source term >>> from fipy.meshes import Grid2D >>> from fipy import numerix, serialComm >>> mesh = Grid2D(dx = 1., dy = 1., nx = 2, ny = 2, communicator=serialComm) >>> from fipy.variables.distanceVariable import DistanceVariable >>> distance = DistanceVariable(mesh = mesh, value = (-.5, .5, .5, 1.5)) >>> ionVar = CellVariable(mesh = mesh, value = (1, 1, 1, 1)) >>> depositionRate = CellVariable(mesh=mesh, value=(1, 1, 1, 1)) >>> source = depositionRate * distance.cellInterfaceAreas / mesh.cellVolumes / ionVar >>> sqrt = numerix.sqrt(2) >>> ans = CellVariable(mesh=mesh, value=(0, 1 / sqrt, 1 / sqrt, 0)) >>> print(numerix.allclose(source, ans)) True >>> distance[:] = (-1.5, -0.5, -0.5, 0.5) >>> print(numerix.allclose(source, (0, 0, 0, sqrt))) True :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. """ diffusionCoeff = _LevelSetDiffusionVariable(distanceVar, diffusionCoeff) eq = TransientTerm(transientCoeff) - DiffusionTermNoCorrection( diffusionCoeff) mesh = distanceVar.mesh coeff = depositionRate * distanceVar.cellInterfaceAreas / ( mesh.cellVolumes * metalIonMolarVolume) / ionVar return eq + ImplicitSourceTerm(coeff)
## Define boundary condition values leftValue = 1.0 rightValue = 0 ## Creation of boundary conditions from fipy.boundaryConditions.fixedValue import FixedValue BCs = (FixedValue(faces = mesh_example.getFacesRight(), value=rightValue), FixedValue(faces=mesh_example.getFacesLeft(),value=leftValue)) D = 1.0 ## diffusivity (m^2/s) ## Transient diffusion equation is defined next from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm eqX = TransientTerm() == ExplicitDiffusionTerm(coeff = D) timeStep = 0.09*deltax**2/(2*D) ## size of time step steps = 9000 ## number of time-steps ## create a GUI from fipy import viewers viewer = viewers.make(vars = phi, limits={'datamin':0.0, 'datamax':1.0}) ## iterate until you get tired for step in range(steps): eqX.solve(var = phi, boundaryConditions = BCs, dt = timeStep) ## solving the equation viewer.plot() ## update the GUI
steps = 1000 mesh = Grid1D(dx=dx, nx=nx) startingArray = numerix.zeros(nx, 'd') startingArray[50:90] = 1. var = CellVariable(name="advection variable", mesh=mesh, value=startingArray) boundaryConditions = (FixedValue(mesh.getFacesLeft(), valueLeft), FixedValue(mesh.getFacesRight(), valueRight)) from fipy.terms.transientTerm import TransientTerm from fipy.terms.powerLawConvectionTerm import PowerLawConvectionTerm eq = TransientTerm() - PowerLawConvectionTerm(coeff=(velocity, )) if __name__ == '__main__': viewer = fipy.viewers.make(vars=(var, )) viewer.plot() raw_input("press key to continue") for step in range(steps): eq.solve(var, dt=timeStepDuration, boundaryConditions=boundaryConditions, solver=LinearLUSolver(tolerance=1.e-15)) viewer.plot() viewer.plot() raw_input('finished')
class AdsorbingSurfactantEquation(): r""" 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, .. math:: \dot{\theta} = J v \theta + k c (1 - \theta - \theta_{\text{other}}) - \theta c_{\text{other}} k_{\text{other}} - k^- \theta where :math:`\theta`, :math:`J`, :math:`v`, :math:`k`, :math:`c`, :math:`k^-` and :math:`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 :math:`\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 :math:`S_p = -k c`. The other terms are added to the source in a similar way. The following is a test case: >>> from fipy.variables.distanceVariable \ ... import DistanceVariable >>> from fipy import SurfactantVariable >>> from fipy.meshes import Grid2D >>> from fipy.tools import numerix >>> from fipy.variables.cellVariable import CellVariable >>> dx = .5 >>> dy = 2.3 >>> dt = 0.25 >>> k = 0.56 >>> initialValue = 0.1 >>> c = 0.2 >>> from fipy.meshes import Grid2D >>> from fipy import serialComm >>> mesh = Grid2D(dx = dx, dy = dy, nx = 5, ny = 1, communicator=serialComm) >>> 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.variables.distanceVariable \ ... import DistanceVariable >>> from fipy 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, communicator=serialComm) >>> 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 adsorption 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, communicator=serialComm) >>> x, y = mesh.cellCenters >>> disVar = DistanceVariable(mesh=mesh, value=1., hasOld=True) >>> disVar[y < dy] = -1 >>> disVar[x < dx] = -1 >>> disVar.calcDistanceFunction() #doctest: +LSM >>> 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 import TransientTerm, AdvectionTerm >>> advEq = TransientTerm() + AdvectionTerm(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) #doctest: +LSM >>> # The following test fails sometimes on linux with scipy solvers >>> # See issue #575. We ignore for now. >>> print (accVar >= -1e-10).all() #doctest: +NOTLINUXSCIPY True """ def __init__(self, surfactantVar=None, distanceVar=None, bulkVar=None, rateConstant=None, otherVar=None, otherBulkVar=None, otherRateConstant=None, consumptionCoeff=None): """ 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. """ self.eq = TransientTerm(coeff=1) - ExplicitUpwindConvectionTerm( SurfactantConvectionVariable(distanceVar)) self.dt = Variable(0.) mesh = distanceVar.mesh adsorptionCoeff = self.dt * bulkVar * rateConstant spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes self.eq += ImplicitSourceTerm(spCoeff) - scCoeff if otherVar is not None: otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag otherScCoeff = -otherVar.interfaceVar * scCoeff self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff vars = (surfactantVar, otherVar) else: vars = (surfactantVar, ) total = 0 for var in vars: total += var.interfaceVar maxVar = (total > 1) * distanceVar._cellInterfaceFlag val = distanceVar.cellInterfaceAreas / mesh.cellVolumes for var in vars[1:]: val -= distanceVar._cellInterfaceFlag * var spMaxCoeff = 1e20 * maxVar scMaxCoeff = spMaxCoeff * val * (val > 0) self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40 if consumptionCoeff is not None: self.eq += ImplicitSourceTerm(consumptionCoeff) def solve(self, 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. """ self.dt.setValue(dt) if solver is None: import fipy.solvers.solver if fipy.solvers.solver == 'pyamg': from fipy.solvers.pyAMG.linearGeneralSolver import LinearGeneralSolver solver = LinearGeneralSolver(tolerance=1e-15, iterations=2000) else: from fipy.solvers import LinearPCGSolver solver = LinearPCGSolver() if type(boundaryConditions) not in (type(()), type([])): boundaryConditions = (boundaryConditions, ) var.constrain(0, var.mesh.exteriorFaces) self.eq.solve(var, boundaryConditions=boundaryConditions, solver=solver, dt=1.) def sweep(self, var, solver=None, boundaryConditions=(), dt=None, underRelaxation=None, residualFn=None): r""" 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 """ self.dt.setValue(dt) if solver is None: from fipy.solvers import DefaultAsymmetricSolver solver = DefaultAsymmetricSolver() if type(boundaryConditions) not in (type(()), type([])): boundaryConditions = (boundaryConditions, ) var.constrain(0, var.mesh.exteriorFaces) return self.eq.sweep(var, solver=solver, boundaryConditions=boundaryConditions, underRelaxation=underRelaxation, residualFn=residualFn, dt=1.)
phase = CellVariable(name='PhaseField', mesh=mesh, value=1.) from fipy.variables.modularVariable import ModularVariable theta = ModularVariable(name='Theta', mesh=mesh, value=1.) theta.setValue(0., where=mesh.getCellCenters()[..., 0] > L / 2.) from fipy.terms.implicitSourceTerm import ImplicitSourceTerm mPhiVar = phase - 0.5 + temperature * phase * (1 - phase) thetaMag = theta.getOld().getGrad().getMag() implicitSource = mPhiVar * (phase - (mPhiVar < 0)) implicitSource += (2 * s + epsilon**2 * thetaMag) * thetaMag from fipy.terms.transientTerm import TransientTerm from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm phaseEq = TransientTerm(phaseTransientCoeff) == \ ExplicitDiffusionTerm(alpha**2) \ - ImplicitSourceTerm(implicitSource) \ + (mPhiVar > 0) * mPhiVar * phase if __name__ == '__main__': import fipy.viewers phaseViewer = fipy.viewers.make(vars=phase) phaseViewer.plot() for step in range(steps): phaseEq.solve(phase, dt=timeStepDuration) phaseViewer.plot() raw_input('finished')
def __init__(self, surfactantVar=None, distanceVar=None, bulkVar=None, rateConstant=None, otherVar=None, otherBulkVar=None, otherRateConstant=None, consumptionCoeff=None): """ 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. """ self.eq = TransientTerm(coeff=1) - ExplicitUpwindConvectionTerm( SurfactantConvectionVariable(distanceVar)) self.dt = Variable(0.) mesh = distanceVar.mesh adsorptionCoeff = self.dt * bulkVar * rateConstant spCoeff = adsorptionCoeff * distanceVar._cellInterfaceFlag scCoeff = adsorptionCoeff * distanceVar.cellInterfaceAreas / mesh.cellVolumes self.eq += ImplicitSourceTerm(spCoeff) - scCoeff if otherVar is not None: otherSpCoeff = self.dt * otherBulkVar * otherRateConstant * distanceVar._cellInterfaceFlag otherScCoeff = -otherVar.interfaceVar * scCoeff self.eq += ImplicitSourceTerm(otherSpCoeff) - otherScCoeff vars = (surfactantVar, otherVar) else: vars = (surfactantVar, ) total = 0 for var in vars: total += var.interfaceVar maxVar = (total > 1) * distanceVar._cellInterfaceFlag val = distanceVar.cellInterfaceAreas / mesh.cellVolumes for var in vars[1:]: val -= distanceVar._cellInterfaceFlag * var spMaxCoeff = 1e20 * maxVar scMaxCoeff = spMaxCoeff * val * (val > 0) self.eq += ImplicitSourceTerm(spMaxCoeff) - scMaxCoeff - 1e-40 if consumptionCoeff is not None: self.eq += ImplicitSourceTerm(consumptionCoeff)
dx = 1. dy = 1. nx = 10 ny = 1 valueLeft = 0. valueRight = 1. timeStepDuration = 0.02 mesh = Tri2D(dx, dy, nx, ny) var = CellVariable( name = "concentration", mesh = mesh, value = valueLeft) eq = TransientTerm() == ExplicitDiffusionTerm() solver = LinearLUSolver(tolerance = 1.e-6, iterations = 100) boundaryConditions=(FixedValue(mesh.getFacesLeft(),valueLeft), FixedValue(mesh.getFacesRight(),valueRight)) answer = numerix.array([ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.58508452e-07, 6.84325019e-04, 7.05111362e-02, 7.81376523e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 4.99169535e-05, 1.49682805e-02, 3.82262622e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 4.06838361e-06, 3.67632029e-03, 1.82227062e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
mesh = Grid2D(dx, dy, nx, ny) from fipy.variables.cellVariable import CellVariable from fipy.tools.numerix import random var = CellVariable(name="phase field", mesh=mesh, value=random.random(nx * ny)) faceVar = var.getArithmeticFaceValue() doubleWellDerivative = asq * (1 - 6 * faceVar * (1 - faceVar)) from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm diffTerm2 = ImplicitDiffusionTerm(coeff=(diffusionCoeff * doubleWellDerivative, )) diffTerm4 = ImplicitDiffusionTerm(coeff=(diffusionCoeff, -epsilon**2)) eqch = TransientTerm() - diffTerm2 - diffTerm4 from fipy.solvers.linearPCGSolver import LinearPCGSolver from fipy.solvers.linearLUSolver import LinearLUSolver ##solver = LinearLUSolver(tolerance = 1e-15,steps = 1000) solver = LinearPCGSolver(tolerance=1e-15, steps=1000) from fipy.boundaryConditions.fixedValue import FixedValue from fipy.boundaryConditions.fixedFlux import FixedFlux from fipy.boundaryConditions.nthOrderBoundaryCondition import NthOrderBoundaryCondition BCs = (FixedFlux(mesh.getFacesRight(), 0), FixedFlux(mesh.getFacesLeft(), 0), NthOrderBoundaryCondition(mesh.getFacesLeft(), 0, 3), NthOrderBoundaryCondition(mesh.getFacesRight(), 0, 3), NthOrderBoundaryCondition(mesh.getFacesTop(), 0, 3), NthOrderBoundaryCondition(mesh.getFacesBottom(), 0, 3))
phaseY = phase.getFaceGrad().dot((0, 1)) phaseX = phase.getFaceGrad().dot((1, 0)) psi = theta + numerix.arctan2(phaseY, phaseX) Phi = numerix.tan(N * psi / 2) PhiSq = Phi**2 beta = (1. - PhiSq) / (1. + PhiSq) betaPsi = -N * 2 * Phi / (1 + PhiSq) A = alpha**2 * c * (1.+ c * beta) * betaPsi D = alpha**2 * (1.+ c * beta)**2 dxi = phase.getFaceGrad()._take((1, 0), axis = 1) * (-1, 1) anisotropySource = (A * dxi).getDivergence() from fipy.terms.transientTerm import TransientTerm from fipy.terms.explicitDiffusionTerm import ExplicitDiffusionTerm from fipy.terms.implicitSourceTerm import ImplicitSourceTerm phaseEq = TransientTerm(tau) == ExplicitDiffusionTerm(D) + \ ImplicitSourceTerm(mVar * ((mVar < 0) - phase)) + \ ((mVar > 0.) * mVar * phase + anisotropySource) from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm temperatureEq = TransientTerm() == \ ImplicitDiffusionTerm(tempDiffusionCoeff) + \ (phase - phase.getOld()) / timeStepDuration bench.stop('terms') phase.updateOld() temperature.updateOld() phaseEq.solve(phase, dt=timeStepDuration) temperatureEq.solve(temperature, dt=timeStepDuration) steps = 10
bench.start() from fipy.variables.cellVariable import CellVariable C = CellVariable(mesh=mesh) C.setValue(1, where=abs(mesh.getCellCenters()[..., 0] - L / 2.) < L / 10.) bench.stop('variables') bench.start() D = 1. from fipy.terms.implicitDiffusionTerm import ImplicitDiffusionTerm from fipy.terms.transientTerm import TransientTerm eq = TransientTerm() == ImplicitDiffusionTerm(coeff=D) bench.stop('terms') ## from fipy import viewers ## viewer = viewers.make(vars = C, limits = {'datamin': 0, 'datamax': 1}) ## viewer.plot() ## raw_input("initial") bench.start() dt = 1e0 steps = 1 for step in range(steps): eq.solve(var=C, dt=dt) ## viewer.plot()