Skip to main content
. 2024 Jul 29;16(15):2158. doi: 10.3390/polym16152158
<Coding of sheet, sphere- and cylinder-shaped specimen in the emission mode>
     // Total amount of diffusing gas which has entered the sheet at time t
     // Ref: Crank et.al. The Mathematics of Diffusion (1975) p. 47, Equation (4.18) [24]
     // D: Diffusion coefficient, L: Sheet thickness
     // M: Emitted total amount by diffusion at infinite time.
     public double Ftn_Sheet(double t) {
       double pi2 = Math.PI × Math.PI;
       double zSum = 0;
       for (int n = 0; n < 50; ++n) {
         int n21 = (2 × n + 1) × (2 × n + 1);
         double add = Math.Exp(−D × n21 × pi2 × t/(L × L))/n21;
         double zSumAdded = zSum + add;
         if (zSum >= zSumAdded) break; // When convergence achieved
         zSum = zSumAdded;
       }
       return M − 8/pi2 × (M × zSum);
}
     // Total amount of diffusing gas which has entered the sphere at time t.
     // Ref: Crank et.al. The Mathematics of Diffusion (1975) p. 91, Equation (6.20) [24]
     // D: Diffusion Coefficient, a: Radius of sphere.
     // M: Emitted total amount by diffusion at infinite time.
     public double Ftn_Sphere(double t) {
       double pi2 = Math.PI × Math.PI;
       double zSum = 0;
       for (int n = 1; n < 100; ++n) {
         int n2 = n × n;
         double add = Math.Exp(−D × n2 × pi2 × t/(a × a))/n2;
         double zSumAdded = zSum + add;
         if (zSum >= zSumAdded) break; // When convergence achieved
         zSum = zSumAdded;
       }
       return M − 6/pi2 × (M × zSum);
}
     // Total amount of diffusing gas which has entered the cylinder at time t.
     // Ref: Al Demarez, et. al., Acta Metallurgica (1954), Equation (5) [28]
     // D: Diffusion Coefficient, a: Radius of cylinder, L: Length of cylinder
     // M: Emitted total amount by diffusion at infinite time.
     public double Ftn_Cylinder(double t) {
       double pi2 = Math.PI × Math.PI;
       double zSum = 0;
       for (int n = 0; n < 100; ++n) {
         int n2 = (2 × n + 1) × (2 × n + 1);
         double add = Math.Exp(−n2 × pi2 × D × t/(L × L))/n2;
         double zSumAdded = zSum + add;
         if (zSum >= zSumAdded) break; // When convergence achieved
         zSum = zSumAdded;
       }
       double rSum = 0;
       for (int n = 1; n <= 50; ++n) {
         double b = Bessel0root[n − 1];
         double add = Math.Exp(−D × b × b × t/(a × a))/(b × b);
         double rSumAdded = rSum + add;
         if (rSum >= rSumAdded) break; // When convergence achieved
         rSum = rSumAdded;
       }
       return M − 32/pi2 × (M × zSum × rSum);
}
     // Zeros of first kind Bessel function J_0(x)
     public static double[] bessel0root =
       new double[] {2.40482556, 5.52007811, 8.65372791, 11.79153444, 14.93091771,
         18.07106397, 21.21163663, 24.35247153, 27.49347913, 30.63460647,
         33.77582021, 36.91709835, 40.05842576, 43.19979171, 46.34118837,
         49.4826099, 52.62405184, 55.76551076, 58.90698393, 62.04846919,
         65.1899648, 68.33146933, 71.4729816, 74.61450064, 77.75602563,
         80.89755587, 84.03909078, 87.18062984, 90.32217264, 93.46371878,
         96.605267951, 99.74681986, 102.88837425, 106.02993092, 109.17148965,
         112.3130503, 115.45461265, 118.59617663, 121.73774209, 124.87930891,
         128.020877, 131.1624463, 134.3040166, 137.445588, 140.5871604,
         143.7287336, 146.8703076, 150.0118825, 153.153458, 156.2950343};
     // Nelder-Mead Simplex Optimization.
     // Return value is fit error
     // Optima(class): Manage all optimization procedure and calc. error and FOM etc.
     // Simplex(Class): Polytope of N + 1 vertices in N dim. undetermined param. space.
     // Vertex(Class): One of N + 1 vertices of Simplex.
     // Coord(Class): Having coord. of vertex and methods, reflect(), expand(), …
     // simplexProtocol: ExpFactor = 2.0, ConFactor = 0.5, PrcntInitCoef = 5.0, …
     public double Iterate(double[] unknowns) {
       int b, w;
       int loop = 0; // # of loops
       int dim = unknowns.Length;
       Simplex simplex = new Simplex(unknowns, simplexProtocol.PrcntInitCoef);
       // Calculate errors for each vertexes.
       for (int i = 0; i < dim + 1; ++i)
       simplex.s[i].error = optima.ErrorF(simplex.s[i].coord);
       do { // start iteration
         b = simplex.bestVertex(); // find best and worst vertices
         w = simplex.worstVertex();
         // calculate the midPoint of the non-worst values for later calc’s
         double[] mp = simplex.midPoint(w);
         Vertex refl_vrtx = new Vertex(simplex.s[w]); // save the old values
         Coord.reflect(mp, refl_vrtx.coord); // first try a reflection
         refl_vrtx.error = optima.ErrorF(refl_vrtx.coord);
         // is the new vertex better or equal to the old best vertex
         if (refl_vrtx.error < simplex.s[b].error) {
           // try to expand the reflected vertex next
           Vertex expd_vrtx = new Vertex(refl_vrtx);
           Coord.expand(mp, expd_vrtx.coord, simplexProtocol.ExpFactor);
           expd_vrtx.error = optima.ErrorF(expd_vrtx.coord);
           // if the expanded vertex is not as good or better than the best
           // revert to the reflected vertex
           if (expd_vrtx.error <= refl_vrtx.error) simplex.s[w] = expd_vrtx;
           else simplex.s[w] = refl_vrtx;
         } else {
           if (refl_vrtx.error <= simplex.s[w].error) simplex.s[w] = refl_vrtx;
           else {
             Vertex cont_vrtx = new Vertex(simplex.s[w]);
             Coord.contract(mp, cont_vrtx.coord, simplexProtocol.ConFactor);
             cont_vrtx.error = optima.ErrorF(cont_vrtx.coord);
             if (cont_vrtx.error <= simplex.s[w].error) simplex.s[w] = cont_vrtx;
             else {
               simplex.contract_all(b, simplexProtocol.ConFactor);
               for (int i = 0; i < dim + 1; ++i)
                 simplex.s[i].error = otima.ErrorF(simplex.s[i].coord);
             }; // else
           }; // else
         };
         ++loop;
       } while (!(simplex.s[b].error <= simplexProtocol.Tolerance ||
       loop >= simplexProtocol.InternalLoop));
       // return best result
       for (int i = 0; i < dim; ++i) unknowns[i] = simplex.s[b].coord[i];
       return simplex.s[b].error;
}