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;
        }
Example #3
0
        /// <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;
        }
Example #4
0
        /// <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;
        }
Example #5
0
        /// <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;
        }
Example #6
0
        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;
        }
Example #7
0
        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;
        }