Esempio n. 1
0
def runSimpleTrenchSystem(faradaysConstant=9.6e4,
                          gasConstant=8.314,
                          transferCoefficient=0.5,
                          rateConstant0=1.76,
                          rateConstant3=-245e-6,
                          catalystDiffusion=1e-9,
                          siteDensity=9.8e-6,
                          molarVolume=7.1e-6,
                          charge=2,
                          metalDiffusion=5.6e-10,
                          temperature=298.,
                          overpotential=-0.3,
                          metalConcentration=250.,
                          catalystConcentration=5e-3,
                          catalystCoverage=0.,
                          currentDensity0=0.26,
                          currentDensity1=45.,
                          cellSize=0.1e-7,
                          trenchDepth=0.5e-6,
                          aspectRatio=2.,
                          trenchSpacing=0.6e-6,
                          boundaryLayerDepth=0.3e-6,
                          numberOfSteps=5,
                          displayViewers=True):

    cflNumber = 0.2
    numberOfCellsInNarrowBand = 10
    cellsBelowTrench = 10

    yCells = cellsBelowTrench \
             + int((trenchDepth + boundaryLayerDepth) / cellSize)

    xCells = int(trenchSpacing / 2 / cellSize)

    from fipy.tools import serialComm
    mesh = Grid2D(dx=cellSize,
                  dy=cellSize,
                  nx=xCells,
                  ny=yCells,
                  communicator=serialComm)

    narrowBandWidth = numberOfCellsInNarrowBand * cellSize

    distanceVar = DistanceVariable(name='distance variable',
                                   mesh=mesh,
                                   value=-1.,
                                   hasOld=1)

    bottomHeight = cellsBelowTrench * cellSize
    trenchHeight = bottomHeight + trenchDepth
    trenchWidth = trenchDepth / aspectRatio
    sideWidth = (trenchSpacing - trenchWidth) / 2

    x, y = mesh.cellCenters
    distanceVar.setValue(1.,
                         where=(y > trenchHeight) |
                         ((y > bottomHeight) &
                          (x < xCells * cellSize - sideWidth)))

    distanceVar.calcDistanceFunction(order=2)

    catalystVar = SurfactantVariable(name="catalyst variable",
                                     value=catalystCoverage,
                                     distanceVar=distanceVar)

    bulkCatalystVar = CellVariable(name='bulk catalyst variable',
                                   mesh=mesh,
                                   value=catalystConcentration)

    metalVar = CellVariable(name='metal variable',
                            mesh=mesh,
                            value=metalConcentration)

    expoConstant = -transferCoefficient * faradaysConstant \
                   / (gasConstant * temperature)

    tmp = currentDensity1 * catalystVar.interfaceVar

    exchangeCurrentDensity = currentDensity0 + tmp

    expo = numerix.exp(expoConstant * overpotential)
    currentDensity = expo * exchangeCurrentDensity * metalVar \
                     / metalConcentration

    depositionRateVariable = currentDensity * molarVolume \
                             / (charge * faradaysConstant)

    extensionVelocityVariable = CellVariable(name='extension velocity',
                                             mesh=mesh,
                                             value=depositionRateVariable)

    surfactantEquation = AdsorbingSurfactantEquation(
        surfactantVar=catalystVar,
        distanceVar=distanceVar,
        bulkVar=bulkCatalystVar,
        rateConstant=rateConstant0 + rateConstant3 * overpotential**3)

    advectionEquation = TransientTerm() + AdvectionTerm(
        extensionVelocityVariable)

    metalEquation = buildMetalIonDiffusionEquation(
        ionVar=metalVar,
        distanceVar=distanceVar,
        depositionRate=depositionRateVariable,
        diffusionCoeff=metalDiffusion,
        metalIonMolarVolume=molarVolume,
    )

    metalVar.constrain(metalConcentration, mesh.facesTop)

    from surfactantBulkDiffusionEquation import buildSurfactantBulkDiffusionEquation
    bulkCatalystEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar=bulkCatalystVar,
        distanceVar=distanceVar,
        surfactantVar=catalystVar,
        diffusionCoeff=catalystDiffusion,
        rateConstant=rateConstant0 * siteDensity)

    bulkCatalystVar.constrain(catalystConcentration, mesh.facesTop)

    if displayViewers:
        try:
            from mayaviSurfactantViewer import MayaviSurfactantViewer
            viewer = MayaviSurfactantViewer(distanceVar,
                                            catalystVar.interfaceVar,
                                            zoomFactor=1e6,
                                            datamax=0.5,
                                            datamin=0.0,
                                            smooth=1,
                                            title='catalyst coverage')
        except:
            viewer = MultiViewer(
                viewers=(Viewer(distanceVar, datamin=-1e-9, datamax=1e-9),
                         Viewer(catalystVar.interfaceVar)))
    else:
        viewer = None

    levelSetUpdateFrequency = int(0.8 * narrowBandWidth \
                                  / (cellSize * cflNumber * 2))

    for step in range(numberOfSteps):

        if step > 5 and step % 5 == 0 and viewer is not None:
            viewer.plot()

        if step % levelSetUpdateFrequency == 0:
            distanceVar.calcDistanceFunction(order=2)

        extensionVelocityVariable.setValue(depositionRateVariable())

        distanceVar.updateOld()

        distanceVar.extendVariable(extensionVelocityVariable, order=2)
        dt = cflNumber * cellSize / extensionVelocityVariable.max()

        advectionEquation.solve(distanceVar, dt=dt)
        surfactantEquation.solve(catalystVar, dt=dt)
        metalEquation.solve(metalVar, dt=dt)
        bulkCatalystEquation.solve(bulkCatalystVar,
                                   dt=dt,
                                   solver=GeneralSolver(tolerance=1e-15,
                                                        iterations=2000))

    try:
        import os
        filepath = os.path.splitext(__file__)[0] + '.gz'
        print catalystVar.allclose(numerix.loadtxt(filepath), rtol=1e-4)
    except:
        return 0
Esempio n. 2
0
def runLeveler(kLeveler=0.018,
               bulkLevelerConcentration=0.02,
               cellSize=0.1e-7,
               rateConstant=0.00026,
               initialAcceleratorCoverage=0.0,
               levelerDiffusionCoefficient=5e-10,
               numberOfSteps=400,
               displayRate=10,
               displayViewers=True):

    kLevelerConsumption = 0.0005
    aspectRatio = 1.5
    faradaysConstant = 9.6485e4
    gasConstant = 8.314
    acceleratorDiffusionCoefficient = 4e-10
    siteDensity = 6.35e-6
    atomicVolume = 7.1e-6
    charge = 2
    metalDiffusionCoefficient = 4e-10
    temperature = 298.
    overpotential = -0.25
    bulkMetalConcentration = 250.
    bulkAcceleratorConcentration = 50.0e-3
    initialLevelerCoverage = 0.
    cflNumber = 0.2
    cellsBelowTrench = 10
    trenchDepth = 0.4e-6
    trenchSpacing = 0.6e-6
    boundaryLayerDepth = 98.7e-6
    i0Suppressor = 0.3
    i0Accelerator = 22.5
    alphaSuppressor = 0.5
    alphaAccelerator = 0.4
    alphaAdsorption = 0.62
    m = 4
    b = 2.65
    A = 0.3
    Ba = -40
    Bb = 60
    Vd = 0.098
    Bd = 0.0008

    etaPrime = faradaysConstant * overpotential / gasConstant / temperature

    mesh = TrenchMesh(cellSize=cellSize,
                      trenchSpacing=trenchSpacing,
                      trenchDepth=trenchDepth,
                      boundaryLayerDepth=boundaryLayerDepth,
                      aspectRatio=aspectRatio,
                      angle=numerix.pi * 4. / 180.)

    distanceVar = GapFillDistanceVariable(name='distance variable',
                                          mesh=mesh,
                                          value=-1.)

    distanceVar.setValue(1., where=mesh.electrolyteMask)

    distanceVar.calcDistanceFunction()
    levelerVar = SurfactantVariable(name="leveler variable",
                                    value=initialLevelerCoverage,
                                    distanceVar=distanceVar)

    acceleratorVar = SurfactantVariable(name="accelerator variable",
                                        value=initialAcceleratorCoverage,
                                        distanceVar=distanceVar)

    bulkAcceleratorVar = CellVariable(name='bulk accelerator variable',
                                      mesh=mesh,
                                      value=bulkAcceleratorConcentration)

    bulkLevelerVar = CellVariable(name='bulk leveler variable',
                                  mesh=mesh,
                                  value=bulkLevelerConcentration)

    metalVar = CellVariable(name='metal variable',
                            mesh=mesh,
                            value=bulkMetalConcentration)

    def depositionCoeff(alpha, i0):
        expo = numerix.exp(-alpha * etaPrime)
        return 2 * i0 * (expo - expo * numerix.exp(etaPrime))

    coeffSuppressor = depositionCoeff(alphaSuppressor, i0Suppressor)
    coeffAccelerator = depositionCoeff(alphaAccelerator, i0Accelerator)

    exchangeCurrentDensity = acceleratorVar.interfaceVar * (
        coeffAccelerator - coeffSuppressor) + coeffSuppressor

    currentDensity = metalVar / bulkMetalConcentration * exchangeCurrentDensity

    depositionRateVariable = currentDensity * atomicVolume / charge / faradaysConstant

    extensionVelocityVariable = CellVariable(name='extension velocity',
                                             mesh=mesh,
                                             value=depositionRateVariable)

    kAccelerator = rateConstant * numerix.exp(-alphaAdsorption * etaPrime)
    kAcceleratorConsumption = Bd + A / (numerix.exp(Ba *
                                                    (overpotential + Vd)) +
                                        numerix.exp(Bb * (overpotential + Vd)))
    q = m * overpotential + b

    levelerSurfactantEquation = AdsorbingSurfactantEquation(
        levelerVar,
        distanceVar=distanceVar,
        bulkVar=bulkLevelerVar,
        rateConstant=kLeveler,
        consumptionCoeff=kLevelerConsumption * depositionRateVariable)

    accVar1 = acceleratorVar.interfaceVar
    accVar2 = (accVar1 > 0) * accVar1
    accConsumptionCoeff = kAcceleratorConsumption * (accVar2**(q - 1))

    acceleratorSurfactantEquation = AdsorbingSurfactantEquation(
        acceleratorVar,
        distanceVar=distanceVar,
        bulkVar=bulkAcceleratorVar,
        rateConstant=kAccelerator,
        otherVar=levelerVar,
        otherBulkVar=bulkLevelerVar,
        otherRateConstant=kLeveler,
        consumptionCoeff=accConsumptionCoeff)

    advectionEquation = TransientTerm() + FirstOrderAdvectionTerm(
        extensionVelocityVariable)

    metalEquation = buildMetalIonDiffusionEquation(
        ionVar=metalVar,
        distanceVar=distanceVar,
        depositionRate=depositionRateVariable,
        diffusionCoeff=metalDiffusionCoefficient,
        metalIonMolarVolume=atomicVolume)

    metalVar.constrain(bulkMetalConcentration, mesh.facesTop)

    bulkAcceleratorEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar=bulkAcceleratorVar,
        distanceVar=distanceVar,
        surfactantVar=acceleratorVar,
        otherSurfactantVar=levelerVar,
        diffusionCoeff=acceleratorDiffusionCoefficient,
        rateConstant=kAccelerator * siteDensity)

    bulkAcceleratorVar.constrain(bulkAcceleratorConcentration, mesh.facesTop)

    bulkLevelerEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar=bulkLevelerVar,
        distanceVar=distanceVar,
        surfactantVar=levelerVar,
        diffusionCoeff=levelerDiffusionCoefficient,
        rateConstant=kLeveler * siteDensity)

    bulkLevelerVar.constrain(bulkLevelerConcentration, mesh.facesTop)

    eqnTuple = ((advectionEquation, distanceVar, (),
                 None), (levelerSurfactantEquation, levelerVar, (), None),
                (acceleratorSurfactantEquation, acceleratorVar, (),
                 None), (metalEquation, metalVar, (), None),
                (bulkAcceleratorEquation, bulkAcceleratorVar, (),
                 GeneralSolver()), (bulkLevelerEquation, bulkLevelerVar, (),
                                    GeneralSolver()))

    narrowBandWidth = 20 * cellSize
    levelSetUpdateFrequency = int(0.7 * narrowBandWidth / cellSize /
                                  cflNumber / 2)

    totalTime = 0.0

    if displayViewers:
        try:
            raise Exception
            from mayaviSurfactantViewer import MayaviSurfactantViewer
            viewers = (MayaviSurfactantViewer(distanceVar,
                                              acceleratorVar.interfaceVar,
                                              zoomFactor=1e6,
                                              datamax=0.5,
                                              datamin=0.0,
                                              smooth=1,
                                              title='accelerator coverage'),
                       MayaviSurfactantViewer(distanceVar,
                                              levelerVar.interfaceVar,
                                              zoomFactor=1e6,
                                              datamax=0.5,
                                              datamin=0.0,
                                              smooth=1,
                                              title='leveler coverage'))
        except:

            class PlotVariable(CellVariable):
                def __init__(self, var=None, name=''):
                    CellVariable.__init__(self, mesh=mesh.fineMesh, name=name)
                    self.var = self._requires(var)

                def _calcValue(self):
                    return numerix.array(self.var(self.mesh.cellCenters))

            viewers = (Viewer(PlotVariable(var=acceleratorVar.interfaceVar)),
                       Viewer(PlotVariable(var=levelerVar.interfaceVar)))

    for step in range(numberOfSteps):

        if displayViewers:
            if step % displayRate == 0:
                for viewer in viewers:
                    viewer.plot()

        if step % levelSetUpdateFrequency == 0:
            distanceVar.calcDistanceFunction()

        extensionVelocityVariable.setValue(depositionRateVariable)

        extOnInt = numerix.where(
            distanceVar.globalValue > 0,
            numerix.where(distanceVar.globalValue < 2 * cellSize,
                          extensionVelocityVariable.globalValue, 0), 0)

        dt = cflNumber * cellSize / extOnInt.max()

        distanceVar.extendVariable(extensionVelocityVariable)

        for eqn, var, BCs, solver in eqnTuple:
            eqn.solve(var, boundaryConditions=BCs, dt=dt, solver=solver)

        totalTime += dt

    point = ((1.25e-08, ), (3.125e-07, ))
    value = 2.02815779e-08
    return abs(float(distanceVar(point, order=1)) - value) < cellSize / 10.0
Esempio n. 3
0
def runGold(faradaysConstant=9.6e4,
            consumptionRateConstant=2.6e+6,
            molarVolume=10.21e-6,
            charge=1.0,
            metalDiffusion=1.7e-9,
            metalConcentration=20.0,
            catalystCoverage=0.15,
            currentDensity0=3e-2 * 16,
            currentDensity1=6.5e-1 * 16,
            cellSize=0.1e-7,
            trenchDepth=0.2e-6,
            aspectRatio=1.47,
            trenchSpacing=0.5e-6,
            boundaryLayerDepth=90.0e-6,
            numberOfSteps=10,
            taperAngle=6.0,
            displayViewers=True):
    
    cflNumber = 0.2
    numberOfCellsInNarrowBand = 20
    
    mesh = TrenchMesh(cellSize = cellSize,
                      trenchSpacing = trenchSpacing,
                      trenchDepth = trenchDepth,
                      boundaryLayerDepth = boundaryLayerDepth,
                      aspectRatio = aspectRatio,
                      angle = numerix.pi * taperAngle / 180.)

    narrowBandWidth = numberOfCellsInNarrowBand * cellSize

    distanceVar = GapFillDistanceVariable(
       name = 'distance variable',
       mesh = mesh,
       value = -1.)

    distanceVar.setValue(1., where=mesh.electrolyteMask)
    distanceVar.calcDistanceFunction()

    catalystVar = SurfactantVariable(
        name = "catalyst variable",
        value = catalystCoverage,
        distanceVar = distanceVar)

    metalVar = CellVariable(
        name = 'metal variable',
        mesh = mesh,
        value = metalConcentration)

    exchangeCurrentDensity = currentDensity0 + currentDensity1 * catalystVar.interfaceVar
    
    currentDensity = metalVar / metalConcentration * exchangeCurrentDensity

    depositionRateVariable = currentDensity * molarVolume / charge / faradaysConstant

    extensionVelocityVariable = CellVariable(
        name = 'extension velocity',
        mesh = mesh,
        value = depositionRateVariable)   

    catalystSurfactantEquation = AdsorbingSurfactantEquation(
        catalystVar,
        distanceVar = distanceVar,
        bulkVar = 0,
        rateConstant = 0,
        consumptionCoeff = consumptionRateConstant * extensionVelocityVariable)

    advectionEquation = TransientTerm() + FirstOrderAdvectionTerm(extensionVelocityVariable)

    metalEquation = buildMetalIonDiffusionEquation(
        ionVar = metalVar,
        distanceVar = distanceVar,
        depositionRate = depositionRateVariable,
        diffusionCoeff = metalDiffusion,
        metalIonMolarVolume = molarVolume)

    metalVar.constrain(metalConcentration, mesh.facesTop)

    if displayViewers:

        try:
            from mayaviSurfactantViewer import MayaviSurfactantViewer
            viewer = MayaviSurfactantViewer(distanceVar, catalystVar.interfaceVar, zoomFactor = 1e6, datamax=1.0, datamin=0.0, smooth = 1, title = 'catalyst coverage', animate=True)
            
        except:
            
            class PlotVariable(CellVariable):
                def __init__(self, var = None, name = ''):
                    CellVariable.__init__(self, mesh = mesh.fineMesh, name = name)
                    self.var = self._requires(var)

                def _calcValue(self):
                    return numerix.array(self.var(self.mesh.cellCenters))

            viewer = MultiViewer(viewers=(
                    Viewer(PlotVariable(var = distanceVar), datamax=1e-9, datamin=-1e-9),
                    Viewer(PlotVariable(var = catalystVar.interfaceVar))))
    else:
        viewer = None

    levelSetUpdateFrequency = int(0.7 * narrowBandWidth / cellSize / cflNumber / 2)
    step = 0

    while step < numberOfSteps:

        if step % 10 == 0 and viewer is not None:
            viewer.plot()

        if step % levelSetUpdateFrequency == 0:
            
            distanceVar.calcDistanceFunction()

        extensionVelocityVariable.setValue(numerix.array(depositionRateVariable))

        dt = cflNumber * cellSize / max(extensionVelocityVariable.globalValue)
        distanceVar.extendVariable(extensionVelocityVariable)

        advectionEquation.solve(distanceVar, dt = dt)

        catalystSurfactantEquation.solve(catalystVar, dt = dt)

        metalEquation.solve(metalVar, dt = dt)
                    
        step += 1

    point = ((5e-09,), (1.15e-07,))
    value = 1.45346701e-09
    return abs(float(distanceVar(point, order=1)) - value) < cellSize / 10.0
Esempio n. 4
0
def runSimpleTrenchSystem(
    faradaysConstant=9.6e4,
    gasConstant=8.314,
    transferCoefficient=0.5,
    rateConstant0=1.76,
    rateConstant3=-245e-6,
    catalystDiffusion=1e-9,
    siteDensity=9.8e-6,
    molarVolume=7.1e-6,
    charge=2,
    metalDiffusion=5.6e-10,
    temperature=298.0,
    overpotential=-0.3,
    metalConcentration=250.0,
    catalystConcentration=5e-3,
    catalystCoverage=0.0,
    currentDensity0=0.26,
    currentDensity1=45.0,
    cellSize=0.1e-7,
    trenchDepth=0.5e-6,
    aspectRatio=2.0,
    trenchSpacing=0.6e-6,
    boundaryLayerDepth=0.3e-6,
    numberOfSteps=5,
    displayViewers=True,
):

    cflNumber = 0.2
    numberOfCellsInNarrowBand = 10
    cellsBelowTrench = 10

    yCells = cellsBelowTrench + int((trenchDepth + boundaryLayerDepth) / cellSize)

    xCells = int(trenchSpacing / 2 / cellSize)

    from fipy.tools import serialComm

    mesh = Grid2D(dx=cellSize, dy=cellSize, nx=xCells, ny=yCells, communicator=serialComm)

    narrowBandWidth = numberOfCellsInNarrowBand * cellSize

    distanceVar = DistanceVariable(name="distance variable", mesh=mesh, value=-1.0, hasOld=1)

    bottomHeight = cellsBelowTrench * cellSize
    trenchHeight = bottomHeight + trenchDepth
    trenchWidth = trenchDepth / aspectRatio
    sideWidth = (trenchSpacing - trenchWidth) / 2

    x, y = mesh.cellCenters
    distanceVar.setValue(1.0, where=(y > trenchHeight) | ((y > bottomHeight) & (x < xCells * cellSize - sideWidth)))

    distanceVar.calcDistanceFunction(order=2)

    catalystVar = SurfactantVariable(name="catalyst variable", value=catalystCoverage, distanceVar=distanceVar)

    bulkCatalystVar = CellVariable(name="bulk catalyst variable", mesh=mesh, value=catalystConcentration)

    metalVar = CellVariable(name="metal variable", mesh=mesh, value=metalConcentration)

    expoConstant = -transferCoefficient * faradaysConstant / (gasConstant * temperature)

    tmp = currentDensity1 * catalystVar.interfaceVar

    exchangeCurrentDensity = currentDensity0 + tmp

    expo = numerix.exp(expoConstant * overpotential)
    currentDensity = expo * exchangeCurrentDensity * metalVar / metalConcentration

    depositionRateVariable = currentDensity * molarVolume / (charge * faradaysConstant)

    extensionVelocityVariable = CellVariable(name="extension velocity", mesh=mesh, value=depositionRateVariable)

    surfactantEquation = AdsorbingSurfactantEquation(
        surfactantVar=catalystVar,
        distanceVar=distanceVar,
        bulkVar=bulkCatalystVar,
        rateConstant=rateConstant0 + rateConstant3 * overpotential ** 3,
    )

    advectionEquation = TransientTerm() + AdvectionTerm(extensionVelocityVariable)

    metalEquation = buildMetalIonDiffusionEquation(
        ionVar=metalVar,
        distanceVar=distanceVar,
        depositionRate=depositionRateVariable,
        diffusionCoeff=metalDiffusion,
        metalIonMolarVolume=molarVolume,
    )

    metalVar.constrain(metalConcentration, mesh.facesTop)

    from surfactantBulkDiffusionEquation import buildSurfactantBulkDiffusionEquation

    bulkCatalystEquation = buildSurfactantBulkDiffusionEquation(
        bulkVar=bulkCatalystVar,
        distanceVar=distanceVar,
        surfactantVar=catalystVar,
        diffusionCoeff=catalystDiffusion,
        rateConstant=rateConstant0 * siteDensity,
    )

    bulkCatalystVar.constrain(catalystConcentration, mesh.facesTop)

    if displayViewers:
        try:
            from mayaviSurfactantViewer import MayaviSurfactantViewer

            viewer = MayaviSurfactantViewer(
                distanceVar,
                catalystVar.interfaceVar,
                zoomFactor=1e6,
                datamax=0.5,
                datamin=0.0,
                smooth=1,
                title="catalyst coverage",
            )
        except:
            viewer = MultiViewer(
                viewers=(Viewer(distanceVar, datamin=-1e-9, datamax=1e-9), Viewer(catalystVar.interfaceVar))
            )
    else:
        viewer = None

    levelSetUpdateFrequency = int(0.8 * narrowBandWidth / (cellSize * cflNumber * 2))

    for step in range(numberOfSteps):

        if step % 5 == 0 and viewer is not None:
            viewer.plot()

        if step % levelSetUpdateFrequency == 0:
            distanceVar.calcDistanceFunction(order=2)

        extensionVelocityVariable.setValue(depositionRateVariable())

        distanceVar.updateOld()

        distanceVar.extendVariable(extensionVelocityVariable, order=2)
        dt = cflNumber * cellSize / extensionVelocityVariable.max()

        advectionEquation.solve(distanceVar, dt=dt)
        surfactantEquation.solve(catalystVar, dt=dt)
        metalEquation.solve(metalVar, dt=dt)
        bulkCatalystEquation.solve(bulkCatalystVar, dt=dt, solver=GeneralSolver(tolerance=1e-15, iterations=2000))

    try:
        import os

        filepath = os.path.splitext(__file__)[0] + ".gz"
        print catalystVar.allclose(numerix.loadtxt(filepath), rtol=1e-4)
    except:
        return 0