Beispiel #1
0
        protected void Get_Potential(ref Band_Data dft_band_offset, ILayer[] layers)
        {
            for (int i = 0; i < nx; i++)
            {
                for (int j = 0; j < ny; j++)
                {
                    for (int k = 0; k < nz; k++)
                    {
                        double pos_x    = xmin + i * dx;
                        double pos_y    = ymin + j * dy;
                        double pos_z    = zmin + k * dz;
                        double band_gap = Geom_Tool.GetLayer(layers, pos_x, pos_y, pos_z).Band_Gap;

                        if (carrier_type == Carrier.electron)
                        {
                            dft_band_offset.vol[k][i, j] = 0.5 * band_gap - dft_band_offset.vol[k][i, j] + dft_pot.vol[k][i, j];
                        }
                        else
                        {
                            dft_band_offset.vol[k][i, j] = 0.5 * band_gap + dft_band_offset.vol[k][i, j] + dft_pot.vol[k][i, j];
                        }
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Generates a laplacian matrix in one-dimension on a regular grid with Dirichlet BCs wot varying permitivity
        /// </summary>
        DoubleTriDiagMatrix Generate_Laplacian(ILayer[] layers)
        {
            DoubleTriDiagMatrix result = new DoubleTriDiagMatrix(exp.Nz_Pot, exp.Nz_Pot);
            double factor_plus, factor_minus;

            // cycle through the structure and fill in the Laplacian with the correct permittivities
            for (int i = 1; i < exp.Nz_Pot - 1; i++)
            {
                double eps_plus  = Geom_Tool.GetLayer(layers, i * exp.Dz_Pot + 0.5 * exp.Dz_Pot + exp.Zmin_Pot).Permitivity;
                double eps_minus = Geom_Tool.GetLayer(layers, i * exp.Dz_Pot - 0.5 * exp.Dz_Pot + exp.Zmin_Pot).Permitivity;

                // the factor which multiplies the Laplace equation
                factor_plus  = eps_plus / (exp.Dz_Pot * exp.Dz_Pot);
                factor_minus = eps_minus / (exp.Dz_Pot * exp.Dz_Pot);

                // on-diagonal term
                result[i, i] = -1.0 * factor_minus + -1.0 * factor_plus;
                // off-diagonal
                result[i, i - 1] = 1.0 * factor_minus;
                result[i, i + 1] = 1.0 * factor_plus;
            }

            // and fix boundary conditions
            double factor = Geom_Tool.GetLayer(layers, exp.Zmin_Pot).Permitivity / (exp.Dz_Pot * exp.Dz_Pot);

            result[0, 0] = 1.0 * factor;
            result[0, 1] = 0.0;
            factor       = Geom_Tool.GetLayer(layers, (exp.Nz_Pot - 1) * exp.Dz_Pot + exp.Zmin_Pot).Permitivity / (exp.Dz_Pot * exp.Dz_Pot);
            result[exp.Nz_Pot - 1, exp.Nz_Pot - 1] = 1.0 * factor;
            result[exp.Nz_Pot - 1, exp.Nz_Pot - 2] = 0.0;

            return(result);
        }
Beispiel #3
0
        protected void Get_Potential(ref Band_Data dft_band_offset, ILayer[] layers)
        {
            for (int i = 0; i < nx; i++)
            {
                for (int j = 0; j < ny; j++)
                {
                    double pos_x    = xmin + i * dx;
                    double pos_y    = ymin + j * dy;
                    double band_gap = Geom_Tool.GetLayer(layers, plane, pos_x, pos_y, pos_z).Band_Gap;

                    if (carrier_type == Carrier.electron)
                    {
                        dft_band_offset.mat[i, j] = 0.5 * band_gap - dft_band_offset.mat[i, j] + dft_pot.mat[i, j];
                    }
                    else if (carrier_type == Carrier.hole)
                    {
                        dft_band_offset.mat[i, j] = 0.5 * band_gap + dft_band_offset.mat[i, j] + dft_pot.mat[i, j];
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
            }
        }
Beispiel #4
0
        public override void Initiate_Poisson_Solver(Dictionary <string, double> device_dimensions, Dictionary <string, double> boundary_conditions)
        {
            // get permittivities at top and bottom of the domain
            top_eps    = Geom_Tool.GetLayer(exp.Layers, device_dimensions["top_position"]).Permitivity;
            bottom_eps = Geom_Tool.GetLayer(exp.Layers, device_dimensions["bottom_position"]).Permitivity;

            this.top_bc    = boundary_conditions["top_V"] * Physics_Base.energy_V_to_meVpzC;
            this.bottom_bc = boundary_conditions["bottom_V"] * Physics_Base.energy_V_to_meVpzC;

            Console.WriteLine("WARNING - If you are trying to use FlexPDE in the 1D solver, it will not work...");
        }
Beispiel #5
0
        public static Band_Data Get_BandStructure_Grid(ILayer[] layers, double dz, int nz, double zmin)
        {
            DoubleVector result = new DoubleVector(nz);

            for (int i = 0; i < nz; i++)
            {
                result[i] = 0.5 * Geom_Tool.GetLayer(layers, zmin + i * dz).Band_Gap;
            }

            return(new Band_Data(result));
        }
Beispiel #6
0
        public static Band_Data Get_BandStructure_Grid(ILayer[] layers, double dy, double dz, int ny, int nz, double ymin, double zmin)
        {
            DoubleMatrix result = new DoubleMatrix(ny, nz);

            for (int i = 0; i < ny; i++)
            {
                for (int j = 0; j < nz; j++)
                {
                    result[i, j] = 0.5 * Geom_Tool.GetLayer(layers, ymin + i * dy, zmin + j * dz).Band_Gap;
                }
            }

            return(new Band_Data(result));
        }
Beispiel #7
0
        /// <summary>
        /// The density calculations must have lattice points on all of the boundaries between zmin and zmax
        /// This method finds these boundaries and checks that the lattice has points on them
        /// </summary>
        protected bool Check_Boundary_Points(ILayer[] layers, double zmin, double zmax, double dx)
        {
            // find out how many layer iterfaces are between zmin and zmax
            int init_layer_no = Geom_Tool.GetLayer(layers, zmin).Layer_No - 1;
            int count         = Geom_Tool.GetLayer(layers, zmax).Layer_No - Geom_Tool.GetLayer(layers, zmin).Layer_No;

            // check that these interfaces have lattice points on them
            for (int i = 0; i < count; i++)
            {
                if (Math.IEEERemainder(layers[init_layer_no + i].Zmax - zmin, dx) > 1e-9)
                {
                    Console.WriteLine("WARNING - I don't think there's a lattice point on the interface at z = " + layers[init_layer_no + i].Zmax.ToString());
                    return(false);
                }
            }

            return(true);
        }
Beispiel #8
0
        public static Band_Data Get_BandStructure_Grid(ILayer[] layers, double dx, double dy, double dz, int nx, int ny, int nz, double xmin, double ymin, double zmin)
        {
            DoubleMatrix[] result = new DoubleMatrix[nz];

            for (int k = 0; k < nz; k++)
            {
                result[k] = new DoubleMatrix(nx, ny);
                for (int i = 0; i < nx; i++)
                {
                    for (int j = 0; j < ny; j++)
                    {
                        result[k][i, j] = 0.5 * Geom_Tool.GetLayer(layers, xmin + i * dx, ymin + j * dy, zmin + k * dz).Band_Gap;
                    }
                }
            }

            return(new Band_Data(result));
        }
Beispiel #9
0
 void Get_Potential(ref Band_Data dft_band_offset, ILayer[] layers)
 {
     for (int i = 0; i < nz; i++)
     {
         double pos      = zmin + i * dz;
         double band_gap = Geom_Tool.GetLayer(layers, pos).Band_Gap;
         if (carrier_type == Carrier.electron)
         {
             dft_band_offset[i] = 0.5 * band_gap - dft_band_offset[i] + dft_pot.vec[i];
         }
         else if (carrier_type == Carrier.hole)
         {
             dft_band_offset[i] = 0.5 * band_gap + dft_band_offset[i] + dft_pot.vec[i];
         }
         else
         {
             throw new NotImplementedException();
         }
     }
 }
Beispiel #10
0
        public override bool Run()
        {
            // get temperatures to run the experiment at
            double[] run_temps   = Freeze_Out_Temperatures();
            double   target_temp = temperature;

            // run experiment using Thomas-Fermi solver
            for (int i = 0; i < run_temps.Length; i++)
            {
                current_temperature = run_temps[i];
                this.temperature    = current_temperature;
                if (surface_charge.ContainsKey(current_temperature))
                {
                    no_dft = false;
                    continue;
                }

                OneD_ThomasFermiSolver dens_solv = new OneD_ThomasFermiSolver(this, Dz_Pot, Zmin_Pot, Nz_Pot);
                dens_solv.DFT_Mixing_Parameter = 0.0;

                if (!Geom_Tool.GetLayer(layers, zmin_pot).Dopents_Frozen_Out(current_temperature) && !fix_bottom_V)
                {
                    boundary_conditions["bottom_V"] = dens_solv.Get_Chemical_Potential(zmin_pot, layers, current_temperature) / (Physics_Base.q_e * Physics_Base.energy_V_to_meVpzC);
                }

                // reset the converged flag for every temperature
                converged = false;
                if (dopents_calculated)
                {
                    continue;
                }

                if (illuminated && i == run_temps.Length - 1)
                {
                    for (int j = 0; j < dopent_charge_density.Spin_Summed_Data.Length - 1; j++)
                    {
                        double pos = Zmin_Pot + j * Dz_Pot;
                        dopent_charge_density.Spin_Up[j]   = 0.5 * Physics_Base.q_e * (Geom_Tool.GetLayer(layers, pos).Donor_Conc - Geom_Tool.GetLayer(layers, pos).Acceptor_Conc);
                        dopent_charge_density.Spin_Down[j] = 0.5 * Physics_Base.q_e * (Geom_Tool.GetLayer(layers, pos).Donor_Conc - Geom_Tool.GetLayer(layers, pos).Acceptor_Conc);
                    }
                }

                converged = Run_Iteration_Routine(dens_solv, pois_solv, tol, max_iterations);
                if (!converged)
                {
                    temperature = target_temp;
                    no_dft      = true;
                    return(converged);
                }

                // save the surface charge for this temperature
                surface_charge.Add(current_temperature, pois_solv.Get_Surface_Charge(chem_pot, layers));

                pois_solv.Reset();
            }

            if (!no_dft)
            {
                // reset the converged flag for the quantum calculation
                converged = false;

                // get the correct density solver
                IOneD_Density_Solve dft_solv;
                if (carrier_type == Carrier.electron || carrier_type == Carrier.hole)
                {
                    dft_solv = new OneD_DFTSolver(this, carrier_type);
                }
                else if (carrier_type == Carrier.both)
                {
                    dft_solv = new OneD_eh_DFTSolver(this);
                }
                else
                {
                    throw new NotImplementedException();
                }

                dft_solv.DFT_Mixing_Parameter = 1.0;                 //NOTE: This method doesn't mix in the DFT potential, it is stable enough when V_xc is calculated every iteration
                dft_solv.Zmin_Pot             = zmin_pot; dft_solv.Dz_Pot = dz_pot;

                // and then run the DFT solver at the base temperature
                Console.WriteLine("Starting DFT calculation");
                converged = Run_Iteration_Routine(dft_solv, pois_solv, tol, max_iterations);

                pois_solv.Reset();

                (Input_Band_Structure.Get_BandStructure_Grid(layers, dz_pot, nz_pot, zmin_pot) - chem_pot).Save_Data("potential" + output_suffix);
            }

            // calculate the density of the negative and positive charges separately
            double neg_dens = (from val in carrier_charge_density.Spin_Summed_Data.vec
                               where val < 0.0
                               select - 1.0e14 * val * dz_dens / Physics_Base.q_e).ToArray().Sum();
            double pos_dens = (from val in carrier_charge_density.Spin_Summed_Data.vec
                               where val > 0.0
                               select 1.0e14 * val * dz_dens / Physics_Base.q_e).ToArray().Sum();

            double unit_charge = -1.0 * Physics_Base.q_e;

            if (pos_dens == 0.0)
            {
                Console.WriteLine("Electron carrier density at heterostructure interface: \t" + neg_dens.ToString("e3") + " cm^-2");
            }
            else if (neg_dens == 0.0)
            {
                Console.WriteLine("Hole carrier density at heterostructure interface: \t" + pos_dens.ToString("e3") + " cm^-2");
                unit_charge = Physics_Base.q_e;
            }
            else
            {
                Console.WriteLine("WARNING!  Carriers of both charges found on the interface");
                Console.WriteLine("Electron density at heterostructure interface: \t" + neg_dens.ToString("e3") + " cm^-2");
                Console.WriteLine("Hole density at heterostructure interface: \t" + pos_dens.ToString("e3") + " cm^-2");
            }

            // there is no iteration timeout for the 1D solver so if it gets to this point the solution will definitely have converged
            Close(unit_charge, converged, max_iterations);

            return(converged);
        }