Exemplo n.º 1
0
        public override void Initialise(Dictionary <string, object> input_dict)
        {
            Console.WriteLine("Initialising Experiment");

            // simulation domain inputs
            Get_From_Dictionary <double>(input_dict, "dx", ref dx_dens); dx_pot = dx_dens;
            Get_From_Dictionary <double>(input_dict, "dy", ref dy_dens); dy_pot = dy_dens;
            Get_From_Dictionary <double>(input_dict, "dz", ref dz_dens); dz_pot = dz_dens;

            Get_From_Dictionary(input_dict, "nx", ref nx_dens); nx_pot = nx_dens;
            Get_From_Dictionary(input_dict, "ny", ref ny_dens); ny_pot = ny_dens;
            Get_From_Dictionary(input_dict, "nz", ref nz_dens); nz_pot = nz_dens;

            // physics parameters are done by the base method (the base will also try to get specific parameters detailed in the input files)
            base.Initialise(input_dict);

            // and initialise the data classes for density, its derivatives and the chemical potential
            Initialise_DataClasses(input_dict);

            // initialise the density solver
            dens_solv = Get_Density_Solver(input_dict);

            // initialise potential solver
            if (using_flexPDE)
            {
                pois_solv = new ThreeD_PoissonSolver(this, using_flexPDE, input_dict);
            }
            else if (using_dealii)
            {
                pois_solv = new ThreeD_dealII_Solver(this, using_dealii, input_dict);
            }
            else
            {
                throw new NotImplementedException("Error - Must use either FlexPDE or deal.II for 2D potential solver!");
            }

            device_dimensions.Add("interface_depth", Layers[1].Zmax);
            pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions);

            Console.WriteLine("Experimental parameters initialised");
        }
Exemplo n.º 2
0
        protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
        {
            // calculate initial potential with the given charge distribution
            Console.WriteLine("Calculating initial potential grid");
            pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions);

            if (chem_pot == null)
                chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data);
            Console.WriteLine("Initial grid complete");
            //    dens_solv.Set_DFT_Potential(carrier_charge_density);
            //    dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);
            //    dens_solv.Set_DFT_Potential(carrier_charge_density);

            dens_solv.Reset_DFT_Potential();
            dens_solv.Update_DFT_Potential(carrier_charge_density);

            int count = 0;
            t = 1.0;
            bool converged = false;
            while (!converged)
            {
                Band_Data dens_old = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data;

                // Get charge rho(phi)
                dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);

                // Generate charge-dependent part of the Jacobian, g'(phi) = -d(eps * d( )) - rho'(phi)
                SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot);

                // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi)
                // Calculate Laplacian operating on the given band energy, d(eps * d(phi))
                gphi = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data;
                gphi[0] = 0.0; gphi[gphi.Length - 1] = 0.0;
                x = pois_solv.Calculate_Newton_Step(rho_prime, gphi);

                // Calculate optimal damping parameter, t
                t = t_damp * Calculate_optimal_t(t / t_damp, (chem_pot / Physics_Base.q_e), x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min);

                // Check convergence
                Band_Data dens_spin_summed = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data;
                Band_Data dens_diff = dens_spin_summed - dens_old;
                double dens_abs_max = Math.Max(Math.Abs(dens_spin_summed.Max()), Math.Abs(dens_spin_summed.Min()));
                for (int i = 0; i < dens_diff.Length; i++)
                    // only calculate density difference for densities more than 1% of the maximum value
                    if (Math.Abs(dens_spin_summed[i]) > 0.01 * dens_abs_max)
                        dens_diff[i] = Math.Abs(dens_diff[i] / dens_spin_summed[i]);
                    else
                        dens_diff[i] = 0.0;

                // Update the DFT potential
                dens_solv.Update_DFT_Potential(carrier_charge_density);

                double[] diff = new double[Nz_Pot];
                for (int j = 0; j < nz_pot; j++)
                    diff[j] = Math.Abs(gphi.vec[j]);
                double convergence = diff.Sum();
                if (Physics_Base.q_e * x.InfinityNorm() < tol)
                    converged = true;

                // update band energy phi_new = phi_old + t * x
                Console.WriteLine(Generate_Output_String(count, x, dens_diff));
                chem_pot = chem_pot + t * Physics_Base.q_e * x;
                count++;

                base.Checkpoint();
                // reset the potential if the added potential t * x is too small
                if (converged || count > max_iterations)
                {
                     Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString() + "meV");
                    break;
                }
            }

            Console.WriteLine("Iteration complete");

            return converged;
        }
Exemplo n.º 3
0
        protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
        {
            dens_solv.Reset_DFT_Potential();
            dens_solv.Update_DFT_Potential(carrier_charge_density);

            int  count     = 0;
            bool converged = false;

            if (!no_dft)
            {
                dens_solv.DFT_Mixing_Parameter = 0.1;
            }
            dens_diff_lim = 0.12;


            while (!converged)
            {
                Stopwatch stpwch = new Stopwatch();
                stpwch.Start();

                // save old density data
                Band_Data dens_old = carrier_charge_density.Spin_Summed_Data.DeepenThisCopy();

                // Get charge rho(phi) (not dopents as these are included as a flexPDE input)
                dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);
                Set_Edges(carrier_charge_density);

                // Generate an approximate charge-dependent part of the Jacobian, g'(phi) = - d(eps * d( )) - rho'(phi) using the Thomas-Fermi semi-classical method
                SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot);
                Set_Edges(rho_prime);

                // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi)
                gphi = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data;
                Set_Edges(gphi);
                x = pois_solv.Calculate_Newton_Step(rho_prime, gphi, carrier_charge_density, dens_solv.DFT_Potential, dens_solv.Get_XC_Potential(carrier_charge_density));
                // chem_pot = pois_solv.Chemical_Potential;

                // Calculate optimal damping parameter, t, (but damped damping....)
                if (t == 0.0)
                {
                    t = t_min;
                }

                t = t_damp * Calculate_optimal_t(t / t_damp, chem_pot / Physics_Base.q_e, x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min);
                if (t < 0.0)
                {
                    Console.WriteLine("Iterator has stalled, setting t = 0");
                    t = 0.0;
                }

                // and check convergence of density
                Band_Data dens_diff            = carrier_charge_density.Spin_Summed_Data - dens_old;
                Band_Data car_dens_spin_summed = carrier_charge_density.Spin_Summed_Data;
                double    carrier_dens_abs_max = Math.Max(Math.Abs(car_dens_spin_summed.Min()), Math.Abs(car_dens_spin_summed.Max()));
                // using the relative absolute density difference
                for (int i = 0; i < dens_diff.Length; i++)
                {
                    // only calculate density difference for densities more than 1% of the maximum value
                    if (Math.Abs(car_dens_spin_summed[i]) > 0.01 * carrier_dens_abs_max)
                    {
                        dens_diff[i] = Math.Abs(dens_diff[i] / car_dens_spin_summed[i]);
                    }
                    else
                    {
                        dens_diff[i] = 0.0;
                    }
                }

                // only renew DFT potential when the difference in density has converged and the iterator has done at least 3 iterations
                if (dens_diff.Max() < dens_diff_lim && t > 10.0 * t_min && count > 3)
                {
                    // and set the DFT potential
                    if (dens_solv.DFT_Mixing_Parameter != 0.0)
                    {
                        dens_solv.Print_DFT_diff(carrier_charge_density);
                    }
                    dens_solv.Update_DFT_Potential(carrier_charge_density);

                    // also... if the difference in the old and new dft potentials is greater than for the previous V_xc update, reduce the dft mixing parameter
                    double current_vxc_diff = Math.Max(dens_solv.DFT_diff(carrier_charge_density).Max(), (-1.0 * dens_solv.DFT_diff(carrier_charge_density).Min()));
                    if (current_vxc_diff > max_vxc_diff && dens_diff_lim / 2.0 > min_dens_diff || no_dft)
                    {
                        dens_diff_lim /= 2.0;
                        Console.WriteLine("Minimum percentage density difference reduced to " + dens_diff_lim.ToString());
                    }
                    max_vxc_diff = current_vxc_diff;

                    // solution is converged if the density accuracy is better than half the minimum possible value for changing the dft potential
                    if (dens_diff.Max() < min_dens_diff / 2.0 && current_vxc_diff < min_vxc_diff && Physics_Base.q_e * x.InfinityNorm() < tol && t != t_min)
                    {
                        converged = true;
                    }
                }

                // update t for Poisson solver
                pois_solv.T = t;
                chem_pot    = chem_pot + t * Physics_Base.q_e * x;

                base.Checkpoint();

                if (count == 0)
                {
                    pot_init = Physics_Base.q_e * x.InfinityNorm();
                }

                stpwch.Stop();
                Console.WriteLine("Iter = " + count.ToString() + "\tDens = " + dens_diff.Max().ToString("F4") + "\tPot = " + (Physics_Base.q_e * x.InfinityNorm()).ToString("F6") + "\tt = " + t.ToString("F5") + "\ttime = " + stpwch.Elapsed.TotalMinutes.ToString("F"));
                count++;

                //    File.Copy("split_gate.pg6", "split_gate_" + count.ToString("000") + ".pg6");

                // reset the potential if the added potential t * x is too small
                if (converged || count > max_iterations)
                {
                    Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString());
                    break;
                }
            }

            Console.WriteLine("Iteration complete");
            return(converged);
        }
Exemplo n.º 4
0
        protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
        {
            dens_solv.Reset_DFT_Potential();
            dens_solv.Update_DFT_Potential(carrier_charge_density);

            int count = 0;
            bool converged = false;
            if (!no_dft)
                dens_solv.DFT_Mixing_Parameter = 0.1;
            dens_diff_lim = 0.12;

            while (!converged)
            {
                Stopwatch stpwch = new Stopwatch();
                stpwch.Start();

                // save old density data
                Band_Data dens_old = carrier_charge_density.Spin_Summed_Data.DeepenThisCopy();

                // Get charge rho(phi) (not dopents as these are included as a flexPDE input)
                dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);
                Set_Edges(carrier_charge_density);

                // Generate an approximate charge-dependent part of the Jacobian, g'(phi) = - d(eps * d( )) - rho'(phi) using the Thomas-Fermi semi-classical method
                SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot);
                Set_Edges(rho_prime);

                // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi)
                gphi = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data;
                Set_Edges(gphi);
                x = pois_solv.Calculate_Newton_Step(rho_prime, gphi, carrier_charge_density, dens_solv.DFT_Potential, dens_solv.Get_XC_Potential(carrier_charge_density));
               // chem_pot = pois_solv.Chemical_Potential;

                // Calculate optimal damping parameter, t, (but damped damping....)
                if (t == 0.0)
                    t = t_min;

                t = t_damp * Calculate_optimal_t(t / t_damp, chem_pot / Physics_Base.q_e, x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min);
                if (t < 0.0)
                {
                    Console.WriteLine("Iterator has stalled, setting t = 0");
                    t = 0.0;
                }

                // and check convergence of density
                Band_Data dens_diff = carrier_charge_density.Spin_Summed_Data - dens_old;
                Band_Data car_dens_spin_summed = carrier_charge_density.Spin_Summed_Data;
                double carrier_dens_abs_max = Math.Max(Math.Abs(car_dens_spin_summed.Min()), Math.Abs(car_dens_spin_summed.Max()));
                // using the relative absolute density difference
                for (int i = 0; i < dens_diff.Length; i++)
                    // only calculate density difference for densities more than 1% of the maximum value
                    if (Math.Abs(car_dens_spin_summed[i]) > 0.01 * carrier_dens_abs_max)
                        dens_diff[i] = Math.Abs(dens_diff[i] / car_dens_spin_summed[i]);
                    else
                        dens_diff[i] = 0.0;

                // only renew DFT potential when the difference in density has converged and the iterator has done at least 3 iterations
                if (dens_diff.Max() < dens_diff_lim && t > 10.0 * t_min && count > 3)
                {
                    // and set the DFT potential
                    if (dens_solv.DFT_Mixing_Parameter != 0.0)
                        dens_solv.Print_DFT_diff(carrier_charge_density);
                    dens_solv.Update_DFT_Potential(carrier_charge_density);

                    // also... if the difference in the old and new dft potentials is greater than for the previous V_xc update, reduce the dft mixing parameter
                    double current_vxc_diff = Math.Max(dens_solv.DFT_diff(carrier_charge_density).Max(), (-1.0 * dens_solv.DFT_diff(carrier_charge_density).Min()));
                    if (current_vxc_diff > max_vxc_diff && dens_diff_lim / 2.0 > min_dens_diff || no_dft)
                    {
                        dens_diff_lim /= 2.0;
                        Console.WriteLine("Minimum percentage density difference reduced to " + dens_diff_lim.ToString());
                    }
                    max_vxc_diff = current_vxc_diff;

                    // solution is converged if the density accuracy is better than half the minimum possible value for changing the dft potential
                    if (dens_diff.Max() < min_dens_diff / 2.0 && current_vxc_diff < min_vxc_diff &&  Physics_Base.q_e * x.InfinityNorm() < tol && t != t_min)
                        converged = true;
                }

                // update t for Poisson solver
                pois_solv.T = t;
                chem_pot = chem_pot + t * Physics_Base.q_e * x;

                base.Checkpoint();

                if (count == 0)
                    pot_init = Physics_Base.q_e * x.InfinityNorm();

                stpwch.Stop();
                Console.WriteLine("Iter = " + count.ToString() + "\tDens = " + dens_diff.Max().ToString("F4") + "\tPot = " + (Physics_Base.q_e * x.InfinityNorm()).ToString("F6") + "\tt = " + t.ToString("F5") + "\ttime = " + stpwch.Elapsed.TotalMinutes.ToString("F"));
                count++;

            //    File.Copy("split_gate.pg6", "split_gate_" + count.ToString("000") + ".pg6");

                // reset the potential if the added potential t * x is too small
                if (converged || count > max_iterations)
                {
                    Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString());
                    break;
                }
            }

            Console.WriteLine("Iteration complete");
            return converged;
        }
Exemplo n.º 5
0
        public override void Initialise(Dictionary<string, object> input_dict)
        {
            Console.WriteLine("Initialising Experiment");

            // simulation domain inputs
            Get_From_Dictionary<double>(input_dict, "dx", ref dx_dens); dx_pot = dx_dens;
            Get_From_Dictionary<double>(input_dict, "dy", ref dy_dens); dy_pot = dy_dens;
            Get_From_Dictionary<double>(input_dict, "dz", ref dz_dens); dz_pot = dz_dens;

            Get_From_Dictionary(input_dict, "nx", ref nx_dens); nx_pot = nx_dens;
            Get_From_Dictionary(input_dict, "ny", ref ny_dens); ny_pot = ny_dens;
            Get_From_Dictionary(input_dict, "nz", ref nz_dens); nz_pot = nz_dens;

            // physics parameters are done by the base method (the base will also try to get specific parameters detailed in the input files)
            base.Initialise(input_dict);

            // and initialise the data classes for density, its derivatives and the chemical potential
            Initialise_DataClasses(input_dict);

            // initialise the density solver
            dens_solv = Get_Density_Solver(input_dict);

            // initialise potential solver
            if (using_flexPDE)
                pois_solv = new ThreeD_PoissonSolver(this, using_flexPDE, input_dict);
            else if (using_dealii)
                pois_solv = new ThreeD_dealII_Solver(this, using_dealii, input_dict);
            else
                throw new NotImplementedException("Error - Must use either FlexPDE or deal.II for 2D potential solver!");

            device_dimensions.Add("interface_depth", Layers[1].Zmax);
            pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions);

            Console.WriteLine("Experimental parameters initialised");
        }
Exemplo n.º 6
0
        void Print_VP(Band_Data band_energy, Band_Data x, SpinResolved_Data car_dens, SpinResolved_Data dop_dens, IPoisson_Solve pois_solv, IDensity_Solve dens_solv)
        {
            StreamWriter sw        = new StreamWriter("vp");
            int          count_max = 100;
            double       dt        = 0.01;

            for (int i = 0; i < count_max; i++)
            {
                sw.WriteLine(calc_vp(i * dt, band_energy, x, car_dens, dop_dens, pois_solv, dens_solv).ToString());
            }

            sw.Close();
        }
Exemplo n.º 7
0
        protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
        {
            // calculate initial potential with the given charge distribution
            Console.WriteLine("Calculating initial potential grid");
            pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions);

            if (chem_pot == null)
            {
                chem_pot = Physics_Base.q_e * pois_solv.Get_Potential(carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data);
            }
            Console.WriteLine("Initial grid complete");
            //    dens_solv.Set_DFT_Potential(carrier_charge_density);
            //    dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);
            //    dens_solv.Set_DFT_Potential(carrier_charge_density);

            dens_solv.Reset_DFT_Potential();
            dens_solv.Update_DFT_Potential(carrier_charge_density);

            int count = 0;

            t = 1.0;
            bool converged = false;

            while (!converged)
            {
                Band_Data dens_old = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data;

                // Get charge rho(phi)
                dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);

                // Generate charge-dependent part of the Jacobian, g'(phi) = -d(eps * d( )) - rho'(phi)
                SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot);

                // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi)
                // Calculate Laplacian operating on the given band energy, d(eps * d(phi))
                gphi    = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data;
                gphi[0] = 0.0; gphi[gphi.Length - 1] = 0.0;
                x       = pois_solv.Calculate_Newton_Step(rho_prime, gphi);

                // Calculate optimal damping parameter, t
                t = t_damp * Calculate_optimal_t(t / t_damp, (chem_pot / Physics_Base.q_e), x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min);

                // Check convergence
                Band_Data dens_spin_summed = carrier_charge_density.Spin_Summed_Data + dopent_charge_density.Spin_Summed_Data;
                Band_Data dens_diff        = dens_spin_summed - dens_old;
                double    dens_abs_max     = Math.Max(Math.Abs(dens_spin_summed.Max()), Math.Abs(dens_spin_summed.Min()));
                for (int i = 0; i < dens_diff.Length; i++)
                {
                    // only calculate density difference for densities more than 1% of the maximum value
                    if (Math.Abs(dens_spin_summed[i]) > 0.01 * dens_abs_max)
                    {
                        dens_diff[i] = Math.Abs(dens_diff[i] / dens_spin_summed[i]);
                    }
                    else
                    {
                        dens_diff[i] = 0.0;
                    }
                }

                // Update the DFT potential
                dens_solv.Update_DFT_Potential(carrier_charge_density);

                double[] diff = new double[Nz_Pot];
                for (int j = 0; j < nz_pot; j++)
                {
                    diff[j] = Math.Abs(gphi.vec[j]);
                }
                double convergence = diff.Sum();
                if (Physics_Base.q_e * x.InfinityNorm() < tol)
                {
                    converged = true;
                }

                // update band energy phi_new = phi_old + t * x
                Console.WriteLine(Generate_Output_String(count, x, dens_diff));
                chem_pot = chem_pot + t * Physics_Base.q_e * x;
                count++;

                base.Checkpoint();
                // reset the potential if the added potential t * x is too small
                if (converged || count > max_iterations)
                {
                    Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString() + "meV");
                    break;
                }
            }

            Console.WriteLine("Iteration complete");

            return(converged);
        }
Exemplo n.º 8
0
        /// <summary>
        /// calculates an optimal t based on bisection
        /// </summary>
        /// <param name="t"></param>
        /// <param name="phi"></param>
        /// <param name="x"></param>
        /// <param name="car_dens"></param>
        /// <param name="dop_dens"></param>
        /// <param name="pois_solv"></param>
        /// <param name="dens_solv"></param>
        /// <returns></returns>
        protected double Calculate_optimal_t(double t, Band_Data phi, Band_Data x, SpinResolved_Data car_dens, SpinResolved_Data dop_dens, IPoisson_Solve pois_solv, IDensity_Solve dens_solv, double minval)
        {
            double            maxval        = 3.0;
            SpinResolved_Data car_dens_copy = car_dens.DeepenThisCopy();
            SpinResolved_Data dop_dens_copy = dop_dens.DeepenThisCopy();

            double vpa    = calc_vp(t, phi, x, car_dens_copy, dop_dens_copy, pois_solv, dens_solv);
            double vpb    = calc_vp(div_fact * t, phi, x, car_dens_copy, dop_dens_copy, pois_solv, dens_solv);
            double t_orig = t;

            // work out whether this is going in the right direction (assuming vp is monotonic)
            if (Math.Abs(vpb) < Math.Abs(vpa))
            {
                // if 0.5 * t was going downhill, first, halve t seeing as you've already done this step
                t = div_fact * t;
                // then halve the damping parameter and check whether you've found a root yet
                while (Math.Sign(vpb) == Math.Sign(vpa))
                {
                    t = div_fact * t;
                    if (t < minval)
                    {
                        if (Math.Sign(calc_vp(1.0, phi, x, car_dens_copy, dop_dens_copy, pois_solv, dens_solv)) == Math.Sign(vpb))
                        {
                            return(0.5);
                        }
                        //return 1.0 / div_fact;
                        else
                        {
                            return(Calculate_optimal_t(1.0, phi, x, car_dens_copy, dop_dens_copy, pois_solv, dens_solv, minval));
                        }
                    }


                    vpa = vpb;
                    vpb = calc_vp(t, phi, x, car_dens_copy, dop_dens_copy, pois_solv, dens_solv);
                }

                //return 0.5 * (1.0 + (1.0 / div_fact)) * t;
                return(t - t * (1.0 - 1.0 / div_fact) * vpb / (vpa - vpb));
            }
            else
            {
                // if 0.5 * t was going uphill, then we need to be doubling t and looking for the root
                while (Math.Sign(vpb) == Math.Sign(vpa))
                {
                    t = (1.0 / div_fact) * t;
                    if (t > maxval)
                    {
                        return(maxval);
                    }

                    vpa = vpb;
                    vpb = calc_vp(t, phi, x, car_dens_copy, dop_dens_copy, pois_solv, dens_solv);
                }

                //return 0.5 * (1.0 + div_fact) * t;
                return(t - t * (1.0 - div_fact) * vpb / (vpb - vpa));
            }
        }
Exemplo n.º 9
0
        protected virtual double calc_vp(double t, Band_Data phi, Band_Data x, SpinResolved_Data car_dens, SpinResolved_Data dop_dens, IPoisson_Solve pois_solv, IDensity_Solve dens_solv)
        {
            double vp;

            SpinResolved_Data tmp_dens = dens_solv.Get_ChargeDensity(layers, car_dens, dop_dens, Physics_Base.q_e * (phi + t * x));
            Band_Data         V_Prime  = -1.0 * (phi.Laplacian + t * x.Laplacian) - tmp_dens.Spin_Summed_Data;

            vp = 0.0;
            for (int i = 0; i < x.Length; i++)
            {
                vp += V_Prime[i] * x[i];
            }

            // multiply by volume element (this works in all dimensions as default dx, dy, dz are 1.0)
            return(vp * dx_dens * dy_dens * dz_dens);
        }
Exemplo n.º 10
0
 protected abstract bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations);
Exemplo n.º 11
0
 protected bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol)
 {
     return(Run_Iteration_Routine(dens_solv, pois_solv, tol, int.MaxValue));
 }
Exemplo n.º 12
0
        protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
        {
            // calculate initial potential with the given charge distribution
            //    Console.WriteLine("Calculating initial potential grid");
            //     pois_solv.Initiate_Poisson_Solver(device_dimensions, boundary_conditions);
            //    chem_pot = pois_solv.Get_Chemical_Potential(carrier_density.Spin_Summed_Data);
            //    Console.WriteLine("Initial grid complete");
            //dens_solv.Set_DFT_Potential(carrier_charge_density);
            //if (!no_dft)
            //{
            //   dens_solv.DFT_Mixing_Parameter = 0.3;
            //dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);
            //}
            dens_solv.Reset_DFT_Potential();
            dens_solv.Update_DFT_Potential(carrier_charge_density);

            int    count         = 0;
            bool   converged     = false;
            double dens_diff_lim = 0.1;             // the maximum percentage change in the density required for update of V_xc
            double max_vxc_diff  = double.MaxValue; // maximum difference for dft potential... if this increases, the dft mixing parameter is reduced

            while (!converged)
            {
                Stopwatch stpwch = new Stopwatch();
                stpwch.Start();

                // save old density data
                Band_Data dens_old = carrier_charge_density.Spin_Summed_Data.DeepenThisCopy();

                // Get charge rho(phi) (not dopents as these are included as a flexPDE input)
                dens_solv.Get_ChargeDensity(layers, ref carrier_charge_density, ref dopent_charge_density, chem_pot);

                // Generate an approximate charge-dependent part of the Jacobian, g'(phi) = - d(eps * d( )) - rho'(phi) using the Thomas-Fermi semi-classical method
                SpinResolved_Data rho_prime = dens_solv.Get_ChargeDensity_Deriv(layers, carrier_charge_density_deriv, dopent_charge_density_deriv, chem_pot);

                // Solve stepping equation to find raw Newton iteration step, g'(phi) x = - g(phi)
                gphi = -1.0 * chem_pot.Laplacian / Physics_Base.q_e - carrier_charge_density.Spin_Summed_Data - dopent_charge_density.Spin_Summed_Data;
                x    = pois_solv.Calculate_Newton_Step(rho_prime, gphi, carrier_charge_density, dens_solv.DFT_Potential, dens_solv.Get_XC_Potential(carrier_charge_density));
                //chem_pot = pois_solv.Chemical_Potential;

                // Calculate optimal damping parameter, t, (but damped damping....)
                if (t == 0.0)
                {
                    t = t_min;
                }

                t = t_damp * Calculate_optimal_t(t / t_damp, chem_pot / Physics_Base.q_e, x, carrier_charge_density, dopent_charge_density, pois_solv, dens_solv, t_min);
                //             if (count % 5 == 0 && t == t_damp * t_min)
                //             {
                //                 t_min *= 2.0;
                //                 Console.WriteLine("Iterator has stalled, doubling t_min to " + t_min.ToString());
                //             }

                // and check convergence of density
                Band_Data car_dens_spin_summed = carrier_charge_density.Spin_Summed_Data;
                Band_Data dens_diff            = car_dens_spin_summed - dens_old;
                double    carrier_dens_abs_max = Math.Max(Math.Abs(car_dens_spin_summed.Min()), Math.Abs(car_dens_spin_summed.Max()));
                // using the relative absolute density difference
                for (int i = 0; i < dens_diff.Length; i++)
                {
                    // only calculate density difference for densities more than 1% of the maximum value
                    if (Math.Abs(car_dens_spin_summed[i]) > 0.01 * carrier_dens_abs_max)
                    {
                        dens_diff[i] = Math.Abs(dens_diff[i] / car_dens_spin_summed[i]);
                    }
                    else
                    {
                        dens_diff[i] = 0.0;
                    }
                }

                //if (Math.Max(t * x.Max(), (-t * x).Max()) < pot_lim && t > 10.0 * t_min)

                // only renew DFT potential when the difference in density has converged and the iterator has done at least 3 iterations
                if (dens_diff.Max() < dens_diff_lim && t > 10.0 * t_min && count > 3)
                {
                    // once dft potential is starting to be mixed in, set the maximum count to lots
//                    max_count = 1000;

                    // and set the DFT potential
                    dens_solv.Update_DFT_Potential(carrier_charge_density);

                    // also... if the difference in the old and new dft potentials is greater than for the previous V_xc update, reduce the dft mixing parameter
                    double current_vxc_diff = Math.Max(dens_solv.DFT_diff(carrier_charge_density).Max(), (-1.0 * dens_solv.DFT_diff(carrier_charge_density).Min()));
                    //      if (current_dens_diff > max_diff && dens_solv.DFT_Mixing_Parameter / 3.0 > min_alpha)
                    //      {
                    //          dens_solv.DFT_Mixing_Parameter /= 3.0;      // alpha is only incremented if it will be above the value of min_alpha
                    //          dens_diff_lim /= 3.0;
                    //          Console.WriteLine("DFT mixing parameter reduced to " + dens_solv.DFT_Mixing_Parameter.ToString());
                    //      }
                    if (current_vxc_diff > max_vxc_diff && !no_dft)
                    {
                        dens_diff_lim /= 2.0;
                        //dens_solv.Print_DFT_diff(carrier_charge_density);
                        Console.WriteLine("Minimum percentage density difference reduced to " + dens_diff_lim.ToString());
                    }
                    max_vxc_diff = current_vxc_diff;

                    // if (alpha_dft <= 0.1)
                    // {
                    //     alpha_dft += 0.01;
                    //     Console.WriteLine("Setting DFT mixing parameter to " + alpha_dft.ToString());
                    //     dens_solv.Set_DFT_Mixing_Parameter(alpha_dft);
                    // }

                    //   if (Math.Max(dens_solv.DFT_diff(carrier_density).Max(), (-1.0 * dens_solv.DFT_diff(carrier_density).Min())) < pot_lim)
                    //       converged = true;

                    // solution is converged if the density accuracy is better than half the minimum possible value for changing the dft potential
                    // also, check that the maximum change in the absolute value of the potential is less than a tolerance (default is 0.1meV)
                    if (dens_solv.DFT_diff(carrier_charge_density).InfinityNorm() < tol && Physics_Base.q_e * x.InfinityNorm() < tol)
                    {
                        converged = true;
                    }
                }

                /*
                 * // Recalculate the charge density but for the updated potential rho(phi + t * x)
                 * bool edges_fine = false;
                 * while (!edges_fine)
                 * {
                 *  edges_fine = true;
                 *  SpinResolved_Data tmp_dens = dens_solv.Get_ChargeDensity(layers, carrier_density, dopent_density, chem_pot + t * x);
                 *  for (int i = 1; i < ny_dens - 1; i++)
                 *      for (int j = 1; j < nz_dens - 1; j++)
                 *          //if (i == 1 || j == 1 || i == ny_dens - 2 || j == nz_dens - 2)
                 *          if (i == 1 || i == ny_dens - 2)
                 *              if (Math.Abs(tmp_dens.Spin_Summed_Data.mat[i, j]) > edge_min_charge)
                 *              {
                 *                  if (x.mat.Max() > 0)
                 *                      t = 0.5 * t;
                 *                  else
                 *                      t = 2.0 * t;
                 *
                 *                  if (t > t_min)
                 *                  {
                 *                      edges_fine = false;
                 *                      goto end;
                 *                  }
                 *                  else
                 *                  {
                 *                      // although the edges are not fine at this point, we don't want the code to decrease t any further so we
                 *                      // break the loop by setting...
                 *                      edges_fine = true;
                 *                      goto end;
                 *                  }
                 *              }
                 *
                 *  if (!edges_fine)
                 *      throw new Exception("Error - Unable to reduce density to zero at edge of density domain.\nSimulation aborted");
                 *
                 *  end:
                 *  //if (t < t_damp * t_min)
                 *  //{
                 *  //    Console.WriteLine("Unable to reduce density to zero at edge of density domain\nRecalculating potential");
                 *  //    pois_solv.Set_Boundary_Conditions(top_V, split_V, split_width, bottom_V, surface_charge);
                 *  //    chem_pot = pois_solv.Get_Chemical_Potential(carrier_density.Spin_Summed_Data);
                 *  //    dens_solv.Get_ChargeDensity(layers, ref carrier_density, ref dopent_density, chem_pot);
                 *  //    Console.WriteLine("Potential recalculated");
                 *  //    edges_fine = true;
                 *  //}
                 *  //else
                 *      continue;
                 * }*/

                // update band energy phi_new = phi_old + t * x
                pois_solv.T = t;
                chem_pot    = chem_pot + t * Physics_Base.q_e * x;

                //// and set the DFT potential
                //if (count % 10 == 0)
                //    dens_solv.Print_DFT_diff(carrier_density);
                //dens_solv.Set_DFT_Potential(carrier_density);

                base.Checkpoint();

                if (count == 0)
                {
                    pot_init = Physics_Base.q_e * x.InfinityNorm();
                }

                stpwch.Stop();
                Console.WriteLine(Generate_Output_String(count, x, dens_diff) + "\ttime = " + stpwch.Elapsed.TotalMinutes.ToString("F"));
                if (dens_solv.DFT_Mixing_Parameter != 0.0 && dens_diff.Max() < dens_diff_lim && count > 3)
                {
                    dens_solv.Print_DFT_diff(carrier_charge_density);
                }
                count++;

                // reset the potential if the added potential t * x is too small

                if (converged || count > max_iterations)
                {
                    Console.WriteLine("Maximum potential change at end of iteration was " + (t * Physics_Base.q_e * x.InfinityNorm()).ToString());
                    break;
                }
            }

            Console.WriteLine("Iteration complete");
            return(converged);
        }
Exemplo n.º 13
0
 protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
 {
     throw new NotImplementedException();
 }
Exemplo n.º 14
0
 protected override bool Run_Iteration_Routine(IDensity_Solve dens_solv, IPoisson_Solve pois_solv, double tol, int max_iterations)
 {
     throw new NotImplementedException();
 }