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); }
/// <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(); }
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"); }
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..."); } }