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; } }
// 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); }