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