Extreme Fill

This Python package generates the data required to reproduce the figures in Modeling Extreme Bottom-Up Filling of through Silicon Vias by Josell, Wheeler and Moffat.

Requirements

The main requirements are a working version of FiPy to solve the PDEs and PyTables to store the data in an HDF5 file. See requirements.txt for specific versions of dependencies used to run this package on the maintainer’s system. The requirements.txt file is auto-generated so most of the packages listed are not necessarily required. If you are having issues with installation and missing packages this would be a good place to start looking. If the plots are not generated correctly for some reason or latex errors are occurring, it might be worth checking the maintainer’s matplotlibrc file for clues on the correct latex packages to install and the correct matplotlib configuration.

Installation

The following should get you most of the way to an install.

$ pip install numpy
$ pip install tables
$ pip install pysparse
$ pip install fipy
$ pip install matplotlib

and then clone the git repository

$ git clone git://github.com/wd15/extremefill.git

See the Github project page for further details. After cloning, install with

$ cd extremefill
$ python setup.py install

Documentation

Use:

$ cd doc
$ make html

to generate this documentation.

Usage

extremefill.generateFigures(filesuffix=('.png', ), datafile='data.h5', fignumbers=(2, 3, 4, 5, 6, 7, 8, 9))

Generate all the figures in the paper. By default PNG images are generated.

To generate Figure 3 from the paper:

>>> import extremefill
>>> extremefill.generateFigures(fignumbers=3)
Figure 3 from the paper
Parameters :
  • filesuffix: tuple of the file suffixes of the generated images.
  • datafile: path to the cached HDF5 data file to either read from or write to.
  • fignumbers : tuple of figure numbers to generate.
extremefill.test()

Run all the doctests available.

extremefill.run(view=True, **parameters)

Run a single simulation using Simulation.run.

Run the default simulation for 10 time steps

>>> import extremefill
>>> extremefill.run(totalSteps=10)
Default simulation after 10 time steps

The negative x values represents the trench domain while the positive values represent the electrolyte domain. The red, blue, green and cyan curves represent normalized values for the cupric concentration, adsorbed suppressor, suppressor concentration and potential, respectively.

Parameters :
  • view : view the simulation as it is running
  • parameters : any of the parameters used in Simulation.run
class extremefill.simulation.Simulation

This class solves the 1D extreme fill problem modeled with the equations below. It can represent either a via or a trench geometry depending on the choice of the geometric parameters. It is assumed that there is no lateral variation in any of the fields and the deposition rate is slow compared with the adjustment of the fields. These are gross approximations, but the model demonstrates how the critical phenomenon of extreme fill is initiated.

The equations in order of potential, cupric concentration and suppressor concentration and surfactant suppressor integrated over space.

\int_{-h}^{\delta}  dz \left[ c_{DL} \frac{\partial \psi}{\partial t} \Theta \left( z \right) =
\kappa \frac{\partial^2 \psi}{\partial z^2} A \left(z \right) -
i_F \left(z\right) \Theta \left(z \right)  \right]

\int_{-h}^{\delta}  dz  \left[\frac{\partial c_{\text{cu}}}{\partial t} A \left( z \right)  =
D_{cu} \frac{\partial^2 c_{\text{cu}}}{\partial z^2} A \left(z \right)  -
\frac{i_F\left(z\right)}{n F} \Theta \left(z \right) \right]

\int_{-h}^{\delta}  dz \left[\frac{\partial c_{\theta}}{\partial t} A \left( z \right) =
D_{\theta} \frac{\partial^2 c_{\theta}}{\partial z^2} A \left(z \right)  -
\Gamma k^+ c_{\theta} \left(1 - \theta \right)  \Theta \left(z \right)  \right]

\int_{-h}^{\delta}  dz \left[\frac{\partial \theta}{\partial t} \Theta \left( z \right) =
k^+ c_{\theta} \left(1 - \theta \right)  \Theta \left(z \right)  -
k^- \theta \frac{i_F \Omega}{n F} \Theta \left(z \right) \right]

where \Theta\left( z \right) = H\left(- z \right) \frac{l
\left( z \right)}{A_F} + \delta \left( z \right)\left(1 -
\frac{A_T}{A_F} \right) + \delta(z + h) \frac{A_T}{A_F}. The cross-sectional area ratio is given by,

A \left( z \right) = \begin{cases}
1 & \text{when $z > 0$,} \\
\frac{A_T}{A_F} & \text{when $z \le 0$,}
\end{cases}

where A_F is the cross-sectional area above of the modeling domain and A_S is the cross-sectional area in the trench/via. The length of the perimeter is given by l\left(z\right) and is a step-function through 0. Also, \delta\left(z\right) is the Dirac delta function and H\left(z\right) is the Heaviside step function with z=-h at the bottom of the trench. The current density is given by,

i_F = \frac{c_{\text{cu}}}{c_{\text{cu}}^{\infty}} \left(i_0 + i_{\theta} \theta\right) \left[\exp{\left(\frac{\alpha F \psi}{R T} \right)} -  \exp{\left(-\frac{\left(2 -\alpha\right) F \psi}{R T} \right)}  \right]

The boundary conditions on the working electrode are included in the volume integrals. Additionally,

\psi = -\eta_{\text{applied}} \;\; & \text{at $z = \delta_{\text{ref}}$} \\
\psi = -\eta_{\text{applied}} \;\; & \text{at $t = 0$} \\
c_{\text{cu}} = c_{\text{cu}}^{\infty} \;\; & \text{at $z = \delta$} \\
c_{\text{cu}} = c_{\text{cu}}^{\infty} \;\; & \text{at $t = 0$} \\
c_{\theta} = c_{\theta}^{\infty} \;\; & \text{at $z = \delta$} \\
c_{\theta} = c_{\theta}^{\infty} \;\; & \text{at $t = 0$}\\
\theta=0 \;\; & \text{at $t = 0$}

and

\psi_{\text{ref}} = \psi\left(0\right) \left(1 - \frac{\delta_{\text{ref}}}{\delta}\right)

The following code compares the full 1D feature model (but with no feature) with the simple 1D ODE for solving the electrical equation with no suppressor and no cupric depeletion.

>>> import numpy
>>> i0 = 40.
>>> alpha = 0.4
>>> F = 9.6485e4 ## C / mol = J / V / mol
>>> R = 8.314 ## J / K / mol
>>> T = 298. ## K
>>> appliedPotential = -0.275
>>> simulation = Simulation()
>>> simulation.run(delta=100e-6,
...                deltaRef=200e-6,
...                featureDepth=0.0,
...                i0=i0,
...                i1=0.0,
...                diffusionCupric=1e+10,
...                appliedPotential=appliedPotential,
...                faradaysConstant=F,
...                gasConstant=R,
...                alpha=alpha,
...                temperature=T,
...                totalSteps=200,
...                dt=.5e-7,
...                dtMax=.5e-7,
...                sweeps=5)
>>> timesScipy, potentialsScipy = SimulationODE().run(deltaRef=200e-6)
>>> print numpy.allclose(simulation.parameters['potentials'], potentialsScipy, atol=1e-4)
True
>>> ##import pylab
>>> ##pylab.figure()
>>> ##pylab.plot(timesScipy, simulation.parameters['potentials'], timesScipy, potentialsScipy)
>>> ##pylab.ylabel(r'$\phi\left(0\right)$ (V)')
>>> ##pylab.xlabel(r'$t$ (s)')
>>> ##pylab.savefig('FiPyVScipy.png')
>>> ##raw_input('stopped')

Agreement is good for \psi.

comparison of FiPy and SciPy for the potential equation

Another test is to check that the steady state cupric concentration is correct in the absence of any suppressor.

>>> delta = 150e-6
>>> D = 5.6e-10
>>> charge = 2
>>> cinf = 1000.
>>> simulation = Simulation()
>>> simulation.run(featureDepth=0.0,
...                i0=i0,
...                alpha=alpha,
...                i1=0.0,
...                view=False,
...                dt=1e-6,
...                dtMax=10.,
...                totalSteps=200,
...                PRINT=False,
...                appliedPotential=appliedPotential,
...                faradaysConstant=F,
...                gasConstant=R,
...                delta=delta,
...                diffusionCupric=D,
...                charge=charge,
...                bulkCupric=cinf)
>>> def iF0():
...     Fbar = F / R / T
...     V = simulation.parameters['potentials'][-1] 
...     return i0 * (numpy.exp(-alpha * Fbar * V) - numpy.exp((2 - alpha) * Fbar * V))
>>> cupric = simulation.parameters['cupric']
>>> print numpy.allclose(1 / (1 + iF0() * delta / D / charge / F / cinf), cupric[0] / cinf, rtol=1e-3)
True
run(dt=4.9999999999999998e-08, dtMax=1e+20, dtMin=4.9999999999999998e-08, totalSteps=400, view=False, PRINT=False, sweeps=5, tol=1e-10, delta=0.00014999999999999999, deltaRef=0.029999999999999999, featureDepth=5.5999999999999999e-05, i1=-40.0, i0=40.0, diffusionCupric=2.6500000000000002e-10, appliedPotential=-0.25, faradaysConstant=96485.0, gasConstant=8.3140000000000001, temperature=298.0, alpha=0.40000000000000002, charge=2, bulkCupric=1000.0, bulkSuppressor=0.02, diffusionSuppressor=9.2000000000000005e-11, kappa=15.26, kPlus=150.0, kMinus=24500000.0, omega=7.0999999999999998e-06, gamma=2.4999999999999999e-07, perimeterRatio=33214.285714285717, areaRatio=0.092999999999999999, capacitance=0.29999999999999999)

Run an individual simulation.

Parameters :
  • dt: time step size
  • dtMax: maximum time step size
  • dtMin: minimum time step size
  • totalSteps: total time steps
  • view: whether to view the simulation while running
  • PRINT: print convergence data
  • sweeps: number of sweeps at each time step
  • tol: tolerance to exit sweep loop
  • delta: boundary layer depth
  • deltaRef: distance to reference electrode
  • featureDepth: depth of the feature
  • i1: current density constant
  • i0: current density constant
  • diffusionCupric: cupric diffusion
  • appliedPotential: applied potential
  • faradaysConstant: Faraday’s constant
  • gasConstant: gas constant
  • temperature: temperature
  • alpha: kinetic factor
  • charge: charge
  • bulkCupric: bulk cupric concentration
  • bulkSuppressor: bulk suppressor concentration
  • diffusionSuppressor: suppressor diffusion
  • kappa: conductivity
  • kPlus: suppressor adsorption factor
  • kMinus: suppressor incorporation factor
  • omega: copper molar volume
  • gamma: saturation suppressor coverage,
  • perimeterRatio: feature perimeter ratio
  • areaRatio: feature area ratio
  • capacitance: capacitance

Indices and tables

Table Of Contents

This Page