Beispiel #1
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 #2
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 #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++)
                {
                    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 #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 double Get_Surface_Charge(Band_Data chem_pot, ILayer[] layers)
        {
            // calculate the electric field just below the surface
            int    surface = (int)(-1.0 * Math.Floor(Geom_Tool.Get_Zmin(layers) / exp.Dz_Pot));
            double eps     = Geom_Tool.Find_Layer_Below_Surface(layers).Permitivity;
            // by Gauss' theorem, rho = - epsilon_0 * epsilon_r * dV/dz
            double surface_charge = -1.0 * eps * (chem_pot[surface - 1] - chem_pot[surface - 2]) / exp.Dz_Pot;

            // divide by - q_e to convert the chemical potential into a potential
            surface_charge /= -1.0 * Physics_Base.q_e;

            return(surface_charge);
        }
Beispiel #7
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 #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
        /// <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 #10
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 #11
0
        static void Calculate_1D_Band_Structure(Dictionary <string, object> inputs)
        {
            OneD_ThomasFermiPoisson.Experiment exp_init = new OneD_ThomasFermiPoisson.Experiment();

            Console.WriteLine("Performing density dopent calculation");
            Dictionary <string, object> inputs_init = new Dictionary <string, object>();

            if ((int)(double)inputs["dim"] != 1)
            {
                inputs_init = inputs.Where(s => s.Key.ToLower().EndsWith("_1d")).ToDictionary(dict => dict.Key.Remove(dict.Key.Length - 3), dict => dict.Value);
                inputs_init.Add("BandStructure_File", inputs["BandStructure_File"]);
                inputs_init.Add("output_suffix", "_1d.dat");
                inputs_init.Add("T", inputs["T"]);
            }
            else
            {
                inputs_init = inputs.Where(s => s.Key.ToLower().EndsWith("")).ToDictionary(dict => dict.Key, dict => dict.Value);
            }


            //    Inputs_to_Dictionary.Add_Input_Parameters_to_Dictionary(ref inputs_init, "Input_Parameters_1D.txt");
            exp_init.Initialise(inputs_init);
            exp_init.Run();
            inputs.Add("Carrier_Density", exp_init.Carrier_Density);
            inputs.Add("Dopent_Density", exp_init.Dopent_Density);
            inputs.Add("Chemical_Potential", exp_init.Chemical_Potential);
            inputs.Add("nz_pot_1d", inputs_init["nz"]);
            inputs.Add("zmin_pot_1d", inputs_init["zmin"]);
            inputs.Add("zmax_pot_1d", inputs_init["zmax"]);
            // get the frozen out surface charge at 70K
            if (!inputs.ContainsKey("surface_charge"))
            {
                inputs.Add("surface_charge", exp_init.Surface_Charge(70.0));
            }
            else
            {
                Console.WriteLine("Surface charge set from Input_Parameters.txt to " + ((double)inputs["surface_charge"]).ToString());
            }
            Console.WriteLine("Calculated 1D density for dopents");

            if ((int)(double)inputs["dim"] == 2)
            {
                // create a scaled data file containing the dopent density
                double scaling_factor = ((double)inputs["ny"] * (double)inputs["dy"]) / ((double)inputs["nz"] * (double)inputs["dz"]);
                Input_Band_Structure.Expand_BandStructure(exp_init.Dopent_Density, (int)(double)inputs["ny_1d"]).Spin_Summed_Data.Save_2D_Data("dens_2D_dopents.dat", (double)inputs["dy"] * ((double)inputs["ny"] + 2.0) / ((double)inputs["ny_1d"] - 1.0), scaling_factor * (double)inputs_init["dz"], -1.0 * (double)inputs["dy"] * ((double)inputs["ny"] + 2.0) / 2.0, scaling_factor * Geom_Tool.Get_Zmin(exp_init.Layers));
            }
            else if ((int)(double)inputs["dim"] == 3)
            {
                // this is a scaled version for the dopents!
                double y_scaling = ((double)inputs["nx"] * (double)inputs["dx"]) / ((double)inputs["ny"] * (double)inputs["dy"]);
                double z_scaling = ((double)inputs["nx"] * (double)inputs["dx"]) / ((double)inputs["nz"] * (double)inputs["dz"]);
                // extract the dopent layer (leaving the top and bottom set to zero)
                int    dopent_min   = -1;
                int    dopent_max   = -2;
                ILayer dopent_layer = exp_init.Layers[0];
                for (int i = 0; i < exp_init.Layers.Length; i++)
                {
                    if (exp_init.Layers[i].Donor_Conc != 0.0 || exp_init.Layers[i].Acceptor_Conc != 0)
                    {
                        dopent_layer = exp_init.Layers[i];
                        dopent_min   = (int)Math.Round((dopent_layer.Zmin - Geom_Tool.Get_Zmin(exp_init.Layers)) / (int)(double)inputs_init["dz"]);
                        dopent_max   = (int)Math.Round((dopent_layer.Zmax - Geom_Tool.Get_Zmin(exp_init.Layers)) / (int)(double)inputs_init["dz"]);
                    }
                }
                Band_Data tmp_dop_dens_1D = new Band_Data(dopent_max - dopent_min, 0.0);
                for (int i = dopent_min + 1; i < dopent_max - 1; i++)
                {
                    tmp_dop_dens_1D.vec[i - dopent_min] = exp_init.Dopent_Density.Spin_Summed_Data.vec[i];
                }
                // and expand into the correct data structure
                Band_Data tmp_dop_dens = Input_Band_Structure.Expand_BandStructure(tmp_dop_dens_1D.vec, (int)(double)inputs["nx_1d"], (int)(double)inputs["ny_1d"]);
                tmp_dop_dens.Save_3D_Data("dens_3D_dopents.dat", (double)inputs["dx"] * ((double)inputs["nx"] + 1.0) / ((double)inputs["nx_1d"] - 1.0), y_scaling * (double)inputs["dy"] * ((double)inputs["ny"] + 1.0) / ((double)inputs["ny_1d"] - 1.0), z_scaling * (double)inputs["dz_1d"], -1.0 * (double)inputs["dx"] * ((double)inputs["nx"] + 1.0) / 2.0, -1.0 * y_scaling * (double)inputs["dy"] * ((double)inputs["ny"] + 1.0) / 2.0, z_scaling * dopent_layer.Zmin);
                Console.WriteLine("Saved 1D dopent density");
            }
        }
        public void Create_FlexPDE_File(double top_bc, double top_length, double split_bc1, double split_bc2, double split_width, double split_length, double surface, double bottom_bc, string output_file)
        {
            StreamWriter sw = new StreamWriter(output_file);

            // write out output file
            sw.WriteLine("TITLE \'Full Split Gate Geometry\'");
            sw.WriteLine("COORDINATES cartesian3");
            sw.WriteLine("VARIABLES");
            sw.WriteLine("\tu");
            sw.WriteLine("SELECT");
            // gives the flexPDE tolerance for the finite element solve
            sw.WriteLine("\tERRLIM=" + pot_tol.ToString());
            sw.WriteLine("\tGRIDLIMIT=20");
            sw.WriteLine("DEFINITIONS");
            sw.WriteLine("\tband_gap");
            sw.WriteLine();
            // and the tables for carrier and donor densities
            sw.WriteLine("\trho_carrier = TABLE(\'" + dens_filename + "\', x, y, z)");
            sw.WriteLine("\trho_dopent = TABLE(\'" + densdopent_filename + "\', x, y, z)");
            sw.WriteLine();
            // simulation dimension
            sw.WriteLine("\tlx = " + (exp.Dx_Pot * exp.Nx_Pot).ToString());
            sw.WriteLine("\tly = " + (exp.Dy_Pot * exp.Ny_Pot).ToString());
            sw.WriteLine();
            sw.WriteLine("\t! Scale factors");
            sw.WriteLine("\ty_scaling = " + y_scaling.ToString());
            sw.WriteLine("\tz_scaling = " + z_scaling.ToString());
            sw.WriteLine();
            sw.WriteLine("\tbottom_bc = " + bottom_bc.ToString());
            sw.WriteLine("\ttop_bc = " + top_bc.ToString());
            sw.WriteLine("\tsurface_bc = " + surface.ToString() + " * z_scaling");
            sw.WriteLine();
            sw.WriteLine("\t! GATE VOLTAGE INPUTS (in meV zC^-1)");
            for (int i = 0; i < gate_bcs.Count; i++)
            {
                sw.WriteLine("\tV" + i.ToString() + " = " + gate_bcs[i].ToString());
            }
            sw.WriteLine();
            sw.WriteLine("\t! SPLIT GATE DIMENSIONS (in nm)");
            sw.WriteLine("\tsplit_width = " + split_width.ToString() + "");
            sw.WriteLine("\tsplit_length = " + split_length.ToString());
            sw.WriteLine("\ttop_length = " + top_length.ToString());
            sw.WriteLine("\tsplit_depth = 10! depth of the split gate metal material");
            sw.WriteLine("\ttop_depth = 10! depth of the top gate metal material");
            sw.WriteLine();
            sw.WriteLine("\t! WELL DEPTH (in nm)");
            sw.WriteLine("\twell_depth = " + z_2DEG.ToString());
            sw.WriteLine();
            sw.WriteLine("\t! Electrical permitivity");
            sw.WriteLine("\teps");
            sw.WriteLine();
            // other physical parameters
            sw.WriteLine("\tq_e = " + Physics_Base.q_e.ToString() + "! charge of electron in zC");
            sw.WriteLine();
            sw.WriteLine("EQUATIONS");
            // Poisson's equation
            sw.WriteLine("\tu: dx(eps * dx(u)) + y_scaling * dy(eps * y_scaling * dy(u)) + z_scaling * dz(eps * z_scaling * dz(u)) = - (rho_carrier + rho_dopent)\t! Poisson's equation");
            sw.WriteLine();

            // draw the domain
            Draw_Domain(sw);

            sw.WriteLine();
            sw.WriteLine("\t\tFRONT(z - well_depth * z_scaling, 50 * z_scaling)");
            sw.WriteLine("\t\tFRONT(z - well_depth, 50 * z_scaling)");
            sw.WriteLine();
            sw.WriteLine("!MONITORS");
            sw.WriteLine("\t!CONTOUR(rho_carrier) ON z = well_depth * z_scaling");
            sw.WriteLine("\t!CONTOUR(u) ON z = well_depth * z_scaling");
            sw.WriteLine("\t!CONTOUR(u) ON x = 0");
            sw.WriteLine("\t!CONTOUR(u) ON y = 0");
            sw.WriteLine("PLOTS");
            sw.WriteLine("\t!CONTOUR(rho_carrier + rho_dopent) ON x = 0");
            sw.WriteLine("\t!CONTOUR(u) ON x = 0");
            sw.WriteLine("\t!CONTOUR(u) ON y = 0");
            sw.WriteLine("\t!CONTOUR(rho_carrier) ON z = well_depth * z_scaling");
            sw.WriteLine("\t!CONTOUR(- q_e * u + 0.5 * band_gap) ON z = well_depth * z_scaling");
            sw.WriteLine("\t!ELEVATION(rho_carrier + rho_dopent) FROM (0,0, " + Geom_Tool.Get_Zmin(exp.Layers).ToString() + " * z_scaling) TO (0, 0, " + exp.Layers[exp.Layers.Length - 1].Zmax.ToString() + " * z_scaling)");
            sw.WriteLine("\t!ELEVATION(- q_e * u + 0.5 * band_gap) FROM (0, 0, " + Geom_Tool.Get_Zmin(exp.Layers).ToString() + " * z_scaling) TO (0, 0, " + exp.Layers[exp.Layers.Length - 1].Zmax.ToString() + " * z_scaling)");
            sw.WriteLine("\t!ELEVATION(- q_e * u + 0.5 * band_gap) FROM (0, -ly / 2 * y_scaling, well_depth * z_scaling) TO (0, ly / 2 * y_scaling, well_depth * z_scaling)");
            sw.WriteLine("\t!ELEVATION(- q_e * u + 0.5 * band_gap) FROM (-lx/2, 0, well_depth * z_scaling) TO (lx / 2, 0, well_depth * z_scaling)");
            sw.WriteLine();
            sw.WriteLine("\tTABLE(u) ZOOM (" + exp.Xmin_Dens.ToString() + ", " + (y_scaling * exp.Ymin_Dens).ToString() + ", " + (z_scaling * exp.Zmin_Dens).ToString() + ", " + ((exp.Nx_Dens - 1) * exp.Dx_Dens).ToString() + ", " + (y_scaling * (exp.Ny_Dens - 1) * exp.Dy_Dens).ToString() + ", " + (z_scaling * (exp.Nz_Dens - 1) * exp.Dz_Dens).ToString() + ") EXPORT FORMAT \"#1\" POINTS = (" + exp.Nx_Dens.ToString() + ", " + exp.Ny_Dens.ToString() + ", " + exp.Nz_Dens.ToString() + ") FILE = \"pot.dat\"");
            sw.WriteLine("\tTABLE(-1.0 * rho_carrier - rho_dopent) ZOOM (" + exp.Xmin_Dens.ToString() + ", " + (y_scaling * exp.Ymin_Dens).ToString() + ", " + (z_scaling * exp.Zmin_Dens).ToString() + ", " + ((exp.Nx_Dens - 1) * exp.Dx_Dens).ToString() + ", " + (y_scaling * (exp.Ny_Dens - 1) * exp.Dy_Dens).ToString() + ", " + (z_scaling * (exp.Nz_Dens - 1) * exp.Dz_Dens).ToString() + ") EXPORT FORMAT \"#1\" POINTS = (" + exp.Nx_Dens.ToString() + ", " + exp.Ny_Dens.ToString() + ", " + exp.Nz_Dens.ToString() + ") FILE = \"" + laplacian_file + "\"");
            sw.WriteLine("\tTRANSFER(u) FILE = \'" + pot_filename + "\'");
            sw.WriteLine("\tTRANSFER(0.0 * u) FILE = \'" + new_pot_filename + "\' ! dummy file for smoother function");
            sw.WriteLine();
            sw.WriteLine("END");

            sw.Close();
        }
Beispiel #13
0
        /// <summary>
        /// initiates the poisson solver by writing the input file for the parameter handlers of the initcalc and newton methods
        /// </summary>
        public override void Initiate_Poisson_Solver(Dictionary <string, double> device_dimensions, Dictionary <string, double> boundary_conditions)
        {
            // get split gate specific device dimensions
            device_dimensions["zmin_pot"]        = exp.Layers[1].Zmin;
            device_dimensions["pmma_depth"]      = exp.Layers[exp.Layers.Length - 1].Zmax;
            device_dimensions["cap_depth"]       = Geom_Tool.Find_Layer_Below_Surface(exp.Layers).Zmin;
            device_dimensions["interface_depth"] = exp.Layers[1].Zmax;
            device_dimensions["buffer_depth"]    = exp.Layers[2].Zmax;

            // write the parameter details for the initial potential calculation
            StreamWriter sw_initcalc = new StreamWriter(initcalc_parameterfile);

            // check if the top layer is air... if so, we need to use natural boundary conditions on the upper surface
            bool natural_top_bc = (exp.Layers[exp.Layers.Length - 1].Material == Material.Air);

            if (natural_top_bc)
            {
                device_dimensions["top_V"] = 0.0;
            }

            sw_initcalc.WriteLine("subsection System Geometry");
            sw_initcalc.WriteLine("\tset zmin_pot = " + device_dimensions["zmin_pot"].ToString());
            sw_initcalc.WriteLine("\tset split_width = " + device_dimensions["split_width"].ToString());
            sw_initcalc.WriteLine("\tset pmma_depth = " + device_dimensions["pmma_depth"].ToString());
            sw_initcalc.WriteLine("\tset cap_depth = " + device_dimensions["cap_depth"].ToString());
            sw_initcalc.WriteLine("\tset interface_depth = " + device_dimensions["interface_depth"].ToString());
            sw_initcalc.WriteLine("\tset buffer_depth = " + device_dimensions["buffer_depth"].ToString());
            sw_initcalc.WriteLine("end");

            sw_initcalc.WriteLine("subsection Boundary Conditions");
            sw_initcalc.WriteLine("\tset top_bc = " + (boundary_conditions["top_V"] * Physics_Base.energy_V_to_meVpzC).ToString());
            sw_initcalc.WriteLine("\tset bottom_bc = " + (boundary_conditions["bottom_V"] * Physics_Base.energy_V_to_meVpzC).ToString());
            sw_initcalc.WriteLine("\tset split_bc1 = " + (boundary_conditions["V0"] * Physics_Base.energy_V_to_meVpzC).ToString());
            sw_initcalc.WriteLine("\tset split_bc2 = " + (boundary_conditions["V1"] * Physics_Base.energy_V_to_meVpzC).ToString());
            sw_initcalc.WriteLine("\tset surface_bc = " + (0.5 * boundary_conditions["surface"]).ToString());                                   // note that the surface "kink" is halved...
            // not sure why, but this is deal.II specific
            sw_initcalc.WriteLine("end");

            sw_initcalc.WriteLine("subsection Carrier Density Parameters");
            sw_initcalc.WriteLine("\tset ny_dens = " + exp.Ny_Dens.ToString());
            sw_initcalc.WriteLine("\tset nz_dens = " + exp.Nz_Dens.ToString());
            sw_initcalc.WriteLine("\tset ymin_dens = " + exp.Ymin_Dens.ToString());
            sw_initcalc.WriteLine("\tset ymax_dens = " + (exp.Ymin_Dens + exp.Dy_Dens * (exp.Ny_Dens - 1)).ToString());
            sw_initcalc.WriteLine("\tset zmin_dens = " + exp.Zmin_Dens.ToString());
            sw_initcalc.WriteLine("\tset zmax_dens = " + (exp.Zmin_Dens + exp.Dz_Dens * (exp.Nz_Dens - 1)).ToString());
            sw_initcalc.WriteLine("end");

            sw_initcalc.WriteLine("subsection Donor Density Parameters");
            sw_initcalc.WriteLine("\tset nz_donor = " + nz_donor);
            sw_initcalc.WriteLine("\tset zmin_donor = " + zmin_donor);
            sw_initcalc.WriteLine("\tset zmax_donor = " + zmax_donor);
            sw_initcalc.WriteLine("end");

            sw_initcalc.WriteLine("set natural top_bc = " + natural_top_bc.ToString().ToLower());

            sw_initcalc.Close();

            // and write the parameter details needed for the newton step
            StreamWriter sw_newton = new StreamWriter(newton_parameterfile);

            sw_newton.WriteLine("subsection System Geometry");
            sw_newton.WriteLine("\tset zmin_pot = " + device_dimensions["zmin_pot"].ToString());
            sw_newton.WriteLine("\tset split_width = " + device_dimensions["split_width"].ToString());
            sw_newton.WriteLine("\tset pmma_depth = " + device_dimensions["pmma_depth"].ToString());
            sw_newton.WriteLine("\tset cap_depth = " + device_dimensions["cap_depth"].ToString());
            sw_newton.WriteLine("\tset interface_depth = " + device_dimensions["interface_depth"].ToString());
            sw_newton.WriteLine("\tset buffer_depth = " + device_dimensions["buffer_depth"].ToString());
            sw_newton.WriteLine("end");

            sw_newton.WriteLine("subsection Carrier Density Parameters");
            sw_newton.WriteLine("\tset ny_dens = " + exp.Ny_Dens.ToString());
            sw_newton.WriteLine("\tset nz_dens = " + exp.Nz_Dens.ToString());
            sw_newton.WriteLine("\tset ymin_dens = " + exp.Ymin_Dens.ToString());
            sw_newton.WriteLine("\tset ymax_dens = " + (exp.Ymin_Dens + exp.Dy_Dens * (exp.Ny_Dens - 1)).ToString());
            sw_newton.WriteLine("\tset zmin_dens = " + exp.Zmin_Dens.ToString());
            sw_newton.WriteLine("\tset zmax_dens = " + (exp.Zmin_Dens + exp.Dz_Dens * (exp.Nz_Dens - 1)).ToString());
            sw_newton.WriteLine("end");

            sw_newton.WriteLine("set natural top_bc = " + natural_top_bc.ToString().ToLower());

            sw_newton.Close();
        }
Beispiel #14
0
        static void Main(string[] args)
        {
            // set nmath license key
            CenterSpace.NMath.Core.NMathConfiguration.LicenseKey = License.NMath_License_Key;

            Console.WriteLine("Program starting");

            Console.WriteLine("Loading input parameters from file");
            Dictionary <string, object> inputs = new Dictionary <string, object>();

            Inputs_to_Dictionary.Add_Input_Parameters_to_Dictionary(ref inputs, "Input_Parameters.txt");
            Inputs_to_Dictionary.Add_Input_Parameters_to_Dictionary(ref inputs, "Solver_Config.txt");
            Console.WriteLine("Input parameters loaded");

            // read in the value of vsg to be used
            Console.WriteLine("Enter split gate voltage");
            inputs["split_V"] = double.Parse(Console.ReadLine());
            Console.WriteLine("Setting \"split_V\" to " + ((double)inputs["split_V"]).ToString() + "V");

            // check to make sure it's negative
            if ((double)inputs["split_V"] > 0)
            {
                Console.WriteLine("\"split_V\" has been set positive at " + ((double)inputs["split_V"]).ToString() + "V.  Are you sure you want to do this?");
                Console.ReadKey();
            }

            // temporarily, just set the output suffix to something boring
            inputs.Add("output_suffix", ".dat");

            // initialise the band structure experiment
            Experiment exp = new Experiment();

            OneD_ThomasFermiPoisson.Experiment exp_init = new OneD_ThomasFermiPoisson.Experiment();

            Console.WriteLine("Performing density dopent calculation");
            Dictionary <string, object> inputs_init = new Dictionary <string, object>();

            inputs_init = inputs.Where(s => s.Key.ToLower().EndsWith("_1d")).ToDictionary(dict => dict.Key.Remove(dict.Key.Length - 3), dict => dict.Value);
            inputs_init.Add("BandStructure_File", inputs["BandStructure_File"]);
            inputs_init.Add("T", inputs["T"]);
            inputs_init.Add("output_suffix", "_1d.dat");

            exp_init.Initialise(inputs_init);
            exp_init.Run();
            inputs.Add("SpinResolved_Density", exp_init.Carrier_Density);
            inputs.Add("Dopent_Density", exp_init.Dopent_Density);
            inputs.Add("Chemical_Potential", exp_init.Chemical_Potential);
            inputs.Add("nz_pot_1d", inputs_init["nz"]);
            inputs.Add("zmin_pot_1d", inputs_init["zmin"]);
            inputs.Add("zmax_pot_1d", inputs_init["zmax"]);
            // get the frozen out surface charge at 70K
            if (!inputs.ContainsKey("surface_charge"))
            {
                inputs.Add("surface_charge", exp_init.Surface_Charge(70.0));
            }
            else
            {
                Console.WriteLine("Surface charge set from Input_Parameters.txt to " + ((double)inputs["surface_charge"]).ToString());
            }
            Console.WriteLine("Calculated 1D density for dopents");

            // this is a scaled version for the dopents!
            double y_scaling = ((double)inputs["nx"] * (double)inputs["dx"]) / ((double)inputs["ny"] * (double)inputs["dy"]);
            double z_scaling = ((double)inputs["nx"] * (double)inputs["dx"]) / ((double)inputs["nz"] * (double)inputs["dz"]);
            // extract the dopent layer (leaving the top and bottom set to zero)
            int    dopent_min   = -1;
            int    dopent_max   = -2;
            ILayer dopent_layer = exp_init.Layers[0];

            for (int i = 0; i < exp_init.Layers.Length; i++)
            {
                if (exp_init.Layers[i].Donor_Conc != 0.0 || exp_init.Layers[i].Acceptor_Conc != 0)
                {
                    dopent_layer = exp_init.Layers[i];
                    dopent_min   = (int)Math.Round((dopent_layer.Zmin - Geom_Tool.Get_Zmin(exp_init.Layers)) / (int)(double)inputs_init["dz"]);
                    dopent_max   = (int)Math.Round((dopent_layer.Zmax - Geom_Tool.Get_Zmin(exp_init.Layers)) / (int)(double)inputs_init["dz"]);
                }
            }
            Band_Data tmp_dop_dens_1D = new Band_Data(dopent_max - dopent_min, 0.0);

            for (int i = dopent_min + 1; i < dopent_max - 1; i++)
            {
                tmp_dop_dens_1D.vec[i - dopent_min] = exp_init.Dopent_Density.Spin_Summed_Data.vec[i];
            }
            // and expand into the correct data structure
            Band_Data tmp_dop_dens = Input_Band_Structure.Expand_BandStructure(tmp_dop_dens_1D.vec, (int)(double)inputs["nx_1d"], (int)(double)inputs["ny_1d"]);

            tmp_dop_dens.Save_3D_Data("dens_3D_dopents.dat", (double)inputs["dx"] * ((double)inputs["nx"] + 1.0) / ((double)inputs["nx_1d"] - 1.0), y_scaling * (double)inputs["dy"] * ((double)inputs["ny"] + 1.0) / ((double)inputs["ny_1d"] - 1.0), z_scaling * (double)inputs["dz_1d"], -1.0 * (double)inputs["dx"] * ((double)inputs["nx"] + 1.0) / 2.0, -1.0 * y_scaling * (double)inputs["dy"] * ((double)inputs["ny"] + 1.0) / 2.0, z_scaling * dopent_layer.Zmin);
            Console.WriteLine("Saved 1D dopent density");

            Console.WriteLine("Starting experiment");
            exp.Initialise(inputs);
            Console.WriteLine("Experiment initialised");
            exp.Run();
            Console.WriteLine("Experiment complete");
        }
Beispiel #15
0
        static void Main(string[] args)
        {
            Console.WriteLine("Setting Centerspace key");

            // set nmath license key
            CenterSpace.NMath.Core.NMathConfiguration.LicenseKey = License.NMath_License_Key;

            Console.WriteLine("Program starting");

            Console.WriteLine("Loading input parameters from file");
            Dictionary <string, object> inputs = new Dictionary <string, object>();

            Inputs_to_Dictionary.Add_Input_Parameters_to_Dictionary(ref inputs, "Input_Parameters.txt");
            Inputs_to_Dictionary.Add_Input_Parameters_to_Dictionary(ref inputs, "Solver_Config.txt");
            Console.WriteLine("Input parameters loaded");

            ////////////////////////////////////////////////
            //
            //    EDITS FOR BATCH RUNS
            //
            ////////////////////////////////////////////////

            // read in the value of vsg to be used
            Console.WriteLine("Enter split gate voltage");
            //         inputs["split_V"] = double.Parse(Console.ReadLine());
            int index = int.Parse(args[0]);

            int maxval = (int)(double)inputs["nVsg"];
            int i1     = index % maxval;
            int i2     = (index - i1) / maxval;

            // split gate with bias
//            double v1 = -0.5 - 0.25 * (double)i1;
//            double v2 = -0.5 - 0.02 * (double)i2;
//            if (v1 + v2 < -2.2 || v1 < v2)
//                return;
//            inputs["split_V1"] = v1;
//            inputs["split_V2"] = v2;
//            inputs["voltages"] = "{" + v1.ToString() + ", " + v2.ToString() + "}";
//            Console.WriteLine("Setting \"split_V1\" to " + ((double)inputs["split_V1"]).ToString() + "V");
//            Console.WriteLine("Setting \"split_V2\" to " + ((double)inputs["split_V2"]).ToString() + "V");
//            inputs["top_V"] = 0.0;
//            Console.WriteLine("Setting \"top_V\" to " + ((double)inputs["top_V"]).ToString() + "V");
//            inputs["output_suffix"] = "_sg1" + ((double)inputs["split_V1"]).ToString("F2") + "_sg2" + ((double)inputs["split_V2"]).ToString("F2") + ".dat";

            //top gated with constant side gate
            double v1 = (double)inputs["sg_init"] + (double)inputs["dVsg"] * (double)i1;

            inputs["split_V"] = v1;
            Console.WriteLine("Setting \"split_V\" to " + ((double)inputs["split_V"]).ToString() + "V");
            inputs["top_V"] = (double)inputs["tg_init"] + (double)inputs["dVtg"] * (double)i2;
            Console.WriteLine("Setting \"top_V\" to " + ((double)inputs["top_V"]).ToString() + "V");
            inputs["output_suffix"] = "_sg" + ((double)inputs["split_V"]).ToString("F3") + "_tg" + ((double)inputs["top_V"]).ToString("F3") + ".dat";

            ////////////////////////////////////////////////

            inputs["voltages"] = "{" + v1.ToString() + ", " + v1.ToString() + "}";
            // check to make sure it's negative
            if ((double)inputs["split_V"] > 0)
            {
                Console.WriteLine("\"split_V\" has been set positive at " + ((double)inputs["split_V"]).ToString() + "V.  Are you sure you want to do this?");
                Console.ReadKey();
            }

            // initialise the band structure experiment
            Experiment exp = new Experiment();

            OneD_ThomasFermiPoisson.Experiment exp_init = new OneD_ThomasFermiPoisson.Experiment();

            // check if we should start from a precalculated density
            // consistency of band-structure, etc is the responsibility of the user...
            //if (!(bool)inputs["hot_start"])
            {
                Console.WriteLine("Performing density dopent calculation");
                Dictionary <string, object> inputs_init = new Dictionary <string, object>();
                inputs_init = inputs.Where(s => s.Key.ToLower().EndsWith("_1d")).ToDictionary(dict => dict.Key.Remove(dict.Key.Length - 3), dict => dict.Value);
                inputs_init.Add("BandStructure_File", inputs["BandStructure_File"]);
                inputs_init.Add("T", inputs["T"]);

                //    Inputs_to_Dictionary.Add_Input_Parameters_to_Dictionary(ref inputs_init, "Input_Parameters_1D.txt");
                exp_init.Initialise(inputs_init);
                exp_init.Run();
                inputs.Add("Carrier_Density", exp_init.Carrier_Density);
                inputs.Add("Dopent_Density", exp_init.Dopent_Density);
                inputs.Add("Chemical_Potential", exp_init.Chemical_Potential);
                inputs.Add("nz_pot_1d", inputs_init["nz"]);
                inputs.Add("zmin_pot_1d", inputs_init["zmin"]);
                inputs.Add("zmax_pot_1d", inputs_init["zmax"]);
                // get the frozen out surface charge at 70K
                if (!inputs.ContainsKey("surface_charge"))
                {
                    inputs.Add("surface_charge", exp_init.Surface_Charge(70.0));
                }
                else
                {
                    Console.WriteLine("Surface charge set from Input_Parameters.txt to " + ((double)inputs["surface_charge"]).ToString());
                }
                Console.WriteLine("Calculated 1D density for dopents");

                //Input_Band_Structure.Expand_BandStructure(exp_init.Dopent_Density, (int)(double)inputs_init["ny_1d"]).Spin_Summed_Data.Save_2D_Data("dens_2D_dopents.dat", (double)inputs["dy"] * (double)inputs["ny"] / (double)inputs_init["ny_1d"], (double)inputs_init["dz"], -1.0 * (double)inputs["dy"] * (double)inputs["ny"] / 2.0, Geom_Tool.Get_Zmin(exp_init.Layers));

                // this is a scaled version for the dopents!
                double scaling_factor = ((double)inputs["ny"] * (double)inputs["dy"]) / ((double)inputs["nz"] * (double)inputs["dz"]);
                Input_Band_Structure.Expand_BandStructure(exp_init.Dopent_Density, (int)(double)inputs["ny_1d"]).Spin_Summed_Data.Save_2D_Data("dens_2D_dopents.dat", (double)inputs["dy"] * ((double)inputs["ny"] + 2.0) / ((double)inputs["ny_1d"] - 1.0), scaling_factor * (double)inputs_init["dz"], -1.0 * (double)inputs["dy"] * ((double)inputs["ny"] + 2.0) / 2.0, scaling_factor * Geom_Tool.Get_Zmin(exp_init.Layers));
                //       Input_Band_Structure.Expand_BandStructure(exp_init.Carrier_Density, (int)(double)inputs_init["ny_1d"]).Spin_Summed_Data.Save_2D_Data("dens_2D.dat", (double)inputs["dy"] * ((double)inputs["ny"] + 2.0) / ((double)inputs_init["ny_1d"] - 1.0), (double)inputs_init["dz"], -1.0 * (double)inputs["dy"] * ((double)inputs["ny"] + 2.0) / 2.0, Geom_Tool.Get_Zmin(exp_init.Layers));
                Console.WriteLine("Saved 1D dopent density");
            }

            if ((bool)inputs["batch_run"])
            {
                Run_Multiple_SGs(inputs);
            }
            else
            {
                Console.WriteLine("Starting experiment");
                exp.Initialise(inputs);
                // check that the dz_pot are the same for both simulations as this is needed for the interpolation of SpinResolved_Density
                if (!(bool)inputs["hot_start"] && exp_init.Dz_Pot != exp.Dz_Pot)
                {
                    throw new Exception("Error - the dz values for the potentials must be the same for \"Input_Parameters.txt\" and \"Input_Parameters_1D.txt\"");
                }
                Console.WriteLine("Experiment initialised");
                exp.Run();

                Console.WriteLine("Experiment complete");
            }
        }
        private void Draw_Domain(StreamWriter sw)
        {
            sw.WriteLine("EXTRUSION");
            sw.WriteLine("\tSURFACE \"Substrate\"\tz = " + exp.Layers[0].Zmax.ToString() + " * z_scaling");
            for (int i = 1; i < exp.Layers.Length; i++)
            {
                sw.WriteLine("\t\tLAYER \"" + i.ToString() + "\"");
                sw.WriteLine("\tSURFACE	\"" + i.ToString() + "\"\tz = " + exp.Layers[i].Zmax.ToString() + " * z_scaling");
            }
            sw.WriteLine();
            sw.WriteLine("BOUNDARIES");
            sw.WriteLine("\tSURFACE \"Substrate\"	VALUE(u) = bottom_bc");
            sw.WriteLine("\tSURFACE \"" + (Geom_Tool.Find_Layer_Below_Surface(exp.Layers).Layer_No - 1).ToString() + "\" NATURAL(u) = surface_bc");
            //sw.WriteLine("\tSURFACE \"" + (exp.Layers.Length - 1).ToString() + "\" NATURAL(u) = 0");
            sw.WriteLine("\tSURFACE \"" + (exp.Layers.Length - 1).ToString() + "\" VALUE(u) = top_bc");
            sw.WriteLine();
            sw.WriteLine("\tREGION 1");
            for (int i = 1; i < exp.Layers.Length; i++)
            {
                sw.WriteLine("\t\tLAYER \"" + i.ToString() + "\"");

                sw.WriteLine("\t\teps = " + exp.Layers[i].Permitivity.ToString());
                sw.WriteLine("\t\tband_gap = " + exp.Layers[i].Band_Gap.ToString());
                sw.WriteLine();
            }
            sw.WriteLine("\t\tSTART(-lx / 2, -ly / 2 * y_scaling)");
            sw.WriteLine("\t\tLINE TO (-lx / 2, ly / 2 * y_scaling)");
            sw.WriteLine("\t\tLINE TO (lx / 2, ly / 2 * y_scaling)");
            sw.WriteLine("\t\tLINE TO (lx / 2, -ly / 2 * y_scaling)");
            sw.WriteLine("\t\tLINE TO CLOSE");
            sw.WriteLine();

            int count         = 2;
            int voltage_count = 0;

            for (int i = 0; i < exp.Layers.Length; i++)
            {
                if (exp.Layers[i].No_Components > 1)
                {
                    for (int j = 1; j < exp.Layers[i].No_Components; j++)
                    {
                        ILayer current_layer = exp.Layers[i].Get_Component(j);
                        if (current_layer.Geometry == Geometry_Type.triangle_slab)
                        {
                            throw new NotImplementedException("Triangles are not currently implemented...  Sorry");
                        }

                        string xmin = "-1.0 * split_length / 2";
                        string xmax = "split_length / 2";
                        string ymin = "-ly / 2";
                        string ymax = "ly / 2";
                        if (current_layer.Xmin != double.MinValue)
                        {
                            xmin = current_layer.Xmin.ToString();
                        }
                        if (current_layer.Xmax != double.MaxValue)
                        {
                            xmax = current_layer.Xmax.ToString();
                        }
                        if (current_layer.Ymin != double.MinValue)
                        {
                            ymin = current_layer.Ymin.ToString();
                        }
                        if (current_layer.Ymax != double.MaxValue)
                        {
                            ymax = current_layer.Ymax.ToString();
                        }

                        sw.WriteLine("\tLIMITED REGION " + count.ToString());
                        sw.WriteLine("\t\tSURFACE \"" + (i - 1).ToString() + "\" VALUE(u) = V" + voltage_count.ToString());
                        sw.WriteLine("\t\tSURFACE \"" + i.ToString() + "\" VALUE(u) = V" + voltage_count.ToString());
                        sw.WriteLine("\t\tLAYER \"" + i.ToString() + "\" VOID");
                        sw.WriteLine("\t\tSTART (" + xmin + ", " + ymax + " * y_scaling)");
                        sw.WriteLine("\t\tLAYER \"" + i.ToString() + "\"");
                        sw.WriteLine("\t\tVALUE(u) = V" + voltage_count.ToString());
                        sw.WriteLine("\t\tmesh_spacing = 100");
                        sw.WriteLine("\t\tLINE TO (" + xmax + ", " + ymax + " * y_scaling)");
                        sw.WriteLine("\t\tLINE TO (" + xmax + ", " + ymin + " * y_scaling) TO (" + xmin + ", " + ymin + " * y_scaling) TO CLOSE");
                        sw.WriteLine();

                        count++;
                        voltage_count++;
                    }
                }
            }

            if (voltage_count != gate_bcs.Count)
            {
                sw.Close();
                throw new Exception("Error - not enough voltages for the number of gates... see FlexPDE file...");
            }
        }
Beispiel #17
0
        public override void Initialise(Dictionary <string, object> input_dict)
        {
            // simulation domain inputs
            Get_From_Dictionary <double>(input_dict, "dz", ref dz_dens); dz_pot = dz_dens;
            Get_From_Dictionary(input_dict, "nz", ref nz_dens); nz_pot          = nz_dens;

            // physics parameters are done by the base method
            base.Initialise(input_dict);
            Get_From_Dictionary <bool>(input_dict, "illuminated", ref illuminated, true);

            // check that the size of the domain [(nz_pot-1) * dz_pot] is not larger than the band structure
            if (layers[layers.Length - 1].Zmax - Geom_Tool.Get_Zmin(layers) < (Nz_Pot - 1) * Dz_Pot)
            {
                throw new Exception("Error - the band structure provided is smaller than the simulation domain!\nUse nz = " + (int)Math.Ceiling((layers[layers.Length - 1].Zmax - Geom_Tool.Get_Zmin(layers)) / Dz_Pot) + " instead");
            }
            // and check that the top of the domain is the surface (unless this check is overloaded)
            bool surface_override = false; Get_From_Dictionary <bool>(input_dict, "surface_check", ref surface_override, true);

            if (!surface_override && Geom_Tool.Find_Layer_Below_Surface(layers).Zmax - Geom_Tool.Get_Zmin(layers) - Nz_Pot * Dz_Pot != 0.0)
            {
                throw new Exception("Error - the top of the domain is not the surface!\nUse the input \"surface_check\" to override");
            }

            // calculate the top and bottom of the domain
            input_dict["zmin"] = Geom_Tool.Get_Zmin(layers);
            input_dict["zmax"] = Geom_Tool.Get_Zmin(layers) + dz_pot * nz_pot;

            // and split gate dimensions
            device_dimensions.Add("bottom_position", (double)input_dict["zmin"]);
            device_dimensions.Add("top_position", (double)input_dict["zmax"]);

            // check whether the bottom should be fixed
            if (input_dict.ContainsKey("bottom_V"))
            {
                fix_bottom_V = true;
            }

            // initialise the dictionary which contains the surface charges at each temperature
            surface_charge = new Dictionary <double, double>();

            // double check whether you want to use FlexPDE
            if (input_dict.ContainsKey("use_FlexPDE"))
            {
                using_flexPDE = (bool)input_dict["use_FlexPDE"];
            }

            // Initialise potential solver
            pois_solv = new OneD_PoissonSolver(this, using_flexPDE, input_dict);

            Initialise_DataClasses(input_dict);

            // if the input dictionary already has the dopent distribution, we don't need to recalculate it
            if (input_dict.ContainsKey("Dopent_Density"))
            {
                dopents_calculated = true;
            }

            // Get carrier type for DFT calculations (default is electron)
            if (input_dict.ContainsKey("carrier_type"))
            {
                carrier_type = (Carrier)Enum.Parse(typeof(Carrier), (string)input_dict["carrier_type"]);
            }

            Console.WriteLine("Experimental parameters initialised");
        }
Beispiel #18
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);
        }
Beispiel #19
0
        public virtual void Initialise(Dictionary <string, object> input_dict)
        {
            // solver inputs
            Get_From_Dictionary <double>(input_dict, "tolerance", ref tol);
            tol_anneal = tol;
            Get_From_Dictionary <double>(input_dict, "anneal_tolerance", ref tol_anneal, true);
            Get_From_Dictionary(input_dict, "max_iterations", ref max_iterations, true);

            Get_From_Dictionary <bool>(input_dict, "initial_run", ref initial_run, true);
            Get_From_Dictionary(input_dict, "initial_run_steps", ref initial_run_steps, true);

            // will not use FlexPDE unless told to
            if (input_dict.ContainsKey("use_FlexPDE"))
            {
                this.using_flexPDE = (bool)input_dict["use_FlexPDE"];
            }
            else
            {
                using_flexPDE = false;
            }
            // and the same for dealii
            if (input_dict.ContainsKey("use_deal.II"))
            {
                this.using_dealii = (bool)input_dict["use_deal.II"];
            }
            else
            {
                using_dealii = false;
            }

            // check to make sure that we haven't asked to use more than one external program to calculate the potential
            if (using_flexPDE == true && using_dealii == true)
            {
                throw new Exception("Error - Cannot use both FlexPDE and deal.II to calculate the potential!");
            }

            // physical inputs
            Get_From_Dictionary <double>(input_dict, "init_T", ref initial_temperature, true);
            Get_From_Dictionary <double>(input_dict, "T", ref temperature);

            // get the band structure
            if (input_dict.ContainsKey("Layers"))
            {
                layers = (ILayer[])input_dict["Layers"];
            }
            else
            {
                if (input_dict.ContainsKey("BandStructure_File"))
                {
                    layers = Input_Band_Structure.Get_Layers((string)input_dict["BandStructure_File"]);
                    input_dict.Add("Layers", layers);
                }
                else
                {
                    throw new KeyNotFoundException("No band structure file found in input dictionary!");
                }
            }

            // but try to get the specific values
            Get_From_Dictionary <double>(input_dict, "dx_dens", ref dx_dens, true);
            Get_From_Dictionary <double>(input_dict, "dy_dens", ref dy_dens, true);
            Get_From_Dictionary <double>(input_dict, "dz_dens", ref dz_dens, true);
            Get_From_Dictionary <double>(input_dict, "dx_pot", ref dx_pot, true);
            Get_From_Dictionary <double>(input_dict, "dy_pot", ref dy_pot, true);
            Get_From_Dictionary <double>(input_dict, "dz_pot", ref dz_pot, true);

            Get_From_Dictionary(input_dict, "nx_dens", ref nx_dens, true);
            Get_From_Dictionary(input_dict, "ny_dens", ref ny_dens, true);
            Get_From_Dictionary(input_dict, "nz_dens", ref nz_dens, true);
            Get_From_Dictionary(input_dict, "nx_pot", ref nx_pot, true);
            Get_From_Dictionary(input_dict, "ny_pot", ref ny_pot, true);
            Get_From_Dictionary(input_dict, "nz_pot", ref nz_pot, true);


            // and find the domain minimum coordinate values
            xmin_pot = Geom_Tool.Get_Xmin(layers);
            ymin_pot = Geom_Tool.Get_Ymin(layers);
            zmin_pot = Geom_Tool.Get_Zmin(layers);
            // but still try to get them from the dictionary if its there
            Get_From_Dictionary <double>(input_dict, "xmin_pot", ref xmin_pot, true);
            Get_From_Dictionary <double>(input_dict, "ymin_pot", ref ymin_pot, true);
            Get_From_Dictionary <double>(input_dict, "zmin_pot", ref zmin_pot, true);

            // and by default these are the same as for the density
            xmin_dens = xmin_pot;
            ymin_dens = ymin_pot;
            zmin_dens = zmin_pot;
            // and, once again, try to find something in the dictionary
            Get_From_Dictionary <double>(input_dict, "xmin_dens", ref xmin_dens, true);
            Get_From_Dictionary <double>(input_dict, "ymin_dens", ref ymin_dens, true);
            Get_From_Dictionary <double>(input_dict, "zmin_dens", ref zmin_dens, true);

            // and try and get as much information about the split gate dimensions as possible
            device_dimensions = new Dictionary <string, double>();
            device_dimensions.Add("top_length", Get_From_Dictionary <double>(input_dict, "top_length", 0.0));
            device_dimensions.Add("split_width", Get_From_Dictionary <double>(input_dict, "split_width", 0.0));
            device_dimensions.Add("split_length", Get_From_Dictionary <double>(input_dict, "split_length", 0.0));

            // as well as for the gate voltages
            boundary_conditions = new Dictionary <string, double>();
            boundary_conditions.Add("top_V", Get_From_Dictionary <double>(input_dict, "top_V", 0.0));
            boundary_conditions.Add("split_V1", Get_From_Dictionary <double>(input_dict, "split_V1", Get_From_Dictionary <double>(input_dict, "split_V", 0.0)));
            boundary_conditions.Add("split_V2", Get_From_Dictionary <double>(input_dict, "split_V2", Get_From_Dictionary <double>(input_dict, "split_V", 0.0)));
            boundary_conditions.Add("bottom_V", Get_From_Dictionary <double>(input_dict, "bottom_V", 0.0));
            Inputs_to_Dictionary.Parse_Voltages(input_dict, boundary_conditions);

            // work out whether we are doing dft or not
            Get_From_Dictionary <bool>(input_dict, "no_dft", ref no_dft, true);
            if (input_dict.ContainsKey("dft"))
            {
                no_dft = !(bool)input_dict["dft"];
            }
            // and whether to set the mixing parameter to something other than the default
            Get_From_Dictionary <double>(input_dict, "dft_mixing_parameter", ref dft_mixing_parameter, true);

            // get keys for any interesting start-up protocols
            if (input_dict.ContainsKey("hot_start"))
            {
                hot_start = (bool)input_dict["hot_start"];
            }
            Get_From_Dictionary <bool>(input_dict, "initialise_with_1D_data", ref initialise_with_1D_data, true);
            if (File.Exists("restart.flag") && input_dict.ContainsKey("with_checkpointing"))
            {
                if (File.ReadAllLines("restart.flag")[0] == "true" && (bool)input_dict["with_checkpointing"])
                {
                    initialise_from_restart = true;
                }
            }

            // and create a restart flag file if necessary
            if (!initialise_from_restart)
            {
                StreamWriter sw_flag = new StreamWriter("restart.flag"); sw_flag.WriteLine("true"); sw_flag.Close();
            }

            if (!Check_Boundary_Points(layers, Zmin_Dens, Zmin_Dens + Dz_Dens * Nz_Dens, Dz_Dens))
            {
                throw new Exception("Error - there must be lattice points on all of the boundaries between zmin = " + Zmin_Dens.ToString() + " and zmax = " + (Zmin_Dens + Dz_Dens * Nz_Dens).ToString());
            }

            // and load the output suffix for identification of output files
            Get_From_Dictionary <string>(input_dict, "output_suffix", ref output_suffix, true);
        }