/// <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);
        }
Esempio n. 2
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;
        }
        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();
            }
        }
Esempio n. 4
0
        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)));
        }
Esempio n. 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 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);
        }
Esempio n. 7
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;
        }
        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;
        }
Esempio n. 9
0
        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();
            }
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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);
        }
Esempio n. 12
0
        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();
            }
        }
Esempio n. 13
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;
        }
        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();
            }
        }
Esempio n. 15
0
        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;
        }
Esempio n. 17
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 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);
        }
Esempio n. 18
0
        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);
        }
        /// <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;
        }