Alagator Tutorial
Tutorial Examples
These examples are useful for helping to learn alagator and some of its capabilities. Fuller documentation of the language is also done, but that is not a very good teaching tool. The easiest way to learn specification of the equations is to work though some simple examples. More complex examples, including setup and callback procedures, are also available.
Fick's Law Diffusion
The simplest diffusion equation just uses a constant diffusivity and can be described by Fick's first and second law. There are two main steps that need to be done to initialize this equation and solve it. First, a solution must be defined. Second, the equation must be entered into the property data base. At minimum two commands can be used to accomplish this:
solution name=Conc !negative !damp always add pdbSetString Silicon Conc Equation "ddt(Conc) - 1.0e-15 * grad(Conc)"
The fist line creates a new solution with name "Conc". The solution is not allowed to take negative values and numerical damping is not applied to the Newton iteration updates. The solution is always going to be solved.
The second line makes an entry into the property data base, pdb. This is created for material silicon and solution variable "Conc". Please note that the name must match that on the solution command exactly. The entry is made for an Equation, which is the predefined entry that alagator looks for to find a differential equation. The string value set is the differential equation that will be solved for this variable in this material. The equation uses a time operator, "ddt", and the gradient operator, "grad", to implement a simple diffusion equation. The divergence operator is implied, and computed as part of the discretization of the equations. These terms are set to zero during the solution procedure using a Newton iteration. The solution name in the equation, "Conc", also has to be identical to the name on the solution command. The diffusivity is hard wired to be 10-15 cm2/s.
This will work, but will not allow for a temperature dependent diffusivity. To use a temperature dependent diffusivity, the following can be input:
set diff {[Arrhenius 0.1 3.62]} pdbSetString Silicon Conc Equation "ddt(Conc) - ($diff) * grad(Conc)"
In the first line, we create a local tcl variable to hold a string representing the diffusivity. The curly braces, "{}", are necessary to prevent immediate evaluation of the Arrhenius function. The Arrhenius function is a predefined helper function that allows simple creation of Arrhenius expressions. It uses the temperature set by the diffusion command. Since the curly braces are there, the Arrhenius command gets inserted directly into the stored pdb equation, and will be evaluated during the diffuse commands parsing of the equation. This will then depend on the user specified temperature. There also parenthesis added around the diffusion term for safety - future changes that might have a sum in the diffusivity will be handled correctly.
A further enhancement can be made by adding the diffusivity to the property data base. This will other users to change the value in the equation by accessing the properties directly. The following changes make the equation dependent on the stored value in the data base.
pdbSetDouble Silicon Conc D0 {[Arrhenius 0.1 3.62]} set diff [pdbDelayDouble Silicon Conc D0] pdbSetString Silicon Conc Equation "ddt(Conc) - $diff * grad(Conc)"
The first line sets the diffusivity in the data base. This can be made permanent by editing the heirarchy files directly. The second lines uses the pdbDelayDouble to return the expression stored in the data base. This is again necessary so that the evaluation of the expression doesn't happen until the diffuse command executes. Now the equation depends on the data base entry, and users can change that entry to understand the effect of different diffusivities on the final profile.
It would also be nice to allow a user to solve for Conc only after it is implanted or otherwise present in the material. This can be done by modifying the solution command. The new version is:
solution name=Conc !negative !damp ifpresent=Conc add
The ifpresent option enables the solution as a variable for the diffusion equation only if a real data field exists with that name. This means only structures that already have Conc defined (with the select command, for example) will solve the differential equation. This is useful for controlling CPU time and matrix size by not requiring solutions of systems that have none of that species present.
Finally, we'll add a boundary condition to allow indiffusion of this species from a gas source. To keep things simple, we'll assume the gas source fixes the surface concentration of species "Conc" at 5.0*1019/cm3. The following two commands create this boundary condition:
pdbSetBoolean Gas_Silicon Conc Fixed_Silicon 1 pdbSetString Gas_Silicon Conc Equation_Silicon "Conc_Silicon - 5.0e19"
Both commands work on the Gas_Silicon interface for the Conc variable. The first states that we plan to fix the value on the silicon side - i.e., we are going to apply a Dirichlet boundary condition. Fluxes will be ignored at this node and the boundary condition will take over controlling the concentration. The _Silicon option on Fixed indicates we are setting the value on the silicon side. This is critical, because there can be three components on any interface, one for each material and one for the interface. The second command sets the boundary condition equation on the silicon side to be the concentration minus 5.0*1019/cm3. Remember equations are set to zero by definition! The "Conc" variable also has an _Silicon appended to indicate we are setting the concentration on the silicon side.
Chemical Reaction and Diffusion
Let's consider interstitial and vacancy diffusion in silicon. These both are structured around a simple Fick's Law diffusion (electric field should be included, but we'll neglect it here) and a first order recombination between the species. Building on the prior example, we can use the following commands to get started:
solution add name=Int !damp !negative always solution add name=Vac !damp !negative always set Kbulk [pdbDelayDouble Silicon Int Kbulk] set Cis [pdbDelayDouble Silicon Int Cstar] set Cvs [pdbDelayDouble Silicon Vac Cstar] set Rec "$Kbulk * (Int * Vac - $Cis * $Cvs)" set diff [pdbDelayDouble Silicon Int D0] pdbSetString Silicon Int Equation "ddt(Int) - $diff * grad(Int) + $Rec" set diff [pdbDelayDouble Silicon Vac D0] pdbSetString Silicon Vac Equation "ddt(Vac) - $diff * grad(Vac) + $Rec"
The first two lines create solutions for the interstitials and vacancies. The next line retrieves the bulk recombination constant from the property database. The next two lines obtain the equilibrium concentrations for the interstitials and vacancies. These would need to be set in the database, but since we are working with silicon defects, they already have defaults in the database. Also, as in the prior case, pdbDelayDouble is called so that the evaluation of the numerical value is delayed until the execution of the diffuse command. The next line sets the Rec variable to be a subexpression for the bulk recombination. Excess defects are annihilated until the concentrations are at the equilibrium product. Finally, the diffusivity is obtained and the equation set, similar to the prior example. The recombination is added for both defect equations. A common mistake is to not add reaction terms to all affected equations! When the recombination is positive, it will force the time derivative to go negative to make the equation equal zero.
This implementation is somewhat hard to read since the Rec variable gets used twice. It's not hard here but gets more complex with complex systems. This is exactly the situation that terms were created to handle. A term is a common subexpression and can be used in multiple places. When the term appears in multiple equations, the values are simply fetched from memory and accumulated. We can use a term like this:
set Kbulk [pdbDelayDouble Silicon Int Kbulk] set Cis [pdbDelayDouble Silicon Int Cstar] set Cvs [pdbDelayDouble Silicon Vac Cstar] solution name=Rec add silicon const eqn = "$Kbulk * (Int * Vac - $Cis * $Cvs)" set diff [pdbDelayDouble Silicon Int D0] pdbSetString Silicon Int Equation "ddt(Int) - $diff * grad(Int) + Rec" set diff [pdbDelayDouble Silicon Vac D0] pdbSetString Silicon Vac Equation "ddt(Vac) - $diff * grad(Vac) + Rec"
Almost everything is identical to the previous case, except that we created a solution instead of a local variable. Because of this change, we no longer need the dollar sign (indicative of a tcl variable) in the equation. It has become a simple text string that will be resolved to the defined constant solution.
Boundary conditions can also be implemented, and we'll try using a simple surface recombination velocity term at an oxide interface. These will be identical for both interstitials and vacancies, so we'll show only one.
set Ks [pdbDelayDouble Oxide_Silicon Int Ksurf] set Cis [pdbDelayDouble Silicon Int Cstar] pdbSetString Oxide_Silicon Int Silicon Equation "- $Ks * (Int(Silicon) - $Cis)"
The first two lines fetch the surface recombination rate and the equilibrium concentration, and the final line sets the equation. In this case, we are adding a flux to the other equations, so there is no need for the fixed flag. Recombination at an interface gets a negative sign and generation gets a positive sign. The variable again needs to have Silicon argument appended to indicate the value on the silicon side of the interface.
See Also
language, complex examples, callbacks, equation, term, solution, select