Alagator Tutorial

From Flooxs
Jump to navigation Jump to search

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 data base. The next two lines obtain the equilibrium concentrations for the interstitials and vacancies. These would need to be set in the data base, but since we are working with silicon defects, they already have defaults in the data base. Also, as in the prior case, pdbDelayDouble is called so that 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. Its 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]
term name=Rec add silicon 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 previous case, except that we created a term 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 which will be resolved to the term. The terms are kept until you exit the simulator, so it could be used in other equations or in a select command (if you wanted to monitor the recombination rates!)

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 Equation_Silicon "- $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 appended to indicate the value on the silicon side of the interface.

CallBack Procedures

Finally, let's implement the prior example using callback procedures. Callbacks allow additional intelligence to be built into the equations by allowing procedures to be called at runtime. These procedures can then configure the equations as appropriate based on user specified options. These are used in the default case to mimic old floops, so that the user can select simple options which trigger differing physical approximations. In this case, we'll just do the prior example of defects using the call backs to construct the equations. These lines get us started:

solution add name=Int !damp !negative always
solution add name=Vac !damp !negative always
pdbSetString Silicon Int EquationProc DefectBulk
pdbSetString Silicon Vac EquationProc DefectBulk

The first two lines create the solution variables, just as before. The second two place in the data base a string for EquationProc. The EquationProc string is used as a procedure name that is called before parsing the string. This procedure can then build the actual equation that will be used at runtime. These procedures are passed two arguments - the material name and the solution name. The DefectBulk procedure then needs to be defined:

proc DefectBulk {mat sol} {
    set pdbMat [pdbName $mat]

    set Kbulk [pdbDelayDouble $pdbMat $sol Kbulk]
    set Cis [pdbDelayDouble $pdbMat $sol Cstar]

    set rec [pdbGetString $pdbMat $sol Recomb]
    set Cvs [pdbDelayDouble $pdbMat $rec Cstar]
    term name=Rec add $mat eqn = "$Kbulk * ($sol * $rec - $Cis * $Cvs)"
    set d [pdbDelayDouble $pdbMat $sol D0]
    pdbSetString $pdbMat $sol Equation "ddt($sol) - $d * grad($sol)   Rec"
}

The procedure is defined to take two arguments, mat and sol. The mat argument is given in a way consistent with the command line material specification. Pdb material specification is done differently, and pdbName is a function that helps converts the names from command line to pdb. The next two lines are the same as before, and retrieve the bulk recombination and equilibrium concentration using the passed material and solution. The next line is new, and requires an additional entry in the property data base. We need to specify the recombination defect - since we'll use this procedure for both interstitials and vacancies. When the procedure is called with sol set to Int, rec needs to set to Vac, and vice-versa. The next line retrieves the equilibrium concentration of the other defect. The final two lines are the same as before with appropriate substitution of the procedure arguments.

This really didn't give us any additional benefit, and made things somewhat more complicated. However, we can now add additional features. We can check the switch for diffmodel, and set up appropriate equations.

proc DefectBulk {mat sol} {
    set pdbMat [pdbName $mat]

    set Cis [pdbDelayDouble $pdbMat $sol Cstar]

    if { [pdbGetSwitch $pdbMat $sol DiffModel] == 1 } {
         pdbSetString $pdbMat $sol Equation "$sol - $Cis"
    } else {
        set Kbulk [pdbDelayDouble $pdbMat $sol Kbulk]

        set rec [pdbGetString $pdbMat $sol Recomb]
        set Cvs [pdbDelayDouble $pdbMat $rec Cstar]
        term name=Rec add $mat eqn = "$Kbulk * ($sol * $rec - $Cis * $Cvs)"
        set d [pdbDelayDouble $pdbMat $sol D0]
        pdbSetString $pdbMat $sol Equation "ddt($sol) - $d * grad($sol) - Rec"
    }
}

The first option sets the defect equation to the equilibrium concentration everywhere. The second solves a continuity equation for the defect concentration. In this case, the user can select a model parameter that changes the behavior of the system at runtime, a capability not available without the callback routines.

See Also

language, complex examples, callbacks, equation, term, solution, select