public void SolveAC(double appliedVoltage, double dV, double freq, double T)
        {
            BracketAC(appliedVoltage, dV, freq, T, out double hi, out double lo);

            double tol = Tolerance;
            double x0  = CalcX0();
            double V   = BuiltInVoltage + appliedVoltage + dV;

            while (Math.Abs(PhiAC[NumPointsPosition - 1] / Consts.ElementaryCharge - V) > tol)
            {
                PhiAC[0] = 0.5 * (hi + lo);
                PhiAC[1] = PhiAC[0] * Math.Exp(PositionSpacing / x0);
                RhoAC[0] = RhoTable.GetRho(FermiAC[0] - PhiAC[0], 0);
                RhoAC[1] = RhoTable.GetRho(FermiAC[1] - PhiAC[1], 1);

                CalculateProfileAC(0, freq, T);

                if (PhiAC[NumPointsPosition - 1] / Consts.ElementaryCharge > V)
                {
                    hi = PhiAC[0];
                }
                else
                {
                    lo = PhiAC[0];
                }
            }
        }
        private void CalculateProfileDC(int startIndex)
        {
            TotalChargeDC = 0;

            for (int i = startIndex + 1; i < NumPointsPosition - 1; i++)
            {
                PhiDC[i + 1] = 2 * PhiDC[i] - PhiDC[i - 1]
                               + PositionSpacing * PositionSpacing
                               * Consts.ElementaryCharge * RhoDC[i] / DielectricConstant;

                FermiDC[i + 1] = FermiLevel;

                //if (PhiDC[i + 1] - FermiDC[i + 1] > BandGap / 2)
                //{
                //    FermiDC[i + 1] = PhiDC[i + 1] - BandGap / 2;
                //}

                RhoDC[i + 1] = RhoTable.GetRho(FermiDC[i + 1] - PhiDC[i + 1], i + 1);

                PhiDC[i + 1] = NoumerovStep(
                    PhiDC[i], PhiDC[i - 1],
                    Consts.ElementaryCharge * RhoDC[i + 1] / DielectricConstant,
                    Consts.ElementaryCharge * RhoDC[i] / DielectricConstant,
                    Consts.ElementaryCharge * RhoDC[i - 1] / DielectricConstant,
                    PositionSpacing);

                TotalChargeDC += 0.5 * (RhoDC[i] + RhoDC[i - 1]) * PositionSpacing;
            }
        }
        public Device(
            double bandGap,
            double fermiLevel,
            double thickness,
            double builtInVoltage,
            double dielectricConstant,
            double thermalEmissionPrefactor,
            List <Defect> defects,
            int numPointsPosition,
            int numPointsEnergy,
            double tolerance)
        {
            BandGap                  = bandGap;
            FermiLevel               = fermiLevel;
            Thickness                = thickness;
            BuiltInVoltage           = builtInVoltage;
            DielectricConstant       = dielectricConstant;
            ThermalEmissionPrefactor = thermalEmissionPrefactor;
            Defects                  = defects;
            NumPointsPosition        = numPointsPosition;
            NumPointsEnergy          = numPointsEnergy;
            Tolerance                = tolerance;

            EnergySpacing   = 2 * BandGap / NumPointsEnergy;
            PositionSpacing = Thickness / NumPointsPosition;

            FermiDC = new double[NumPointsPosition];
            PhiDC   = new double[NumPointsPosition];
            RhoDC   = new double[NumPointsPosition];

            FermiAC = new double[NumPointsPosition];
            PhiAC   = new double[NumPointsPosition];
            RhoAC   = new double[NumPointsPosition];

            for (int i = 0; i < NumPointsPosition; i++)
            {
                FermiDC[i] = FermiLevel;
                FermiAC[i] = FermiLevel;
            }

            DensityOfStates = new DensityOfStates(this);

            RhoTable = new RhoTable(this);
        }
        private void CalculateProfileAC(int startIndex, double freq, double T)
        {
            double Ee = CalcEe(freq, T);

            TotalChargeAC = 0;

            for (int i = startIndex + 1; i < NumPointsPosition - 1; i++)
            {
                PhiAC[i + 1] = 2 * PhiAC[i] - PhiAC[i - 1]
                               + PositionSpacing * PositionSpacing * Consts.ElementaryCharge * RhoAC[i] / DielectricConstant;

                FermiAC[i + 1] = FermiLevel;

                //if (PhiAC[i + 1] - FermiAC[i + 1] > BandGap / 2)
                //{
                //    FermiAC[i + 1] = PhiAC[i + 1] - BandGap / 2;
                //}

                if (PhiAC[i + 1] < FermiAC[i + 1] + Ee)
                {
                    RhoAC[i + 1] = RhoTable.GetRho(FermiAC[i + 1] - PhiAC[i + 1], i + 1);
                }
                else if (PhiDC[i + 1] < FermiAC[i + 1] + Ee)
                {
                    RhoAC[i + 1] = RhoTable.GetRho(-Ee, i + 1);
                }
                else
                {
                    RhoAC[i + 1] = RhoDC[i + 1];
                }

                PhiAC[i + 1] = NoumerovStep(
                    PhiAC[i], PhiAC[i - 1],
                    Consts.ElementaryCharge * RhoAC[i + 1] / DielectricConstant,
                    Consts.ElementaryCharge * RhoAC[i] / DielectricConstant,
                    Consts.ElementaryCharge * RhoAC[i - 1] / DielectricConstant,
                    PositionSpacing);

                TotalChargeAC += 0.5 * (RhoAC[i] + RhoAC[i - 1]) * PositionSpacing;
            }
        }
        private void BracketAC(double appliedVoltage, double dV, double freq, double T, out double hi, out double lo)
        {
            double x0        = CalcX0();
            double V         = BuiltInVoltage + appliedVoltage + dV;
            int    numPoints = NumPointsPosition;

            PhiAC[0] = Consts.ElementaryCharge * V * Math.Exp(-Thickness / x0);
            PhiAC[1] = PhiAC[0] * Math.Exp(PositionSpacing / x0);
            RhoAC[0] = RhoTable.GetRho(FermiAC[0] - PhiAC[0], 0);
            RhoAC[1] = RhoTable.GetRho(FermiAC[1] - PhiAC[1], 1);
            CalculateProfileAC(0, freq, T);

            hi = 0;
            lo = 0;
            if (PhiAC[numPoints - 1] / Consts.ElementaryCharge < V)
            {
                while (PhiAC[numPoints - 1] / Consts.ElementaryCharge < V)
                {
                    lo       = PhiAC[0];
                    PhiAC[0] = 2 * PhiAC[0];
                    PhiAC[1] = PhiAC[0] * Math.Exp(PositionSpacing / x0);
                    RhoAC[0] = RhoTable.GetRho(FermiAC[0] - PhiAC[0], 0);
                    RhoAC[1] = RhoTable.GetRho(FermiAC[1] - PhiAC[1], 1);
                    CalculateProfileAC(0, freq, T);
                }
                hi = 2 * PhiAC[0];
            }
            else
            {
                while (PhiAC[numPoints - 1] / Consts.ElementaryCharge > V)
                {
                    hi       = PhiAC[0];
                    PhiAC[0] = 0.5 * PhiAC[0];
                    PhiAC[1] = PhiAC[0] * Math.Exp(PositionSpacing / x0);
                    RhoAC[0] = RhoTable.GetRho(FermiAC[0] - PhiAC[0], 0);
                    RhoAC[1] = RhoTable.GetRho(FermiAC[1] - PhiAC[1], 1);
                    CalculateProfileAC(0, freq, T);
                }
                lo = PhiAC[0];
            }
        }