public override bool Run() { if (!initialise_from_restart) { // calculate the bare potential Console.WriteLine("Calculating bare potential"); chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(0.0 * carrier_charge_density.Spin_Summed_Data); Console.WriteLine("Saving bare potential"); (Input_Band_Structure.Get_BandStructure_Grid(layers, dx_dens, dy_dens, dz_dens, nx_dens, ny_dens, nz_dens, xmin_dens, ymin_dens, zmin_dens) - chem_pot).Save_Data("bare_pot.dat"); Console.WriteLine("Bare potential saved"); //if the initial carrier density was not zero, recalculate the chemical potential if (carrier_charge_density.Spin_Summed_Data.Max() != 0.0 || carrier_charge_density.Spin_Summed_Data.Min() != 0.0) { chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data); } } // get the dopent density from the Poisson equation dopent_charge_density.Spin_Up = -0.5 * (chem_pot.Laplacian / Physics_Base.q_e + carrier_charge_density.Spin_Summed_Data); dopent_charge_density.Spin_Down = -0.5 * (chem_pot.Laplacian / Physics_Base.q_e + carrier_charge_density.Spin_Summed_Data); // ThreeD_ThomasFermiSolver dens_solv = new ThreeD_ThomasFermiSolver(this); //ThreeD_EffectiveBandSolver dft_solv = new ThreeD_EffectiveBandSolver(this); // TwoplusOneD_ThomasFermiSolver dft_solv = new TwoplusOneD_ThomasFermiSolver(this); bool converged = false; // start without dft if carrier density is empty if (no_dft || carrier_charge_density.Spin_Summed_Data.Min() == 0.0) { dens_solv.DFT_Mixing_Parameter = 0.0; } else { dens_solv.DFT_Mixing_Parameter = dft_mixing_parameter; } // do preliminary run to correct for initial discretised form of rho_prime if (initial_run) { converged = Run_Iteration_Routine(dens_solv, pois_solv, tol, initial_run_steps); // and calculate the potential given the density from this initial run pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions); chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data); } if (!converged || !initial_run) //if(true) { int count = 0; while (pot_init > tol_anneal && count < 20) { if (count != 0) { pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions); chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data); } // run the iteration routine! converged = Run_Iteration_Routine(dens_solv, pois_solv, tol, max_iterations); count++; } } // save surface charge StreamWriter sw = new StreamWriter("surface_charge.dat"); sw.WriteLine(boundary_conditions["surface"].ToString()); sw.Close(); // save eigen-energies /*DoubleVector energies = dft_solv.Get_EnergyLevels(layers, chem_pot); * StreamWriter sw_e = new StreamWriter("energies.dat"); * for (int i = 0; i < energies.Length; i++) * sw_e.WriteLine(energies[i]); * sw_e.Close();*/ dens_solv.Output(carrier_charge_density, "carrier_density.dat"); dens_solv.Output(carrier_charge_density - dens_solv.Get_ChargeDensity(layers, carrier_charge_density, dopent_charge_density, chem_pot), "density_error.dat"); (Input_Band_Structure.Get_BandStructure_Grid(layers, dx_dens, dy_dens, dz_dens, nx_dens, ny_dens, nz_dens, xmin_dens, ymin_dens, zmin_dens) - chem_pot).Save_Data("potential.dat"); Band_Data pot_exc = dens_solv.DFT_diff(carrier_charge_density) + dens_solv.Get_XC_Potential(carrier_charge_density); pot_exc.Save_Data("xc_pot.dat"); (Input_Band_Structure.Get_BandStructure_Grid(layers, dx_dens, dy_dens, dz_dens, nx_dens, ny_dens, nz_dens, xmin_dens, ymin_dens, zmin_dens) - chem_pot + pot_exc).Save_Data("pot_KS.dat"); // Band_Data ks_ke = dft_solv.Get_KS_KE(layers, chem_pot); // ks_ke.Save_Data("ks_ke.dat"); // clean up intermediate data files File.Delete("phi.dat"); File.Delete("new_phi.dat"); File.Delete("x.dat"); File.Delete("y.dat"); File.Delete("gphi.dat"); File.Delete("car_dens.dat"); File.Delete("rho_prime.dat"); File.Delete("xc_pot.dat"); File.Delete("xc_pot_calc.dat"); File.Delete("pot.dat"); File.Delete("carrier_density.dat"); File.Delete("charge_density.dat"); File.Delete("potential.dat"); File.Delete("lap.dat"); Close(dens_solv.Unit_Charge, converged, max_iterations); return(converged); }
protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations) { // calculate initial potential with the given charge distribution Console.WriteLine("Calculating initial potential grid"); pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions); if (chem_pot == null) chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data); Console.WriteLine("Initial grid complete"); // dens_solv.Set_DFT_Potential(carrier_charge_density); // dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot); // dens_solv.Set_DFT_Potential(carrier_charge_density); dens_solv.Reset_DFT_Potential(); dens_solv.Update_DFT_Potential(carrier_charge_density); int count = 0; t = 1.0; bool converged = false; while (!converged) { Band_Data dens_old = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data; // Get charge rho(phi) dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot); // Generate charge-dependent part of the Jacobian, g'(phi) = -d(eps * d( )) - rho'(phi) SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot); // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi) // Calculate Laplacian operating on the given band energy, d(eps * d(phi)) gphi = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data; gphi[0] = 0.0; gphi[gphi.Length - 1] = 0.0; x = pois_solv.Calculate_Newton_Step(rho_prime, gphi); // Calculate optimal damping parameter, t t = t_damp * Calculate_optimal_t(t / t_damp, (chem_pot / Physics_Base.q_e), x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min); // Check convergence Band_Data dens_spin_summed = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data; Band_Data dens_diff = dens_spin_summed - dens_old; double dens_abs_max = Math.Max(Math.Abs(dens_spin_summed.Max()), Math.Abs(dens_spin_summed.Min())); for (int i = 0; i < dens_diff.Length; i++) // only calculate density difference for densities more than 1% of the maximum value if (Math.Abs(dens_spin_summed[i]) > 0.01 * dens_abs_max) dens_diff[i] = Math.Abs(dens_diff[i] / dens_spin_summed[i]); else dens_diff[i] = 0.0; // Update the DFT potential dens_solv.Update_DFT_Potential(carrier_charge_density); double[] diff = new double[Nz_Pot]; for (int j = 0; j < nz_pot; j++) diff[j] = Math.Abs(gphi.vec[j]); double convergence = diff.Sum(); if (Physics_Base.q_e * x.InfinityNorm() < tol) converged = true; // update band energy phi_new = phi_old + t * x Console.WriteLine(Generate_Output_String(count, x, dens_diff)); chem_pot = chem_pot + t * Physics_Base.q_e * x; count++; base.Checkpoint(); // reset the potential if the added potential t * x is too small if (converged || count > max_iterations) { Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString() + "meV"); break; } } Console.WriteLine("Iteration complete"); return converged; }
protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations) { // calculate initial potential with the given charge distribution Console.WriteLine("Calculating initial potential grid"); pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions); if (chem_pot == null) { chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data); } Console.WriteLine("Initial grid complete"); // dens_solv.Set_DFT_Potential(carrier_charge_density); // dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot); // dens_solv.Set_DFT_Potential(carrier_charge_density); dens_solv.Reset_DFT_Potential(); dens_solv.Update_DFT_Potential(carrier_charge_density); int count = 0; t = 1.0; bool converged = false; while (!converged) { Band_Data dens_old = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data; // Get charge rho(phi) dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot); // Generate charge-dependent part of the Jacobian, g'(phi) = -d(eps * d( )) - rho'(phi) SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot); // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi) // Calculate Laplacian operating on the given band energy, d(eps * d(phi)) gphi = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data; gphi[0] = 0.0; gphi[gphi.Length - 1] = 0.0; x = pois_solv.Calculate_Newton_Step(rho_prime, gphi); // Calculate optimal damping parameter, t t = t_damp * Calculate_optimal_t(t / t_damp, (chem_pot / Physics_Base.q_e), x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min); // Check convergence Band_Data dens_spin_summed = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data; Band_Data dens_diff = dens_spin_summed - dens_old; double dens_abs_max = Math.Max(Math.Abs(dens_spin_summed.Max()), Math.Abs(dens_spin_summed.Min())); for (int i = 0; i < dens_diff.Length; i++) { // only calculate density difference for densities more than 1% of the maximum value if (Math.Abs(dens_spin_summed[i]) > 0.01 * dens_abs_max) { dens_diff[i] = Math.Abs(dens_diff[i] / dens_spin_summed[i]); } else { dens_diff[i] = 0.0; } } // Update the DFT potential dens_solv.Update_DFT_Potential(carrier_charge_density); double[] diff = new double[Nz_Pot]; for (int j = 0; j < nz_pot; j++) { diff[j] = Math.Abs(gphi.vec[j]); } double convergence = diff.Sum(); if (Physics_Base.q_e * x.InfinityNorm() < tol) { converged = true; } // update band energy phi_new = phi_old + t * x Console.WriteLine(Generate_Output_String(count, x, dens_diff)); chem_pot = chem_pot + t * Physics_Base.q_e * x; count++; base.Checkpoint(); // reset the potential if the added potential t * x is too small if (converged || count > max_iterations) { Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString() + "meV"); break; } } Console.WriteLine("Iteration complete"); return(converged); }