Ejemplo n.º 1
0
        public int sn = 0; // TODO: make sn an enumeration
        private void suggest()
        {
            double[] x = new double[es.number()];
            switch (sn)
            {
            case 0:
                if (list.Count >= es.number() + 1)
                {
                    double[,] Mm = new double[es.number(), es.number()];
                    for (int j = 0; j < es.number(); j++)
                    {
                        for (int k = 0; k < es.number(); k++)
                        {
                            Mm[j, k] = list[k].getF(j) - list[es.number()].getF(j);
                        }
                    }
                    double[] mF0 = new double[es.number()];
                    for (int j = 0; j < es.number(); j++)
                    {
                        mF0[j] = -list[es.number()].getF(j);
                    }
                    double[] u = Linalg.Solve(Mm, mF0);
                    double[,] Vm = new double[es.number(), es.number()];
                    for (int j = 0; j < es.number(); j++)
                    {
                        for (int k = 0; k < es.number(); k++)
                        {
                            Vm[j, k] = list[k].getIndex(j) - list[es.number()].getIndex(j);
                        }
                    }
                    double[] delta = Linalg.Product(Vm, u);
                    for (int j = 0; j < es.number(); j++)
                    {
                        x[j] = list[es.number()].getIndex(j) + delta[j];
                    }
                }
                break;

            case 1:
                for (int j = 0; j < es.number(); j++)
                {
                    x[j] = list[0].getIndex(j) * (rand.NextDouble() - 0.5) * 4.0;
                }
                break;

            case 2:
                for (int j = 0; j < es.number(); j++)
                {
                    x[j] = (rand.NextDouble() - 0.5) * 4.0;
                }
                break;

            case 3:
                for (int j = 0; j < es.number(); j++)
                {
                    double min, max;
                    min = max = list[0].getIndex(j);
                    for (int k = 0; k < list.Count; k++)
                    {
                        double v = list[k].getIndex(j);
                        if (v < min)
                        {
                            min = v;
                        }
                        if (v > max)
                        {
                            max = v;
                        }
                    }
                    if (min == max)
                    {
                        if (min > 0.0)
                        {
                            min *= 0.8;
                            max *= 1.2;
                        }
                        else if (min < 0.0)
                        {
                            min *= 1.2;
                            max *= 0.8;
                        }
                        else
                        {
                            min = -1.0;
                            max = 1.0;
                        }
                    }
                    x[j] = (min + max) / 2.0 + (max - min) * (rand.NextDouble() - 0.5) * 3.0;
                }
                break;
            }

            list.Add(new Point(x, es));
            sn++;
            if (sn > 3)
            {
                sn = 0;
            }
        }
Ejemplo n.º 2
0
        // This function is balanced by the equation solver, not called directly by the user.
        public static double Ljp(List <Ion> ionList, double[] startingPhis, double[] startingCLs, double temperatureC)
        {
            double KT = Constants.boltzmann * (temperatureC + Constants.zeroCinK);

            double cdadc = 1.0; // fine for low concentrations

            int ionCount               = ionList.Count;
            int ionCountMinusOne       = ionCount - 1;
            int ionCountMinusTwo       = ionCount - 2;
            int indexLastIon           = ionCount - 1;
            int indexSecondFromLastIon = ionCount - 2;

            Ion lastIon           = ionList[indexLastIon];
            Ion secondFromLastIon = ionList[indexSecondFromLastIon];

            if (startingPhis.Length != ionCount - 2)
            {
                throw new ArgumentException();
            }

            if (startingCLs.Length != ionCount - 2)
            {
                throw new ArgumentException();
            }

            // populate charges, mus, and rhos from all ions except the last one
            double[] charges = new double[ionCountMinusOne];
            double[] mus     = new double[ionCountMinusOne];
            double[] rhos    = new double[ionCountMinusOne];
            for (int j = 0; j < ionCountMinusOne; j++)
            {
                Ion ion = ionList[j];
                charges[j] = ion.charge;
                mus[j]     = ion.mu;
                rhos[j]    = ion.c0;
            }

            // populate phis from all ions except the last two
            double[] phis = new double[ionCountMinusOne];
            for (int j = 0; j < ionCountMinusTwo; j++)
            {
                phis[j] = startingPhis[j];
            }

            // second from last phi is the concentration difference
            phis[indexSecondFromLastIon] = secondFromLastIon.cL - secondFromLastIon.c0;

            // prepare info about second from last ion concentration difference for loop
            if (secondFromLastIon.c0 == secondFromLastIon.cL)
            {
                throw new InvalidOperationException("second from last ion concentrations cannot be equal");
            }

            double KC0 = secondFromLastIon.c0;
            double KCL = secondFromLastIon.cL;
            double dK  = (KCL - KC0) / 1000.0;

            // set last ion C0 based on charges, rhos, and linear algebra
            double zCl   = ionList[indexLastIon].charge;
            double rhoCl = -Linalg.ScalarProduct(charges, rhos) / zCl;

            lastIon.c0 = rhoCl;

            // cycle to determine junction voltage

            double V = 0.0;

            for (double rhoK = KC0; ((dK > 0) ? rhoK <= KCL : rhoK >= KCL); rhoK += dK)
            {
                rhoCl = -Linalg.ScalarProduct(rhos, charges) / zCl;

                double DCl = lastIon.mu * KT * cdadc;
                double vCl = zCl * Constants.e * lastIon.mu * rhoCl;

                double[] v = new double[ionCountMinusOne];
                double[,] mD = new double[ionCountMinusOne, ionCountMinusOne];

                for (int j = 0; j < ionCountMinusOne; j++)
                {
                    for (int k = 0; k < ionCountMinusOne; k++)
                    {
                        mD[j, k] = 0.0;
                    }
                }

                for (int j = 0; j < ionCountMinusOne; j++)
                {
                    for (int k = 0; k < ionCountMinusOne; k++)
                    {
                        mD[j, k] = 0.0;
                    }
                    mD[j, j] = mus[j] * KT * cdadc;
                    v[j]     = charges[j] * Constants.e * mus[j] * rhos[j];
                }

                if (Linalg.ScalarProduct(charges, v) + zCl * vCl == 0.0)
                {
                    return(Double.NaN); // Singularity; abort calculation
                }

                double[,] identity  = Linalg.Identity(ionCountMinusOne);
                double[,] linAlgSum = Linalg.Sum(1, mD, -DCl, identity);
                double[] sumCharge         = Linalg.Product(linAlgSum, charges);
                double   chargesProd       = Linalg.ScalarProduct(charges, v);
                double   chargesProdPlusCl = chargesProd + zCl * vCl;
                double[] delta             = Linalg.ScalarMultiply(sumCharge, 1.0 / chargesProdPlusCl);

                double[,] mDyadic = new double[ionCountMinusOne, ionCountMinusOne];
                for (int j = 0; j < ionCountMinusOne; j++)
                {
                    for (int k = 0; k < ionCountMinusOne; k++)
                    {
                        mDyadic[j, k] = v[j] * delta[k];
                    }
                }
                double[,] mM = Linalg.Sum(1, mDyadic, -1, mD);

                double[] rhop  = Linalg.Solve(mM, phis);
                double   rhopK = rhop[indexSecondFromLastIon];
                rhos = Linalg.Sum(1, rhos, dK / rhopK, rhop);

                double E = Linalg.ScalarProduct(delta, rhop);
                V -= E * dK / rhopK;
            }

            // modify CLs based on the rhos we calculated
            for (int j = 0; j < ionCountMinusTwo; j++)
            {
                startingCLs[j] = rhos[j];
            }

            return(V);
        }