/// <summary> /// returns an eigenvector decomposition for the x-direction after having calculated the density in the /// y-direction and storing it in "charge_density" /// </summary> /// <param name="dft_pot"></param> /// <param name="charge_density"></param> /// <returns></returns> private DoubleHermitianEigDecomp Solve_Eigenvector_Problem(Band_Data dft_pot, ref SpinResolved_Data charge_density) { DoubleHermitianEigDecomp eig_decomp; double[] x_energy = new double[nx]; DoubleMatrix dens_up = new DoubleMatrix(nx, ny, 0.0); DoubleMatrix dens_down = new DoubleMatrix(nx, ny, 0.0); // cycle over x-direction calculating the ground state energy and eigenstate in the y-direction for (int i = 0; i < nx; i++) { // pull out the chemical potential for this slice double[] y_dft_pot = new double[ny]; for (int j = 0; j < ny; j++) { y_dft_pot[j] = dft_pot.mat[i, j]; } // calculate its eigendecomposition DoubleHermitianMatrix h_y = Create_Hamiltonian(y_dft_pot, ty, ny); eig_decomp = new DoubleHermitianEigDecomp(h_y); // insert the eigenstate into density and record the local confinement energy x_energy[i] = eig_decomp.EigenValue(0); for (int j = 0; j < ny; j++) { double dens_tot = DoubleComplex.Norm(eig_decomp.EigenVector(0)[j]) * DoubleComplex.Norm(eig_decomp.EigenVector(0)[j]); dens_up[i, j] = 0.5 * dens_tot; dens_down[i, j] = 0.5 * dens_tot; } } // check whether to enforce symmetry in the transverse direction if (force_symmetry) { for (int i = nx / 2 + 1; i < nx; i++) { x_energy[i] = x_energy[nx - i - 1]; for (int j = 0; j < ny; j++) { dens_up[i, j] = dens_up[nx - i - 1, j]; dens_down[i, j] = dens_down[nx - i - 1, j]; } } } // calculate the eigenstates in the x-direction DoubleHermitianMatrix h_x = Create_Hamiltonian(x_energy, tx, nx); eig_decomp = new DoubleHermitianEigDecomp(h_x); energies = eig_decomp.EigenValues; // put the calculated densities into charge_density charge_density = new SpinResolved_Data(new Band_Data(dens_up), new Band_Data(dens_down)); return(eig_decomp); }
/// <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; }
void Output_Wavefunctions(DoubleHermitianEigDecomp eig, int no_wavefunctions) { for (int i = 0; i < no_wavefunctions; i++) { System.IO.StreamWriter sw = new System.IO.StreamWriter("wav_" + i.ToString("00")); for (int j = 0; j < nx; j++) { sw.WriteLine((eig.EigenVector(i)[j].Real * Math.Sqrt(Get_OneD_DoS(eig.EigenValue(i), no_kb_T))).ToString()); } sw.Close(); } }
SpinResolved_Data Calculate_Density_Derivative(DoubleHermitianEigDecomp eig_decomp_old, DoubleHermitianEigDecomp eig_decomp_new, int wavefunction) { DoubleMatrix dens_up_deriv = new DoubleMatrix(nx, ny, 0.0); DoubleMatrix dens_down_deriv = new DoubleMatrix(nx, ny, 0.0); 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) { continue; } // calculate the density of this spin configuration this hamiltonian dens_up_deriv[i, j] += g_1D * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j]) * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j]) * Interpolate_Fermi_Function_Derivative(eig_decomp_old, eig_decomp_new, wavefunction); dens_down_deriv[i, j] += g_1D * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j + nx * ny]) * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j + nx * ny]) * Interpolate_Fermi_Function_Derivative(eig_decomp_old, eig_decomp_new, wavefunction); } } // and multiply the density by -e to get the charge density (as these are electrons) return(unit_charge * unit_charge * new SpinResolved_Data(new Band_Data(dens_up_deriv), new Band_Data(dens_down_deriv))); }
/// <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 void Get_ChargeDensity_Deriv(ILayer[] layers, ref SpinResolved_Data charge_density_deriv, Band_Data chem_pot) { // interpolate the input charge density and chemical potential onto a reduced domain to simplify DFT solve SpinResolved_Data dft_dens_deriv = new SpinResolved_Data(nz); Get_ChargeDensity(layers, ref charge_density_deriv, chem_pot); Band_Data dft_pot = new Band_Data(new DoubleVector(nz)); Interpolate_DFT_Grid(ref dft_dens_deriv, ref dft_pot, charge_density_deriv, chem_pot); Get_Potential(ref dft_pot, layers); // // set dft_dens to zero so that the hamiltonian doesn't include the XC term // dft_dens = 0.0 * dft_dens; DoubleHermitianMatrix hamiltonian = Create_Hamiltonian(layers, dft_pot); DoubleHermitianEigDecomp eig_decomp = new DoubleHermitianEigDecomp(hamiltonian); 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; DoubleVector dens_up_deriv = new DoubleVector(nz, 0.0); DoubleVector dens_down_deriv = new DoubleVector(nz, 0.0); for (int j = 0; j < nz; j++) { double dens_val = 0.0; for (int i = 0; i < max_wavefunction; i++) { // 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 += dens_of_states.Integrate(min_eigval, no_kb_T * Physics_Base.kB * temperature); dens_val += DoubleComplex.Norm(eig_decomp.EigenVector(i)[j]) * DoubleComplex.Norm(eig_decomp.EigenVector(i)[j]) * Get_TwoD_DoS_Deriv(eig_decomp.EigenValue(i), no_kb_T);// *mass / (2.0 * Math.PI * Physics_Base.hbar * Physics_Base.hbar); } // just share the densities (there is no spin polarisation) dens_up_deriv[j] = 0.5 * dens_val; dens_down_deriv[j] = 0.5 * dens_val; } // 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 ) dft_dens_deriv = -1.0 * unit_charge * unit_charge * new SpinResolved_Data(new Band_Data(dens_up_deriv), new Band_Data(dens_down_deriv)); Insert_DFT_Charge(ref charge_density_deriv, dft_dens_deriv); }
/// <summary> /// returns an eigenvector decomposition for the xy-plane after having calculated the density in the /// z-direction and storing it in "charge_density" /// </summary> /// <param name="dft_pot"></param> /// <param name="charge_density"></param> /// <returns></returns> private double[,] Solve_Eigenvector_Problem(Band_Data dft_pot, ref SpinResolved_Data charge_density) { DoubleHermitianEigDecomp eig_decomp; double[,] xy_energy = new double[nx, ny]; Band_Data dens_up = new Band_Data(nx, ny, nz, 0.0); Band_Data dens_down = new Band_Data(nx, ny, nz, 0.0); // cycle over xy-plane calculating the ground state energy and eigenstate in the growth direction for (int i = 0; i < nx; i++) { for (int j = 0; j < ny; j++) { // pull out the chemical potential for this slice double[] z_dft_pot = new double[nz]; for (int k = 0; k < nz; k++) { z_dft_pot[k] = dft_pot.vol[k][i, j]; } // calculate its eigendecomposition DoubleHermitianMatrix h_z = Create_Hamiltonian(z_dft_pot, tz, nz); eig_decomp = new DoubleHermitianEigDecomp(h_z); // insert the eigenstate into density and record the local confinement energy xy_energy[i, j] = eig_decomp.EigenValue(0); for (int k = 0; k < nz; k++) { double dens_tot = DoubleComplex.Norm(eig_decomp.EigenVector(0)[k]) * DoubleComplex.Norm(eig_decomp.EigenVector(0)[k]); dens_up.vol[k][i, j] = 0.5 * dens_tot; dens_down.vol[k][i, j] = 0.5 * dens_tot; } } } // calculate the eigenstates in the xy-plane /*DoubleHermitianMatrix h_xy = Create_2DEG_Hamiltonian(xy_energy, tx, ty, nx, ny, true, false); * eig_decomp = new DoubleHermitianEigDecomp(h_xy); * energies = eig_decomp.EigenValues;*/ // put the calculated densities into charge_density charge_density = new SpinResolved_Data(dens_up, dens_down); return(xy_energy); }
/// <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 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; }
void Write_Out_Wavefunction_Densities(DoubleHermitianEigDecomp eig_decomp) { 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 k = 0; k < max_wavefunction; k++) { System.IO.StreamWriter sw = new System.IO.StreamWriter("dens_wavefunction_" + k.ToString("00")); DoubleMatrix tmp = new DoubleMatrix(nx, ny, 0.0); 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) { continue; } // 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 tmp[i, j] = unit_charge * 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); } } for (int i = 0; i < nx; i++) { for (int j = 0; j < ny; j++) { sw.Write(tmp[i, j].ToString() + '\t'); if (j == ny - 1) { sw.WriteLine(); } } } sw.Close(); } }
public override void Get_ChargeDensity(ILayer[] layers, ref SpinResolved_Data charge_density, Band_Data chem_pot) { // interpolate the input charge density and chemical potential onto a reduced domain to simplify DFT solve SpinResolved_Data dft_dens = new SpinResolved_Data(nz); Band_Data dft_pot = new Band_Data(new DoubleVector(nz)); Interpolate_DFT_Grid(ref dft_dens, ref dft_pot, charge_density, chem_pot); 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(); max_wavefunction = (from val in eig_decomp.EigenValues where val < no_kb_T * Physics_Base.kB * temperature select val).ToArray().Length; DoubleVector dens_up = new DoubleVector(nz, 0.0); DoubleVector dens_down = new DoubleVector(nz, 0.0); for (int j = 0; j < nz; j++) { double dens_val = 0.0; for (int i = 0; i < max_wavefunction; i++) { // 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 += dens_of_states.Integrate(min_eigval, no_kb_T * Physics_Base.kB * temperature); dens_val += DoubleComplex.Norm(eig_decomp.EigenVector(i)[j]) * DoubleComplex.Norm(eig_decomp.EigenVector(i)[j]) * Get_TwoD_DoS(eig_decomp.EigenValue(i), no_kb_T); } // just share the densities (there is no spin polarisation) dens_up[j] = 0.5 * dens_val; dens_down[j] = 0.5 * dens_val; } // and multiply the density by -e to get the charge density (as these are electrons) dft_dens = unit_charge * new SpinResolved_Data(new Band_Data(dens_up), new Band_Data(dens_down)); Insert_DFT_Charge(ref charge_density, dft_dens); }
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); }
void Write_Out_Wavefunction_Densities(DoubleHermitianEigDecomp eig_decomp) { 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 k = 0; k < max_wavefunction; k++) { System.IO.StreamWriter sw = new System.IO.StreamWriter("dens_wavefunction_" + k.ToString("00")); DoubleMatrix tmp = new DoubleMatrix(nx, ny, 0.0); 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) continue; // 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 tmp[i, j] = unit_charge * 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); } for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { sw.Write(tmp[i, j].ToString() + '\t'); if (j == ny - 1) sw.WriteLine(); } sw.Close(); } }
/// <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; }
void Output_Wavefunctions(DoubleHermitianEigDecomp eig, int no_wavefunctions) { for (int i = 0; i < no_wavefunctions; i++) { System.IO.StreamWriter sw = new System.IO.StreamWriter("wav_" + i.ToString("00")); for (int j = 0; j < nx; j++) sw.WriteLine((eig.EigenVector(i)[j].Real * Math.Sqrt(Get_OneD_DoS(eig.EigenValue(i), no_kb_T))).ToString()); sw.Close(); } }
SpinResolved_Data Calculate_Density_Derivative(DoubleHermitianEigDecomp eig_decomp_old, DoubleHermitianEigDecomp eig_decomp_new, int wavefunction) { DoubleMatrix dens_up_deriv = new DoubleMatrix(nx, ny, 0.0); DoubleMatrix dens_down_deriv = new DoubleMatrix(nx, ny, 0.0); 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) continue; // calculate the density of this spin configuration this hamiltonian dens_up_deriv[i, j] += g_1D * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j]) * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j]) * Interpolate_Fermi_Function_Derivative(eig_decomp_old, eig_decomp_new, wavefunction); dens_down_deriv[i, j] += g_1D * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j + nx * ny]) * DoubleComplex.Norm(eig_decomp_old.EigenVector(wavefunction)[i * ny + j + nx * ny]) * Interpolate_Fermi_Function_Derivative(eig_decomp_old, eig_decomp_new, wavefunction); } // and multiply the density by -e to get the charge density (as these are electrons) return unit_charge * unit_charge * new SpinResolved_Data(new Band_Data(dens_up_deriv), new Band_Data(dens_down_deriv)); }
/// <summary> /// returns an eigenvector decomposition for the xy-plane after having calculated the density in the /// z-direction and storing it in "charge_density" /// </summary> private double[,] Solve_Eigenvector_Problem(Band_Data dft_pot, ref SpinResolved_Data charge_density) { DoubleHermitianEigDecomp eig_decomp; double[,] xy_energy = new double[nx, ny]; Band_Data dens_up = new Band_Data(nx, ny, nz, 0.0); Band_Data dens_down = new Band_Data(nx, ny, nz, 0.0); // cycle over xy-plane calculating the ground state energy and eigenstate in the growth direction for (int i = 0; i < nx; i++) for (int j = 0; j < ny; j++) { // pull out the chemical potential for this slice double[] z_dft_pot = new double[nz]; for (int k = 0; k < nz; k++) z_dft_pot[k] = dft_pot.vol[k][i, j]; // calculate its eigendecomposition DoubleHermitianMatrix h_z = Create_Hamiltonian(z_dft_pot, tz, nz); eig_decomp = new DoubleHermitianEigDecomp(h_z); // insert the eigenstate into density and record the local confinement energy xy_energy[i, j] = eig_decomp.EigenValue(0); for (int k = 0; k < nz; k++) { double dens_tot = DoubleComplex.Norm(eig_decomp.EigenVector(0)[k]) * DoubleComplex.Norm(eig_decomp.EigenVector(0)[k]); dens_up.vol[k][i, j] = 0.5 * dens_tot; dens_down.vol[k][i, j] = 0.5 * dens_tot; } } // put the calculated densities into charge_density charge_density = new SpinResolved_Data(dens_up, dens_down); return xy_energy; }
/// <summary> /// returns an eigenvector decomposition for the x-direction after having calculated the density in the /// y-direction and storing it in "charge_density" /// </summary> /// <param name="dft_pot"></param> /// <param name="charge_density"></param> /// <returns></returns> private DoubleHermitianEigDecomp Solve_Eigenvector_Problem(Band_Data dft_pot, ref SpinResolved_Data charge_density) { DoubleHermitianEigDecomp eig_decomp; double[] x_energy = new double[nx]; DoubleMatrix dens_up = new DoubleMatrix(nx, ny, 0.0); DoubleMatrix dens_down = new DoubleMatrix(nx, ny, 0.0); // cycle over x-direction calculating the ground state energy and eigenstate in the y-direction for (int i = 0; i < nx; i++) { // pull out the chemical potential for this slice double[] y_dft_pot = new double[ny]; for (int j = 0; j < ny; j++) y_dft_pot[j] = dft_pot.mat[i, j]; // calculate its eigendecomposition DoubleHermitianMatrix h_y = Create_Hamiltonian(y_dft_pot, ty, ny); eig_decomp = new DoubleHermitianEigDecomp(h_y); // insert the eigenstate into density and record the local confinement energy x_energy[i] = eig_decomp.EigenValue(0); for (int j = 0; j < ny; j++) { double dens_tot = DoubleComplex.Norm(eig_decomp.EigenVector(0)[j]) * DoubleComplex.Norm(eig_decomp.EigenVector(0)[j]); dens_up[i, j] = 0.5 * dens_tot; dens_down[i, j] = 0.5 * dens_tot; } } // check whether to enforce symmetry in the transverse direction if (force_symmetry) for (int i = nx / 2 + 1; i < nx; i++) { x_energy[i] = x_energy[nx - i - 1]; for (int j = 0; j < ny; j++) { dens_up[i, j] = dens_up[nx - i - 1, j]; dens_down[i, j] = dens_down[nx - i - 1, j]; } } // calculate the eigenstates in the x-direction DoubleHermitianMatrix h_x = Create_Hamiltonian(x_energy, tx, nx); eig_decomp = new DoubleHermitianEigDecomp(h_x); energies = eig_decomp.EigenValues; // put the calculated densities into charge_density charge_density = new SpinResolved_Data(new Band_Data(dens_up), new Band_Data(dens_down)); return eig_decomp; }