예제 #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");
        }
예제 #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;
        }
예제 #3
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);
        }