/// <summary>
        /// Calculate quality from time or location.
        /// </summary>
        /// <param name="q">The location or time (l or t).</param>
        /// <param name="zq">The quality factor.</param>
        public void FZQ(float q, ref float zq)
        {
            FArray zgrid = new FArray(115);

            for (int i = 1; i <= 57; i++)
            {
                zgrid[i]      = -FCCDataMatrix.ZGRI[i];
                zgrid[i + 58] = FCCDataMatrix.ZGRI[58 - i];
            }

            zgrid[58] = FCCDataMatrix.ZGRI[58];

            for (int i = 1; i <= 115; i++)
            {
                if (FCCDataMatrix.VGRID[i] < q)
                {
                    continue;
                }

                // found point calculate zq and return
                float perc = (q - FCCDataMatrix.VGRID[i - 1]) / (FCCDataMatrix.VGRID[i] - FCCDataMatrix.VGRID[i - 1]);
                zq = zgrid[i - 1] + (perc * (zgrid[i] - zgrid[i - 1]));

                return;
            }
        }
Beispiel #2
0
        /// <summary>Interpolates the specified lx.</summary>
        /// <param name="lx">NUMBER OF INPUT GRID POINTS IN THE X COORDINATE (MUST BE 2 OR GREATER).</param>
        /// <param name="ly">NUMBER OF INPUT GRID POINTS IN THE Y COORDINATE (MUST BE 2 OR GREATER).</param>
        /// <param name="x">ARRAY OF DIMENSION LX STORING THE X COORDINATES OF INPUT GRID POINTS (IN ASCENDING ORDER).</param>
        /// <param name="y">ARRAY OF DIMENSION LY STORING THE Y COORDINATES OF INPUT GRID POINTS (IN ASCENDING ORDER).</param>
        /// <param name="z">DOUBLY-DIMENSIONED ARRAY OF DIMENSION (LX,LY) STORING THE VALUES OF THE FUNCTION (Z VALUES) AT INPUT GRID POINTS.</param>
        /// <param name="npoints">NUMBER OF POINTS AT WHICH INTERPOLATION OF THE Z VALUE IS DESIRED (MUST BE 1 OR GREATER).</param>
        /// <param name="u">ARRAY OF DIMENSION N STORING THE X COORDINATES OF DESIRED POINTS.</param>
        /// <param name="v">ARRAY OF DIMENSION N STORING THE Y COORDINATES OF DESIRED POINTS.</param>
        /// <param name="w">ARRAY OF DIMENSION N WHERE THE INTERPOLATED Z VALUES AT DESIRED POINTS ARE TO BE DISPLAYED.</param>
        public void Interpolate(int lx, int ly, FArray x, FArray y, F2DArray z, int npoints, FArray u, FArray v, FArray w)
        {
            // BIVARIATE INTERPOLATION
            // THIS SUBROUTINE INTERPOLATES, FROM VALUES OF THE FUNCTION
            // GIVEN AT INPUT GRID POINTS IN AN X-Y PLANE AND FOR A GIVEN
            // SET OF POINTS IN THE PLANE, THE VALUES OF A SINGLE-VALUED
            // BIVARIATE FUNCTION Z = Z(X,Y).
            // THE METHOD IS BASED ON A PIECE-WISE FUNCTION COMPOSED OF
            // A SET OF BICUBIC POLYNOMIALS IN X AND Y.  EACH POLYNOMIAL
            // IS APPLICABLE TO A RECTANGLE OF THE INPUT GRID IN THE X-Y
            // PLANE.  EACH POLYNOMIAL IS DETERMINED LOCALLY.
            // THE INPUT PARAMETERS ARE
            // LX  = NUMBER OF INPUT GRID POINTS IN THE X COORDINATE
            //       (MUST BE 2 OR GREATER)
            // LY  = NUMBER OF INPUT GRID POINTS IN THE Y COORDINATE
            //       (MUST BE 2 OR GREATER)
            // X   = ARRAY OF DIMENSION LX STORING THE X COORDINATES
            //       OF INPUT GRID POINTS (IN ASCENDING ORDER)
            // Y   = ARRAY OF DIMENSION LY STORING THE Y COORDINATES
            //       OF INPUT GRID POINTS (IN ASCENDING ORDER)
            // Z   = DOUBLY-DIMENSIONED ARRAY OF DIMENSION (LX,LY)
            //       STORING THE VALUES OF THE FUNCTION (Z VALUES)
            //       AT INPUT GRID POINTS
            // N   = NUMBER OF POINTS AT WHICH INTERPOLATION OF THE
            //       Z VALUE IS DESIRED (MUST BE 1 OR GREATER)
            // U   = ARRAY OF DIMENSION N STORING THE X COORDINATES
            //       OF DESIRED POINTS
            // V   = ARRAY OF DIMENSION N STORING THE Y COORDINATES
            //       OF DESIRED POINTS
            // THE OUTPUT PARAMETER IS
            // W   = ARRAY OF DIMENSION N WHERE THE INTERPOLATED Z
            //       VALUES AT DESIRED POINTS ARE TO BE DISPLAYED
            //       SOME VARIABLES INTERNALLY USED ARE
            // ZA  = DIVIDED DIFFERENCE OF Z WITH RESPECT TO X
            // ZB  = DIVIDED DIFFERENCE OF Z WITH RESPECT TO Y
            // ZAB = SECOND ORDER DIVIDED DIFFERENCE OF Z WITH;
            //       RESPECT TO X AND Y
            // ZX  = PARTIAL DERIVATIVE OF Z WITH RESPECT TO X
            // ZY  = PARTIAL DERIVATIVE OF Z WITH RESPECT TO Y
            // ZXY = SECOND ORDER PARTIAL DERIVATIVE OF Z WITH
            //       RESPECT TO X AND Y

            // variable declaration
            int   k, jxml, jyml;
            float x3, a3, y3, b3;
            float sw = 0.0f, zx3b3 = 0.0f, zx4b3 = 0.0f, zy3a3 = 0.0f, zy4a3 = 0.0f;

            k = jxml = jyml = 0;

            x3 = a3 = y3 = b3 = 0.0f;

            ZA  za  = new ZA(5, 2);
            ZB  zb  = new ZB(2, 5);
            ZAB zab = new ZAB(3, 3);
            ZX  zx  = new ZX(4, 4);
            ZY  zy  = new ZY(4, 4);
            ZXY zxy = new ZXY(4, 4);

            SharedVariables sh = new SharedVariables();

            zx.LX0  = lx;
            zx.LXM1 = zx.LX0 - 1;
            zx.LXM2 = zx.LXM1 - 1;
            zx.LXP1 = zx.LX0 + 1;
            zy.LY0  = ly;
            zy.LYM1 = zy.LY0 - 1;
            zy.LYM2 = zy.LYM1 - 1;
            zy.LYP1 = zy.LY0 + 1;

            zxy.IXPV = 0;
            zxy.IYPV = 0;

            // main loop
            for (k = 1; k <= npoints; k++)
            {
                sh.UK = u[k];
                sh.VK = v[k];

                // (U(K).GE.X(IX-1)).AND.(U(K).LT.X(IX))
                if (zx.LXM2 == 0)
                {
                    goto lbl80;
                }

                if (sh.UK >= x[zx.LX0])
                {
                    goto lbl70;
                }

                if (sh.UK < x[1])
                {
                    goto lbl60;
                }

                sh.IMN = 2;
                sh.IMX = zx.LX0;

lbl30:
                zxy.IX = (sh.IMN + sh.IMX) / 2;

                // UK.GE.X(IX)
                if (sh.UK >= x[zxy.IX])
                {
                    goto lbl40;
                }

                sh.IMX = zxy.IX;
                goto lbl50;

lbl40:
                sh.IMN = zxy.IX + 1;

lbl50:
                if (sh.IMX > sh.IMN)
                {
                    goto lbl30;
                }

                zxy.IX = sh.IMX; // continue to lbl90
                goto lbl90;

lbl60:
                zxy.IX = 1;
                goto lbl90;

lbl70:
                zxy.IX = zx.LXP1; // goto lbl90
                goto lbl90;

lbl80:
                zxy.IX = 2;

                ////  TO FIND OUT THE IY VALUE FOR WHICH
                ////  (V(K).GE.Y(IY-1)).AND.(V(K).LT.Y(IY))
lbl90:
                if (zy.LYM2 == 0)
                {
                    goto lbl150;
                }

                // VK.GE.Y(LY0)
                if (sh.VK >= y[zy.LY0])
                {
                    goto lbl140;
                }

                if (sh.VK < y[1])
                {
                    goto lbl130;
                }

                sh.IMN = 2;
                sh.IMX = zy.LY0;

lbl100:
                zxy.IY = (sh.IMN + sh.IMX) / 2;
                if (sh.VK >= y[zxy.IY])
                {
                    goto lbl110;
                }

                sh.IMX = zxy.IY;
                goto lbl120;

lbl110:
                sh.IMN = zxy.IY + 1;

lbl120:
                if (sh.IMX > sh.IMN)
                {
                    goto lbl100;
                }

                zxy.IY = sh.IMX;
                goto lbl160;

lbl130:
                zxy.IY = 1;
                goto lbl160;

lbl140:
                zxy.IY = zy.LYP1;
                goto lbl160;

lbl150:
                zxy.IY = 2;

                ////  TO CHECK IF THE DESIRED POINT IS IN THE SAME RECTANGLE
                ////  AS THE PREVIOUS POINT. IF YES, SKIP TO THE COMPUTATION
                ////  OF THE POLYNOMIAL

lbl160:
                if (zxy.IX == zxy.IXPV && zxy.IY == zxy.IYPV)
                {
                    goto lbl690;
                }

                zxy.IXPV = zxy.IX;
                zxy.IYPV = zxy.IY;

                ////  ROUTINES TO PICK UP NECESSARY X,Y, AND Z VALUES, TO
                ////  COMPUTE THE ZA, ZB AND ZAB VALUES, AND TO ESTIMATE THEM
                ////  WHEN NECESSARY

                sh.JX = zxy.IX;
                if (sh.JX == 1)
                {
                    sh.JX = 2;
                }

                // IF (JX.EQ.LXP1) JX = LX0
                if (sh.JX == zx.LXP1)
                {
                    sh.JX = zx.LX0;
                }

                sh.JY = zxy.IY;

                // IF (JY.EQ.1) JY = 2
                if (sh.JY == 1)
                {
                    sh.JY = 2;
                }

                // IF (JY.EQ.LYP1) JY = LY0
                if (sh.JY == zy.LYP1)
                {
                    sh.JY = zy.LY0;
                }

                sh.JXM2 = sh.JX - 2;
                jxml    = sh.JX - zx.LX0;
                sh.JYM2 = sh.JY - 2;
                jyml    = sh.JY - zy.LY0;

                ////  IN THE CORE AREA, I.E., IN THE RECTANGLE THAT CONTAINS
                ////  THE DESIRED POINT

                x3    = x[sh.JX - 1];
                zx.X4 = x[sh.JX];            // X4 = X(JX)
                a3    = 1.0f / (zx.X4 - x3); // A3 = 1/(X4-X3)
                if (float.IsNaN(a3))
                {
                    a3 = 0.0f;
                }

                y3    = y[sh.JY - 1];        // Y3 = Y(JY-1)
                zy.Y4 = y[sh.JY];            // Y4 = Y(JY)
                b3    = 1.0f / (zy.Y4 - y3); // B3 = 1/(Y4-Y3)
                if (float.IsNaN(b3))
                {
                    b3 = 0.0f;
                }

                sh.Z33 = z[sh.JX - 1, (sh.JY - 1)];   // Z(JX-1,JY-1)

                zxy.Z43 = z[sh.JX, sh.JY - 1];        // Z43 = Z(JX,JY-1)

                zy.Z34 = z[sh.JX - 1, sh.JY];         // Z34 = Z(JX-1,JY)

                zxy.Z44 = z[sh.JX, sh.JY];            // Z(JX,JY)

                za.Z3A3 = (zxy.Z43 - sh.Z33) * a3;    // Z3A3 = (Z43-Z33)*A3

                za.Z4A3 = (zxy.Z44 - zy.Z34) * a3;    // Z4A3 = (Z44-Z34)*A3

                zb.Z3B3 = (zy.Z34 - sh.Z33) * b3;     // Z3B3 = (Z34-Z33)*B3

                zb.Z4B3 = (zxy.Z44 - zxy.Z43) * b3;   // Z4B3 = (Z44-Z43)*B3

                zab.ZA3B3 = (zb.Z4B3 - zb.Z3B3) * a3; // ZA3B3 = (Z4B3-Z3B3)*A3

                ////  IN THE X DIRECTION

                // IF (LXM2.EQ.0) GO TO 230
                if (zx.LXM2 == 0)
                {
                    goto lbl230;
                }

                // IF (JXM2.EQ.0) GO TO 170
                if (sh.JXM2 == 0)
                {
                    goto lbl170;
                }

                zx.X2 = x[sh.JX - 2];        // X2 = X(JX-2)
                zx.A2 = 1.0f / (x3 - zx.X2); // A2 = 1/(X3-X2)
                if (float.IsNaN(zx.A2))
                {
                    zx.A2 = 0.0f;
                }

                zy.Z23  = z[sh.JX - 2, sh.JY - 1];   // Z23 = Z(JX-2,JY-1)
                zy.Z24  = z[sh.JX - 2, sh.JY];       // Z24 = Z(JX-2,JY)
                za.Z3A2 = (sh.Z33 - zy.Z23) * zx.A2; // Z3A2 = (Z33-Z23)*A2
                za.Z4A2 = (zy.Z34 - zy.Z24) * zx.A2; // Z4A2 = (Z34-Z24)*A2

                // IF (JXML.EQ.0) GO TO 180
                if (jxml == 0)
                {
                    goto lbl180;
                }

lbl170:
                zx.X5 = x[sh.JX + 1];           // X5 = X(JX+1)
                zx.A4 = 1.0f / (zx.X5 - zx.X4); // A4 = 1/(X5-X4)
                if (float.IsNaN(zx.A4))
                {
                    zx.A4 = 0.0F;
                }

                zxy.Z53 = z[sh.JX + 1, sh.JY - 1];     // Z53 = Z(JX+1,JY-1)
                zxy.Z54 = z[sh.JX + 1, sh.JY];         // Z54 = Z(JX+1,JY)
                za.Z3A4 = (zxy.Z53 - zxy.Z43) * zx.A4; // Z3A4 = (Z53-Z43)*A4
                za.Z4A4 = (zxy.Z54 - zxy.Z44) * zx.A4; // Z4A4 = (Z54-Z44)*A4

                if (sh.JXM2 != 0)
                {
                    goto lbl190; // IF (JXM2.NE.0) GO TO 190
                }

                za.Z3A2 = za.Z3A3 + za.Z3A3 - za.Z3A4; // Z3A2 = Z3A3 + Z3A3 - Z3A4
                za.Z4A2 = za.Z4A3 + za.Z4A3 - za.Z4A4; // Z4A2 = Z4A3 + Z4A3 - Z4A4

                goto lbl190;

lbl180:
                za.Z3A4 = za.Z3A3 + za.Z3A3 - za.Z3A2; // Z3A4 = Z3A3 + Z3A3 - Z3A2
                za.Z4A4 = za.Z4A3 + za.Z4A3 - za.Z4A2; // Z4A4 = Z4A3 + Z4A3 - Z4A2

lbl190:
                zab.ZA2B3 = (za.Z4A2 - za.Z3A2) * b3; // ZA2B3 = (Z4A2-Z3A2)*B3
                zab.ZA4B3 = (za.Z4A4 - za.Z3A4) * b3; // ZA4B3 = (Z4A4-Z3A4)*B3

                // IF (JX.LE.3) GO TO 200
                if (sh.JX <= 3)
                {
                    goto lbl200;
                }

                zx.A1 = 1.0f / (zx.X2 - x[sh.JX - 3]); // A1 = 1/(X2-X(JX-3))
                if (float.IsNaN(zx.A1))
                {
                    zx.A1 = 0.0f;
                }

                za.Z3A1 = (zy.Z23 - z[sh.JX - 3, sh.JY - 1]) * zx.A1; // Z3A1 = (Z23-Z(JX-3,JY-1))*A1
                za.Z4A1 = (zy.Z24 - z[sh.JX - 3, sh.JY]) * zx.A1;     // Z4A1 = (Z24-Z(JX-3,JY))*A1

                goto lbl210;

lbl200:
                za.Z3A1 = za.Z3A2 + za.Z3A2 - za.Z3A3; // Z3A1 = Z3A2 + Z3A2 - Z3A3
                za.Z4A1 = za.Z4A2 + za.Z4A2 - za.Z4A3; // Z4A1 = Z4A2 + Z4A2 - Z4A3

lbl210:

                // IF (JX.GE.LXM1) GO TO 220
                if (sh.JX >= zx.LXM1)
                {
                    goto lbl220;
                }

                zx.A5 = 1.0f / (x[sh.JX + 2] - zx.X5); // A5 = 1/(X(JX+2)-X5)
                if (float.IsNaN(zx.A5))
                {
                    zx.A5 = 0.0f;
                }

                za.Z3A5 = (z[sh.JX + 2, sh.JY - 1] - zxy.Z53) * zx.A5; // Z3A5 = (Z(JX+2,JY-1)-Z53)*A5
                za.Z4A5 = (z[sh.JX + 2, sh.JY] - zxy.Z54) * zx.A5;     // Z4A5 = (Z(JX+2,JY)-Z54)*A5

                goto lbl240;

lbl220:
                za.Z3A5 = za.Z3A4 + za.Z3A4 - za.Z3A3; // Z3A5 = Z3A4 + Z3A4 - Z3A3
                za.Z4A5 = za.Z4A4 + za.Z4A4 - za.Z4A3; // Z4A5 = Z4A4 + Z4A4 - Z4A3

                goto lbl240;

lbl230:
                za.Z3A2 = za.Z3A3; // Z3A2 = Z3A3
                za.Z4A2 = za.Z4A3; // Z4A2 = Z4A3

                goto lbl180;

                //// IN THE Y DIRECTION

lbl240:

                // IF (LYM2.EQ.0) GO TO 310
                if (zy.LYM2 == 0)
                {
                    goto lbl310;
                }

                // IF (JYM2.EQ.0) GO TO 250
                if (sh.JYM2 == 0)
                {
                    goto lbl250;
                }

                zx.Y2 = y[sh.JY - 2];        // Y2 = Y(JY-2)
                zy.B2 = 1.0f / (y3 - zx.Y2); // B2 = 1/(Y3-Y2)
                if (float.IsNaN(zy.B2))
                {
                    zy.B2 = 0.0f;
                }

                zy.Z32  = z[sh.JX - 1, sh.JY - 2];     // Z32 = Z(JX-1,JY-2)
                zxy.Z42 = z[sh.JX, sh.JY - 2];         // Z42 = Z(JX,JY-2)
                zb.Z3B2 = (sh.Z33 - zy.Z32) * zy.B2;   // Z3B2 = (Z33-Z32)*B2
                zb.Z4B2 = (zxy.Z43 - zxy.Z42) * zy.B2; // Z4B2 = (Z43-Z42)*B2

                // IF (JYML.EQ.0) GO TO 260
                if (jyml == 0)
                {
                    goto lbl260;
                }

lbl250:
                zx.Y5 = y[sh.JY + 1];           ////  Y5 = Y(JY+1)
                zy.B4 = 1.0f / (zx.Y5 - zy.Y4); // B4 = 1/(Y5-Y4)
                if (float.IsNaN(zy.B4))
                {
                    zy.B4 = 0.0f;
                }

                zy.Z35  = z[sh.JX - 1, sh.JY + 1];     // Z(JX-1,JY+1)
                zxy.Z45 = z[sh.JX, sh.JY + 1];         // Z45 = Z(JX,JY+1)
                zb.Z3B4 = (zy.Z35 - zy.Z34) * zy.B4;   // Z3B4 = (Z35-Z34)*B4
                zb.Z4B4 = (zxy.Z45 - zxy.Z44) * zy.B4; // Z4B4 = (Z45-Z44)*B4

                // IF (JYM2.NE.0) GO TO 270
                if (sh.JYM2 != 0)
                {
                    goto lbl270;
                }

                zb.Z3B2 = zb.Z3B3 + zb.Z3B3 - zb.Z3B4; // Z3B2 = Z3B3 + Z3B3 - Z3B4
                zb.Z4B2 = zb.Z4B3 + zb.Z4B3 - zb.Z4B4; // Z4B2 = Z4B3 + Z4B3 - Z4B4

                goto lbl270;

lbl260:
                zb.Z3B4 = zb.Z3B3 + zb.Z3B3 - zb.Z3B2; // Z3B4 = Z3B3 + Z3B3 - Z3B2
                zb.Z4B4 = zb.Z4B3 + zb.Z4B3 - zb.Z4B2; // Z4B4 = Z4B3 + Z4B3 - Z4B2

lbl270:
                zab.ZA3B2 = (zb.Z4B2 - zb.Z3B2) * a3; // ZA3B2 = (Z4B2-Z3B2)*A3
                zab.ZA3B4 = (zb.Z4B4 - zb.Z3B4) * a3; // ZA3B4 = (Z4B4-Z3B4)*A3

                if (sh.JY <= 3)
                {
                    goto lbl280; // IF (JY.LE.3) GO TO 280
                }

                zx.B1 = 1.0f / (zx.Y2 - y[sh.JY - 3]); // B1 = 1/(Y2-Y(JY-3))
                if (float.IsNaN(zx.B1))
                {
                    zx.B1 = 0.0f;
                }

                zb.Z3B1 = (zy.Z32 - z[sh.JX - 1, sh.JY - 3]) * zx.B1; // Z3B1 = (Z32-Z(JX-1,JY-3))*B1
                zb.Z4B1 = (zxy.Z42 - z[sh.JX, sh.JY - 3]) * zx.B1;    // Z4B1 = (Z42-Z(JX,JY-3))*B1

                goto lbl290;

lbl280:
                zb.Z3B1 = zb.Z3B2 + zb.Z3B2 - zb.Z3B3; // Z3B1 = Z3B2 + Z3B2 - Z3B3
                zb.Z4B1 = zb.Z4B2 + zb.Z4B2 - zb.Z4B3; // Z4B1 = Z4B2 + Z4B2 - Z4B3

lbl290:

                // IF (JY.GE.LYM1) GO TO 300
                if (sh.JY >= zy.LYM1)
                {
                    goto lbl300;
                }

                zx.B5 = 1.0f / (y[sh.JY + 2] - zx.Y5); // B5 = 1/(Y(JY+2)-Y5)
                if (float.IsNaN(zx.B5))
                {
                    zx.B5 = 0.0f;
                }

                zb.Z3B5 = (z[sh.JX - 1, sh.JY + 2] - zy.Z35) * zx.B5; // Z3B5 = (Z(JX-1,JY+2)-Z35)*B5
                zb.Z4B5 = (z[sh.JX, sh.JY + 2] - zxy.Z45) * zx.B5;    // Z4B5 = (Z(JX,JY+2)-Z45)*B5

                goto lbl320;

lbl300:
                zb.Z3B5 = zb.Z3B4 + zb.Z3B4 - zb.Z3B3; // Z3B5 = Z3B4 + Z3B4 - Z3B3
                zb.Z4B5 = zb.Z4B4 + zb.Z4B4 - zb.Z4B3; // Z4B5 = Z4B4 + Z4B4 - Z4B3

                goto lbl320;

lbl310:
                zb.Z3B2 = zb.Z3B3; // Z3B2 = Z3B3
                zb.Z4B2 = zb.Z4B3; // Z4B2 = Z4B3

                goto lbl260;

                //// IN THE DIAGONAL DIRECTIONS

lbl320:

                // IF (LXM2.EQ.0) GO TO 400
                if (zx.LXM2 == 0)
                {
                    goto lbl400;
                }

                // IF (LYM2.EQ.0) GO TO 410
                if (zy.LYM2 == 0)
                {
                    goto lbl410;
                }

                // IF (JXML.EQ.0) GO TO 350
                if (jxml == 0)
                {
                    goto lbl350;
                }

                // IF (JYM2.EQ.0) GO TO 330
                if (sh.JYM2 == 0)
                {
                    goto lbl330;
                }

                zab.ZA4B2 = (((zxy.Z53 - z[sh.JX + 1, sh.JY - 2]) * zy.B2) - zb.Z4B2) * zx.A4; // ZA4B2 = ((Z53-Z(JX+1,JY-2))*B2-Z4B2)*A4

                // IF (JYML.EQ.0) GO TO 340
                if (jyml == 0)
                {
                    goto lbl340;
                }

lbl330:
                zab.ZA4B4 = (((z[sh.JX + 1, sh.JY + 1] - zxy.Z54) * zy.B4) - zb.Z4B4) * zx.A4; // ZA4B4 = ((Z(JX+1,JY+1)-Z54)*B4-Z4B4)*A4

                // IF (JYM2.NE.0) GO TO 380
                if (sh.JYM2 != 0)
                {
                    goto lbl380;
                }

                zab.ZA4B2 = zab.ZA4B3 + zab.ZA4B3 - zab.ZA4B4; // ZA4B2 = ZA4B3 + ZA4B3 - ZA4B4

                goto lbl380;

lbl340:
                zab.ZA4B4 = zab.ZA4B3 + zab.ZA4B3 - zab.ZA4B2; // ZA4B4 = ZA4B3 + ZA4B3 - ZA4B2
                goto lbl380;

lbl350:

                // IF (JYM2.EQ.0) GO TO 360
                if (sh.JYM2 == 0)
                {
                    goto lbl360;
                }

                zab.ZA2B2 = (zb.Z3B2 - ((zy.Z23 - z[sh.JX - 2, sh.JY - 2]) * zy.B2)) * zx.A2; // ZA2B2 = (Z3B2-(Z23-Z(JX-2,JY-2))*B2)*A2

                // IF (JYML.EQ.0) GO TO 370
                if (jyml == 0)
                {
                    goto lbl370;
                }

lbl360:
                zab.ZA2B4 = (zb.Z3B4 - ((z[sh.JX - 2, sh.JY + 1] - zy.Z24) * zy.B4)) * zx.A2; // ZA2B4 = (Z3B4-(Z(JX-2,JY+1)-Z24)*B4)*A2

                // IF (JYM2.NE.0) GO TO 390
                if (sh.JYM2 != 0)
                {
                    goto lbl390;
                }

                zab.ZA2B2 = zab.ZA2B3 + zab.ZA2B3 - zab.ZA2B4; // ZA2B2 = ZA2B3 + ZA2B3 - ZA2B4
                goto lbl390;

lbl370:
                zab.ZA2B4 = zab.ZA2B3 + zab.ZA2B3 - zab.ZA2B2; // ZA2B4 = ZA2B3 + ZA2B3 - ZA2B2
                goto lbl390;

lbl380:

                // IF (JXM2.NE.0) GO TO 350
                if (sh.JXM2 != 0)
                {
                    goto lbl350;
                }

                zab.ZA2B2 = zab.ZA3B2 + zab.ZA3B2 - zab.ZA4B2; // ZA2B2 = ZA3B2 + ZA3B2 - ZA4B2
                zab.ZA2B4 = zab.ZA3B4 + zab.ZA3B4 - zab.ZA4B4; // ZA2B4 = ZA3B4 + ZA3B4 - ZA4B4

                goto lbl420;

lbl390:

                // IF (JXML.NE.0) GO TO 420
                if (jxml != 0)
                {
                    goto lbl420;
                }

                zab.ZA4B2 = zab.ZA3B2 + zab.ZA3B2 - zab.ZA2B2; // ZA4B2 = ZA3B2 + ZA3B2 - ZA2B2
                zab.ZA4B4 = zab.ZA3B4 + zab.ZA3B4 - zab.ZA2B4; // ZA4B4 = ZA3B4 + ZA3B4 - ZA2B4

                goto lbl420;

lbl400:
                zab.ZA2B2 = zab.ZA3B2; // ZA2B2 = ZA3B2
                zab.ZA4B2 = zab.ZA3B2; // ZA2B4 = ZA2B3
                zab.ZA2B4 = zab.ZA3B4; // ZA2B4 = ZA3B4
                zab.ZA4B4 = zab.ZA3B4; // ZA4B4 = ZA3B4

                goto lbl420;

lbl410:
                zab.ZA2B2 = zab.ZA2B3; // ZA2B2 = ZA2B3
                zab.ZA2B4 = zab.ZA2B3; // ZA2B4 = ZA2B3
                zab.ZA4B2 = zab.ZA4B3; // ZA4B2 = ZA4B3
                zab.ZA4B4 = zab.ZA4B3; // ZA4B4 = ZA4B3

                //// NUMERICAL DIFFERENTIATION   ---   TO DETERMINE PARTIAL
                //// DERIVATIVES ZX, ZY, AND ZXY AS WEIGHTED MEANS OF DIVIDED
                //// DIFFERENCES ZA, ZB, AND ZAB, RESPECTIVELY

lbl420:

                // DO 480 JY=2,3
                for (sh.JY = 2; sh.JY <= 3; sh.JY++)
                {
                    // DO 470 JX=2,3
                    for (sh.JX = 2; sh.JX <= 3; sh.JX++)
                    {
                        // W2 = ABS(ZA(JX+2,JY-1)-ZA(JX+1,JY-1))
                        sh.W2 = Math.Abs(za[sh.JX + 2, sh.JY - 1] - za[sh.JX + 1, sh.JY - 1]);

                        // W3 = ABS(ZA(JX,JY-1)-ZA(JX-1,JY-1))
                        sh.W3 = Math.Abs(za[sh.JX, sh.JY - 1] - za[sh.JX - 1, sh.JY - 1]);

                        sw = sh.W2 + sh.W3;

                        // IF (SW.EQ.0.0) GO TO 430
                        if (sw < 0.0000001)
                        {
                            goto lbl430;
                        }

                        zxy.WX2 = sh.W2 / sw;
                        if (float.IsNaN(zxy.WX2))
                        {
                            zxy.WX2 = 0.0f;
                        }

                        zxy.WX3 = sh.W3 / sw;
                        if (float.IsNaN(zxy.WX3))
                        {
                            zxy.WX3 = 0.0f;
                        }

                        goto lbl440;

lbl430:
                        zxy.WX2 = 0.5f; // WX2 = 0.5
                        zxy.WX3 = 0.5f; // WX3 = 0.5

lbl440:

                        // ZX(JX,JY) = WX2*ZA(JX,JY-1) + WX3*ZA(JX+1,JY-1)
                        zx[sh.JX, sh.JY] = (zxy.WX2 * za[sh.JX, sh.JY - 1]) + (zxy.WX3 * za[sh.JX + 1, sh.JY - 1]);

                        // W2 = ABS(ZB(JX-1,JY+2)-ZB(JX-1,JY+1))
                        sh.W2 = Math.Abs(zb[sh.JX - 1, sh.JY + 2] - zb[sh.JX - 1, sh.JY + 1]);

                        // W3 = ABS(ZB(JX-1,JY)-ZB(JX-1,JY-1))
                        sh.W3 = Math.Abs(zb[sh.JX - 1, sh.JY] - zb[sh.JX - 1, sh.JY - 1]);

                        sw = sh.W2 + sh.W3; // SW = W2 + W3

                        // IF (SW.EQ.0.0) GO TO 450
                        if (sw == 0)
                        {
                            goto lbl450;
                        }

                        sh.WY2 = sh.W2 / sw; ////  WY2 = W2/SW
                        sh.WY3 = sh.W3 / sw; // WY3 = W3/SW

                        goto lbl460;

lbl450:
                        sh.WY2 = 0.5f; // WY2 = 0.5
                        sh.WY3 = 0.5f; // WY3 = 0.5

lbl460:

                        // ZY(JX,JY) = WY2*ZB(JX-1,JY) + WY3*ZB(JX-1,JY+1)
                        zy[sh.JX, sh.JY] = (sh.WY2 * zb[sh.JX - 1, sh.JY]) + (sh.WY3 * zb[sh.JX - 1, sh.JY + 1]);

                        // ZXY(JX,JY) = WY2*(WX2*ZAB(JX-1,JY-1)+WX3*ZAB(JX,JY-1)) + WY3*(WX2*ZAB(JX-1,JY)+WX3*ZAB(JX,JY))
                        zxy[sh.JX, sh.JY] = (sh.WY2 * ((zxy.WX2 * zab[sh.JX - 1, sh.JY - 1]) + (zxy.WX3 * zab[sh.JX, sh.JY - 1]))) + (sh.WY3 * ((zxy.WX2 * zab[sh.JX - 1, sh.JY]) + (zxy.WX3 * zab[sh.JX, sh.JY])));
                    }
                }

                //// WHEN (U(K).LT.X(1)).OR.(U(K).GT.X(LX))

                // IF (IX.EQ.LXP1) GO TO 530
                if (zxy.IX == zx.LXP1)
                {
                    goto lbl530;
                }

                // IF (IX.NE.1) GO TO 590
                if (zxy.IX != 1)
                {
                    goto lbl590;
                }

                sh.W2 = zx.A4 * ((3.0f * a3) + zx.A4);      // W2 = A4*(3*A3+A4)
                sh.W1 = (a3 * 2.0f * (a3 - zx.A4)) + sh.W2; // W1 = 2*A3*(A3-A4) + W2

                // DO 500 JY=2,3
                for (sh.JY = 2; sh.JY <= 3; sh.JY++)
                {
                    // ZX(1,JY) = (W1*ZA(1,JY-1)+W2*ZA(2,JY-1))/(W1+W2)
                    zx[1, sh.JY] = ((sh.W1 * za[1, sh.JY - 1]) + (sh.W2 * za[2, sh.JY - 1])) / (sh.W1 + sh.W2);
                    if (float.IsNaN(zx[1, sh.JY]))
                    {
                        zx[1, sh.JY] = 0.0f;
                    }

                    // ZY(1,JY) = ZY(2,JY) + ZY(2,JY) - ZY(3,JY)
                    zy[1, sh.JY] = zy[2, sh.JY] + zy[2, sh.JY] - zy[3, sh.JY];

                    // ZXY(1,JY) = ZXY(2,JY) + ZXY(2,JY) - ZXY(3,JY)
                    zxy[1, sh.JY] = zxy[2, sh.JY] + zxy[2, sh.JY] - zxy[3, sh.JY];

                    // DO 490 JX1=2,3
                    for (sh.JX1 = 2; sh.JX1 <= 3; sh.JX1++)
                    {
                        sh.JX             = 5 - sh.JX1;            // JX = 5 - JX1
                        zx[sh.JX, sh.JY]  = zx[sh.JX - 1, sh.JY];  // ZX(JX,JY) = ZX(JX-1,JY)
                        zy[sh.JX, sh.JY]  = zy[sh.JX - 1, sh.JY];  // ZY(JX,JY) = ZY(JX-1,JY)
                        zxy[sh.JX, sh.JY] = zxy[sh.JX - 1, sh.JY]; // ZXY(JX,JY) = ZXY(JX-1,JY)
                    }
                }

                x3     = x3 - (1.0f / zx.A4);        // X3 = X3 - 1/A4
                sh.Z33 = sh.Z33 - (za.Z3A2 / zx.A4); // Z33 = Z33 - Z3A2/A4
                if (float.IsNaN(sh.Z33))
                {
                    sh.Z33 = 0.0f;
                }

                // DO 510 JY=1,5
                for (sh.JY = 1; sh.JY <= 5; sh.JY++)
                {
                    // ZB(2,JY) = ZB(1,JY)
                    zb[2, sh.JY] = zb[1, sh.JY];
                }

                // DO 520 JY=2,4
                for (sh.JY = 2; sh.JY <= 4; sh.JY++)
                {
                    // ZB(1,JY) = ZB(1,JY) - ZAB(1,JY-1)/A4
                    zb[1, sh.JY] = zb[1, sh.JY] - (zab[1, sh.JY - 1] / zx.A4);
                    if (float.IsNaN(zb[1, sh.JY]))
                    {
                        zb[1, sh.JY] = 0.0f;
                    }
                }

                a3    = zx.A4; // A3 = A4
                sh.JX = 1;     // JX = 1
                goto lbl570;

lbl530:
                sh.W4 = zx.A2 * ((3.0f * a3) + zx.A2);      // W4 = A2*(3*A3+A2)
                sh.W5 = (2.0f * a3 * (a3 - zx.A2)) + sh.W4; // W5 = 2*A3*(A3-A2) + W4

                // DO 550 JY=2,3
                for (sh.JY = 2; sh.JY <= 3; sh.JY++)
                {
                    // ZX(4,JY) = (W4*ZA(4,JY-1)+W5*ZA(5,JY-1))/(W4+W5)
                    zx[4, sh.JY] = ((sh.W4 * za[4, sh.JY - 1]) + (sh.W5 * za[5, sh.JY - 1])) / (sh.W4 + sh.W5);
                    if (float.IsNaN(zx[4, sh.JY]))
                    {
                        zx[4, sh.JY] = 0.0f;
                    }

                    // ZY(4,JY) = ZY(3,JY) + ZY(3,JY) - ZY(2,JY)
                    zy[4, sh.JY] = (zy[3, sh.JY] + zy[3, sh.JY]) - zy[2, sh.JY];

                    // ZXY(4,JY) = ZXY(3,JY) + ZXY(3,JY) - ZXY(2,JY)
                    zxy[4, sh.JY] = (zxy[3, sh.JY] + zxy[3, sh.JY]) - zxy[2, sh.JY];

                    // DO 540 JX=2,3
                    for (sh.JX = 2; sh.JX <= 3; sh.JX++)
                    {
                        zx[sh.JX, sh.JY]  = zx[sh.JX + 1, sh.JY];  // ZX(JX,JY) = ZX(JX+1,JY)
                        zy[sh.JX, sh.JY]  = zy[sh.JX + 1, sh.JY];  // ZY(JX,JY) = ZY(JX+1,JY)
                        zxy[sh.JX, sh.JY] = zxy[sh.JX + 1, sh.JY]; // ZXY(JX,JY) = ZXY(JX+1,JY)
                    }
                }

                x3     = zx.X4;   // X3 = X4
                sh.Z33 = zxy.Z43; // Z33 = Z43

                // DO 560 JY=1,5
                for (sh.JY = 1; sh.JY <= 5; sh.JY++)
                {
                    zb[1, sh.JY] = zb[2, sh.JY]; // ZB(1,JY) = ZB(2,JY)
                }

                a3    = zx.A2; // A3 = A2
                sh.JX = 3;     // JX = 3

lbl570:
                za[3, 1] = za[sh.JX + 1, 1]; // ZA(3,1) = ZA(JX+1,1)

                // DO 580 JY=1,3
                for (sh.JY = 1; sh.JY <= 3; sh.JY++)
                {
                    // ZAB(2,JY) = ZAB(JX,JY)
                    zab[2, sh.JY] = zab[sh.JX, sh.JY];
                }

                //// WHEN (V(K).LT.Y(1)).OR.(V(K).GT.Y(LY))

lbl590:

                // IF (IY.EQ.LYP1) GO TO 630
                if (zxy.IY == zy.LYP1)
                {
                    goto lbl630;
                }

                // IF (IY.NE.1) GO TO 680
                if (zxy.IY != 1)
                {
                    goto lbl680;
                }

                sh.W2 = zy.B4 * ((b3 * 3) + zy.B4);      // W2 = B4*(3*B3+B4)
                sh.W1 = (b3 * 2 * (b3 - zy.B4)) + sh.W2; // W1 = 2*B3*(B3-B4) + W2

                // DO 620 JX=2,3
                for (sh.JX = 2; sh.JX <= 3; sh.JX++)
                {
                    // IF (JX.EQ.3 .AND. IX.EQ.LXP1) GO TO 600
                    // IF (JX.EQ.2 .AND. IX.EQ.1) GO TO 600
                    if ((sh.JX == 3 && zxy.IX == zx.LXP1) || (sh.JX == 2 && zxy.IX == 1))
                    {
                        goto lbl600;
                    }
                    else
                    {
                        //// ZY(JX,1) = (W1*ZB(JX-1,1)+W2*ZB(JX-1,2))/(W1+W2) /// Narendra needs to figure out the NAN issue.
                        zy[sh.JX, 1] = ((sh.W1 * zb[sh.JX - 1, 1]) + (sh.W2 * zb[sh.JX - 1, 2])) / (sh.W1 + sh.W2);

                        if (float.IsNaN(zy[sh.JX, 1]))
                        {
                            zy[sh.JX, 1] = 0.0f;
                        }

                        // ZX(JX,1) = ZX(JX,2) + ZX(JX,2) - ZX(JX,3)
                        zx[sh.JX, 1] = (zx[sh.JX, 2] + zx[sh.JX, 2]) - zx[sh.JX, 3];

                        // ZXY(JX,1) = ZXY(JX,2) + ZXY(JX,2) - ZXY(JX,3)
                        zxy[sh.JX, 1] = (zxy[sh.JX, 2] + zxy[sh.JX, 2]) - zxy[sh.JX, 3];
                    }

lbl600:

                    // DO 610 JY1=2,3
                    for (sh.JY1 = 2; sh.JY1 <= 3; sh.JY1++)
                    {
                        sh.JY             = 5 - sh.JY1;            // JY = 5 - JY1
                        zy[sh.JX, sh.JY]  = zy[sh.JX, sh.JY - 1];  // ZY(JX,JY) = ZY(JX,JY-1)
                        zx[sh.JX, sh.JY]  = zx[sh.JX, sh.JY - 1];  // ZX(JX,JY) = ZX(JX,JY-1)
                        zxy[sh.JX, sh.JY] = zxy[sh.JX, sh.JY - 1]; // ZXY(JX,JY) = ZXY(JX,JY-1)
                    }
                }

                y3        = y3 - (1.0f / zy.B4);           // Y3 = Y3 - 1/B4
                sh.Z33    = sh.Z33 - (zb.Z3B2 / zy.B4);    // Z33 = Z33 - Z3B2/B4
                za.Z3A3   = za.Z3A3 - (zab.ZA3B2 / zy.B4); // Z3A3 = Z3A3 - ZA3B2/B4
                zb.Z3B3   = zb.Z3B2;                       // Z3B3 = Z3B2
                zab.ZA3B3 = zab.ZA3B2;                     // ZA3B3 = ZA3B2
                b3        = zy.B4;                         // B3 = B4
                goto lbl670;

lbl630:
                sh.W4 = zy.B2 * ((3.0f * b3) + zy.B2);      // W4 = B2*(3*B3+B2)
                sh.W5 = (2.0f * b3 * (b3 - zy.B2)) + sh.W4; // W5 = 2*B3*(B3-B2) + W4

                // DO 660 JX=2,3
                for (sh.JX = 2; sh.JX <= 3; sh.JX++)
                {
                    // IF (JX.EQ.3 .AND. IX.EQ.LXP1) GO TO 640
                    // IF (JX.EQ.2 .AND. IX.EQ.1) GO TO 640
                    if ((sh.JX == 3 && zxy.IX == zx.LXP1) || (sh.JX == 2 && zxy.IX == 1))
                    {
                        goto lbl640;
                    }
                    else
                    {
                        // ZY(JX,4) = (W4*ZB(JX-1,4)+W5*ZB(JX-1,5))/(W4+W5)
                        zy[sh.JX, 4] = ((sh.W4 * zb[sh.JX - 1, 4]) + (sh.W5 * zb[sh.JX - 1, 5])) / (sh.W4 + sh.W5);
                        if (float.IsNaN(zy[sh.JX, 4]))
                        {
                            zy[sh.JX, 4] = 0.0f;
                        }

                        // ZX(JX,4) = ZX(JX,3) + ZX(JX,3) - ZX(JX,2)
                        zx[sh.JX, 4] = (zx[sh.JX, 3] + zx[sh.JX, 3]) - zx[sh.JX, 2];

                        // ZXY(JX,4) = ZXY(JX,3) + ZXY(JX,3) - ZXY(JX,2)
                        zxy[sh.JX, 4] = (zxy[sh.JX, 3] + zxy[sh.JX, 3]) - zxy[sh.JX, 2];
                    }

lbl640:

                    // DO 650 JY=2,3
                    for (sh.JY = 2; sh.JY <= 3; sh.JY++)
                    {
                        zy[sh.JX, sh.JY]  = zy[sh.JX, sh.JY + 1];  // ZY(JX,JY) = ZY(JX,JY+1)
                        zx[sh.JX, sh.JY]  = zx[sh.JX, sh.JY + 1];  // ZX(JX,JY) = ZX(JX,JY+1)
                        zxy[sh.JX, sh.JY] = zxy[sh.JX, sh.JY + 1]; // ZXY(JX,JY) = ZXY(JX,JY+1)
                    }
                }

                y3        = zy.Y4;                      // Y3 = Y4
                sh.Z33    = sh.Z33 + (zb.Z3B3 / b3);    // Z33 = Z33 + Z3B3/B3
                za.Z3A3   = za.Z3A3 + (zab.ZA3B3 / b3); // Z3A3 = Z3A3 + ZA3B3/B3
                zb.Z3B3   = zb.Z3B4;                    // Z3B3 = Z3B4
                zab.ZA3B3 = zab.ZA3B4;                  // ZA3B3 = ZA3B4
                b3        = zy.B2;                      // B3 = B2

lbl670:

                // IF (IX.NE.1 .AND. IX.NE.LXP1) GO TO 680
                if (zxy.IX != 1 && zxy.IX != zx.LXP1)
                {
                    goto lbl680;
                }

                sh.JX  = (zxy.IX / zx.LXP1) + 2; // JX = IX/LXP1 + 2
                sh.JX1 = 5 - sh.JX;              // JX1 = 5 - JX
                sh.JY  = (zxy.IY / zy.LYP1) + 2; // JY = IY/LYP1 + 2
                sh.JY1 = 5 - sh.JY;              // JY1 = 5 - JY

                // ZX(JX,JY) = ZX(JX1,JY) + ZX(JX,JY1) - ZX(JX1,JY1)
                zx[sh.JX, sh.JY] = (zx[sh.JX1, sh.JY] + zx[sh.JX, sh.JY1]) - zx[sh.JX1, sh.JY1];

                // ZY(JX,JY) = ZY(JX1,JY) + ZY(JX,JY1) - ZY(JX1,JY1)
                zy[sh.JX, sh.JY] = (zy[sh.JX1, sh.JY] + zy[sh.JX, sh.JY1]) - zy[sh.JX1, sh.JY1];

                // ZXY(JX,JY) = ZXY(JX1,JY) + ZXY(JX,JY1) - ZXY(JX1,JY1)
                zxy[sh.JX, sh.JY] = (zxy[sh.JX1, sh.JY] + zxy[sh.JX, sh.JY1]) - zxy[sh.JX1, sh.JY1];

                ////  DETERMINATION OF THE COEFFICIENTS OF THE POLYNOMIAL

lbl680:
                zx3b3   = (zx.ZX34 - zx.ZX33) * b3;                                // ZX3B3 = (ZX34-ZX33)*B3
                zx4b3   = (zx.ZX44 - zx.ZX43) * b3;                                // ZX4B3 = (ZX44-ZX43)*B3
                zy3a3   = (zy.ZY43 - zy.ZY33) * a3;                                // ZY3A3 = (ZY43-ZY33)*A3
                zy4a3   = (zy.ZY44 - zy.ZY34) * a3;                                // ZY4A3 = (ZY44-ZY34)*A3
                zx.A    = zab.ZA3B3 - zx3b3 - zy3a3 + zxy.ZXY33;                   // A = ZA3B3 - ZX3B3 - ZY3A3 + ZXY33
                zx.B    = zx4b3 - zx3b3 - zxy.ZXY43 + zxy.ZXY33;                   // B = ZX4B3 - ZX3B3 - ZXY43 + ZXY33
                zx.C    = zy4a3 - zy3a3 - zxy.ZXY34 + zxy.ZXY33;                   // C = ZY4A3 - ZY3A3 - ZXY34 + ZXY33
                zy.D    = zxy.ZXY44 - zxy.ZXY43 - zxy.ZXY34 + zxy.ZXY33;           // D = ZXY44 - ZXY43 - ZXY34 + ZXY33
                zy.E    = zx.A + zx.A - zx.B - zx.C;                               // E = A + A - B - C
                zx.A3SQ = a3 * a3;                                                 // A3SQ = A3*A3
                zy.B3SQ = b3 * b3;                                                 // B3SQ = B3*B3
                zx.P02  = ((2.0f * (zb.Z3B3 - zy.ZY33)) + zb.Z3B3 - zy.ZY34) * b3; // P02 = (2*(Z3B3-ZY33)+Z3B3-ZY34)*B3
                zy.P03  = ((-2.0f * zb.Z3B3) + zy.ZY34 + zy.ZY33) * zy.B3SQ;       // P03 = (-2*Z3B3+ZY34+ZY33)*B3SQ
                zy.P12  = ((2.0f * (zx3b3 - zxy.ZXY33)) + zx3b3 - zxy.ZXY34) * b3; // P12 = (2*(ZX3B3-ZXY33)+ZX3B3-ZXY34)*B3
                zy.P13  = ((-2.0f * zx3b3) + zxy.ZXY34 + zxy.ZXY33) * zy.B3SQ;     // P13 = (-2*ZX3B3+ZXY34+ZXY33)*B3SQ
                zy.P20  = ((2.0f * (za.Z3A3 - zx.ZX33)) + za.Z3A3 - zx.ZX43) * a3; // P20 = (2*(Z3A3-ZX33)+Z3A3-ZX43)*A3
                zy.P21  = ((2.0f * (zy3a3 - zxy.ZXY33)) + zy3a3 - zxy.ZXY43) * a3; // P21 = (2*(ZY3A3-ZXY33)+ZY3A3-ZXY43)*A3
                zxy.P22 = ((3.0f * (zx.A + zy.E)) + zy.D) * a3 * b3;               // P22 = (3*(A+E)+D)*A3*B3
                zxy.P23 = ((-3.0f * zy.E) - zx.B - zy.D) * a3 * zy.B3SQ;           // P23 = (-3*E-B-D)*A3*B3SQ
                zxy.P30 = ((-2.0f * za.Z3A3) + zx.ZX43 + zx.ZX33) * zx.A3SQ;       // P30 = (-2*Z3A3+ZX43+ZX33)*A3SQ
                zxy.P31 = ((-2.0f * zy3a3) + zxy.ZXY43 + zxy.ZXY33) * zx.A3SQ;     // P31 = (-2*ZY3A3+ZXY43+ZXY33)*A3SQ
                zxy.P32 = ((-3.0f * zy.E) - zx.C - zy.D) * b3 * zx.A3SQ;           // P32 = (-3*E-C-D)*B3*A3SQ
                zxy.P33 = (zy.D + zy.E + zy.E) * zx.A3SQ * zy.B3SQ;                // P33 = (D+E+E)*A3SQ*B3SQ

                //// COMPUTATION OF THE POLYNOMIAL

lbl690:
                sh.DY = sh.VK - y3;                                                              // DY = VK - Y3
                zx.Q0 = sh.P00 + (sh.DY * (zy.P01 + (sh.DY * (zx.P02 + (sh.DY * zy.P03)))));     // Q0 = P00 + DY*(P01+DY*(P02+DY*P03))
                zx.Q1 = zx.P10 + (sh.DY * (zxy.P11 + (sh.DY * (zy.P12 + (sh.DY * zy.P13)))));    // Q1 = P10 + DY*(P11+DY*(P12+DY*P13))
                zx.Q2 = zy.P20 + (sh.DY * (zy.P21 + (sh.DY * (zxy.P22 + (sh.DY * zxy.P23)))));   // Q2 = P20 + DY*(P21+DY*(P22+DY*P23))
                zy.Q3 = zxy.P30 + (sh.DY * (zxy.P31 + (sh.DY * (zxy.P32 + (sh.DY * zxy.P33))))); // Q3 = P30 + DY*(P31+DY*(P32+DY*P33))
                sh.DX = sh.UK - x3;                                                              //// DX = UK - X3
                w[k]  = zx.Q0 + sh.DX * (zx.Q1 + sh.DX * (zx.Q2 + (sh.DX * zy.Q3)));             //// W(K) = Q0 + DX*(Q1+DX*(Q2+DX*Q3))
            }
        }
        /// <summary>
        /// Calculates the curve matrix.
        /// </summary>
        /// <param name="freq">The FM or TV frequency, in MHz.</param>
        /// <param name="location">The percent of locations .</param>
        /// <param name="time">The percent of time .</param>
        /// <param name="npoints">The number of points to be calculated for the curve.</param>
        /// <param name="distances">Array of NP distances at which the field is to be calculated in kilometers.</param>
        /// <param name="heights">Array of NP antenna heights above average terrain at which the field is to be calculated in meters.</param>
        /// <param name="fieldStrengths">The field strengths.</param>
        public void CalculateCurveMatrix(float freq, int location, int time, int npoints, FArray distances, FArray heights, FArray fieldStrengths)
        {
            //// The arguments are:
            //// freq -- The FM or TV frequency, in MHz, input, real.
            //// location - l -> The percent of locations
            //// time - t -> The percent of time
            //// npoints - np -> The number of points to be calculated for the field strength vs distance curve.
            //// d -- Array of np distances at which the field is to be calculated in kilometers.
            //// h -- Array of np antenna heights above average terrain ( HAAT ) corresponding to the distance values in array
            ////      d at which the field is to be calculated in meters.
            //// fs -- output Array of calculated field strength values corresponding to the requested d and h value in db
            ////       above one microvolt per meter for one kilowatt erp.
            ////  distance in km & height in meters

            var f5050 = new FArray(201);
            var f5010 = new FArray(201);

            BivariateInterpolation interpolator = new BivariateInterpolation();

            // low freq curves
            if (freq < 108.01f)
            {
                interpolator.Interpolate(25, 13, FCCDataMatrix.D50, FCCDataMatrix.H50, FCCDataMatrix.F55LV, npoints, distances, heights, f5050);
                interpolator.Interpolate(31, 13, FCCDataMatrix.D10, FCCDataMatrix.H10, FCCDataMatrix.F51LV, npoints, distances, heights, f5010);
            }
            else if (freq > 470.0f)
            {
                // UHF curves
                interpolator.Interpolate(25, 13, FCCDataMatrix.D50, FCCDataMatrix.H50, FCCDataMatrix.F55UV, npoints, distances, heights, f5050);
                interpolator.Interpolate(31, 13, FCCDataMatrix.D10, FCCDataMatrix.H10, FCCDataMatrix.F51UV, npoints, distances, heights, f5010);
            }
            else if (freq > 108.0f && freq < 470.0f)
            {
                // VHF curves
                interpolator.Interpolate(25, 13, FCCDataMatrix.D50, FCCDataMatrix.H50, FCCDataMatrix.F55HV, npoints, distances, heights, f5050);
                interpolator.Interpolate(31, 13, FCCDataMatrix.D10, FCCDataMatrix.H10, FCCDataMatrix.F51HV, npoints, distances, heights, f5010);
            }

            // if the distance is less than 15 km copy f5050 value to f5010
            for (int i = 1; i <= npoints; i++)
            {
                if (distances[i] < 15)
                {
                    f5010[i] = f5050[i];
                }
            }

            // AN F(50,50) FIELD STRENGTH CURVE HAS BEEN REQUESTED
            if (location == 50 && time == 50)
            {
                for (int i = 1; i <= npoints; i++)
                {
                    fieldStrengths[i] = f5050[i];
                }
            }
            else if (location == 50 && time == 10)
            {
                // AN F(50,10) FIELD STRENGTH CURVE HAS BEEN REQUESTED
                for (int i = 1; i <= npoints; i++)
                {
                    fieldStrengths[i] = f5010[i];
                }
            }
            else if (location == 50 && time == 90)
            {
                // AN F(50,90) FIELD STRENGTH CURVE HAS BEEN REQUESTED
                float zq = 0;

                this.FZQ(location, ref zq);

                float sigma = 8.58f;

                if (freq > 470)
                {
                    sigma = 11.88f;
                }

                float rl = zq * sigma;
                float rt = 0;

                this.FZQ(time, ref zq);

                for (int i = 1; i <= npoints; i++)
                {
                    rt = (f5010[i] - f5050[i]) * zq / 1.28155f;
                    fieldStrengths[i] = (float)(f5050[i] + rl + rt);
                }
            }
        }
        /// <summary>
        /// Calculates the curve value.
        /// </summary>
        /// <param name="erpx">ERP in kW.</param>
        /// <param name="haatx">HAAT in meters.</param>
        /// <param name="ichannel">The channel no.</param>
        /// <param name="field">field strength in dBu.</param>
        /// <param name="distance">distance to the contour in km.</param>
        /// <param name="ichoise">choice 1-&gt; field strength, given distance, 2 -&gt; distance, given field strength.</param>
        /// <param name="isDigital">if set to <c>true</c> [is digital].</param>
        /// <returns>returns field strength or distance.</returns>
        public float CalculateCurveValue(float erpx, float haatx, int ichannel, float field, float distance, int ichoise, bool isDigital)
        {
            //// ichannel --- input channel
            //// ichoise  --- 1 = field strength, given distance;
            ////              2 = distance, given field strength.
            //// erpx -------- proposed erp in kW
            //// haatx ------   proposed haat in meters
            //// field ---   field strength in dBu
            //// distance ----  distance to the contour in km.

            FArray fs = new FArray(201);
            FArray d  = new FArray(201);
            FArray h  = new FArray(201);

            float range    = 100.0f;
            int   n_points = 201;
            float freq     = 0.0f;

            if (ichannel >= 2 && ichannel <= 6)
            {
                freq = 100.0F; // channels 2-6
            }
            else if (ichannel >= 7 && ichannel <= 13)
            {
                freq = 180.1F; // channels 7-13
            }
            else if (ichannel >= 14)
            {
                freq = 480.0F; // channels 14 and above
            }

            float erp_db = (float)(10 * Math.Log10(erpx));

            if (ichoise == 1)
            {
                // find field strength, given distance
                d[1] = (float)distance;
                h[1] = (float)haatx;

                if (isDigital)
                {
                    this.CalculateCurveMatrix(freq, 50, 90, 1, d, h, fs);
                }
                else
                {
                    this.CalculateCurveMatrix(freq, 50, 50, 1, d, h, fs);
                }

                field = erp_db + fs[1];

                return(field);
            }
            else
            {
                float d_first = 1.5f;   // start at 1.5 kM
                float d_last  = 300.0f; // end at 300 kM

                float elevHeight = 0.0f;

                if (haatx < 30)
                {
                    elevHeight = 30;
                }
                else if (haatx > 1600)
                {
                    elevHeight = 1600;
                }
                else
                {
                    elevHeight = haatx;
                }

                for (int kk = 1; kk <= n_points; kk++)
                {
                    // increments of 0.5 km
                    d[kk] = (float)(d_first + ((kk - 1) * 0.5));
                    h[kk] = (float)elevHeight;
                }

lbl510:
                if (isDigital)
                {
                    this.CalculateCurveMatrix(freq, 50, 90, n_points, d, h, fs);
                }
                else
                {
                    this.CalculateCurveMatrix(freq, 50, 50, n_points, d, h, fs);
                }

                for (int kk = 1; kk <= n_points; kk++)
                {
                    fs[kk] = (float)(fs[kk] + erp_db);
                    ////Console.WriteLine("Index :- " + kk + " :: " + fs[kk]);
                }

                // check the first point
                if (field > fs[1])
                {
                    // free space equation
                    float e_volts_meter = (float)(1.0E-6 * Math.Pow(10.0, field / 20.0));

                    if (isDigital)
                    {
                        distance = (float)(0.007014271F * Math.Sqrt(erpx * 1000));
                    }
                    else
                    {
                        distance = (float)(0.007014271F * Math.Sqrt(erpx * 1000)) / e_volts_meter;
                        if (distance > 1.5)
                        {
                            distance = 1.5F;
                        }
                    }
                }
                else if (field < fs[n_points])
                {
                    // check the last point
                    for (int i = 1; i <= n_points; i++)
                    {
                        d[i] = d[i] + range;
                    }

                    if (d[1] < d_last)
                    {
                        goto lbl510;
                    }
                    else
                    {
                        // if distance is greater than last curve value then set it to last curve value
                        distance = d_last;
                    }
                }
                else
                {
                    // field value lies within the range
                    for (int i = 2; i <= n_points; i++)
                    {
                        if (field <= fs[i - 1] && field >= fs[i])
                        {
                            distance = ((field - fs[i - 1]) / (fs[i] - fs[i - 1]) * (d[i] - d[i - 1])) + d[i - 1];

                            if (distance > d_last)
                            {
                                // if distance is greater than last curve value then set it to last curve value
                                distance = d_last;
                            }

                            break;
                        }
                    }
                }

                return(distance);
            }
        }