public override void Get_ChargeDensity(ILayer[] layers, ref SpinResolved_Data charge_density, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); double[,] xy_energy = Solve_Eigenvector_Problem(dft_pot, ref charge_density); double beta = 1.0 / (Physics_Base.kB * temperature); // multiply the z-densities by the xy-density for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) for (int k = 0; k < nz; k++) { charge_density.Spin_Up.vol[k][i, j] *= g_2d * Math.Log(1.0 + Math.Exp(-1.0 * beta * xy_energy[i, j])) / beta; charge_density.Spin_Down.vol[k][i, j] *= g_2d * Math.Log(1.0 + Math.Exp(-1.0 * beta * xy_energy[i, j])) / beta; } // and multiply the density by -e to get the charge density (as these are electrons) charge_density = unit_charge * charge_density; }
public override void Get_ChargeDensity(ILayer[] layers, ref SpinResolved_Data charge_density, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); DoubleHermitianEigDecomp eig_decomp = Solve_Eigenvector_Problem(dft_pot, ref charge_density); int max_wavefunction = (from val in eig_decomp.EigenValues where val < no_kb_T * Physics_Base.kB * temperature select val).ToArray().Length; double[] dens_x = new double[nx]; // and generate a density for the y-direction for (int i = 0; i < nx; i++) for (int k = 0; k < max_wavefunction; k++) dens_x[i] += DoubleComplex.Norm(eig_decomp.EigenVector(k)[i]) * DoubleComplex.Norm(eig_decomp.EigenVector(k)[i]) * Get_OneD_DoS(energies[k], no_kb_T); // multiply the z-densities by the y-density for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { // do not add anything to the density if on the edge of the domain if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) { charge_density.Spin_Up.mat[i, j] *= 0.0; charge_density.Spin_Down.mat[i, j] *= 0.0; } charge_density.Spin_Up.mat[i, j] *= dens_x[i]; charge_density.Spin_Down.mat[i, j] *= dens_x[i]; } // and multiply the density by -e to get the charge density (as these are electrons) charge_density = unit_charge * charge_density; }
/// <summary> /// Calculate the charge density for this potential /// NOTE!!! that the boundary potential is (essentially) set to infty by ringing the density with a set of zeros. /// this prevents potential solvers from extrapolating any residual density at the edge of the eigenstate /// solution out of the charge density calculation domain /// </summary> /// <param name="layers"></param> /// <param name="charge_density"></param> /// <param name="chem_pot"></param> public override void Get_ChargeDensity(ILayer[] layers, ref SpinResolved_Data charge_density, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); DoubleHermitianMatrix hamiltonian = Create_Hamiltonian(layers, dft_pot); DoubleHermitianEigDecompServer eig_server = new DoubleHermitianEigDecompServer(); eig_server.ComputeEigenValueRange(dft_pot.mat.Min(), no_kb_T * Physics_Base.kB * temperature); eig_server.ComputeVectors = true; DoubleHermitianEigDecomp eig_decomp = eig_server.Factor(hamiltonian); int max_wavefunction = 0; if (eig_decomp.EigenValues.Length != 0) { double min_eigval = eig_decomp.EigenValues.Min(); max_wavefunction = (from val in eig_decomp.EigenValues where val < no_kb_T * Physics_Base.kB * temperature select val).ToArray().Length; } for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { double dens_val = 0.0; // do not add anything to the density if on the edge of the domain if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) { charge_density.Spin_Up.mat[i, j] = 0.0; charge_density.Spin_Down.mat[i, j] = 0.0; continue; } for (int k = 0; k < max_wavefunction; k++) { // and integrate the density of states at this position for this eigenvector from the minimum energy to // (by default) 50 * k_b * T above mu = 0 dens_val += DoubleComplex.Norm(eig_decomp.EigenVector(k)[i * ny + j]) * DoubleComplex.Norm(eig_decomp.EigenVector(k)[i * ny + j]) * Get_OneD_DoS(eig_decomp.EigenValue(k), no_kb_T); } // just share the densities (there is no spin polarisation) charge_density.Spin_Up.mat[i, j] = 0.5 * dens_val; charge_density.Spin_Down.mat[i, j] = 0.5 * dens_val; } // and multiply the density by -e to get the charge density (as these are electrons) charge_density = unit_charge * charge_density; }
/// <summary> /// returns the eigen-energies for the given potential and charge density /// </summary> public override DoubleVector Get_EnergyLevels(ILayer[] layers, Band_Data pot) { // convert the chemical potential into a quantum mechanical potential Band_Data band_pot = pot.DeepenThisCopy(); Get_Potential(ref band_pot, layers); DoubleHermitianMatrix hamiltonian = Create_Hamiltonian(layers, band_pot); DoubleHermitianEigDecomp eig_decomp = new DoubleHermitianEigDecomp(hamiltonian); return eig_decomp.EigenValues; }
/// <summary> /// Calculate the charge density for this potential /// NOTE!!! that the boundary potential is (essentially) set to infty by ringing the density with a set of zeros. /// this prevents potential solvers from extrapolating any residual density at the edge of the eigenstate /// solution out of the charge density calculation domain /// </summary> /// <param name="layers"></param> /// <param name="charge_density_deriv"></param> /// <param name="chem_pot"></param> public override void Get_ChargeDensity_Deriv(ILayer[] layers, ref SpinResolved_Data charge_density_deriv, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); DoubleHermitianMatrix hamiltonian = Create_Hamiltonian(layers, dft_pot); DoubleHermitianEigDecomp eig_decomp = new DoubleHermitianEigDecomp(hamiltonian); double min_eigval = eig_decomp.EigenValues.Min(); int max_wavefunction = (from val in eig_decomp.EigenValues where val < no_kb_T * Physics_Base.kB * temperature select val).ToArray().Length; for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { double dens_val_deriv = 0.0; // do not add anything to the density if on the edge of the domain if (i == 0 || i == nx - 1 || j == 0 || j == ny - 1) { charge_density_deriv.Spin_Up.mat[i, j] = 0.0; charge_density_deriv.Spin_Down.mat[i, j] = 0.0; continue; } for (int k = 0; k < max_wavefunction; k++) { // and integrate the density of states at this position for this eigenvector from the minimum energy to // (by default) 50 * k_b * T above mu = 0 dens_val_deriv += DoubleComplex.Norm(eig_decomp.EigenVector(k)[i * ny + j]) * DoubleComplex.Norm(eig_decomp.EigenVector(k)[i * ny + j]) * Get_OneD_DoS_Deriv(eig_decomp.EigenValue(k), no_kb_T); } // just share the densities (there is no spin polarisation) charge_density_deriv.Spin_Up.mat[i, j] = 0.5 * dens_val_deriv; charge_density_deriv.Spin_Down.mat[i, j] = 0.5 * dens_val_deriv; } // and multiply the density derivative by e to get the charge density and by e to convert it to d/dphi (as increasing phi decreases the charge: dn/dphi*-e^2 ) charge_density_deriv = unit_charge * unit_charge * charge_density_deriv; }
public override DoubleVector Get_EnergyLevels(ILayer[] layers, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); // diagonalise matrix for k = 0 int tmp = 0; DoubleHermitianEigDecomp eig_decomp = Diagonalise_Hamiltonian(Create_Hamiltonian(dft_pot, 0.0), out tmp); return eig_decomp.EigenValues; }
public override void Get_ChargeDensity_Deriv(ILayer[] layers, ref SpinResolved_Data charge_density_deriv, Band_Data chem_pot) { Get_SOI_parameters(chem_pot); // if (dV_x == null) // throw new Exception("Error - Band structure derivatives are null! Have you initiated this type properly by calling Get_SOI_parameters(Band_Data chem_pot)?"); // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); // reset charge density charge_density_deriv = 0.0 * charge_density_deriv; // integrate up density from k = 0 to k = k_F int count = 0; double k = 0; // create initial hamiltonian and eigendecomposition int max_wavefunction_old_p, max_wavefunction_old_m; DoubleHermitianMatrix hamiltonian_p = Create_H_Using_SOIP(dft_pot, k); DoubleHermitianEigDecomp eig_decomp_old_p = Diagonalise_Hamiltonian(hamiltonian_p, out max_wavefunction_old_p); DoubleHermitianEigDecomp eig_decomp_old_m = Diagonalise_Hamiltonian(hamiltonian_p, out max_wavefunction_old_m); while (k < kmax) { // increment the wavevector k += delta_k; count += 1; // create new decompositions for forwards and backwards analysis int max_wavefunction_p, max_wavefunction_m; DoubleHermitianEigDecomp eig_decomp_p = Diagonalise_Hamiltonian(Create_H_Using_SOIP(dft_pot, k), out max_wavefunction_p); DoubleHermitianEigDecomp eig_decomp_m = Diagonalise_Hamiltonian(Create_H_Using_SOIP(dft_pot, -1.0 * k), out max_wavefunction_m); SpinResolved_Data new_charge_deriv = new SpinResolved_Data(nx, ny); // cycle over each of the positive bands for (int i = 0; i < max_wavefunction_p; i++) new_charge_deriv += Calculate_Density_Derivative(eig_decomp_old_p, eig_decomp_p, i); // and negative bands for (int i = 0; i < max_wavefunction_m; i++) new_charge_deriv += Calculate_Density_Derivative(eig_decomp_old_m, eig_decomp_m, i); // set new eigenvalue decompositions and max_wavefunctions to the old ones eig_decomp_old_m = eig_decomp_m; eig_decomp_old_p = eig_decomp_p; max_wavefunction_old_m = max_wavefunction_m; max_wavefunction_old_p = max_wavefunction_p; // and finally, add the charge density calculated charge_density_deriv += new_charge_deriv; } }
public override void Get_ChargeDensity_Deriv(ILayer[] layers, ref SpinResolved_Data charge_density_deriv, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); double[,] xy_energy = Solve_Eigenvector_Problem(dft_pot, ref charge_density_deriv); double beta = 1.0 / (Physics_Base.kB * temperature); // multiply the z-densities by the xy-density for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) for (int k = 0; k < nz; k++) { charge_density_deriv.Spin_Up.vol[k][i, j] *= g_2d * Get_Fermi_Function(xy_energy[i, j]); charge_density_deriv.Spin_Down.vol[k][i, j] *= g_2d * Get_Fermi_Function(xy_energy[i, j]); } // and multiply the density derivative by e to get the charge density and by e to convert it to d/dphi (as increasing phi decreases the charge: dn/dphi*-e^2 ) charge_density_deriv = unit_charge * unit_charge * charge_density_deriv; }
public override void Get_ChargeDensity(ILayer[] layers, ref SpinResolved_Data charge_density, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); double[,] xy_energy = new double[nx, ny]; xy_energy = Solve_Eigenvector_Problem(dft_pot, ref charge_density); /*int max_wavefunction = (from val in eig_decomp.EigenValues where val < no_kb_T * Physics_Base.kB * temperature select val).ToArray().Length; double[,] dens_xy = new double[nx, ny]; // and generate a density for the y-direction for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) for (int k = 0; k < max_wavefunction; k++) dens_xy[i, j] += DoubleComplex.Norm(eig_decomp.EigenVector(k)[i * ny + j]) * DoubleComplex.Norm(eig_decomp.EigenVector(k)[i * ny + j]) * Get_Fermi_Function(energies[k]); */ IExperiment exp_green; exp_green = new Iterative_Greens_Function_Test.Experiment(); Iterative_Greens_Function_Test.Iterative_Greens_Function iter = new Iterative_Greens_Function_Test.Iterative_Greens_Function(exp_green, xy_energy); double[,] dens_xy = new double[nx, ny]; double max_energy = Physics_Base.kB * temperature * no_kb_T; DoubleMatrix xy_energy_mat = new DoubleMatrix(xy_energy); double min_energy = xy_energy_mat.Min(); double dE = 0.1; //double min_energy = -1.0 * max_energy; int n_slices = (int)((max_energy - min_energy) / dE); for (int n = 1; n < n_slices-1; n++) { double energy = min_energy + n * dE; double[,] dens_per_E = iter.GetDoS(energy); double fermi_func = Get_Fermi_Function(energy); for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { dens_xy[i, j] += dens_per_E[i,j] * fermi_func; } } //double fermi_fact_max = Math.Exp(max_energy / (Physics_Base.kB * temperature)) + 1; //double fermi_fact_min = 2.0; double[,] dens_per_E_max = iter.GetDoS(max_energy); double[,] dens_per_E_min = iter.GetDoS(min_energy); double fermi_func_max = Get_Fermi_Function(max_energy); double fermi_func_min = Get_Fermi_Function(min_energy); for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { dens_xy[i, j] += 0.5*(dens_per_E_max[i, j] * fermi_func_max + dens_per_E_min[i,j] * fermi_func_min); } // multiply the z-densities by the xy-density for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) for (int k = 0; k < nz; k++) { charge_density.Spin_Up.vol[k][i, j] *= dens_xy[i, j]; charge_density.Spin_Down.vol[k][i, j] *= dens_xy[i, j]; } // and multiply the density by -e to get the charge density (as these are electrons) charge_density = unit_charge * charge_density; }
public Band_Data Get_KS_KE(ILayer[] layers, Band_Data chem_pot) { // convert the chemical potential into a quantum mechanical potential Band_Data dft_pot = chem_pot.DeepenThisCopy(); Get_Potential(ref dft_pot, layers); // create temporary density for input into... DoubleMatrix dens_up = new DoubleMatrix(nx, ny, 0.0); DoubleMatrix dens_down = new DoubleMatrix(nx, ny, 0.0); SpinResolved_Data dens = new SpinResolved_Data(new Band_Data(dens_up), new Band_Data(dens_down)); // calculate eigenvectors DoubleHermitianEigDecomp eig_decomp = Solve_Eigenvector_Problem(dft_pot, ref dens); int max_wavefunction = (from val in eig_decomp.EigenValues where val < no_kb_T * Physics_Base.kB * temperature select val).ToArray().Length; // generate kinetic energy data Band_Data ke = new Band_Data(nx, ny, 0.0); Band_Data dens_tot = dens.Spin_Summed_Data; double ke_prefactor = -0.5 * Physics_Base.hbar * Physics_Base.hbar / mass; for (int i = 1; i < nx - 1; i++) for (int j = 1; j < ny - 1; j++) for (int k = 0; k < max_wavefunction; k++) { double dy2psi = (dens_tot.mat[i, j + 1] + dens_tot.mat[i, j - 1] - 2.0 * dens_tot.mat[i, j]) * DoubleComplex.Norm(eig_decomp.EigenVector(k)[i]); double dx2psi = DoubleComplex.Norm(eig_decomp.EigenVector(k)[i + 1] + eig_decomp.EigenVector(k)[i - 1] - 2.0 * eig_decomp.EigenVector(k)[i]) * dens_tot.mat[i, j]; double psi_div2psi = (dens_tot.mat[i, j] * DoubleComplex.Norm(eig_decomp.EigenVector(k)[i])) * (dx2psi + dy2psi); ke.mat[i, j] += ke_prefactor * psi_div2psi * Get_OneD_DoS(eig_decomp.EigenValue(k), no_kb_T); } return ke; }